Difference between revisions of "Modding:Migrate to Stardew Valley 1.6"

m (→‎Custom farm animals: Adding Hatching data : still missing some elements.)
m (Pet behaviour Name key renamed to Id)
 
Line 2: Line 2:
  
 
{{Modder compatibility header}}
 
{{Modder compatibility header}}
{{SMAPI upcoming|4.0.0}}
 
  
This page explains how to update your mods for compatibility with the next major game version (tentatively {{version|1.6.0|Stardew Valley 1.6.0}}), and documents some of the changes and new functionality. See also [[Modding:Migrate to SMAPI 4.0|''Migrate to SMAPI 4.0'']].
+
This page explains how to update your mods for compatibility with {{version|1.6|Stardew Valley 1.6}}, and documents some of the changes and new functionality. See also [[Modding:Migrate to SMAPI 4.0|''Migrate to SMAPI 4.0'']].
 
 
'''This describes an unreleased alpha version of the game. Things ''will'' change before it's released!'''
 
  
 
{{TOC|limit=3}}
 
{{TOC|limit=3}}
Line 15: Line 12:
  
 
===Is this the modapocalypse?===
 
===Is this the modapocalypse?===
Maybe. The update includes major changes to fundamental parts of the game, and SMAPI and Content Patcher can't feasibly rewrite older mods for compatibility with these changes. This will break a large proportion of existing mods until they're updated for the changes. However, per discussion between the game developers and modding community, we've agreed that this short-term pain is more than offset by the huge long-term improvements to modding.
+
Maybe. The update includes major changes to fundamental parts of the game, and SMAPI and Content Patcher can't feasibly rewrite every older mod for compatibility with some of the changes. This will break many existing mods until they're updated for the changes. However, per discussion between the game developers and modding community, we've agreed that this short-term pain is more than offset by the huge long-term improvements to modding.
  
 
===How to update your mod===
 
===How to update your mod===
# Update your mod code and assets for the changes listed below (particularly [[#Breaking changes for C# mods|''Breaking changes for C# mods'']] and [[#Breaking changes for content packs|''Breaking changes for content packs'']]).
+
The rest of this page may seem overwhelming, but fortunately most of it probably doesn't apply to your specific mods. Here's a suggested 'quick start' guide to update a mod for Stardew Valley 1.6.
# If SMAPI still says your mod is incompatible, check the <samp>TRACE</samp> messages in the log file for the reason why.<br />If the logs say "''marked 'assume broken' in SMAPI's internal compatibility list''", you can increase the <samp>Version</samp> in your content pack's <samp>manifest.json</samp> file to bypass it.
+
 
# Test the mod in-game and make any other changes needed.
+
; For C# mods&#58;
 +
:# Update the [https://www.nuget.org/packages/Pathoschild.Stardew.ModBuildConfig mod build config NuGet package] to the latest version.
 +
:# In each <samp>.csproj</samp> project file, change <code>&lt;TargetFramework&gt;net5.0&lt;/TargetFramework&gt;</code> to <code>&lt;TargetFramework&gt;net6.0&lt;/TargetFramework&gt;</code>.<br /><small>(Tip: if the second line looks like <code>&lt;Project ToolsVersion=...</code> instead of <code>&lt;Project Sdk="Microsoft.NET.Sdk"&gt;</code>, you'll need to [[Modding:Migrate to Stardew Valley 1.5.5|migrate it to Stardew Valley 1.5.5]] first.)</small>
 +
:# Rebuild the solution.
 +
:# Fix any build errors. You can search this page for relevant info as needed.
 +
:# Review all build warnings (particularly obsolete-code warnings), which may indicate code that broke in 1.6.
 +
:# Increment your mod version in <samp>manifest.json</samp>.<br /><small>(Some mods may be added to SMAPI's compatibility blacklist due to runtime errors. Incrementing the mod version will fix that if so.)</small>
 +
:# Test to make sure the mod works.
 +
:# Skim through [[#Breaking changes for C# mods|''breaking changes for C# mods'']] and the table of contents, and check any section that might be relevant to the mod.
 +
 
 +
; For [[Modding:Content Patcher|Content Patcher]] packs&#58;
 +
:# Follow the [https://smapi.io/cp-migrate Content Patcher migration guide] until your content pack has <code>"Format": "2.0.0"</code>.<br /><small>'''Do not skip this step!''' Content Patcher will assume your content pack is pre-1.6 if you don't, which can cause confusing errors if you already updated it.</small>
 +
:# Review [[#Breaking changes for content packs|''breaking changes for content packs'']] and update the content pack as needed.
 +
 
 +
; For content packs which use another framework&#58;
 +
: See the documentation for the framework mod. Often you won't need to update the content pack if the framework mod itself was updated.
  
==What's new for items==
+
==What's new architecturally?==
===Custom items===
+
===.NET 6===
====Overview====
+
: ''See also: [[#.NET 6 2|.NET 6]] under breaking changes.''
Stardew Valley 1.6 makes three major changes to how items work in the game:
+
 
 +
For C# mod authors, Stardew Valley 1.6 updates from .NET 5 to .NET 6. See [https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-6 ''What's new in .NET 6''] and [https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-10 ''What's new in C# 10''] for more info, but some highlights include...
 +
* [https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-6/ improved performance];
 +
* [https://devblogs.microsoft.com/dotnet/update-on-net-hot-reload-progress-and-visual-studio-2022-highlights/ improved hot reload];
 +
* [https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-6#new-linq-apis new LINQ methods];
 +
* [https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/record record structs];
 +
* and support for ARM64 on macOS.
 +
 
 +
===Trigger actions===
 +
{{/doc status|[[Modding:Trigger actions]]|done=true}}
 +
 
 +
Trigger actions are a new feature which lets content packs perform an action when something happens, with support for a wide range of actions (like sending mail, changing friendship, starting a quest, etc).
  
# Each item type now has an <samp>ItemDataDefinition</samp> class which tells the game how to handle it. SMAPI mods can add custom item type definitions or patch the vanilla logic. Each definition has a unique prefix (like <samp>(O)</samp> for objects) which is used in qualified item IDs. The vanilla types are bigcraftables (<samp>(BC)</samp>), boots (<samp>(B)</samp>), furniture (<samp>(F)</samp>), hats (<samp>(H)</samp>), objects (<samp>(O)</samp>), pants (<samp>(P)</samp>), shirts (<samp>(S)</samp>), tools (<samp>(T)</samp>), and weapons (<samp>(W)</samp>).</li>
+
For example, it lets you have logic like "''When the player arrives in the Farm location, if Leo has moved to the valley, then send a letter and start a conversation topic''":
# Each item now has a locally unique string ID (<samp>ItemID</samp>) and a globally unique string ID (<samp>QualifiedItemID</samp>). The <samp>ItemID</samp> is assumed to only contain alphanumeric/underscore/dot characters so they can be used in fields delimited with spaces/slashes/commas, in filenames, etc. The <samp>QualifiedItemID</samp> is auto-generated by prefixing the <samp>ItemID</samp> with the item type identifier.<p>For legacy reasons, the <samp>ItemID</samp> for vanilla item isn't globally unique. For example, Pufferfish (object 128) and Mushroom Box (bigcraftable 128) both have <samp>ItemID: 128</samp>. They can be distinguished by their <samp>QualifiedItemID</samp>, which is <samp>(O)128</samp> and <samp>(BC)128</samp> respectively.</p><p>For mod items, both IDs should be globally unique. By convention the <samp>ItemID</samp> should include your mod ID or author name, like <samp>Example.ModId_ItemName</samp>.</p>
+
<syntaxhighlight lang="js">
# Custom items can now provide their own item texture, specified in a new field in the item data assets (see below). The item's <samp>ParentSheetIndex</samp> field is the index within that texture.
+
{
 +
    "Trigger": "LocationChanged",
 +
    "Location": "Farm",
 +
    "Condition": "PLAYER_HAS_FLAG Host leoMoved",
 +
    "Actions": [
 +
        "AddMail Current Abigail_LeoMoved Today",
 +
        "AddConversationTopic LeoMoved 5"
 +
    ]
 +
}
 +
</syntaxhighlight>
  
In other words, the three important fields for items are:
+
===Hash set fields===
 +
For C# mod authors, the game now uses [https://www.bytehide.com/blog/hashset-csharp hash sets] for many list fields which expect unique values. That allows much more efficient O(1) read/write, prevents duplicate values, and simplifies common logic.
  
 +
This affects:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! name
 
 
! type
 
! type
! description
+
! fields
 +
|-
 +
| <samp>Farmer</samp>
 +
| <samp>achievements</samp><br /><samp>dialogueQuestionsAnswered</samp><br /><samp>eventsSeen</samp><br /><samp>mailForTomorrow</samp><br /><samp>mailReceived</samp><br /><samp>professions</samp><br /><samp>secretNotesSeen</samp><br /><samp>songsHeard</samp>
 
|-
 
|-
| <samp>ItemID</samp>
+
| <samp>FarmerTeam</samp>
| <samp>string</samp>
+
| <samp>acceptedSpecialOrderTypes</samp><br /><samp>broadcastedMail</samp><br /><samp>completedSpecialOrders</samp><br /><samp>collectedNutTracker</samp>
| An item key which is only unique within its item type, like <samp>128</samp> (vanilla item) or <samp>Example.ModId_Watermelon</samp> (custom item).
 
 
|-
 
|-
| <samp>QualifiedItemID</samp>
+
| <samp>Game1</samp>
| <samp>string</samp>
+
| <samp>worldStateIDs</samp>
| A globally unique item key, like <samp>(O)128</samp> (vanilla item) or <samp>(O)Example.ModId_Watermelon</samp> (custom item).
 
 
|-
 
|-
| <samp>ParentSheetIndex</samp>
+
| <samp>NetWorldState</samp>
| <samp>int</samp>
+
| <samp>ActivePassiveFestivals</samp><br /><samp>CheckedGarbage</samp><br /><samp>FoundBuriedNuts</samp><br /><samp>IslandVisitors</samp><br /><samp>LocationsWithBuildings</samp>
| The item's image sprite within its spritesheet (whether it's a vanilla spritesheet or custom one).
 
 
|}
 
|}
  
====Item references====
+
Usage is very similar, and many list methods like <samp>Contains</samp> work the same way with hash sets. Here are the main differences:
Item references throughout the game code now use the <samp>ItemID</samp> instead of the <samp>ParentSheetIndex</samp>. Since the <samp>ItemID</samp> is identical to the index for existing vanilla items, most data assets are unaffected by this change. For example, here's from <samp>Data/NPCDispositions</samp> with one custom item:
+
<ul>
<syntaxhighlight lang="json">
+
<li>Hash sets aren't ordered. For example, there's no guarantee that the first value when you enumerate it was the earliest one added.</li>
"Universal_Like": "-2 -7 -26 -75 -80 72 395 613 634 635 636 637 638 724 459 Example.ModID_watermelon"
+
<li><p>Hash sets can't be indexed. For example, you can no longer use <code>list[0]</code> to get the first value. You can still enumerate them or use LINQ methods like <samp>set.First()</samp>, but in most cases you should use the set methods like <samp>Add</samp> or <samp>Contains</samp> instead.</p>
 +
 
 +
To remove multiple matching values from the set, you can use <samp>RemoveWhere</samp> instead:
 +
<syntaxhighlight lang="c#">
 +
// old code
 +
for (int i = Game1.player.mailReceived.Count - 1; i >= 0; i--)
 +
{
 +
    if (Game1.player.mailReceived[i].StartsWith("Example.ModId_"))
 +
        Game1.player.mailReceived.RemoveAt(i);
 +
}
 +
 
 +
// new code
 +
Game1.player.mailReceived.RemoveWhere(id => id.StartsWith("Example.ModId_"));
 +
</syntaxhighlight>
 +
</li>
 +
<li>You no longer need to check before adding a value, since the hash set will ignore duplicates.</li>
 +
<li>The <samp>Add</samp>/<samp>Remove</samp>/<samp>RemoveWhere</samp> methods return whether a value was added/removed, which lets you check at the same time. For example:
 +
<syntaxhighlight lang="c#">
 +
if (Game1.player.mailReceived.Add("BackpackTip")) // returns true if it wasn't in the set yet
 +
    Game1.addMailForTomorrow("pierreBackpack");
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
</li>
 +
</ul>
  
Unless otherwise noted, unqualified item IDs will produce [[Modding:Items|objects]]. Some assets let you override that by specifying a <samp>QualifiedItemID</samp> value instead. For example, you can add <code>(O)128</code> to the gift taste list to explicitly add for an object. Here's a partial list of data assets and their supported item ID formats:
+
===DataLoader===
 +
<samp>DataLoader</samp> is a new C# utility which provides strongly-typed methods to load the game's data assets.
  
{| class="wikitable"
+
This solves an issue where we often needed fragile code like <code>Game1.content.Load<Dictionary<string, PassiveFestivalData>>("Data\\PassiveFestivals")</code>. With that code, it's easy to accidentally misspell the asset name, use different capitalization (which would break on Linux/macOS), or use the wrong return type. If you did, you likely wouldn't notice until the code actually executed at runtime and threw an exception.
|-
+
 
! data asset
+
In Stardew Valley 1.6, you can now rewrite that code like <code>DataLoader.PassiveFestivals(Game1.content)</code>. That's simpler, you can't use the wrong asset name or type, and it's more future-proof in case the game changes them.
! item ID format
+
 
|-
+
===Unique string IDs===
| [[Modding:Recipe data|<samp>Data/CraftingRecipes</samp><br /><samp>Data/CookingRecipes</samp>]]
+
{{/doc status|[[Modding:Common data field types#Unique string ID]]|done=true}}
| &#32;
+
 
* Ingredients: both supported.
+
Stardew Valley now uses ''unique string IDs'' throughout the code to identify data (like events, locations, items, NPCs, etc). For example, <code>Town</code> is the unique ID for the [[Pelican Town]] location; no other location can use that ID. The IDs are used for a wide range of purposes, from internal game logic to [[Modding:Content Patcher|content pack edits]].
* Output: set field 2 to the unqualified item ID, and field 3 to one of <samp>true</samp> (bigcraftable) or <samp>false</samp> (object) or an item type identifier like <samp>BC</samp>.
+
 
|-
+
For mods, it's '''strongly recommended''' to...
| [[#Custom fruit trees|<samp>Data/fruitTrees</samp>]]
+
* Use namespaced IDs prefixed with your [[Modding:Modder Guide/APIs/Manifest#Basic fields|mod's unique ID]] for all new content. For example, if your mod ID is <code>Example.PufferchickMod</code> and you're adding a pufferchick plushy, your item ID would look like <code>Example.PufferchickMod_PufferchickPlushy</code>. In a [[Modding:Content Patcher|Content Patcher pack]], you can use <code><nowiki>{{ModId}}_PufferchickPlushy</nowiki></code> to insert your mod ID automatically. This eliminates ID conflicts between mods, and makes it easy (for both troubleshooters and mod code) to identify which mod added a particular content. See [[Modding:Common data field types#Unique string ID|the new format docs]] for the recommended format.
| &#32;
+
* Only use alphanumeric (a–z, A–Z, 0–9), underscore (<code>_</code>), and dot (<code>.</code>) characters in string IDs. This is important because they're often used in places where some characters have special meaning (like file names or [[#Game state queries|game state queries]]).
* Fruit: both supported.
+
 
* Sapling: unqualified only.
+
You can optionally migrate pre-1.6 content to use unique string IDs too, without breaking existing players' saves. This is recommended to reduce mod conflicts and simplify troubleshooting going forward. Here's how to migrate for each data type:
|-
+
{{collapse|migration steps for pre-1.6 content|content=&#32;
| [[Modding:Gift taste data|<samp>Data/NPCGiftTastes</samp>]]
+
{{{!}} class="wikitable"
| Both supported, but only <samp>(O)</samp> items can be gifted.
+
{{!}}-
|}
+
! content type
 +
! how to change IDs
 +
{{!}}-
 +
{{!}} [[Modding:Event data|event IDs]]<br />[[Modding:Items|item IDs]]<br />[[Modding:Mail data|mail IDs]]<br />[[Modding:Recipe data|recipe IDs]]<br />[[#Custom jukebox tracks|song IDs for jukebox]]
 +
{{!}} [[Modding:Content Patcher|Content Patcher]] adds a custom [[Modding:Trigger actions|trigger action]] which can migrate IDs everywhere in the save data.
 +
 
 +
For example, this migrates two crafting recipe IDs:
 +
<syntaxhighlight lang="js">
 +
{
 +
    "Action": "EditData",
 +
    "Target": "Data/TriggerActions",
 +
    "Entries": {
 +
        "{{ModId}}_MigrateToUniqueIds": {
 +
            "Id": "{{ModId}}_MigrateToUniqueIds",
 +
            "Trigger": "DayStarted",
 +
            "Actions": [
 +
                // Note: use double-quotes around an argument if it contains spaces. This example has single-quotes for
 +
                // the action itself, so we don't need to escape the double-quotes inside it.
 +
                'Pathoschild.ContentPatcher_MigrateIds CraftingRecipes "Puffer Plush" {{ModId}}_PufferPlush "Puffer Sofa" {{ModId}}_PufferSofa'
 +
            ],
 +
            "HostOnly": true
 +
        }
 +
    }
 +
}
 +
</syntaxhighlight>
 +
 
 +
See the [https://github.com/Pathoschild/StardewMods/blob/develop/ContentPatcher/docs/author-guide/trigger-actions.md Content Patcher docs] for more info about using the trigger action, including restrictions and valid ID types.
 +
{{!}}-
 +
{{!}} [[Modding:Location data|location IDs]]
 +
{{!}} Add the old name to the location's <samp>FormerLocationNames</samp> field in <samp>Data/Locations</samp>.
 +
{{!}}-
 +
{{!}} [[Modding:NPC data|NPC internal names]]
 +
{{!}} Add the old name to the NPC's <samp>FormerCharacterNames</samp> field in <samp>Data/Characters</samp>.
 +
{{!}}-
 +
{{!}} [[Modding:Quest data|quest]] and [[Modding:Special orders|special order]] IDs
 +
{{!}} Currently there's no safe way to migrate quest and special order IDs, since removing and readding them will reset any progress the player has made on them.
 +
{{!}}}
 +
}}
 +
 
 +
==What's new for items==
 +
===Custom items===
 +
{{/doc status|[[Modding:Items]]|done=false}}
 +
 
 +
====Overview====
 +
Stardew Valley 1.6 makes three major changes to how items work in the game:
 +
 
 +
# Each item now has a string ID (<samp>ItemId</samp>) and a globally unique string ID (<samp>QualifiedItemId</samp>). The <samp>QualifiedItemId</samp> is auto-generated by prefixing the <samp>ItemId</samp> with the item type identifier.<p>For legacy reasons, the <samp>ItemId</samp> for vanilla items may not be globally unique. For example, Pufferfish (object 128) and Mushroom Box (bigcraftable 128) both have <samp>ItemId: 128</samp>. They can be distinguished by their <samp>QualifiedItemId</samp>, which are <samp>(O)128</samp> and <samp>(BC)128</samp> respectively.
 +
# Each item type now has an ''item data definition'' in the game code which tells the game how to handle it. [[#For C# mods|C# mods can add or edit definitions]]. Each definition has a unique prefix which is used in the qualified item IDs. The vanilla types are bigcraftables (<samp>(BC)</samp>), boots (<samp>(B)</samp>), farmhouse flooring (<samp>(FL)</samp>), furniture (<samp>(F)</samp>), hats (<samp>(H)</samp>), objects (<samp>(O)</samp>), pants (<samp>(P)</samp>), shirts (<samp>(S)</samp>), tools (<samp>(T)</samp>), wallpaper (<samp>(WP)</samp>), and weapons (<samp>(W)</samp>).</li>
 +
# Custom items can now provide their own item texture, specified in a new field in the item data assets (see below). The item's <samp>ParentSheetIndex</samp> field is the index within that texture.
 +
 
 +
In other words, the four important fields for items are:
  
====Define a custom item====
 
<dl style="margin-left: 2em;">
 
<dt>Overview</dt>
 
<dd>
 
You can define custom items for most vanilla item types using only [[Modding:Content Patcher|Content Patcher]] or [[Modding:Modder Guide/APIs/Content|SMAPI's content API]]. The data asset for each item type has two new fields:
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! name
! effect
+
! type
 +
! description
 
|-
 
|-
| texture name
+
| <samp>ItemId</samp>
| The asset name for the texture under the game's <samp>Content</samp> folder. Use <samp>\</samp> (or <samp>\\</samp> in JSON) to separate name segments if needed. For example, objects use <samp>Maps\springobjects</samp> by default.
+
| <samp>string</samp>
 +
| A [[Modding:Common data field types#Unique string ID|unique string ID]] for this item which should be globally unique (but may not be for existing vanilla items for backwards compatibility). For example, <samp>128</samp> (vanilla item) or <samp>Example.ModId_Watermelon</samp> (custom item).
 +
|-
 +
| <samp>QualifiedItemId</samp>
 +
| <samp>string</samp>
 +
| A globally unique item key, like <samp>(O)128</samp> for a vanilla item or <samp>(O)Example.ModId_Watermelon</samp> for a custom one. This is auto-generated from the <samp>TypeDefinitionId</samp> and <samp>ItemId</samp> fields.
 +
|-
 +
| <samp>ParentSheetIndex</samp>
 +
| <samp>int</samp>
 +
| The item's sprite index within its spritesheet.
 +
|-
 +
| <samp>TypeDefinitionId</samp>
 +
| <samp>string</samp>
 +
| The ID for the data definition which defines the item, like <samp>(O)</samp> for an object. You can use <samp>ItemRegistry.type_*</samp> constants with this field:
 +
<syntaxhighlight lang="c#">
 +
if (item.TypeDefinitionId == ItemRegistry.type_object)
 +
  ...
 +
</syntaxhighlight>
 +
|}
 +
 
 +
====Item references====
 +
Item references throughout the game code now use the <samp>ItemId</samp> instead of the <samp>ParentSheetIndex</samp>. Since the <samp>ItemId</samp> is identical to the index for existing vanilla items, most data assets are unaffected by this change. For example, here's from <samp>Data/NPCGiftTastes</samp> with one custom item:
 +
<syntaxhighlight lang="json">
 +
"Universal_Like": "-2 -7 -26 -75 -80 72 395 613 634 635 636 637 638 724 459 Example.ModID_watermelon"
 +
</syntaxhighlight>
 +
 
 +
Unless otherwise noted, unqualified item IDs will produce [[Modding:Items|objects]]. Some assets let you override that by specifying a <samp>QualifiedItemId</samp> value instead. For example, you can add <code>(O)128</code> to the gift taste list to explicitly add for an object. Here's a partial list of data assets and their supported item ID formats:
 +
 
 +
{| class="wikitable"
 
|-
 
|-
| sprite index
+
! data asset
| The index of the sprite within the above texture, starting at 0 for the top-left sprite.
+
! item ID format
 +
|-
 +
| [[Modding:Recipe data|<samp>Data/CraftingRecipes</samp><br /><samp>Data/CookingRecipes</samp>]]
 +
| &#32;
 +
* Ingredients: both supported.
 +
* Output: set field 2 to the unqualified item ID, and field 3 to one of <samp>true</samp> (bigcraftable) or <samp>false</samp> (object).
 +
|-
 +
| [[#Custom fruit trees|<samp>Data/fruitTrees</samp>]]
 +
| &#32;
 +
* Fruit: both supported.
 +
* Sapling: unqualified only.
 +
|-
 +
| [[Modding:Gift taste data|<samp>Data/NPCGiftTastes</samp>]]
 +
| Both supported, but only <samp>(O)</samp> items can be gifted.
 
|}
 
|}
  
Supported item types:
+
====Item types====
 +
These are the item types for which custom items can added/edited:
  
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
 
! item type
 
! item type
 +
! type identifier
 
! data asset
 
! data asset
! sprite index index
 
! texture name index
 
! default texture name
 
 
|-
 
|-
 
| [[Modding:Items|big craftables]]
 
| [[Modding:Items|big craftables]]
| <samp>Data/BigCraftablesInformation</samp>
+
| <samp>(BC)</samp>
| 10
+
| <samp>Data/BigCraftables</samp><br /><small>Each item can set a custom texture name in the <samp>Texture</samp> field, and sprite index in the <samp>SpriteIndex</samp> field. The default texture is <samp>TileSheets/Craftables</samp>.</small>
| 11
 
| <samp>TileSheets/Craftables</samp>
 
 
|-
 
|-
 
| boots
 
| boots
| <samp>Data/Boots</samp>
+
| <samp>(B)</samp>
| item sprite: 8<br />shoe color: 5
+
| <samp>Data/Boots</samp><br /><small>Each item can set a custom texture name in fields 9 (item) and 7 (shoe color), and sprite index in fields 8 (item) and 5 (shoe color). The default textures are <samp>Maps/springobjects</samp> (item) and <samp>Characters/Farmer/shoeColors</samp> (shoe color).</small>
| item sprite: 9<br />shoe color: 7
 
| item sprite: <samp>Maps/springobjects</samp><br />shoe color: <samp>Characters/Farmer/shoeColors</samp>
 
 
|-
 
|-
 
| [[Modding:Crop data|crops]]
 
| [[Modding:Crop data|crops]]
| <samp>Data/Crops</samp>
+
| <small>''not technically an item type''</small>
| 2
+
| <samp>Data/Crops</samp><br /><small>Each crop can set a custom texture name and sprite index. The default texture is <samp>TileSheets/crops</samp>.</small>
| 9
 
| <samp>TileSheets/crops</samp>
 
 
|-
 
|-
 
| [[Modding:Fish data|fish (in fish tanks)]]
 
| [[Modding:Fish data|fish (in fish tanks)]]
| <samp>Data/AquariumFish</samp>
+
| <small>''not technically an item type''</small>
| 0
+
| <samp>Data/AquariumFish</samp><br /><small>Each fish can set a custom aquarium texture name in field 6, and sprite index in field 0. The default texture is <samp>LooseSprites/AquariumFish</samp>.</small>
| 6
+
|-
| <samp>LooseSprites/AquariumFish</samp>
 
|-
 
 
| [[Modding:Items|furniture]]
 
| [[Modding:Items|furniture]]
| <samp>Data/Furniture</samp>
+
| <samp>(F)</samp>
| 8
+
| <samp>Data/Furniture</samp><br /><small>Each item can set a custom texture name in field 9, and sprite index in field 8. The default texture is <samp>TileSheets/furniture</samp>.</small>
| 9
 
| <samp>TileSheets/furniture</samp>
 
 
|-
 
|-
 
| fruit trees
 
| fruit trees
| <samp>Data/FruitTrees</samp>
+
| <small>''not technically an item type''</small>
| 0
+
| <samp>Data/FruitTrees</samp><br /><small>Each fruit tree can set a custom texture name and sprite index. The default texture is <samp>TileSheets/fruitTrees</samp>.</small>
| 4
 
| <samp>TileSheets/fruitTrees</samp>
 
|-
 
 
|-
 
|-
 
| [[Modding:Items|hats]]
 
| [[Modding:Items|hats]]
| <samp>Data/Hats</samp>
+
| <samp>(H)</samp>
| 6
+
| <samp>Data/Hats</samp><br /><small>Each item can set a custom texture name in field 7, and sprite index in field 6. The default texture is <samp>Characters/Farmer/hats</samp>.</small>
| 7
 
| <samp>Characters/Farmer/hats</samp>
 
 
|-
 
|-
 
| [[Modding:Items|objects]]
 
| [[Modding:Items|objects]]
| <samp>Data/ObjectInformation</samp>
+
| <samp>(O)</samp>
| 9
+
| <samp>Data/Objects</samp><br /><small>Each item can set a custom texture name in the <samp>Texture</samp> field, and sprite index in the <samp>SpriteIndex</samp> field. The default texture is <samp>Maps/springobjects</samp>.</small>
| 10
+
|-
| <samp>Maps/springobjects</samp>
+
| [[#Custom pants|pants]]
 +
| <samp>(P)</samp>
 +
| <samp>Data/pantsData</samp><br /><small>Each item can set a custom texture name in the <samp>Texture</samp> field, and sprite index in the <samp>SpriteIndex</samp> field. The default texture is <samp>Characters/Farmer/pants</samp>.</small>
 +
|-
 +
| [[#Custom shirts|shirts]]
 +
| <samp>(S)</samp>
 +
| <samp>Data/shirtData</samp><br /><small>Each item can set a custom texture name in the <samp>Texture</samp> field, and sprite index in the <samp>SpriteIndex</samp> field. The default texture is <samp>Characters/Farmer/shirts</samp>.</small>
 +
 
 +
<small>Shirt textures must be exactly 256 pixels wide, divided into two halves: the left half for the shirt sprites, and the right half for any dye masks. The remaining space can be left blank if needed.</small>
 +
<pre>
 +
      sprites      dye masks
 +
  /-----------\  /-----------\
 +
┌────────────────────────────────┐
 +
│ ┌───┐┌───┐┌───┐┌───┐┌───┐┌───┐ │
 +
│ │ 0 ││ 1 ││ 2 ││ a ││ b ││ c │ │
 +
│ └───┘└───┘└───┘└───┘└───┘└───┘ │
 +
│ ┌───┐┌───┐┌───┐┌───┐┌───┐┌───┐ │
 +
│ │ 3 ││ 4 ││ 5 ││ d ││ e ││ f │ │
 +
│ └───┘└───┘└───┘└───┘└───┘└───┘ │
 +
└────────────────────────────────┘
 +
</pre>
 
|-
 
|-
| pants & shirts
+
| [[#Custom tools|tools]]
| <samp>Data/ClothingInformation</samp>
+
| <samp>(T)</samp>
| male: 3<br />female: 4
+
| <samp>Data/Tools</samp><br /><small>Each item can set a custom texture name in the <samp>Texture</samp> field, and sprite index in the <samp>SpriteIndex</samp> field. The vanilla tools use the <samp>TileSheets/Tools</samp> texture.</small>
| 10
 
| <samp>Characters/Farmer/pants</samp><br /><samp>Characters/Farmer/shirts</samp>
 
 
|-
 
|-
| tools
+
| Wallpaper & floorpaper
| <samp>Data/ToolData</samp>
+
| <samp>(WP)</samp> and <samp>(FL)</samp>
| 3
+
| <samp>Data/AdditionalWallpaperFlooring</samp><br /><small>See [[Modding:Migrate to Stardew Valley 1.5.5#In the furniture catalogue|format docs]].</small>
| 4
 
| <samp>TileSheets/Tools</samp>
 
 
|-
 
|-
 
| [[Modding:Items|weapons]]
 
| [[Modding:Items|weapons]]
| <samp>Data/Weapons</samp>
+
| <samp>(W)</samp>
| 15
+
| <samp>Data/Weapons</samp><br /><small>[[#Custom melee weapons|Completely overhauled]] into a data model.</small>
| 16
 
| <samp>TileSheets/weapons</samp>
 
 
|}
 
|}
 +
 +
When resolving an unqualified item ID like <samp>128</samp>, the game will get the first item type for which it exists in this order: object, big craftable, furniture, weapon, boots, hat, pants, shirt, tool, wallpaper, and floorpaper.
 +
 +
====Define a custom item====
 +
You can define custom items for most vanilla item types using only [[Modding:Content Patcher|Content Patcher]] or [[Modding:Modder Guide/APIs/Content|SMAPI's content API]].
  
 
For example, this content pack adds a new Pufferchick item with a custom image, custom gift tastes, and a custom crop that produces it. Note that item references in other data assets like <samp>Data/Crops</samp> and <samp>Data/NPCGiftTastes</samp> use the item ID.
 
For example, this content pack adds a new Pufferchick item with a custom image, custom gift tastes, and a custom crop that produces it. Note that item references in other data assets like <samp>Data/Crops</samp> and <samp>Data/NPCGiftTastes</samp> use the item ID.
Line 183: Line 328:
 
         {
 
         {
 
             "Action": "EditData",
 
             "Action": "EditData",
             "Target": "Data/ObjectInformation",
+
             "Target": "Data/Objects",
 
             "Entries": {
 
             "Entries": {
                 "Example.ModId_Pufferchick": "Pufferchick/1200/100/Seeds -74/Pufferchick/An example object.////0/Mods\\Example.ModId\\Objects"
+
                 "{{ModId}}_Pufferchick": {
 +
                    "Name": "{{ModId}}_Pufferchick", // best practice to match the ID, since it's sometimes used as an alternate ID (e.g. in Data/CraftingRecipes)
 +
                    "Displayname": "Pufferchick",
 +
                    "Description": "An example object.",
 +
                    "Type": "Seeds",
 +
                    "Category": -74,
 +
                    "Price": 1200,
 +
 
 +
                    "Texture": "Mods/{{ModId}}/Objects",
 +
                    "SpriteIndex": 0
 +
                }
 
             }
 
             }
 
         },
 
         },
Line 197: Line 352:
 
                     "Operation": "Append",
 
                     "Operation": "Append",
 
                     "Target": ["Entries", "Universal_Love"],
 
                     "Target": ["Entries", "Universal_Love"],
                     "Value": "Example.ModId_Pufferchick",
+
                     "Value": "{{ModId}}_Pufferchick",
 
                     "Delimiter": " " // if there are already values, add a space between them and the new one
 
                     "Delimiter": " " // if there are already values, add a space between them and the new one
 
                 }
 
                 }
Line 208: Line 363:
 
             "Target": "Data/Crops",
 
             "Target": "Data/Crops",
 
             "Entries": {
 
             "Entries": {
                 "Example.ModId_Pufferchick": "1 1 1 1 1/spring summer fall/0/Example.ModId_Pufferchick/-1/0/false/false/false/Mods\\Example.ModId\\Crops"
+
                 "{{ModId}}_Pufferchick": {
 +
                    "Seasons": [ "spring", "summer", "fall" ],
 +
                    "DaysInPhase": [ 1, 1, 1, 1, 1 ],
 +
                    "HarvestItemId": "{{ModId}}_Pufferchick",
 +
 
 +
                    "Texture": "Mods/{{ModId}}/Crops",
 +
                    "SpriteIndex": 0
 +
                }
 
             }
 
             }
 
         },
 
         },
Line 215: Line 377:
 
         {
 
         {
 
             "Action": "Load",
 
             "Action": "Load",
             "Target": "Mods/Example.ModId/Crops, Mods/Example.ModId/Objects",
+
             "Target": "Mods/{{ModId}}/Crops, Mods/{{ModId}}/Objects",
 
             "FromFile": "assets/{{TargetWithoutPath}}.png" // assets/Crops.png, assets/Objects.png
 
             "FromFile": "assets/{{TargetWithoutPath}}.png" // assets/Crops.png, assets/Objects.png
         },
+
         }
 
     ]
 
     ]
 
}</nowiki>|lang=javascript}}
 
}</nowiki>|lang=javascript}}
  
Most item data assets work just like <samp>Data/ObjectInformation</samp>. For fruit trees, see [[#Custom fruit trees|custom fruit trees]].
+
Most item data assets work just like <samp>Data/Objects</samp>. See also specific info for [[#Custom fruit trees|custom fruit trees]], [[#Custom tools|custom tools]], and [[#Custom melee weapon data|melee weapons]].
</dd>
+
 
 +
====Error items====
 +
In-game items with no underlying data (e.g. because you removed the mod which adds them) would previously cause issues like invisible items, errors, and crashes. This was partly mitigated by the bundled Error Handler mod.
 +
 
 +
Stardew Valley 1.6 adds comprehensive handling for such items. They'll be shown with a <samp>🛇</samp> sprite in inventory UIs and in-game, the name Error Item, and a description which indicates the missing item ID for troubleshooting.
 +
 
 +
====For C# mods====
 +
<dl style="margin-left: 2em;">
  
<dt>Tools</dt>
+
<dt>Compare items</dt>
 
<dd>
 
<dd>
Tools are defined in the new <samp>Data/ToolData</samp> asset using this field format:
+
Since <samp>Item.QualifiedItemId</samp> is globally unique, it can be used to simplify comparing items. For example:
  
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! index
+
! old code
! field
+
! new code
! purpose
+
|-
 
|-
 
|-
| 0
+
| <samp>item.ParentSheetIndex == 128</samp>
| class
+
| <samp>item.QualifiedItemId == "(O)128"</samp>
| The name of the class in the <code>StardewValley.Tools</code> namespace. The class must have a constructor with no arguments. For example, given a value of <samp>Axe</samp>, the game will create <code>StardewValley.Tools.Axe</code> instances.
 
 
|-
 
|-
| 1<br />2
+
| <samp>IsNormalObjectAtParentSheetIndex(item, 128)</samp>
| name key<br />description key
+
| <samp>item.QualifiedItemId == "(O)128"</samp>
| The string key to load for the tool's in-game display name and description, in the form {{t|asset name}}:{{t|key}} (''e.g.,'', <code>Strings\StringsFromCSFiles:Axe.cs.1</code>). In JSON, use <samp>\\</samp> for any asset path slashes.
 
 
|-
 
|-
| 3
+
| <samp>!item.bigCraftable && item.ParentSheetIndex == 128</samp>
| parent sheet index
+
| <samp>item.QualifiedItemId == "(O)128"</samp>
| The index of the tool's sprite in its spritesheet. Tool upgrades are handled by adding an offset to this index (''e.g.,'', basic axe = ''index'', copper axe = ''index'' + 1, steel axe = ''index'' + 2, etc).
 
 
|-
 
|-
| 4
+
| <samp>item is Boots && item.ParentSheetIndex == 505</samp>
| texture
+
| <samp>item.QualifiedItemId == "(B)505"</samp>
| ''(Optional)'' The asset name for the item's spritesheet.
 
 
|}
 
|}
 +
 +
You can also use <samp>ItemRegistry.QualifyItemId</samp> to convert any item ID into a qualified one (if it's valid), and <samp>ItemRegistry.HasItemId</samp> to check if an item has a qualified or unqualified item ID.
 +
 +
Note that flavored item don't have their own ID. For example, Blueberry Wine and Wine are both <samp>(O)348</samp>. This affects flavored jellies, juices, pickles, and wines. In those cases you should still compare their separate fields like <samp>preservedParentSheetIndex</samp> (which actually contains the preserved item's <samp>ItemId</samp>, not its <samp>ParentSheetIndex</samp>).
 
</dd>
 
</dd>
  
<dt>Melee weapons</dt>
+
<dt>Construct items</dt>
<dd>
+
<dd>Creating items works just like before, except that you now specify the item's <samp>ItemId</samp> (''not'' <samp>QualifiedItemId</samp>) instead of its <samp>ParentSheetIndex</samp>. For example:
Melee weapons are [[Modding:Items#Weapons|defined in <samp>Data/Weapons</samp>]] like before, but you can now add custom behavior by editing the <samp>Data/AdditionalWeaponProperties</samp> asset. This consists of a string → model lookup, where the key is the unqualified [[#Custom items|item ID]] and the value is a model with these fields:
+
 
 +
<syntaxhighlight lang="c#">
 +
new Object("128", 1);                      // vanilla item
 +
new Object("Example.ModId_Watermelon", 1); // custom item
 +
</syntaxhighlight>
 +
 
 +
You can use a new utility method to construct items from their <samp>QualifiedItemId</samp>:
 +
 
 +
<syntaxhighlight lang="c#">
 +
Item item = ItemRegistry.Create("(B)505"); // Rubber Boots
 +
</syntaxhighlight>
 +
</dd>
 +
 
 +
<dt>Define custom item types</dt>
 +
<dd>You can implement <samp>IItemDataDefinition</samp> for your own item type, and call <samp>ItemRegistry.AddTypeDefinition</samp> to register it. This provides all the logic needed by the game to handle the item type: where to get item data, how to draw them, etc.
 +
 
 +
'''This is extremely specialized''', and multiplayer compatibility is unknown. Most mods should add custom items within the existing types instead.</dd>
  
 +
<dt>New <samp>Is*</samp> methods</dt>
 +
<dd>1.6 adds some <samp>StardewValley.Object</samp> methods to handle custom items in a generic way (and to let mods patch the logic):
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! method
 
! effect
 
! effect
 
|-
 
|-
| <samp>SpecialAttack</samp>
+
| <samp>object.IsBar()</samp>
| ''(Optional)'' The secondary attack type. This can be one of [[Weapons#Club|<samp>Club</samp>]], [[Weapons#Dagger|<samp>Dagger</samp>]], or [[Weapons#Sword|<samp>Sword</samp>]]. Any other value is ignored.
+
| Whether the item is a [[Copper Bar|copper bar]], [[Iron Bar|iron bar]], [[Gold Bar|gold bar]], [[Iridium Bar|iridium bar]], or [[Radioactive Bar|radioactive bar]].
 
|-
 
|-
| <samp>Projectiles</samp>
+
| <samp>object.IsBreakableStone()</samp>
| ''(Optional)'' The projectiles fired when the weapon is used, which continue along their path until they hit a monster and cause damage. These always cause 10 damage and use a generic glowing-yellow-ball sprite. This consists of a list of models with these fields (one projectile will fire for each entry in the list):
+
| Whether the item is a stone debris item which can be broken by a pickaxe.
{| class="wikitable"
 
 
|-
 
|-
! field
+
| <samp>object.IsFence()</samp>
! effect
+
| Whether the item is a [[Crafting#Fences|fence]].
 +
|-
 +
| <samp>object.IsFruitTreeSapling()</samp>
 +
| Whether the item is a [[Fruit Trees|fruit tree]] sapling. This checks the <samp>Data\fruitTrees</samp> keys, so it works with custom fruit trees too.
 +
|-
 +
| <samp>object.IsHeldOverHead()</samp>
 +
| Whether the player is shown holding up the item when it's selected in their toolbar. Default true (except for furniture).
 +
|-
 +
| <samp>object.IsIncubator()</samp>
 +
| Whether the item can incubate [[Animals|farm animal]] eggs when placed in a building.
 +
|-
 +
| <samp>object.IsTapper()</samp>
 +
| Whether the item is a [[Tapper|tapper]] or [[Heavy Tapper|heavy tapper]].
 +
|-
 +
| <samp>object.IsTeaSapling()</samp>
 +
| Whether the item is a [[Tea Sapling|tea sapling]].
 
|-
 
|-
| <samp>MinAngleOffset</samp><br /><samp>MaxAngleOffset</samp>
+
| <samp>object.IsTwig()</samp>
| ''(Optional)'' A random offset applied to the direction of the project each time it's fired. Both fields default to 0, in which case it's always shot at the 90° angle matching the player's facing direction.
+
| Whethere the item is a twig debris item.
|}
 
 
 
Note that these are magic projectiles fired when the weapon is used, these aren't [[slingshot]]-style projectiles.
 
 
|-
 
|-
| <samp>AttackSound</samp><br /><samp>NoAmmoAttackSound</samp><br /><samp>AmmoID</samp>
+
| <samp>object.IsWeeds()</samp>
| ''(Optional)'' '''Unused.'''
+
| Whether the item is a weed debris item.
 
|}
 
|}
 
</dd>
 
</dd>
</dl>
 
  
====Error items====
+
<dt>Work with item metadata</dt>
In-game items with no underlying data (e.g. because you removed the mod which adds them) would previously cause issues like invisible items, errors, and crashes. This was partly mitigated by the bundled ErrorHandler mod.
 
 
 
Stardew Valley 1.6 adds comprehensive handling for such items. They'll be shown with a <samp>🛇</samp> sprite in inventory UIs and in-game, with the name Error Item and a description which indicates the missing item ID for troubleshooting.
 
 
 
====For C# mods====
 
<dl style="margin-left: 2em;">
 
 
 
<dt>Compare items</dt>
 
 
<dd>
 
<dd>
Since <samp>Item.QualifiedItemID</samp> is globally unique, it can be used to simplify comparing items. For example:
+
1.6 adds an <samp>ItemRegistry</samp> API for working with the new item system. Some of the provided methods are:
  
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! old code
+
! method
! new code
+
! effect
 
|-
 
|-
 +
| <samp>ItemRegistry.Create</samp>
 +
| Create an item from its item ID (qualified or unqualified). If the ID doesn't match a real item, the optional <samp>allowNull</samp> parameter indicates whether to return null or an Error Item. For example:
 +
<syntaxhighlight lang="c#">
 +
Item item = ItemRegistry.Create("(B)505"); // Rubber Boots
 +
</syntaxhighlight>
 +
 +
You can also get a specific value type instead of <samp>Item</samp> if needed. This will throw a descriptive exception if the type isn't compatible (e.g. you try to convert furniture to boots).
 +
<syntaxhighlight lang="c#">
 +
Boots item = ItemRegistry.Create<Boots>("(B)505"); // Rubber Boots
 +
</syntaxhighlight>
 
|-
 
|-
| <samp>item.ParentSheetIndex == 128</samp>
+
| <samp>ItemRegistry.Exists</samp>
| <samp>item.QualifiedItemID == "(O)128"</samp>
+
| Get whether a qualified or unqualified item ID matches an existing item. For example:
 +
<syntaxhighlight lang="c#">
 +
bool pufferfishExist = ItemRegistry.Exists("(O)128");
 +
</syntaxhighlight>
 
|-
 
|-
| <samp>IsNormalObjectAtParentSheetIndex(item, 128)</samp>
+
| <samp>ItemRegistry.IsQualifiedId</samp>
| <samp>item.QualifiedItemID == "(O)128"</samp>
+
| Get whether the given item ID is qualified with the type prefix (like <samp>(O)128</samp> instead of <samp>128</samp>).
 
|-
 
|-
| <samp>!item.bigCraftable && item.ParentSheetIndex == 128</samp>
+
| <samp>ItemRegistry.QualifyItemId</samp>
| <samp>item.QualifiedItemID == "(O)128"</samp>
+
| Get the unique qualified item ID given an unqualified or qualified one. For example:
 +
<syntaxhighlight lang="c#">
 +
string qualifiedId = ItemRegistry.QualifyItemId("128"); // returns (O)128
 +
</syntaxhighlight>
 
|-
 
|-
| <samp>item is Boots && item.ParentSheetIndex == 505</samp>
+
| <samp>ItemRegistry.GetMetadata</samp>
| <samp>item.QualifiedItemID == "(B)505"</samp>
+
| This lets you get high-level info about an item:
|}
+
<syntaxhighlight lang="c#">
 +
// get info about Rubber Boots
 +
ItemMetadata info = ItemRegistry.GetMetadata("(B)505");
  
'''Caveat:''' flavored item don't have their own ID. For example, Blueberry Wine and Wine are both <samp>(O)348</samp>. This affects flavored jellies, juices, pickles, and wines. In those cases you should still compare their separate fields like <samp>preservedParentSheetIndex</samp> (which actually contains the preserved item's <samp>ItemID</samp>, not its <samp>ParentSheetIndex</samp>).
+
// get item ID info
</dd>
+
$"The item has unqualified ID {info.LocalId}, qualified ID {info.QualifiedId}, and is defined by the {info.TypeIdentifier} item data definition.";
  
<dt>Construct items</dt>
+
// does the item exist in the data files?
<dd>Creating items works just like before, except that you now specify the item's <samp>ItemID</samp> (''not'' <samp>QualifiedItemID</samp>) instead of its <samp>ParentSheetIndex</samp>. For example:
+
bool exists = info.Exists();
 +
</syntaxhighlight>
  
 +
And get common parsed item data:
 
<syntaxhighlight lang="c#">
 
<syntaxhighlight lang="c#">
new Object("128", 1);                     // vanilla item
+
// get parsed info
new Object("Example.ModId_Watermelon", 1); // custom item
+
ParsedItemData data = info.GetParsedData();
 +
$"The internal name is {data.InternalName}, translated name {data.DisplayName}, description {data.Description}, etc.";
 +
 
 +
// draw an item sprite
 +
Texture2D texture = data.GetTexture();
 +
Rectangle sourceRect = data.GetSourceRect();
 +
spriteBatch.Draw(texture, Vector2.Zero, sourceRect, Color.White);
 
</syntaxhighlight>
 
</syntaxhighlight>
  
You can use a new utility method to construct items from their <samp>QualifiedItemID</samp>:
+
And create an item:
 +
<syntaxhighlight lang="c#">
 +
Item item = metadata.CreateItem();
 +
</syntaxhighlight>
  
 +
And get the type definition (note that this is very specialized, and you should usually use <samp>ItemRegistry</samp> instead to benefit from its caching and optimizations):
 
<syntaxhighlight lang="c#">
 
<syntaxhighlight lang="c#">
Item item = Utility.CreateItemByID("(B)505"); // Rubber Boots
+
IItemDataDefinition typeDefinition = info.GetTypeDefinition();
 
</syntaxhighlight>
 
</syntaxhighlight>
</dd>
 
 
<dt>Define custom item types</dt>
 
<dd>You can subclass <samp>ItemDataDefinition</samp> for your own item type, and add an instance to the <samp>ItemDataDefinition.ItemTypes</samp> and <samp>IdentifierLookup</samp> lists. This provides all the logic needed by the game to handle the item type: where to get item data, how to draw them, etc.
 
 
'''This is extremely specialized''', and multiplayer compatibility is unknown. Most mods should add custom items within the existing types instead.</dd>
 
 
<dt>New <samp>Is*</samp> methods</dt>
 
<dd>1.6 adds some <samp>StardewValley.Object</samp> methods to handle custom items in a generic way (and to let mods patch the logic):
 
{| class="wikitable"
 
 
|-
 
|-
! method
+
| <samp>ItemRegistry.ResolveMetadata</samp>
! effect
+
| Equivalent to <samp>ItemRegistry.GetMetadata</samp>, except that it'll return null if the item doesn't exist.
 
|-
 
|-
| <samp>object.IsBar()</samp>
+
| <samp>ItemRegistry.GetData</samp>
| Whether the item is a [[Copper Bar|copper bar]], [[Iron Bar|iron bar]], [[Gold Bar|gold bar]], [[Iridium Bar|iridium bar]], or [[Radioactive Bar|radioactive bar]].
+
| Get the parsed data about an item, or <samp>null</samp> if the item doesn't exist. This is a shortcut for <code>ItemRegistry.ResolveMetadata(id)?.GetParsedData()</code>; see the previous method for info on the parsed data.
|-
 
| <samp>object.IsFence()</samp>
 
| Whether the item is a [[Crafting#Fences|fence]].
 
 
|-
 
|-
| <samp>object.IsFruitTreeSapling()</samp>
+
| <samp>ItemRegistry.GetDataOrErrorItem</samp>
| Whether the item is a [[Fruit Trees|fruit tree]] sapling. This checks the <samp>Data\fruitTrees</samp> keys, so it works with custom fruit trees too.
+
| Equivalent to <samp>ItemRegistry.GetData</samp>, except that it'll return info for an Error Item if the item doesn't exist (e.g. for drawing in inventory).
 
|-
 
|-
| <samp>object.IsHeldOverHead()</samp>
+
| <samp>ItemRegistry.GetErrorItemName</samp>
| Whether the player is shown holding up the item when it's selected in their toolbar. Default true (except for furniture).
+
| Get a translated ''Error Item'' label.
|-
 
| <samp>object.IsTapper()</samp>
 
| Whether the item is a [[Tapper|tapper]] or [[Heavy Tapper|heavy tapper]].
 
|-
 
| <samp>object.IsTeaSapling()</samp>
 
| Whether the item is a [[Tea Sapling|tea sapling]].
 
 
|}
 
|}
 
</dd>
 
</dd>
 
</dl>
 
</dl>
  
===Custom fences===
+
===Custom big craftables:===
You can now add or customize [[Crafting#Fences|fences]] by editing the <samp>Data/FenceData</samp> asset.
+
{{/doc status|[[Modding:Items#Big craftables]]|done=false}}
 +
 
 +
You can now create/edit [[Modding:Items#Big craftables|big craftables]] by editing the new <samp>Data/BigCraftables</samp> asset, which replaces the previous slash-delimited <samp>Data/BigCraftablesInformation</samp>.
 +
 
 +
Besides the format change, this adds...
 +
* context tags (moved from the former <samp>Data/ObjectContextTags</samp> asset);
 +
* [[#Custom data fields|custom fields]] to let framework mods support additional features.
 +
 
 +
This consists of a string → model lookup, where...
 +
* The key is the unqualified [[#Custom items|item ID]].
 +
* The value is a model with the fields listed below.
  
This consists of a string → model lookup, where the key matches the <samp>ID</samp> field and the value is a model with these fields:
+
====Basic info====
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
 
! field
 
! field
! effect
+
! purpose
 
|-
 
|-
| <samp>ID</samp>
+
| <samp>Name</samp>
| A key which uniquely identifies this fence. The ID should only contain alphanumeric/underscore/dot characters. For custom fences, this should be prefixed with your mod ID like <samp>Example.ModId_FenceName</samp>.
+
| The internal item name.
 
|-
 
|-
| <samp>ItemID</samp>
+
| <samp>DisplayName</samp><br /><samp>Description</samp>
| The unqualified [[#Custom items|item ID]] for the corresponding object-type item.
+
| A [[Modding:Tokenizable strings|tokenizable string]] for the item's in-game display name and description.
 
|-
 
|-
| <samp>Health</samp>
+
| <samp>Price</samp>
| The health points for a fence when it's first placed, which affects how quickly it degrades. A fence loses <sup>1</sup>/<sub>1440</sub> points per in-game minute (roughly 0.04 points per hour or 0.5 points for a 12-hour day).
+
| ''(Optional)'' The price when sold by the player. This is not the price when bought from a shop. Default 0.
 +
|}
  
Repairing a fence sets its max health to ''2 × (base_health + repair_health_adjustment)'', where <samp>base_health</samp> is this field's value and <samp>repair_health_adjustment</samp> is a random value between <samp>RepairHealthAdjustmentMinimum</samp> and <samp>RepairHealthAdjustmentMaximum</samp>.
+
====Behavior====
 +
{| class="wikitable"
 
|-
 
|-
| <samp>Texture</samp>
+
! field
| The asset name for the texture (under the game's <samp>Content</samp> folder) when the flooring is applied or the path is placed. Use <samp>\</samp> (or <samp>\\</samp> in JSON) to separate name segments if needed. For example, the vanilla fences use individual tilesheets like <samp>LooseSprites\Fence1</samp> (wood fence).
+
! purpose
 
|-
 
|-
| <samp>RemovalTool</samp>
+
| <samp>Fragility</samp>
| A space-delimited list of tools which can be used to break the fence, matching the keys in <samp>Data\ToolData</samp>. For example, <samp>"Axe Pickaxe"</samp> will let players use the [[axe]] or [[pickaxe]].
+
| ''(Optional)'' How the item can be picked up. The possible values are 0 (pick up with any tool), 1 (destroyed if hit with an axe/hoe/pickaxe, or picked up with any other tool), or 2 (can't be removed once placed). Default 0.
 
|-
 
|-
| <samp>PlacementSound</samp>
+
| <samp>CanBePlacedIndoors</samp><br /><samp>CanBePlacedOutdoors</samp>
| The [[#Custom audio|audio cue ID]] played when the fence is placed (e.g. <samp>axe</samp> used by [[Wood Floor]]).
+
| ''(Optional)'' Whether the item can be placed indoors or outdoors. Default true.
 
|-
 
|-
| <samp>RemovalSound</samp>
+
| <samp>IsLamp</samp>
| ''(Optional)'' The [[#Custom audio|audio cue ID]] played when the fence is broken or picked up by the player. Defaults to the same sound as <samp>PlacementSound</samp>.
+
| ''(Optional)'' Whether this is a lamp and should produce light when dark. Default false.
 +
|}
 +
 
 +
====Appearance====
 +
{| class="wikitable"
 
|-
 
|-
| <samp>RemovalDebrisType</samp>
+
! field
| ''(Optional)'' The type of cosmetic debris particles to 'splash' from the tile when the fence is broken with a tool. The defined values are 0 (copper), 2 (iron), 4 (coal), 6 (gold), 8 (coins), 10 (iridium), 12 (wood), 14 (stone), 32 (big stone), and 34 (big wood). Default 14 (stone).
+
! purpose
 
|-
 
|-
| <samp>RepairHealthAdjustmentMinimum</samp><br /><samp>RepairHealthAdjustmentMaximum</samp>
+
| <samp>Texture</samp>
| ''(Optional)'' A random amount added to the <samp>Health</samp> when a fence is repaired by a player. See the <samp>Health</samp> field description. Both default to 0.
+
| ''(Optional)'' The asset name for the texture containing the item's sprite. Defaults to <samp>TileSheets/Craftables</samp>.
 
|-
 
|-
| <samp>HeldObjectDrawOffset</samp>
+
| <samp>SpriteIndex</samp>
| ''(Optional)'' When an item like a [[torch]] is placed on the fence, the pixel offset to apply to its draw position. Specified as a string in the form <samp>"{{t|x}}, {{t|y}}"</samp>. Defaults to <samp>"0, -20"</samp> if omitted.
+
| ''(Optional)'' The sprite's index within the <samp>Texture</samp>, where 0 is the top-left sprite.
|-
 
| <samp>LeftEndHeldObjectDrawX</samp><br /><samp>RightEndHeldObjectDrawX</samp>
 
| ''(Optional)'' The X pixel offset to apply when the fence is oriented horizontally, with only one connected fence on the right (for <samp>LeftEndHeldObjectDrawX</samp>) or left (for <samp>RightEndHeldObjectDrawX</samp>). This fully replaces the X value specified by <samp>HeldObjectDrawOffset</samp> when it's applied. Default 0.
 
 
|}
 
|}
  
===Custom flooring & paths===
+
====Context tags====
You can now add or customize [[flooring]]/[[Crafting#Decor|paths]] by editing the <samp>Data/FloorPathData</samp> asset.
 
 
 
This consists of a string → model lookup, where the key matches the <samp>ID</samp> field and the value is a model with these fields:
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
 
! field
 
! field
! effect
+
! purpose
 
|-
 
|-
| <samp>ID</samp>
+
| <samp>ContextTags</samp>
| A key which uniquely identifies this floor/path. The ID should only contain alphanumeric/underscore/dot characters. For vanilla floors & paths, this matches the spritesheet index in the <samp>TerrainFeatures/Flooring</samp> spritesheet; for custom floors & paths, this should be prefixed with your mod ID like <samp>Example.ModId_FloorName</samp>.
+
| ''(Optional)'' The custom [[Modding:Items#Context tags|context tags]] to add for this item (in addition to the tags added automatically based on the other object data). This is formatted as a list; for example:
 +
<syntaxhighlight lang="json">
 +
"ContextTags": [ "light_source", "torch_item" ]
 +
</syntaxhighlight>
 +
|}
 +
 
 +
====Advanced====
 +
{| class="wikitable"
 
|-
 
|-
| <samp>ItemID</samp>
+
! field
| The unqualified [[#Custom items|item ID]] for the corresponding object-type item.
+
! purpose
 +
|-
 +
| <samp>CustomFields</samp>
 +
| ''(Optional)'' The [[#Custom data fields|custom fields]] for this entry.
 +
|}
 +
 
 +
===Custom crops===
 +
[[Modding:Crop data|Crops]] are still stored in <samp>Data/Crops</samp>, but that asset has been overhauled in Stardew Valley 1.6. The slash-delimited entries are now models to simplify edits and enable new features.
 +
 
 +
This consists of a string → model lookup, where...
 +
* The key is the unqualified [[#Custom items|item ID]] for the seed item.
 +
* The value is model with the fields listed below.
 +
 
 +
{| class="wikitable"
 
|-
 
|-
| <samp>Texture</samp>
+
! field
| The asset name for the texture (under the game's <samp>Content</samp> folder) when the flooring is applied or the path is placed. Use <samp>\</samp> (or <samp>\\</samp> in JSON) to separate name segments if needed. For example, the vanilla tilesheet is <samp>TerrainFeatures\Flooring</samp>.
+
! effect
 
|-
 
|-
| <samp>Corner</samp>
+
!colspan="2"| Growth
| The top-left pixel position for the sprite within the <samp>Texture</samp> spritesheet, specified as a model with <samp>X</samp> and <samp>Y</samp> fields.
 
 
|-
 
|-
| <samp>WinterTexture</samp><br /><samp>Corner</samp>
+
| <samp>Seasons</samp>
| Equivalent to <samp>Texture</samp> and <samp>Corner</samp>, but applied if the current location is in winter. These fields are required, but can be set to the same values if you don't need seasonal changes.
+
| The seasons in which this crop can grow (any combination of <samp>spring</samp>, <samp>summer</samp>, <samp>fall</samp>, and <samp>winter</samp>).
 
|-
 
|-
| <samp>PlacementSound</samp>
+
| <samp>DaysInPhase</samp>
| The [[#Custom audio|audio cue ID]] played when the item is applied/placed (e.g. <samp>axchop</samp> used by [[Wood Floor]]).
+
| The number of days in each visual step of growth before the crop is harvestable. Each step corresponds to a sprite in the crop's row (see <samp>SpriteIndex</samp>).
 +
 
 +
For example, a crop with <code>"DaysInPhase": [ 1, 1, 1, 1 ]</code> will grow from seed to harvestable in 4 days, moving to the next sprite in the row each day.
 
|-
 
|-
| <samp>FootstepSound</samp>
+
| <samp>RegrowDays</samp>
| The [[#Custom audio|audio cue ID]] played when the player steps on the tile (e.g. <samp>woodyStep</samp> used by [[Wood Floor]]).
+
| ''(Optional)'' The number of days before the crop regrows after harvesting, or -1 if it can't regrow. The crop will keep the full-grown sprite (i.e. the last phase in <samp>DaysInPhase</samp>) during this time. Default -1.
 
|-
 
|-
| <samp>RemovalSound</samp>
+
| <samp>IsRaised</samp>
| ''(Optional)'' The [[#Custom audio|audio cue ID]] played when the item is unapplied or picked up. Defaults to the same sound as <samp>PlacementSound</samp>.
+
| ''(Optional)'' Whether this is a raised crop on a trellis that can't be walked through. Default false.
 
|-
 
|-
| <samp>RemovalDebrisType</samp>
+
| <samp>IsPaddyCrop</samp>
| ''(Optional)'' The type of cosmetic debris particles to 'splash' from the tile when the item is unapplied or picked up. The defined values are 0 (copper), 2 (iron), 4 (coal), 6 (gold), 8 (coins), 10 (iridium), 12 (wood), 14 (stone), 32 (big stone), and 34 (big wood). Default 12 (wood).
+
| ''(Optional)'' Whether this crop can be planted near water for a unique paddy dirt texture, faster growth time, and auto-watering. For example, [[Rice Shoot|rice]] and [[Taro Root|taro]] are paddy crops. Default false.
 
|-
 
|-
| <samp>DrawContouredShadow</samp>
+
| <samp>NeedsWatering</samp>
| ''(Optional)'' Whether the shadow under the placed/applied item follows the contour of the sprite pixels, instead of just drawing a box around the tile. Default false.
+
| ''(Optional)'' Whether this crop needs to be watered to grow (e.g. [[Fiber Seeds|fiber seeds]] don't). Default true.
 
|-
 
|-
| <samp>ConnectType</samp>
+
!colspan="2"| Harvest
| ''(Optional)'' When drawing the flooring across multiple tiles, how the flooring sprite for each tile is selected. Defaults to <samp>Default</samp>.
 
 
 
The possible values are:
 
{| class="wikitable"
 
 
|-
 
|-
! value
+
| <samp>HarvestItemId</samp>
! usage
+
| The item ID produced when this crop is harvested.
 
|-
 
|-
| <samp>Default</samp>
+
| <samp>HarvestMethod</samp>
| For normal floors, intended to cover large square areas. This uses some logic to draw inner corners.
+
| ''(Optional)'' How the crop can be harvested. This can be <samp>Grab</samp> (crop is harvested by hand) or <samp>Scythe</samp> (harvested with a [[scythe]]). Default <samp>Grab</samp>.
 
|-
 
|-
| <samp>Path</samp>
+
| <samp>HarvestMinStack</samp><br /><samp>HarvestMaxStack</samp>
| For floors intended to be drawn as narrow paths. These are drawn without any consideration for inner corners.
+
| ''(Optional)'' The minimum and maximum number of <samp>HarvestItemId</samp> to produce (before <samp>HarvestMaxIncreasePerFarmingLevel</samp> and <samp>ExtraHarvestChance</samp> are applied). A value within this range (inclusive) will be randomly chosen each time the crop is harvested. The minimum defaults to 1, and the maximum defaults to the minimum.
 
|-
 
|-
| <samp>CornerDecorated</samp>
+
| <samp>HarvestMinQuality</samp><br /><samp>HarvestMaxQuality</samp>
| For floors that have a decorative corner. Use <samp>CornerSize</samp> to change the size of this corner.
+
| ''(Optional)'' If set, the minimum and maximum quality of the harvest crop. These fields set a constraint that's applied after the quality is calculated normally, they don't affect the initial quality logic.
 
|-
 
|-
| <samp>Random</samp>
+
| <samp>HarvestMaxIncreasePerFarmingLevel</samp>
| For floors that don't connect. When placed, one of the tiles is randomly selected.
+
| ''(Optional)'' The number of extra harvests to produce per farming level. This is rounded down to the nearest integer and added to <samp>HarvestMaxStack</samp>. Defaults to 0.
|}
+
 
 +
For example, a value of 0.2 is equivalent to +1 max at level 5 and +2 at level 10.
 
|-
 
|-
| <samp>CornerSize</samp>
+
| <samp>ExtraHarvestChance</samp>
| ''(Optional)'' The pixel size of the decorative border when the <samp>ConnectType</samp> field is set to <samp>CornerDecorated</samp> or <samp>Default</samp>.
+
| ''(Optional)'' The probability that harvesting the crop will produce extra harvest items, as a value between 0 (never) and 0.9 (nearly always). This is repeatedly rolled until it fails, then the number of successful rolls is added to the produced count. For example, [[tomato]]es use 0.05. Default 0. This is [https://www.desmos.com/calculator/ok9c2tw6o5 a geometric series with expected value] of <samp>1/(1-ExtraHarvestChance) - 1</samp>, so it will grow faster than you expect it should. For example, with a value of <samp>0.9</samp>, this field has an expected value of nine additional crops.
 
|-
 
|-
| <samp>FarmSpeedBuff</samp>
+
!colspan="2"| Appearance
| ''(Optional)'' The speed boost applied to the player, on the [[farm]] only, when they're walking on paths of this type. Negative values are ignored. Default 0.1.
 
|}
 
 
 
===Custom machines===
 
You can now add/edit machine logic by editing the <samp>Data/MachinesData</samp> asset. This consists of a string → model lookup, where the key matches the <samp>ID</samp> field and the value is a model with these fields:
 
 
 
====Required fields====
 
{| class="wikitable"
 
 
|-
 
|-
! field
+
| <samp>Texture</samp>
! effect
+
| The asset name for the texture (under the game's <samp>Content</samp> folder) containing the crop sprite. For example, the vanilla crops use <samp>TileSheets\crops</samp>.
 
|-
 
|-
| <samp>ItemID</samp>
+
| <samp>SpriteIndex</samp>
| The [[#Custom items|qualified or unqualified item ID]] for the item which acts as a machine (like <samp>(BC)127</samp> for [[The Cave|mushroom boxes]]).
+
| ''(Optional)'' The index of this crop in the <samp>Texture</samp>, one crop per row, where 0 is the top row. Default 0.
 
 
If a machine has two entries, the ''unqualified'' ID takes priority. To avoid mod conflicts, '''custom machines should always use unqualified item IDs''' (since custom IDs should already be unique).
 
|}
 
 
 
====Item processing rules====
 
{| class="wikitable"
 
 
|-
 
|-
! field
+
| <samp>TintColors</samp>
! effect
+
| ''(Optional)'' The colors with which to tint the sprite when drawn (e.g. for colored flowers). A random color from the list will be chosen for each crop. See [[#Color fields|color format]]. Default none.
 
|-
 
|-
| <samp>ItemConversions</samp>
+
!colspan="2"| Achievements
| ''(Optional)'' The rules which define how to process input items. This consists of a list of models with these fields:
 
{| class="wikitable"
 
 
|-
 
|-
! field
+
| <samp>CountForMonoculture</samp>
! effect
+
| ''(Optional)'' Whether the player can ship 300 of this crop's harvest item to unlock the monoculture [[achievements|achievement]]. Default false.
 
|-
 
|-
| <samp>RequiredTags</samp>
+
| <samp>CountForPolyculture</samp>
| A comma-delimited list of [[Modding:Context tags|context tags]] to match against input items. An item must have all of the listed tags to select this rule. You can negate a tag with <samp>!</samp> (like <code>bone_item,!fossil_item</code> for bone items that aren't fossils).
+
| ''(Optional)'' Whether the player must ship 15 of this crop's harvest item (along with any other required crops) to unlock the polyculture [[achievements|achievement]]. Default false.
 
|-
 
|-
| <samp>RequiredCount</samp>
+
!colspan="2"| Advanced
| The required stack size for the item matching <samp>RequiredTag</samp>.
 
 
|-
 
|-
| <samp>Condition</samp>
+
| <samp>PlantableLocationRules</samp>
| ''(Optional)'' A [[#Game state queries|game state query]] which indicates whether the given input should be matched (if the other requirements are matched too). Item-only tokens are valid for this check. Defaults to always true.
+
| ''(Optional)'' The rules to decide which locations you can plant the seed in, if applicable. The first matching rule is used. This can override location checks (e.g. crops being limited to the farm), but not built-in requirements like crops needing dirt.
|-
 
| <samp>OverrideOutputs</samp>
 
| ''(Optional)'' The output items produced by this conversion rule. This uses the same format as <samp>Outputs</samp> on the machine itself. Defaults to the machine's <samp>Outputs</samp> field if omitted.
 
|-
 
| <samp>UseFirstValidOutput</samp>
 
| ''(Optional)'' If multiple <samp>Outputs</samp> or <samp>OverrideOutputs</samp> entries match, whether to use the first match instead of choosing one randomly. Default false.
 
|-
 
| <samp>OverrideMinutesUntilReady</samp><br /><samp>OverrideDaysUntilReady</samp>
 
| ''(Optional)'' If set, overrides the machine's main <samp>MinutesUntilReady</samp> or <samp>DaysUntilReady</samp> fields.
 
|-
 
| <samp>InvalidCountMessage</samp>
 
| ''(Optional)'' If set, overrides the machine's main <samp>InvalidCountMessage</samp> field.
 
|}
 
|-
 
| <samp>AdditionalConsumedItems</samp>
 
| ''(Optional)'' A list of extra items required before <samp>ItemConversions</samp> or <samp>ConversionMethod</samp> will be checked. If specified, every listed item must be present in the player, [[hopper]], or chest inventory (depending how the machine is being loaded).
 
  
 
This consists of a list of models with these fields:
 
This consists of a list of models with these fields:
 +
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 537: Line 733:
 
! effect
 
! effect
 
|-
 
|-
| <samp>ItemID</samp>
+
| <samp>Id</samp>
| The [[#Custom items|qualified or unqualified item ID]] for the required item.
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the list.
 
|-
 
|-
| <samp>RequiredCount</samp>
+
| <samp>Result</samp>
| ''(Optional)'' The required stack size for the item matching <samp>RequiredTag</samp>. Default 1.
+
| Indicates whether the seed can be planted in a location if this entry is selected. The possible values are:
 +
* <samp>Default</samp>: the seed can be planted if the location normally allows it. This can be used to stop processing further rules, and/or set a custom <samp>DeniedMessage</samp>.
 +
* <samp>Allow</samp>: the seed can be planted here, regardless of whether the location normally allows it.
 +
* <samp>Deny</samp>: the seed can't be planted here, regardless of whether the location normally allows it.
 
|-
 
|-
| <samp>InvalidCountMessage</samp>
+
| <samp>Condition</samp>
| ''(Optional)'' If set, overrides the machine's main <samp>InvalidCountMessage</samp> field.
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this entry applies. Default true.
|}
 
 
|-
 
|-
| <samp>Outputs</samp>
+
| <samp>PlantedIn</samp>
| ''(Optional)'' The items produced by this machine, unless overridden by <samp>OverrideOutputs</samp> under <samp>ItemConversions</samp>. If multiple output entries match, one will be selected randomly unless you specify <samp>UseFirstValidOutput</samp>. This consists of a list of models with these fields:
+
| ''(Optional)'' The planting context to apply this rule for. The possible values are <samp>Ground</samp> (planted directly in dirt), <samp>GardenPot</samp> (planted in a [[Garden Pot|garden pot]]), or <samp>Any</samp>. Default <samp>Any</samp>.
{| class="wikitable"
 
 
|-
 
|-
! field
+
| <samp>DeniedMessage</samp>
! effect
+
| ''(Optional)'' If this rule prevents planting the seed, the tokenizable string to show to the player (or <samp>null</samp> to default to the normal behavior for the context). This also applies when the <samp>Result</samp> is <samp>Default</samp>, if that causes the planting to be denied.
 +
|}
 
|-
 
|-
| <samp>ItemID</samp>
+
| <samp>CustomFields</samp>
| The [[#Custom items|qualified or unqualified item ID]] for the produced item.
+
| The [[#Custom data fields|custom fields]] for this entry.
|-
+
|}
| <samp>MinCount</samp><br /><samp>MaxCount</samp>
+
 
| ''(Optional)'' The minimum and maximum number of this item produced. A value in this range will chosen randomly each time it's produced. If the maximum is set to <samp>-1</samp>, it'll match the minimum automatically. Defaults to 1 (minimum) and -1 (maximum).
+
For example, this adds a custom cucumber crop (assuming you've already added [[#Custom items|custom items]] for cucumber seeds and cucumber):
|-
+
{{#tag:syntaxhighlight|<nowiki>
| <samp>Quality</samp>
+
{
| ''(Optional)'' The produced item's quality. The valid values are -1 (inherit from input item), 0 (normal), 1 (silver), 2 (gold), or 4 (iridium). Default normal-quality.
+
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
|-
+
    "Changes": [
| <samp>PreserveType</samp>
+
        {
| ''(Optional)'' The produced item's preserved item type, if applicable. This sets the equivalent flag on the output item. The valid values are <samp>Jelly</samp>, <samp>Juice</samp>, <samp>Pickle</samp>, <samp>Roe</samp> or <samp>AgedRoe</samp>, and <samp>Wine</samp>. Defaults to none.
+
            "Action": "EditData",
|-
+
            "Target": "Data/Crops",
| <samp>PreserveID</samp>
+
            "Entries": {
| ''(Optional)'' The produced item's preserved unqualified item ID, if applicable. For example, [[Wine|blueberry wine]] has its preserved item ID set to the [[blueberry]] ID. This can be set to <samp>DROP_IN</samp> to use the input item's ID. Default none.
+
                "Example.Id_CucumberSeeds": {
|-
+
                    "Seasons": [ "summer" ],
| <samp>AddPrice</samp><br /><samp>MultiplyPrice</samp>
+
                    "DaysInPhase": [ 1, 2, 2, 2 ], // grows in 7 days with four growing sprites
| ''(Optional)'' Numeric changes applied to the produced item's price, which is calculated as <samp>AddPrice + (MultiplyPrice × normal price)</samp>. These default to 0 (<samp>AddPrice</samp>) and 1 (<samp>MultiplyPrice</samp>).
+
                    "HarvestItemId": "Example.Id_Cucumber",
|-
+
                    "Texture": "{{InternalAssetKey: assets/crops.png}}",
| <samp>Condition</samp>
+
                    "SpriteIndex": 0
| ''(Optional)'' A [[#Game state queries|game state query]] which indicates whether this output can be produced. Item-only tokens are valid for this check, and will check the ''input'' (not output) item. Defaults to always true.
+
                }
|-
+
            }
| <samp>ModifyName</samp>
+
        }
| ''(Optional)'' The internal name (not translated display name) to set for the output item, with <samp>{0}</samp> replaced with the input item's internal name. This is used to prevent flavored items from stacking (''e.g.'' apple [[wine]] and blueberry wine). If omitted, the output item's normal internal name is used.
+
    ]
|-
+
}</nowiki>|lang=javascript}}
| <samp>CopyColor</samp>
 
| ''(Optional)'' Whether to inherit the color of the input item if it was a <samp>ColoredObject</samp>. This mainly affects [[roe]]. Default false.
 
|-
 
| <samp>IncrementMachineParentSheetIndex</samp>
 
| ''(Optional)'' Whether to increment the machine's spritesheet index by one while it's processing this output. This stacks with the <smap>ShowNextIndexWhenLoaded</samp> field (''i.e.'' setting both to true will increment the index by two). Default false.
 
|}
 
|-
 
| <samp>MinutesUntilReady</samp><br /><samp>DaysUntilReady</samp>
 
| ''(Optional)'' The number of in-game minutes or days until the output is ready to collect, unless overridden by <samp>OverrideMinutesUntilReady</samp> or <samp>OverrideDaysUntilReady</samp> under <samp>ItemConversions</samp>. If both days and minutes are specified, days are used. If none are specified, the item will be ready instantly.
 
|-
 
| <samp>UseFirstValidOutput</samp>
 
| ''(Optional)'' If multiple <samp>Output</samp> entries match, whether to use the first match instead of choosing one randomly. Default false.
 
  
This has no effect if <samp>ItemConversions</samp> is set; use the separate <samp>UseFirstValidOutput</samp> field on each item conversion entry instead in that case.
+
===Custom fences===
|-
+
{{/doc status|a new doc page|done=false}}
| <samp>BulkMultiplier</samp>
 
| ''(Optional)'' A multiplier applied to all input ''and'' output items. For output, this stacks with <samp>QuantityModifiers</samp>. Default 1.
 
|-
 
| <samp>ReadyTimeModifiers</samp><br /><samp>QualityModifiers</samp><br /><samp>QuantityModifiers</samp>
 
| ''(Optional)'' Changes to apply to the produced item's processing time, quality, or stack size. If multiple entries match, they'll be applied sequentially (e.g. two matching rules to double output will quadruple it). Note that this doesn't prevent you from setting invalid values (like a negative stack size or a quality beyond iridium), which may cause in-game bugs.
 
  
For <samp>QualityModifiers</samp>, the operations are performed on the numeric quality values: 0 (normal), 1 (silver), 2 (gold), or 4 (iridium).
+
You can now add or customize [[Crafting#Fences|fences]] by editing the <samp>Data/Fences</samp> asset.
  
This consists of a list of models with these fields:
+
This consists of a string → model lookup, where the key is the [[#Custom items|unqualified item ID]] of the fence object, and the value is a model with these fields:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 607: Line 788:
 
! effect
 
! effect
 
|-
 
|-
| <samp>Modification</samp>
+
| <samp>Health</samp>
| The type of change to apply. The possible values are <samp>Add</samp>, <samp>Subtract</samp>, <samp>Multiply</samp>, <samp>Divide</samp>, and <samp>Set</samp>.
+
| The health points for a fence when it's first placed, which affects how quickly it degrades. A fence loses <sup>1</sup>/<sub>1440</sub> points per in-game minute (roughly 0.04 points per hour or 0.5 points for a 12-hour day).
 +
 
 +
Repairing a fence sets its max health to ''2 × (base_health + repair_health_adjustment)'', where <samp>base_health</samp> is this field's value and <samp>repair_health_adjustment</samp> is a random value between <samp>RepairHealthAdjustmentMinimum</samp> and <samp>RepairHealthAdjustmentMaximum</samp>.
 
|-
 
|-
| <samp>Amount</samp>
+
| <samp>Texture</samp>
| The operand applied to the target value (e.g. the multiplier if used with <samp>Multiply</samp>).
+
| The asset name for the texture (under the game's <samp>Content</samp> folder) when the fence is placed. Use <samp>\</samp> (or <samp>\\</samp> in JSON) to separate name segments if needed. For example, the vanilla fences use individual tilesheets like <samp>LooseSprites\Fence1</samp> (wood fence).
 
|-
 
|-
| <samp>Condition</samp>
+
| <samp>RemovalToolIds</samp><br /><samp>RemovalToolTypes</samp>
| ''(Optional)'' A [[#Game state queries|game state query]] which indicates whether this change should be applied. Item-only tokens are valid for this check, and will check the ''input'' (not output) item. Defaults to always true.
+
| A list of tool IDs (matching the keys in <samp>Data\ToolData</samp>) or C# full type names which can be used to break the fence.
|}
+
 
|-
+
For example, this will let the player break the fence with an iridium axe and any pickaxe:
| <samp>ParentID</samp>
+
<syntaxhighlight lang="json">
| ''(Optional)'' The machine ID from which to inherit item conversion rules (including <samp>ItemConversion</samp>, <samp>Outputs</samp>, <samp>ConversionMethod</samp>, etc). Cosmetic effects (like sound effects, particles, changing parent sheet index, etc) aren't inherited. If the parent doesn't have any conversion logic which applies to the current item, the conversion rules defined for this machine are tried afterwards.
+
"RemovalToolIds": ["IridiumAxe"],
|}
+
"RemovalToolTypes": ["StardewValley.Tools.Pickaxe"]
 +
</syntaxhighlight>
  
====Behavior tweaks====
+
A tool must match <samp>RemovalToolIds</samp> ''or'' <samp>RemovalToolTypes</samp> to be a valid removal tool. If both lists are null or empty, all tools can remove the fence.
{| class="wikitable"
 
 
|-
 
|-
! field
+
| <samp>PlacementSound</samp>
! effect
+
| The [[#Custom audio|audio cue ID]] played when the fence is placed or repaired (e.g. <samp>axe</samp> used by [[Wood Fence]]).
 
|-
 
|-
| <samp>PreventTimePass</samp>
+
| <samp>RemovalSound</samp>
| ''(Optional)'' A list of cases when the machine should be paused, so the timer on any item being produced doesn't decrement. Possible values:
+
| ''(Optional)'' The [[#Custom audio|audio cue ID]] played when the fence is broken or picked up by the player. Defaults to the same sound as <samp>PlacementSound</samp>.
{| class="wikitable"
 
 
|-
 
|-
! value
+
| <samp>RemovalDebrisType</samp>
! effect
+
| ''(Optional)'' The type of cosmetic debris particles to 'splash' from the tile when the fence is broken with a tool. The defined values are 0 (copper), 2 (iron), 4 (coal), 6 (gold), 8 (coins), 10 (iridium), 12 (wood), 14 (stone), 32 (big stone), and 34 (big wood). Default 14 (stone).
 
|-
 
|-
| <samp>Outside</samp><br /><samp>Inside</samp>
+
| <samp>RepairHealthAdjustmentMinimum</samp><br /><samp>RepairHealthAdjustmentMaximum</samp>
| Pause when placed in an outside or inside location. For example, [[Bee House|bee houses]] don't work inside.
+
| ''(Optional)'' A random amount added to the <samp>Health</samp> when a fence is repaired by a player. See the <samp>Health</samp> field description. Both default to 0.
 
|-
 
|-
| <samp>Spring</samp><br /><samp>Summer</samp><br /><samp>Fall</samp><br /><samp>Winter</samp>
+
| <samp>HeldObjectDrawOffset</samp>
| Pause in the given season. For example, [[Bee House|bee houses]] don't work in winter.
+
| ''(Optional)'' When an item like a [[torch]] is placed on the fence, the pixel offset to apply to its draw position. Specified as a string in the form <samp>"{{t|x}}, {{t|y}}"</samp>. Defaults to <samp>"0, -20"</samp> if omitted.
 
|-
 
|-
|-
+
| <samp>LeftEndHeldObjectDrawX</samp><br /><samp>RightEndHeldObjectDrawX</samp>
| <samp>Sun</samp><br /><samp>Rain</samp>
+
| ''(Optional)'' The X pixel offset to apply when the fence is oriented horizontally, with only one connected fence on the right (for <samp>LeftEndHeldObjectDrawX</samp>) or left (for <samp>RightEndHeldObjectDrawX</samp>). This fully replaces the X value specified by <samp>HeldObjectDrawOffset</samp> when it's applied. Default 0.
| Pause on days with the given weather.
 
|-
 
| <samp>Always</samp>
 
| Always pause the machine. This is used in specialized cases where the timer is handled by [[#Advanced logic|advanced machine logic]].
 
 
|}
 
|}
|-
+
 
| <samp>Trigger</samp>
+
===Custom floors (craftable) & paths===
| ''(Optional)'' When the machine should start producing output. Possible values:
+
{{/doc status|a new doc page|done=false}}
 +
 
 +
You can now add or customize [[Crafting#Decor|craftable floors & paths]] by editing the <samp>Data/FloorsAndPaths</samp> asset.
 +
 
 +
This consists of a string → model lookup, where the key matches the <samp>ID</samp> field and the value is a model with these fields:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! value
+
! field
 
! effect
 
! effect
 
|-
 
|-
| <samp>Conversion</samp>
+
| <samp>ID</samp>
| After processing an item dropped in by a player based on the item conversion fields. This is the most common machine behavior.
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this floor/path.
 
|-
 
|-
| <samp>Placement</samp>
+
| <samp>ItemId</samp>
| After the item is placed. For example, the [[Worm Bin|worm bin]] uses this to start as soon as it's put down.
+
| The unqualified [[#Custom items|item ID]] for the corresponding object-type item.
 
|-
 
|-
| <samp>DayUpdate</samp>
+
| <samp>Texture</samp>
| After a new day starts. For example, the [[Soda Machine|soda machine]] does this.
+
| The asset name for the texture (under the game's <samp>Content</samp> folder) when the flooring is applied or the path is placed. Use <samp>\</samp> (or <samp>\\</samp> in JSON) to separate name segments if needed. For example, the vanilla tilesheet is <samp>TerrainFeatures\Flooring</samp>.
 
|-
 
|-
| <samp>DayUpdateOrPlacement</samp>
+
| <samp>Corner</samp>
| Combines the <samp>DayUpdate</samp> and <samp>Placement</samp> triggers.
+
| The top-left pixel position for the sprite within the <samp>Texture</samp> spritesheet, specified as a model with <samp>X</samp> and <samp>Y</samp> fields.
|}
 
 
|-
 
|-
| <samp>AllowLoadWhenFull</samp>
+
| <samp>PlacementSound</samp>
| ''(Optional)'' Whether the player can drop a new item into the machine before it's done processing the last one (like the [[crystalarium]]). The previous item will be lost. Default false.
+
| The [[#Custom audio|audio cue ID]] played when the item is applied/placed (e.g. <samp>axchop</samp> used by [[Wood Floor]]).
 
|-
 
|-
| <samp>ReloadOnCollect</samp>
+
| <samp>FootstepSound</samp>
| ''(Optional)'' Whether to restart the machine with the same input when the player collects the output (like the [[crystalarium]]). Default false.
+
| The [[#Custom audio|audio cue ID]] played when the player steps on the tile (e.g. <samp>woodyStep</samp> used by [[Wood Floor]]).
|}
 
 
 
====Audio & visuals====
 
{| class="wikitable"
 
 
|-
 
|-
! field
+
| <samp>WinterTexture</samp><br /><samp>Corner</samp>
! effect
+
| ''(Optional)'' Equivalent to <samp>Texture</samp> and <samp>Corner</samp>, but applied if the current location is in winter.
 
|-
 
|-
| <samp>LoadEffects</samp><br /><samp>WorkingEffects</samp>
+
| <samp>RemovalSound</samp>
| ''(Optional)'' The cosmetic effects shown when an item is loaded into the machine (for <samp>LoadEffects</samp>), or while it's processing the item (for <samp>WorkingEffects</samp>, based on the <samp>WorkingEffectChance</samp> probability). Both default to none. These consist of a list of models with these fields:
+
| ''(Optional)'' The [[#Custom audio|audio cue ID]] played when the item is unapplied or picked up. Defaults to the same sound as <samp>PlacementSound</samp>.
{| class="wikitable"
 
 
|-
 
|-
! field
+
| <samp>RemovalDebrisType</samp>
! effect
+
| ''(Optional)'' The type of cosmetic debris particles to 'splash' from the tile when the item is unapplied or picked up. The defined values are 0 (copper), 2 (iron), 4 (coal), 6 (gold), 8 (coins), 10 (iridium), 12 (wood), 14 (stone), 32 (big stone), and 34 (big wood). Default 14 (stone).
 
|-
 
|-
| <samp>RequiredTags</samp>
+
| <samp>ShadowType</samp>
| ''(Optional)'' A list of [[Modding:Items#Context tags|context tags]] required on the main input item. The effect only plays if the item has ''all'' of these. Defaults to always enabled.
+
| ''(Optional)'' The type of shadow to draw under the tile sprite. Default <samp>None</samp>.
|-
+
 
| <samp>Sound</samp>
+
The possible values are:
| ''(Optional)'' An [[#Custom audio|audio cue ID]] to play. Defaults to no sound.
 
|-
 
| <samp>DelayedSounds</samp>
 
| ''(Optional)'' The audio to play after a short delay. This consists of a list of models with these fields:
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! value
 
! effect
 
! effect
 
|-
 
|-
| <samp>Sound</samp>
+
| <samp>None</samp>
| The [[#Custom audio|audio cue ID]] to play.
+
| Don't draw a shadow.
 +
|-
 +
| <samp>Square</samp>
 +
| Draw a shadow under the entire tile.
 
|-
 
|-
| <samp>Delay</samp>
+
| <samp>Contoured</samp>
| The number of milliseconds until the sound should play.
+
| raw a shadow that follows the lines of the path sprite.
 
|}
 
|}
 
|-
 
|-
| <samp>ShakeDuration</samp>
+
| <samp>ConnectType</samp>
| ''(Optional)'' A duration in milliseconds during which the machine sprite should shake. Default none.
+
| ''(Optional)'' When drawing the flooring across multiple tiles, how the flooring sprite for each tile is selected. Defaults to <samp>Default</samp>.
|-
+
 
| <samp>TemporarySprites</samp>
+
The possible values are:
| ''(Optional)'' The temporary animated sprites to show. This consists of a list of models with these fields:
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! value
! effect
+
! usage
 
|-
 
|-
| <samp>Texture</samp>
+
| <samp>Default</samp>
| The asset name for the texture (under the game's <samp>Content</samp> folder) for the animated sprite.
+
| For normal floors, intended to cover large square areas. This uses some logic to draw inner corners.
 
|-
 
|-
| <samp>SourceRect</samp>
+
| <samp>Path</samp>
| The pixel area for the first animated frame within the <samp>Texture</samp>, specified as an object with <samp>X</samp>, <samp>Y</samp>, <samp>Width</samp>, and <samp>Height</samp> fields.
+
| For floors intended to be drawn as narrow paths. These are drawn without any consideration for inner corners.
 
|-
 
|-
| <samp>PositionOffset</samp>
+
| <samp>CornerDecorated</samp>
| ''(Optional)'' A pixel offset applied to the sprite, relative to the top-left corner of the machine's collision box, specified as an object with <samp>X</samp> and <samp>Y</samp> fields. Defaults to (0, 0).
+
| For floors that have a decorative corner. Use <samp>CornerSize</samp> to change the size of this corner.
 
|-
 
|-
| <samp>Color</samp>
+
| <samp>Random</samp>
| ''(Optional)'' A tint color to apply to the sprite. This can be any of the [https://docs.microsoft.com/en-us/previous-versions/windows/xna/ff433752(v=xnagamestudio.42) <samp>Color</samp> field names], like <samp>ForestGreen</samp>. Default <samp>White</samp> (no tint).
+
| For floors that don't connect. When placed, one of the tiles is randomly selected.
 +
|}
 
|-
 
|-
| <samp>AlphaFade</samp><br /><samp>Loops</samp><br /><samp>Rotation</samp><br /><samp>RotationChange</samp><br /><samp>ScaleChange</samp><br /><samp>SortOffset</samp>
+
| <samp>CornerSize</samp>
| ''(Optional)'' See equivalent fields in the [[#Other changes|<samp>temporaryAnimatedSprite</samp> event command]]. Default 0.
+
| ''(Optional)'' The pixel size of the decorative border when the <samp>ConnectType</samp> field is set to <samp>CornerDecorated</samp> or <samp>Default</samp>.
 
|-
 
|-
| <samp>Frames</samp><br /><samp>Scale</samp>
+
| <samp>FarmSpeedBuff</samp>
| ''(Optional)'' See equivalent fields in the [[#Other changes|<samp>temporaryAnimatedSprite</samp> event command]]. Default 1.
+
| ''(Optional)'' The speed boost applied to the player, on the [[farm]] only, when they're walking on paths of this type. Negative values are ignored. Default 0.1.
|-
 
| <samp>Interval</samp>
 
| ''(Optional)'' See equivalent fields in the [[#Other changes|<samp>temporaryAnimatedSprite</samp> event command]]. Default 100.
 
|-
 
| <samp>Flicker</samp><br /><samp>Flip</samp>
 
| ''(Optional)'' See equivalent fields in the [[#Other changes|<samp>temporaryAnimatedSprite</samp> event command]]. Default false.
 
 
|}
 
|}
|}
+
 
|-
+
===Custom machines===
| <samp>WorkingEffectChance</samp>
+
{{/doc status|[[Modding:Machines]]|done=true}}
| ''(Optional)'' The percentage chance to apply <samp>WorkingEffects</samp> each time the day starts or the in-game clock changes, as a value between 0 (never) and 1 (always). Default 0.33.
+
 
 +
You can now add/edit machine logic by editing the <samp>Data/Machines</samp> asset. This supports the full range of vanilla functionality, including calling custom code define in C# mods.
 +
 
 +
For C# mods, 1.6 also adds a new <samp>MachineDataUtility</samp> class and various <samp>Object</samp> to simplify working with machines in code. These are used by the game code itself to implement the base machine logic.
 +
 
 +
===Custom melee weapons===
 +
{{/doc status|[[Modding:Items#Weapons]]|done=false}}
 +
 
 +
[[Modding:Items#Weapons|Melee weapons]] are still stored in <samp>Data/Weapons</samp>, but that asset has been overhauled in Stardew Valley 1.6. The slash-delimited entries are now models to simplify edits and enable new features (like the new <samp>Projectiles</samp> feature).
 +
 
 +
This consists of a string → model lookup, where...
 +
* The key is the unqualified [[#Custom items|item ID]] for the weapon.
 +
* The value is model with the fields listed below.
 +
 
 +
====Basic weapon info====
 +
{| class="wikitable"
 +
|-
 +
! field
 +
! effect
 
|-
 
|-
| <samp>LitWhileWorking</samp>
+
| <samp>Name</samp>
| ''(Optional)'' Whether the machine produces light while it's processing an item. Default false.
+
| The internal weapon name.
 
|-
 
|-
| <samp>WobbleWhileWorking</samp>
+
| <samp>DisplayName</samp><br /><samp>Description</samp>
| ''(Optional)'' Whether the machine sprite should bulge in & out while it's processing an item. Default false.
+
| A [[Modding:Tokenizable strings|tokenizable string]] for the translated display name & description.
 
|-
 
|-
| <samp>ShowNextIndexWhileWorking</samp><br /><samp>ShowNextIndexWhenReady</samp>
+
| <samp>Type</samp>
| ''(Optional)'' Whether to show the next sprite in the machine's spritesheet while it's processing an item (<samp>ShowNextIndexWhileWorking</samp>) or ready (<samp>ShowNextIndexWhenReady</samp>). Default false.
+
| The weapon type. One of <samp>0</samp> (stabbing sword), <samp>1</samp> (dagger), <samp>2</samp> (club or hammer), or <samp>3</samp> (slashing sword).
 
|}
 
|}
  
====Player interaction messages====
+
====Appearance====
These only apply when the player interacts with a chest directly, instead of using a [[hopper]] or mod like {{nexus mod|1063|Automate}}.
 
 
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 765: Line 950:
 
! effect
 
! effect
 
|-
 
|-
| <samp>InvalidItemMessage</samp>
+
| <samp>Texture</samp>
| ''(Optional)'' A [[#Tokenizable string format|tokenizable string]] for the message shown in a toaster notification if the player tries to input an item that isn't accepted by the machine.
+
| The asset name for the spritesheet containing the weapon's sprite.
 
|-
 
|-
| <samp>InvalidCountMessage</samp>
+
| <samp>SpriteIndex</samp>
| ''(Optional)'' A [[#Tokenizable string format|tokenizable string]] for the message shown in a toaster notification if the input inventory doesn't contain this item, unless overridden by <samp>InvalidCountMessage</samp> under <samp>ItemConversions</samp>.
+
| The index within the <samp>Texture</samp> for the weapon sprite, where 0 is the top-left sprite.
 
 
This can use extra custom tokens:
 
* <samp>[ItemCount]</samp>: the number of remaining items needed. For example, if you're holding three and need five, <samp>[ItemCount]</samp> will be replaced with <samp>2</samp>.
 
 
|}
 
|}
  
====Advanced logic====
+
====Stats====
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 781: Line 963:
 
! effect
 
! effect
 
|-
 
|-
| <samp>ConversionMethod</samp>
+
| <samp>MinDamage</samp><br /><samp>MaxDamage</samp>
| ''(Optional)'' A C# method which applies custom processing logic when the player tries to drop an item into the machine.
+
| The minimum and maximum based damage caused when hitting a monster with this weapon.
 
+
|-
This must be specified in the form <samp>{{t|full type name}}.{{t|method name}}</samp> (like <samp>StardewValley.Object.DropInDeconstructor</samp>). The method must be static, take five arguments (<code>Object machine, Item dropped_in_item, Farmer player, bool probe, ref Item output</code>), and return a boolean indicating whether the input was successfully processed.
+
| <samp>Knockback</samp>
 
+
| ''(Optional)'' How far the target is pushed when hit, as a multiplier relative to a base weapon like the [[Rusty Sword]] (e.g. <samp>1.5</samp> for 150% of Rusty Sword's weight). Default 1.
⚠️ Caveats:
+
|-
* This will completely disable the <samp>ItemConversions</samp>, <samp>InvalidItemMessage</samp>, <samp>InvalidCountMessage</samp>, and <samp>Outputs</samp> fields.
+
| <samp>Speed</samp>
* This will prevent any other mod from registering their own processing rules for this machine.
+
| ''(Optional)'' How fast the player can swing the weapon. Each point of speed is worth 40ms of swing time relative to 0. This stacks with the [[speed|player's weapon speed]]. Default 0.
* This will prevent {{nexus mod|1063|Automate}} from automating the machine, since it has no way to know which items will be accepted by the method. For Automate support, you'd need to [https://github.com/Pathoschild/StardewMods/blob/develop/Automate/docs/technical.md#extensibility-for-modders use Automate's API] to register a custom machine factory to handle it in code.
+
|-
* This should ''only'' perform conversion logic. Don't handle interaction logic like animations, sounds, or UI messages in this method, since that'll interfere with [[hopper]]s and other machine mods. See the other fields instead for that.
+
| <samp>Precision</samp>
 +
| ''(Optional)'' Reduces the chance that a strike will miss. Default 0.
 
|-
 
|-
| <samp>InteractMethod</samp>
+
| <samp>Defense</samp>
| ''(Optional)'' A C# method invoked when the player interacts with the machine when it doesn't have output ready to harvest.
+
| ''(Optional)'' Reduces damage received by the player. Default 0.
 
 
This must be specified in the form <samp>{{t|full type name}}.{{t|method name}}</samp> (like <samp>StardewValley.Object.SomeInteractMethod</samp>). The method must be static, take three arguments (<code>Object machine, GameLocation location, Farmer player</code>), and return a boolean indicating whether the interaction succeeded.
 
 
|-
 
|-
| <samp>OutputMethod</samp>
+
| <samp>AreaOfEffect</samp>
| ''(Optional)'' A C# method which produces the item to output.
+
| ''(Optional)'' Slightly increases the area of effect. Default 0.
 
 
This must be specified in the form <samp>{{t|full type name}}.{{t|method name}}</samp> (like <samp>StardewValley.Object.OutputSolarPanel</samp>). The method must be static, take three arguments (<code>Object machine, GameLocation location, Farmer player</code>), and return the <samp>Item</samp> instance to output. If this method returns null, the machine won't output anything.
 
 
 
⚠️ Caveats:
 
* If you also specify other fields like <samp>ItemConversions</samp> or <samp>Outputs</samp>, any output they return will override this value.
 
 
|-
 
|-
| <samp>HasInput</samp><br /><samp>HasOutput</samp>
+
| <samp>CritChance</samp>
| ''(Optional)'' Whether to force adding the <samp>machine_input</samp> or <samp>machine_output</samp> [[#New context tags|context tags]] respectively. This isn't needed for most machines, since they'll be set based on the other fields. Default false.
+
| ''(Optional)'' The chance of a critical hit, as a decimal value between 0 (never) and 1 (always). Default 0.02.
 
|-
 
|-
| <samp>ResetBuildingIncubatorFlag</samp>
+
| <samp>CritMultiplier</samp>
| ''(Optional)'' When the machine is placed in a [[barn]] or [[coop]], whether to reset the 'has shown incubator building full message' flag on the building when an item is placed in the machine. Default false.
+
| ''(Optional)'' A multiplier applied to the base damage for a critical hit. This can be a decimal value. Default 3.
 +
|}
  
This is used by the [[incubator]] and [[Ostrich Incubator|ostrich incubator]]. The game logic assumes there's only one such machine in each building, so this generally shouldn't be used by custom machines.
+
====Game logic====
|-
 
| <samp>StatsToIncrementWhenLoaded</samp><br /><samp>StatsToIncrementWhenHarvested</samp>
 
| ''(Optional)'' The game stat counters to increment when an item is placed in the machine (<samp>StatsToIncrementWhenLoaded</samp>) or when the processed output is collected (<samp>StatsToIncrementWhenHarvested</samp>). Default none. This consists of a list of models with these fields:
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 820: Line 994:
 
! effect
 
! effect
 
|-
 
|-
| <samp>StatName</samp>
+
| <samp>CanBeLostOnDeath</samp>
| The name of the stat counter field on <samp>Game1.stats</samp>.
+
| Whether the player can [[Adventurer's Guild#Item Recovery Service|lose this tool when they die]]. Default true.
 
|-
 
|-
| <samp>RequiredTags</samp>
+
| <samp>MineBaseLevel</samp><br /><samp>MineMinLevel</samp>
| ''(Optional)'' A comma-delimited list of [[Modding:Items#Context tags|context tags]] required on the main input item. The stat is only incremented if the item has ''all'' of these. You can negate a tag with <samp>!</samp> (like <code>bone_item,!fossil_item</code> for bone items that aren't fossils). Defaults to always enabled.
+
| ''(Optional)'' The base and minimum mine level, which affect [[#Mine container drops|mine container drops]]. Both default to -1, which disables automatic mine drops.
 
|}
 
|}
  
It's fine to use this with custom machines, but you can only increment built-in stats so it won't be applicable for most custom machines. For example, the vanilla game increments <samp>PiecesOfTrashRecycled</samp> for the [[Recycling Machine|recycling machine]] and <samp>GeodesCracked</samp> for the [[Geode Crusher|geode crusher]].
+
====Advanced====
|}
 
 
 
===Custom museum donations & rewards===
 
You can now add/edit the items which the [[museum]] accepts in donation and gives back in rewards through the new <samp>Data/MuseumRewards</samp> data asset.
 
 
 
====Format====
 
The data asset consists of a string → model lookup, where the key matches the <samp>ID</samp> field and the value is a model with these fields:
 
 
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 841: Line 1,007:
 
! effect
 
! effect
 
|-
 
|-
| <samp>ID</samp>
+
| <samp>Projectiles</samp>
| A key which uniquely identifies the reward group (i.e. a set of items and the reward once they're all donated). The ID should only contain alphanumeric/underscore/dot characters. For custom entries, this should be prefixed with your mod ID like <samp>Example.ModId_GroupName</samp>.
+
| ''(Optional)'' The projectiles fired when the weapon is used, which continue along their path until they hit a monster and cause damage. A separate projectile is fired for each entry in this list.
|-
+
 
| <samp>TargetContextTags</samp>
+
This consists of a list of models with these fields (one projectile will fire for each entry in the list):
| The items that must be donated to complete this reward group. The player must fulfill every entry in the list to unlock the reward. This consists of a list of models with these fields:
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 851: Line 1,016:
 
! effect
 
! effect
 
|-
 
|-
| <samp>Tag</samp>
+
| <samp>Id</samp>
| The [[Modding:Context tags|context tag]] for the items to require.
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for the projectile within the current weapon's data.
 
|-
 
|-
| <samp>Count</samp>
+
| <samp>Damage</samp>
| The minimum number of items matching the context tags that must be donated.
+
| ''(Optional)'' The amount of damage caused when the projectile hits a monster. Default 10.
|}
+
|-
 
+
| <samp>Explodes</samp>
For example, an entry with the tag <samp>forage_item</samp> and count 2 will require donating any two forage items.
+
| ''(Optional)'' Whether the projectile explodes when it collides with something. Default false.
 
+
|-
Special case: an entry with the exact values <code>Tag: "", Count: -1</code> passes if the museum is complete (i.e. the player has donated the max number of items).
+
| <samp>Bounces</samp>
 +
| ''(Optional)'' The number of times the projectile can bounce off walls before being destroyed. Default 0.
 +
|-
 +
| <samp>MaxDistance</samp>
 +
| ''(Optional)'' The maximum tile distance the projectile can travel. Default 4.
 +
|-
 +
| <samp>Velocity</samp>
 +
| ''(Optional)'' The speed at which the projectile moves. Default 10.
 +
|-
 +
| <samp>RotationVelocity</samp>
 +
| ''(Optional)'' The rotation velocity. Default 32.
 +
|-
 +
| <samp>TailLength</samp>
 +
| ''(Optional)'' The length of the tail which trails behind the main projectile. Default 1.
 +
|-
 +
| <samp>FireSound</samp><br /><samp>BounceSound</samp><br /><samp>CollisionSound</samp>
 +
| ''(Optional)'' The sound played when the projectile is fired, bounces off a wall, or collides with something. All three default to none.
 +
|-
 +
| <samp>MinAngleOffset</samp><br /><samp>MaxAngleOffset</samp>
 +
| ''(Optional)'' A random offset applied to the direction of the project each time it's fired. Both fields default to 0, in which case it's always shot at the 90° angle matching the player's facing direction.
 
|-
 
|-
| <samp>FlagOnCompletion</samp>
+
| <samp>SpriteIndex</samp>
| ''(Optional if <samp>RewardItemIsSpecial</samp> is true)'' Whether to add the <samp>ID</samp> value to the player's received mail. This is used to track whether the player has collected the reward, and should almost always be true. If this is omitted and <samp>RewardItemIsSpecial</samp> is false, the player will be able collect the reward infinite times. Default false.
+
| ''(Optional)'' The sprite index in the <samp>TileSheets/Projectiles</samp> asset to draw for this projectile. Defaults to 11 (a glowing-yellow-ball sprite).
 
 
After the reward is collected, you can check this value using the <samp><nowiki>HasFlag</nowiki></samp> condition in [[Modding:Content Patcher|Content Patcher]].
 
 
|-
 
|-
| <samp>RewardEventSeenFlag</samp>
+
| <samp>Item</samp>
| ''(Optional)'' The ID to add to the player's event-seen list when the reward is collected. (You must still specify <samp>FlagOnCompletion</samp> or <samp>RewardItemIsSpecial</samp> either way.)
+
| ''(Optional)'' The item to shoot. If set, this overrides <samp>SpriteIndex</samp>.
  
After the reward is collected, you can check this value using the <samp><nowiki>HasSeenEvent</nowiki></samp> condition in [[Modding:Content Patcher|Content Patcher]].
+
This consists of a list of models with these fields:
 +
{| class="wikitable"
 
|-
 
|-
| <samp>RewardItemID</samp>
+
! field
| ''(Optional)'' The [[#Custom items|qualified item ID]] for the item given to the player when they donate all required items for this group. There's no reward item if omitted.
+
! effect
 
|-
 
|-
| <samp>RewardItemCount</samp>
+
| ''common fields''
| ''(Optional)'' The stack size for the <samp>RewardItemID</samp> (if the item supports stacking). Default 1.
+
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields supported for ammo items.
 +
 
 +
If set to an [[Modding:Item queries|item query]] which returns multiple items, one of them will be selected at random.
 +
|}
 +
|}
 +
 
 +
Note that these are magic projectiles fired when the weapon is used, they're not aimed directly like [[slingshot]] projectiles.
 
|-
 
|-
| <samp>RewardItemIsSpecial</samp>
+
| <samp>CustomFields</samp>
| ''(Optional)'' Whether to mark the <samp>RewardItemID</samp> as a special permanent item, which can't be destroyed/dropped and can only be collected once. Default false.
+
| The [[#Custom data fields|custom fields]] for this entry.
|-
 
| <samp>RewardItemIsRecipe</samp>
 
| ''(Optional)'' Whether to give the player a cooking/crafting recipe which produces the <samp>RewardItemID</samp>, instead of the item itself. Ignored if the item type can't be cooked/crafted (i.e. non-object-type items). Default false.
 
 
|}
 
|}
  
====Achievements====
+
===Custom movie concessions===
The ''A Complete Collection'' [[Achievements|achievement]] is automatically adjusted to require any custom donations added too. This is based on the number of donated items though, so removing custom donations later may incorrectly mark the museum complete (since you may have donated enough items to meet the total required).
+
{{/doc status|[[Modding:Movie theater data]]|done=false}}
 +
: ''See also: [[#Custom movies|custom movies]].''
  
===Custom fruit trees===
+
You could already [[Modding:Movie theater data#Concession data|add/edit concessions]] sold in the [[Movie Theater|movie theater]], but conflicts were likely since each concession had an incrementing numeric ID which matched its position in the vanilla tilesheet.
====Data format====
 
You can now add custom [[Fruit Trees|fruit trees]] by editing the modified <samp>Data/fruitTrees</samp> asset. This consists of a string → string lookup, where the key is the sapling item ID and the value is a slash (<samp>/</samp>)-delimited list of these fields:
 
  
 +
Stardew Valley 1.6 addresses that with two changes:
 +
<ul>
 +
<li>The <samp>Id</samp> field is now a [[Modding:Common data field types#Unique string ID|unique string ID]].</li>
 +
<li>You can now use a different texture with two new required fields:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! index
 
 
! field
 
! field
 
! effect
 
! effect
 
|-
 
|-
| 0
+
| <samp>Texture</samp>
| tree ID
+
| The asset name for the texture containing the concession's sprite.
| A key which uniquely identifies this tree. For vanilla trees, this matches the spritesheet index. For custom trees, the ID should only contain alphanumeric/underscore/dot characters.
 
 
|-
 
|-
| 1
+
| <samp>SpriteIndex</samp>
| season
+
| The index within the <samp>Texture</samp> for the concession sprite, where 0 is the top-left sprite.
| The season in which the fruit tree bears fruit.
+
|}
|-
+
</li>
| 2
+
</ul>
| fruit
 
| The unqualified object ID for the fruit it produces.
 
|-
 
| 3
 
| sapling price
 
| '''Unused.'''
 
|-
 
| 4
 
| sprite index
 
| The tree's row index in the spritesheet (e.g. 0 for the first tree, 1 for the second tree, etc). If omitted, the game will try to parse the item ID as an index.
 
|-
 
| 5
 
| texture
 
| The asset name for the texture under the game's <samp>Content</samp> folder. Use <samp>\</samp> (or <samp>\\</samp> in JSON) to separate name segments if needed. For example, fruit trees use <samp>TileSheets\fruitTrees</samp> by default.
 
|}
 
 
 
For example, this content pack adds a custom fruit tree, including [[#Custom items|custom items]] for the sapling and fruit:
 
  
 +
For example, this content pack adds a new 'Pufferchick Pop' concession with a custom image:
 
{{#tag:syntaxhighlight|<nowiki>
 
{{#tag:syntaxhighlight|<nowiki>
 
{
 
{
 
     "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
 
     "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
 
     "Changes": [
 
     "Changes": [
        // add fruit + sapling items
 
        // note: sapling must have an edibility under 0 (usually -300) to be plantable
 
 
         {
 
         {
 
             "Action": "EditData",
 
             "Action": "EditData",
             "Target": "Data/ObjectInformation",
+
             "Target": "Data/Concessions",
 
             "Entries": {
 
             "Entries": {
                 "Example.ModId_Pufferfruit": "Pufferfruit/1200/100/Basic -6/Pufferfruit/An example fruit item.////1/Mods\\Example.ModId\\Objects",
+
                 "{{ModId}}_PufferchickPop": {
                "Example.ModId_Puffersapling": "Puffersapling/1200/-300/Basic -74/Puffersapling/An example tree sapling.////2/Mods\\Example.ModId\\Objects"
+
                    "Id": "{{ModId}}_PufferchickPop",  // must specify ID again when creating a new entry
 +
                    "Name": "{{ModId}}_PufferchickPop", // best practice to match the ID, since it's sometimes used as an alternate ID
 +
                    "DisplayName": "Pufferchick Pop",
 +
                    "Description": "A cute cake pop shaped like a pufferchick.",
 +
                    "Price": 25,
 +
                    "Texture": "{{InternalAssetKey: assets/pufferchick-pop.png}}" // an image in your content pack
 +
                    "SpriteIndex": 0
 +
                }
 
             }
 
             }
         },
+
         }
 
 
        // add fruit tree
 
        {
 
            "Action": "EditData",
 
            "Target": "Data/FruitTrees",
 
            "Entries": {
 
                "Example.ModId_Puffersapling": "Example.ModId_Puffertree/spring/Example.ModId_Pufferfruit/1000/0/Mods\\Example.ModId\\FruitTrees"
 
            }
 
        },
 
 
 
        // add images
 
        {
 
            "Action": "Load",
 
            "Target": "Mods/Example.ModId/FruitTrees, Mods/Example.ModId/Objects",
 
            "FromFile": "assets/{{TargetWithoutPath}}.png" // assets/FruitTrees.png, assets/Objects.png
 
        },
 
 
     ]
 
     ]
 
}</nowiki>|lang=javascript}}
 
}</nowiki>|lang=javascript}}
  
The fruit trees can then be added to the game by giving the player a sapling item in the usual ways (e.g. from [[#Custom shops|a shop]]).
+
===Custom museum donations & rewards===
 +
{{/doc status|a new doc page|done=false}}
  
====Fruit items====
+
You can now add/edit the items which the [[museum]] gives back in rewards through the new <samp>Data/MuseumRewards</samp> data asset.
The <samp>fruitsOnTree</samp> field was previously the number of fruit on the tree. It's now a list of fruit items instead, so C# mods can make the same fruit tree produce different fruit.
 
  
===Custom wild trees===
+
====Format====
You can now create/edit [[Trees|wild trees]] by editing the <samp>Data/WildTrees</samp> asset. This consists of a string → model lookup, where the asset key is the wild tree ID: one of <samp>1</samp> (oak), <samp>2</samp> (maple), <samp>3</samp> (pine), <samp>6</samp> (palm), <samp>7</samp> (mushroom), <samp>8</samp> (mahogany), or a custom string ID defined by a mod. The asset value is a model with these fields:
+
The data asset consists of a string → model lookup, where...
 +
* The key is a [[Modding:Common data field types#Unique string ID|unique string ID]] for the reward group.
 +
* The value is a model with the fields listed below.
  
 
{| class="wikitable"
 
{| class="wikitable"
Line 971: Line 1,133:
 
! effect
 
! effect
 
|-
 
|-
| <samp>TreeType</samp>
+
| <samp>TargetContextTags</samp>
| The tree ID; this should match the asset key.
+
| The items that must be donated to complete this reward group. The player must fulfill every entry in the list to unlock the reward. This consists of a list of models with these fields:
 +
{| class="wikitable"
 
|-
 
|-
| <samp>Textures</samp>
+
! field
| The tree textures to show in game. This can be a list containing either a single asset name, or four asset names (for spring, summer, fall, and winter in that order).
+
! effect
 
|-
 
|-
| <samp>SeedItemID</samp>
+
| <samp>Tag</samp>
| The [[#Custom items|qualified item ID]] for the seed item.
+
| The [[Modding:Context tags|context tag]] for the items to require.
 
|-
 
|-
| <samp>SeedPlantable</samp>
+
| <samp>Count</samp>
| ''(Optional)'' Whether the seed can be planted by the player. If this is false, it can only be spawned automatically via map properties. Default true.
+
| The minimum number of items matching the context tags that must be donated.
 +
|}
 +
 
 +
For example, an entry with the tag <samp>forage_item</samp> and count 2 will require donating any two forage items.
 +
 
 +
Special case: an entry with the exact values <code>Tag: "", Count: -1</code> passes if the museum is complete (i.e. the player has donated the max number of items).
 
|-
 
|-
| <samp>GrowthChance</samp>
+
| <samp>FlagOnCompletion</samp>
| ''(Optional)'' The probability each day that the tree will grow to the next stage without [[Tree Fertilizer|tree fertilizer]], expressed as a value from 0 (will never grow) to 1 (will grow every day). Defaults to 0.2 (20% chance).
+
| ''(Optional if <samp>RewardItemIsSpecial</samp> is true)'' Whether to add the <samp>ID</samp> value to the player's received mail. This is used to track whether the player has collected the reward, and should almost always be true. If this is omitted and <samp>RewardItemIsSpecial</samp> is false, the player will be able collect the reward infinite times. Default false.
 +
 
 +
After the reward is collected, you can check this value using the <samp><nowiki>HasFlag</nowiki></samp> condition in [[Modding:Content Patcher|Content Patcher]].
 
|-
 
|-
| <samp>FertilizedGrowthChance</samp>
+
| <samp>RewardActions</samp>
| ''(Optional)'' Equivalent to <samp>GrowthChance</samp>, but with [[Tree Fertilizer|tree fertilizer]]. Defaults to 1 (100% chance).
+
| Run one or more [[Modding:Trigger actions|trigger action strings]]. For example, this adds {{price|500}} to the current player:
 +
<syntaxhighlight lang="js">
 +
"RewardActions": [
 +
    "AddMoney 500"
 +
]
 +
</syntaxhighlight>
 
|-
 
|-
| <samp>SeedChance</samp>
+
| <samp>RewardItemId</samp>
| ''(Optional)'' The probability each day that the tree will produce a seed that will drop when the tree is shaken. Default 0.05 (5% chance).
+
| ''(Optional)'' The [[#Custom items|qualified item ID]] for the item given to the player when they donate all required items for this group. There's no reward item if omitted.
 
|-
 
|-
| <samp>SeedOnChopChance</samp>
+
| <samp>RewardItemCount</samp>
| ''(Optional)'' The probability that a seed will drop when the player chops down the tree. Default 0.75 (75% chance).
+
| ''(Optional)'' The stack size for the <samp>RewardItemId</samp> (if the item supports stacking). Default 1.
 
|-
 
|-
| <samp>DropWoodOnChop</samp>
+
| <samp>RewardItemIsSpecial</samp>
| ''(Optional)'' Whether to drop [[wood]] when the player chops down the tree. Default true.
+
| ''(Optional)'' Whether to mark the <samp>RewardItemId</samp> as a special permanent item, which can't be destroyed/dropped and can only be collected once. Default false.
 
|-
 
|-
| <samp>DropHardwoodOnLumberChop</samp>
+
| <samp>RewardItemIsRecipe</samp>
| ''(Optional)'' Whether to drop [[hardwood]] when the player chops down the tree, if they have the [[Skills#Foraging|Lumberjack profession]]. Default true.
+
| ''(Optional)'' Whether to give the player a cooking/crafting recipe which produces the <samp>RewardItemId</samp>, instead of the item itself. Ignored if the item type can't be cooked/crafted (i.e. non-object-type items). Default false.
 
|-
 
|-
| <samp>IsLeafy</samp>
+
| <samp>CustomFields</samp>
| ''(Optional)'' Whether shaking or chopping the tree causes cosmetic leaves to drop from tree and produces a leaf rustle sound. When a leaf drops, the game will use one of the four leaf sprites in the tree's spritesheet in the slot left of the stump sprite. Default true.
+
| The [[#Custom data fields|custom fields]] for this entry.
|-
+
|}
| <samp>IsLeafyInWinter</samp>
+
 
| ''(Optional)'' Whether <samp>IsLeafy</samp> also applies in winter. Default false.
+
For example, this content pack adds two rewards (one mail and one item):
 +
{{#tag:syntaxhighlight|<nowiki>
 +
{
 +
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
 +
    "Changes": [
 +
        {
 +
            "Action": "EditData",
 +
            "Target": "Data/MuseumRewards",
 +
            "Entries": {
 +
                // send a letter when a specific item is donated
 +
                "{{ModId}}_ShinyArtifact": {
 +
                    "TargetContextTags": [
 +
                        {
 +
                            "Tag": "id_{{ModId}}_ShinyArtifact", // unique context tag identifying the item by ID
 +
                            "Count": 1
 +
                        },
 +
                    ],
 +
                    "FlagOnCompletion": true,
 +
                    "RewardActions": [ "AddMail Current {{ModId}}_ShinyArtifact" ]
 +
                },
 +
 
 +
                // give item when 18 minerals are donated
 +
                "{{ModId}}_18MineralItems": {
 +
                    "TargetContextTags": [
 +
                        {
 +
                            "Tag": "item_type_minerals",
 +
                            "Count": 18
 +
                        },
 +
                    ],
 +
                    "RewardItemId": "(BC){{ModId}}_SuperMachine",
 +
                    "RewardItemCount": 1,
 +
                    "FlagOnCompletion": true
 +
                }
 +
            }
 +
        }
 +
    ]
 +
}</nowiki>|lang=javascript}}
 +
 
 +
See also [[Modding:Mail data|mail data]], [[#Custom items|custom items]], and [[#custom machines|custom machines]] to add the custom mail and items.
 +
 
 +
====Achievements====
 +
The ''A Complete Collection'' [[Achievements|achievement]] is automatically adjusted to require any custom donations added too. This is based on the number of donated items though, so removing custom donations later may incorrectly mark the museum complete (since you may have donated enough items to meet the total required).
 +
 
 +
===Custom fruit trees===
 +
{{/doc status|[[Modding:Fruit trees]]|done=false}}
 +
 
 +
====Data format====
 +
You can now add custom [[Fruit Trees|fruit trees]] by editing the revamped <samp>Data/fruitTrees</samp> asset. This consists of a string → model lookup, where...
 +
* The key is the [[#Custom items|unqualified item ID]] for the sapling item in <samp>Data/Objects</samp>.
 +
* The value is a model with the fields listed below.
 +
 
 +
{| class="wikitable"
 
|-
 
|-
| <samp>GrowsInWinter</samp>
+
! field
| ''(Optional)'' Whether the tree can grow in winter (subject to <samp>GrowthChance</samp> and <samp>FertilizedGrowthChance</samp>). Default false.
+
! effect
 
|-
 
|-
| <samp>IsStumpDuringWinter</samp>
+
| <samp>DisplayName</samp>
| ''(Optional)'' Whether the tree is reduced to a stump in winter and regrows in spring, like the vanilla [[Trees#Mushroom Tree|mushroom tree]]. Default false.
+
| A [[Modding:Tokenizable strings|tokenizable string]] for the tree's display name. This should return a display name without 'tree' (like <samp>Cherry</samp> for a cherry tree). This is used in UI messages like "''Your &lt;display name&gt; tree wasn't able to grow last night''".
 
|-
 
|-
| <samp>AllowWoodpeckers</samp>
+
| <samp>Seasons</samp>
| ''(Optional)'' Whether woodpeckers can spawn on the tree. Default true.
+
| The seasons in which the fruit tree bears fruit. This consists of an array of season names (any combination of <samp>spring</samp>, <samp>summer</samp>, <samp>fall</samp>, or <samp>winter</samp>).
 +
 
 +
'''Note:''' the previous '<samp>island</samp>' season value is no longer valid. Using <samp>summer</samp> is equivalent to how it worked before (since we now have [[#Custom location contexts|per-location seasons]]).
 
|-
 
|-
| <samp>UseAlternateSeedSprite</samp>
+
| <samp>Fruit</samp>
| ''(Optional)'' Whether to render a different tree sprite when it has a seed ready. If true, the tree spritesheet should be double-width with the alternate textures on the right. Default false.
+
| The fruit items to add to the tree each day while the tree is in-season. The first matching fruit (if any) is selected each day.
|-
+
 
| <samp>DebrisColor</samp>
+
This consists of a list of models with these fields:
| ''(Optional)'' The color of the cosmetic wood chips when chopping the tree. The valid values are <samp>12</samp> (brown/woody), <samp>100001</samp> (light green),  <samp>100002</samp> (light blue), <samp>100003</samp> (red), <samp>100004</samp> (yellow), <samp>100005</samp> (black), <samp>100006</samp> (gray), <samp>100007</samp> (charcoal / dim gray), or any other value for white. Defaults to brown/woody.
 
|-
 
| <samp>AdditionalChopDrops</samp><br /><samp>BushChopDrops</samp><br /><samp>StumpChopDrops</samp>
 
| ''(Optional)'' The additional items to drop when the tree is chopped. One field applies depending on the tree's current state: <samp>AdditionalChopDrops</samp> for a full-grown tree, <samp>BushChopDrops</samp> for a bush (one step below full-grown), and <samp>StumpChopDrops</samp> for the stump left behind after chopping a full-grown tree. This consists of a list of models with these fields:
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 1,029: Line 1,253:
 
! effect
 
! effect
 
|-
 
|-
| <samp>ItemID</samp>
+
| ''common fields''
| The [[#Custom items|qualified item ID]].
+
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields supported for fruit items.
 +
 
 +
Notes:
 +
* If set to an [[Modding:Item queries|item query]] which returns multiple items, one of them will be selected at random.
 +
* Season conditions are ignored in non-seasonal locations like the [[greenhouse]] and [[Ginger Island]].
 
|-
 
|-
| <samp>MinCount</samp><br /><samp>MaxCount</samp>
+
| <samp>Season</samp>
| The minimum/maximum number of the item to drop.
+
| ''(Optional)'' If set, the group only applies if the tree's location is in this season. This is ignored in non-seasonal locations like the [[greenhouse]] and [[Ginger Island]].
 
|-
 
|-
 
| <samp>Chance</samp>
 
| <samp>Chance</samp>
| ''(Optional)'' The probability that the item will drop, as a value between 0 (never drops) and 1 (always drops). This has no effect on other drops (e.g. if there are ten drops with 100% chance, all ten will drop). Default 1 (100% chance).
+
| ''(Optional)'' The probability that this entry is selected, as a value between 0 (never drops) and 1 (always drops). Default 1 (100% chance).
|-
 
| <samp>Condition</samp>
 
| ''(Optional)'' If set, the drop is only available if the given [[#Game state queries|game state query]] is true.
 
 
|}
 
|}
 
|-
 
|-
| <samp>SpringTapItems</samp><br /><samp>SummerTapItems</samp><br /><samp>FallTapItems</samp><br /><samp>WinterTapItems</samp>
+
| <samp>Texture</samp>
| The items produced by [[Tapper|tapping]] the tree in each season, as a list of models with these fields. If multiple items can be produced, the first available one is selected.
+
| The asset name for the texture under the game's <samp>Content</samp> folder. Use <samp>\</samp> (or <samp>\\</samp> in JSON) to separate name segments if needed. For example, vanilla fruit trees use <samp>TileSheets\fruitTrees</samp>.
{| class="wikitable"
 
 
|-
 
|-
! field
+
| <samp>TextureSpriteRow</samp>
! effect
+
| The tree's row index in the <samp>Texture</samp> spritesheet (e.g. 0 for the first tree, 1 for the second tree, etc).
 
|-
 
|-
| <samp>PossibleItems<samp>
+
| <samp>PlantableLocationRules</samp>
| The possible items to produce, as a list of models with these fields. If there are multiple items listed, one will be chosen at random each time.
+
| ''(Optional)'' The rules to decide which locations you can plant the sapling in, if applicable. The first matching rule is used. This can override location checks (e.g. crops being limited to the farm), but not built-in requirements like crops needing dirt.
 +
 
 +
This consists of a list of models with these fields:
 +
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 1,056: Line 1,283:
 
! effect
 
! effect
 
|-
 
|-
| <samp>ItemID</samp>
+
| <samp>Id</samp>
| The [[#Custom items|qualified item ID]].
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the list.
 
|-
 
|-
| <samp>MinCount</samp><br /><samp>MaxCount</samp>
+
| <samp>Result</samp>
| The minimum/maximum number of the item to produce when the tapper is emptied.
+
| Indicates whether the sapling can be planted in a location if this entry is selected. The possible values are:
 +
* <samp>Default</samp>: the sapling can be planted if the location normally allows it. This can be used to stop processing further rules, and/or set a custom <samp>DeniedMessage</samp>.
 +
* <samp>Allow</samp>: the sapling can be planted here, regardless of whether the location normally allows it.
 +
* <samp>Deny</samp>: the sapling can't be planted here, regardless of whether the location normally allows it.
 
|-
 
|-
| <samp>DaysUntilReady</samp>
+
| <samp>Condition</samp>
| The number of days before the tapper is ready to empty.
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this entry applies. Default true.
|}
 
 
|-
 
|-
| <samp>IsInitialTap</samp>
+
| <samp>PlantedIn</samp>
| ''(Optional)'' Whether this group only applies the first time a tree is tapped. Default false.
+
| ''(Optional)'' The planting context to apply this rule for. The possible values are <samp>Ground</samp> (planted directly in the ground), <samp>GardenPot</samp> (planted in a [[Garden Pot|garden pot]]), or <samp>Any</samp>. Default <samp>Any</samp>.
 +
 
 +
Note that saplings can't be planted in garden pots.
 
|-
 
|-
| <samp>PreviousItemID</samp>
+
| <samp>DeniedMessage</samp>
| ''(Optional)'' If set, the group only applies if the previous item produced by the tapper matches the given [[#Custom items|unqualified item ID]].
+
| ''(Optional)'' If this rule prevents planting the sapling, the tokenizable string to show to the player (or <samp>null</samp> to default to the normal behavior for the context). This also applies when the <samp>Result</samp> is <samp>Default</samp>, if that causes the planting to be denied.
 +
|}
 
|-
 
|-
| <samp>Condition</samp>
+
| <samp>CustomFields</samp>
| ''(Optional)'' If set, the group only applies if the given [[#Game state queries|game state query]] is true.
+
| The [[#Custom data fields|custom fields]] for this entry.
|}
 
 
|}
 
|}
  
Trees can then be added to the game by...
+
For example, this content pack adds a custom fruit tree, including [[#Custom items|custom items]] for the sapling and fruit:
* spawning them on [[Modding:Maps|map tiles]] by adding <samp>Paths</samp> index 34 to the <samp>Paths</samp> layer, with a <samp>TreeType</samp> tile property with the tree ID;
 
* or giving the player a seed item in the usual ways (e.g. from [[#Custom shops|a shop]], [[Modding:Mail data|mail letter]], etc).
 
  
===Hats on aquarium fish===
+
{{#tag:syntaxhighlight|<nowiki>
Custom [[Modding:Fish data|fish in aquariums]] can now wear [[hats]], just like vanilla [[Sea Urchin|sea urchins]]. This can be enabled by specifying a new field in <samp>Data/AquariumFish</samp>:
+
{
 +
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
 +
    "Changes": [
 +
        // add fruit + sapling items
 +
        // note: sapling must have an edibility under 0 (usually -300) to be plantable
 +
        {
 +
            "Action": "EditData",
 +
            "Target": "Data/Objects",
 +
            "Entries": {
 +
                "{{ModId}}_Pufferfruit": {
 +
                    "Name": "{{ModId}}_Pufferfruit", // best practice to match the ID, since it's sometimes used as an alternate ID
 +
                    "DisplayName": "Pufferfruit",
 +
                    "Description": "An example fruit item.",
 +
                    "Type": "Basic",
 +
                    "Category": -6,
 +
                    "Price": 1200,
  
{| class="wikitable"
+
                    "Texture": "Mods/{{ModId}}/Objects",
|-
+
                    "SpriteIndex": 0
! index
+
                },
! field
+
                "{{ModId}}_Puffersapling": {
! purpose
+
                    "Name": "{{ModId}}_Puffersapling",
|-
+
                    "DisplayName": "Puffersapling",
| 7
+
                    "Description": "An example tree sapling.",
| hat position
+
                    "Type": "Basic",
| The pixel position of the hat on the sprite, specified as an object with <samp>X</samp> and <samp>Y</samp> values.
+
                    "Category": -74,
 +
                    "Price": 1200,
  
'''Note:''' currently this is only used to check if the fish can wear a hat, and has no effect on its position.
+
                    "Texture": "Mods/{{ModId}}/Objects",
|}
+
                    "SpriteIndex": 1
 +
                }
 +
            }
 +
        },
  
===New context tags===
+
        // add fruit tree
1.6 adds several new [[Modding:Items#Context tags|item context tags]]:
+
        {
 +
            "Action": "EditData",
 +
            "Target": "Data/FruitTrees",
 +
            "Entries": {
 +
                "{{ModId}}_Puffersapling": {
 +
                    "DisplayName": "Pufferfruit",
 +
                    "Seasons": [ "spring" ],
 +
                    "Fruit": [
 +
                        {
 +
                            "Id": "E{{ModId}}_Pufferfruit",
 +
                            "ItemId": "{{ModId}}_Pufferfruit"
 +
                        }
 +
                    ],
 +
                    "Texture": "Mods/{{ModId}}/FruitTrees",
 +
                    "TextureSpriteRow": 0
 +
                }
 +
            }
 +
        },
 +
 
 +
        // add images
 +
        {
 +
            "Action": "Load",
 +
            "Target": "Mods/{{ModId}}/FruitTrees, Mods/{{ModId}}/Objects",
 +
            "FromFile": "assets/{{TargetWithoutPath}}.png" // assets/FruitTrees.png, assets/Objects.png
 +
        },
 +
    ]
 +
}</nowiki>|lang=javascript}}
  
 +
The fruit trees can then be added to the game by giving the player a sapling item in the usual ways (e.g. from [[#Custom shops|a shop]]).
 +
 +
====Fruit items====
 +
For C# mods, the <samp>fruitsOnTree</samp> field (number of fruit on the tree) has been replaced by <samp>fruit</samp> (list of fruit items).
 +
 +
====Spawning fruit trees====
 +
Custom trees can be added to the game in two ways:
 +
* Spawn them on [[Modding:Maps|map tiles]] when the location is created, using the new <samp>SpawnTree: fruit {{t|tree ID}} {{o|growth stage on location created}} {{o|growth stage on day-update regrowth}}</samp> tile property. This must be added on the <samp>Paths</samp> layer, which must also have tile index 34 from the <samp>paths</samp> tilesheet.
 +
* Or give the player a seed item in the usual ways (e.g. from [[#Custom shops|a shop]], [[Modding:Mail data|mail letter]], etc).
 +
 +
===Custom objects===
 +
{{/doc status|[[Modding:Items#Objects]]|done=false}}
 +
 +
You can now create/edit objects (the main item type) by editing the new <samp>Data/Objects</samp> asset, which replaces the previous slash-delimited <samp>Data/objectInformation</samp>.
 +
 +
Besides the format change, this adds...
 +
* support for custom textures;
 +
* revamped geode drops with support for conditions, probabilities, and item queries;
 +
* expanded food/drink buffs (e.g. set a custom buff ID, add a custom buff icon, etc);
 +
* context tags (moved from the former <samp>Data/ObjectContextTags</samp> asset);
 +
* [[#Custom data fields|custom fields]] to let framework mods support additional features.
 +
 +
This consists of a string → model lookup, where...
 +
* The key is the unqualified [[#Custom items|item ID]].
 +
* The value is a model with the fields listed below.
 +
 +
====Basic info====
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! context tag
+
! field
! effect
+
! purpose
 
|-
 
|-
| <samp>campfire_item</samp>
+
| <samp>Name</samp>
| Marks the item as a [[campfire]]. If the item also has the <samp>torch_item</samp> context tag, when it's placed in the world and turned on...
+
| The internal item name.
* campfire flames are drawn over it;
 
* if the item is [[Modding:Items#Big craftables|big craftable]], light is emitted from its center instead of the top.
 
 
|-
 
|-
| <samp>fish_legendary</samp>
+
| <samp>DisplayName</samp><br /><samp>Description</samp>
| Marks the fish as a [[Fish#Legendary Fish|legendary fish]]. For example: it can't be caught again, shows an alternate sprite in the fishing minigame and a 'caught legendary fish' message after catching it, can't be added to a [[Fish Pond|fish pond]], etc.
+
| A [[Modding:Tokenizable strings|tokenizable string]] for the item's in-game display name and description.
 
|-
 
|-
| <samp>fish_legendary_family</samp>
+
| <samp>Type</samp>
| Marks the fish as part of the [[Quests#Extended Family|legendary fish family]] for the fishing minigame. For example: requires [[Magic Bait|magic bait]], can't catch two at once, smaller bobber bar, 5× XP gain, etc.
+
| The item's general type, like <samp>Arch</samp> (artifact) or <samp>Minerals</samp>. See details at [[Modding:Items#Objects]].
 
|-
 
|-
| <samp>geode_special</samp>
+
| <samp>Category</samp>
| Marks the item as a [[geode]] item, and prevents it from being broken open at [[Blacksmith|Clint's blacksmith shop]].
+
| The [[Modding:Items#Categories|item category]].
 
|-
 
|-
| <samp>item_type_{{t|type}}</samp>
+
| <samp>Price</samp>
| For an [[Modding:Items#Objects|object-type item]], the type value from the 'type and category' field. (Non-object items always have the exact tag <samp>item_type_</samp> with nothing after the last underscore.) This is automatic and shouldn't be set manually. The tag is checked in a few places (''e.g.'' the [[museum]] to check if an item is an artifact or mineral), but most of the game won't be affected.
+
| ''(Optional)'' The price when sold by the player. This is not the price when bought from a shop. Default 0.
 +
|}
 +
 
 +
====Appearance====
 +
{| class="wikitable"
 
|-
 
|-
| <samp>museum_donatable</samp><br /><samp>not_museum_donatable</samp>
+
! field
| Set whether the item can be donated to the [[museum]], overriding the vanilla logic.
+
! purpose
 +
|-
 +
| <samp>Texture</samp>
 +
| The asset name for the texture containing the item's sprite. Defaults to <samp>Maps/springobjects</samp>.
 
|-
 
|-
| <samp>not_placeable</samp><br /><samp>placeable</samp>
+
| <samp>SpriteIndex</samp>
| Sets whether the item can be placed on the ground.
+
| The sprite's index within the <samp>Texture</samp>, where 0 is the top-left sprite.
 +
|}
 +
 
 +
====Edibility====
 +
{| class="wikitable"
 
|-
 
|-
| <samp>not_plantable_context_{{t|context ID}}</samp><br /><samp>not_plantable_location_{{t|location name}}</samp><br /><samp>plantable_context_{{t|context ID}}</samp><br /><samp>plantable_greenhouse</samp><br /><samp>plantable_location_{{t|location name}}</samp>
+
! field
| See [[#Custom planting restrictions|''custom planting restrictions'']].
+
! purpose
 
|-
 
|-
| <samp>paddy_crop</samp>
+
| <samp>Edibility</samp>
| Marks the item as a paddy [[Crops|crop]] like [[Unmilled Rice|rice]] or [[Taro Root|taro]]. This enables paddy-related logic like needing to be planted near water.
+
| ''(Optional)'' A numeric value that determines how much energy (edibility × 2.5) and health (edibility × 1.125) is restored when this item is eaten. An item with an edibility of -300 can't be eaten, values from -299 to -1 reduce health and energy, and zero can be eaten but doesn't change health/energy. Default -300.
 
|-
 
|-
| <samp>sign_item</samp>
+
| <samp>IsDrink</samp>
| Marks the item as a [[Crafting#Signs|sign]], which lets player display items on it or place it on a [[Fish Pond|fish pond]] to show the fish count.
+
| ''(Optional)'' Whether to drink the item instead of eating it. Default false.
 
|-
 
|-
| <samp>torch_item</samp>
+
| <samp>Buffs</samp>
| Marks the item as a [[torch]], which lets the player turn it on/off to emit light.
+
| ''(Optional)'' The buffs to apply to the player when this item is eaten, if any. Default none.
  
See also <samp>campfire_item</samp>.
+
This consists of a list of models with these fields:
|}
 
 
 
Contexts which affect [[#Custom machines|machine processing]]:
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! context tag
+
! field
! effect
+
! purpose
 
|-
 
|-
| <samp>crystalarium_banned</samp>
+
| <samp>Id</samp>
| When applied to a gem or mineral item, prevents players from placing it in a [[crystalarium]].
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the list.
 
|-
 
|-
| <samp>fairy_dust_banned</samp>
+
| <samp>Duration</samp>
| When applied to a machine, prevents players from using [[Fairy Dust|fairy dust]] to speed it up.
+
| ''(Optional if <samp>BuffId</samp> is set)'' The buff duration measured in in-game minutes. This can be set to <samp>-2</samp> for a buff that should last for the rest of the day.
 
|-
 
|-
| <samp>is_machine</samp>
+
| <samp>BuffId</samp>
| Indicates the item has [[#Custom machines|machine logic]]. This is added automatically based on <samp>Data/MachinesData</samp> and is informational only (it has no effect on the game logic).
+
| ''(Optional)'' The unique ID of a buff from [[#Custom buffs|<samp>Data/Buffs</samp>]] to apply, or <samp>null</samp> to ignore <samp>Data/Buffs</samp> and set the ID to <samp>food</samp> or <samp>drink</samp> depending on the item's <samp>IsDrink</samp> field.
 +
 
 +
If a buff from <samp>Data/Buffs</samp> is applied and you also specify other fields, here's how the buff data is combined:
 +
{| class="wikitable"
 
|-
 
|-
| <samp>keg_juice</samp><br /><samp>keg_wine</samp>
+
! field
| Allows processing the item in a [[keg]] to produce a juice or wine variant.
+
! result
 
|-
 
|-
| <samp>machine_input</samp><br /><samp>machine_output</samp>
+
| <samp>Duration</samp><br /><samp>IconTexture</samp><br /><samp>SpriteIndex</samp><br /><samp>GlowColor</samp>
| Whether the item is a machine which accepts items from the player (<samp>machine_input</samp>) and/or which produces items for the player to collect (<samp>machine_output</samp>). If the [[#Custom machines|machine data]] sets the <samp>ConversionMethod</samp> field, both tags are added since there's no way to know what the method does.
+
| If specified, the value in <samp>Data/Objects</samp> is used instead of the one in <samp>Data/Buffs</samp>. If omitted, defaults to the value from <samp>Data/Buffs</samp>.
 
 
These are added automatically based on <samp>Data/MachinesData</samp> and are informational only (they have no effect on the game logic). The <samp>is_machine</samp> tag is always added if these are.
 
 
|-
 
|-
| <samp>preserves_jelly</samp><br /><samp>preserves_pickle</samp>
+
| <samp>CustomAttributes</samp>
| Allows processing the item in a [[Preserves Jar|preserves jar]] to produce a jelly or pickled variant.
+
| The values from both entries are combined (e.g. +1 speed in <samp>Data/Objects</samp> and +1 speed in <samp>Data/Buffs</samp> results in +2 speed).
 
|-
 
|-
| <samp>seedmaker_banned</samp>
+
| <samp>IsDebuff</samp>
| When applied to a seed item, prevents players from placing it in a [[Seed Maker|seed maker]].
+
| The value in <samp>Data/Objects</samp> is used.
 +
|}
 
|-
 
|-
| <samp>tapper_item</samp>
+
| <samp>IsDebuff</samp>
| Marks the item as a [[tapper]] or [[Heavy Tapper|heavy tapper]].
+
| ''(Optional)'' Whether this buff counts as a debuff, so its duration should be halved when wearing a Sturdy Ring. Default false.
 
|-
 
|-
| <samp>tapper_multiplier_{{t|multiplier}}</samp>
+
| <samp>IconTexture</samp>
| The multiplier applied to the tapper production speed. For example, <samp>2</samp> will make items take half their base time (''i.e.'' each item will finish in <sup>base time</sup>/<sub>speed multiplier</sub>). Defaults to 1 if omitted.
+
| ''(Optional)'' The asset name for the icon texture to load. This must contain one or more 16x16 icons in a grid of any size. If omitted, the game will draw a default icon based on the <samp>BuffId</samp> and <samp>CustomAttributes</samp> fields.
|}
+
|-
 
+
| <samp>SpriteIndex</samp>
===Other item changes===
+
| ''(Optional)'' The buff's icon index within the <samp>IconTexture</samp>, where 0 is the top-left icon. Default 0.
* Added a display name field in English too for <samp>Data/Boots</samp>, <samp>Data/CookingRecipes</samp>, <samp>Data/CraftingRecipes</samp>, and <samp>Data/Furniture</samp>.
+
|-
* Added optional <samp>Condition</samp> [[#Game state queries|game state query]] field to <samp>Data/SpecialOrders</samp>.
+
| <samp>GlowColor</samp>
* The <samp>Object.performObjectDropInAction</samp> method now applies the <samp>probe</samp> argument much more consistently. This only affects method calls with <samp>probe: true</samp>.
+
| ''(Optional)'' The glow color to apply to the player. See [[#Color fields|color format]]. Default none.
* The <samp>IsRecipe</samp>, <samp>Quality</samp>, <samp>Stack</samp> properties are now part of the base <samp>Item</samp> class instead of <samp>Object</samp>.
+
|-
 
+
| <samp>CustomAttributes</samp>
==What's new for locations & weather==
+
| The custom buff attributes to apply, if any.
===Custom locations===
 
You can now add/edit locations by editing the new <samp>Data/AdditionalLocationsData</samp> asset.
 
 
 
The asset consists of a string → model lookup, where the key matches the <samp>ID</samp> field and the value is a model with these fields:
 
  
 +
This consists of a model with any combination of these fields:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
 
! field
 
! field
! effect
+
! purpose
 
|-
 
|-
| <samp>ID</samp>
+
| <samp>FarmingLevel</samp><br /><samp>FishingLevel</samp><br /><samp>ForagingLevel</samp><br /><samp>LuckLevel</samp><br /><samp>MiningLevel</samp>
| A key which uniquely identifies this location, which will be used as the location's <samp>Name</samp> (not <samp>DisplayName</samp>) field. The ID should only contain alphanumeric/underscore/dot characters. For custom locations, this should be prefixed with your mod ID like <samp>Example.ModId_LocationName</samp>.
+
| ''(Optional)'' An amount applied to the matching [[Skills|skill level]] while the buff is active. This can be negative for a debuff. Default 0.
 
|-
 
|-
| <samp>MapPath</samp>
+
| <samp>Attack</samp><br /><samp>Defense</samp><br /><samp>MagneticRadius</samp><br /><samp>MaxStamina</samp><br /><samp>Speed</samp>
| The asset name for the map to use for this location.
+
| ''(Optional)'' An amount applied to the player's [[attack]], [[defense]], [[Magnetism|magnetic radius]], maximum [[Energy|stamina]], or [[speed]] while the buff is active. This can be negative for a debuff. Default 0.
 +
|}
 
|-
 
|-
| <samp>DisplayName</samp>
+
| <samp>CustomFields</samp>
| ''(Optional but strongly recommended)'' A [[#Tokenizable string format|tokenizable string]] for the translated location name. This is used anytime the location name is shown in-game for base game logic or mods.
+
| ''(Optional)'' The [[#Custom data fields|custom fields]] for this entry.  
|-
+
|}
| <samp>Type</samp>
 
| ''(Optional)'' The full name of the C# location class to create. This must be one of the vanilla types to avoid a crash when saving. There are too many to list here, but the most useful types are likely <samp>StardewValley.GameLocation</samp> (default value) and <samp>StardewValley.Locations.DecoratableLocation</samp>.
 
 
|}
 
|}
  
===Custom location contexts===
+
====Geodes & artifact spots====
====Vanilla contexts====
 
* The game previously had two hardcoded location context enums: <samp>Default</samp> (for the valley) and <samp>Island</samp> (for [[Ginger Island]]). These have been replaced with data models which define the location context settings, loaded from the <samp>Data/LocationContexts</samp> asset.
 
* [[The Desert|The desert]] is now part of a new <samp>Desert</samp> context (instead of <samp>Default</samp>). Some of the previously hardcoded desert logic (like always sunny weather) is now just part of the context data in <samp>Data/LocationContexts</samp>.
 
 
 
====Format====
 
Custom contexts can be created by editing the new <samp>Data/LocationContexts</samp> asset, and setting the context name in the location's <samp>LocationContext</samp> [[Modding:Maps|map property]].
 
 
 
The data asset consists of a string → model lookup, where the key matches the <samp>Name</samp> field and the value is a model with these fields:
 
 
 
<dl style="margin-left: 2em;">
 
<dt>Required fields:</dt>
 
<dd>
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
 
! field
 
! field
! effect
+
! purpose
 
|-
 
|-
| <samp>Name</samp>
+
| <samp>GeodeDrops</samp><br /><samp><samp>GeodeDropsDefaultItems</samp>
| The unique ID for the location context. This should only contain alphanumeric/underscore/dot characters. For custom contexts, this should be prefixed with your mod ID like <samp>Example.ModId_ContextName</samp>.
+
| ''(Optional)'' The items that can be dropped when breaking open this item as a [[Minerals#Geodes|geode]]. Specifying either or both fields automatically enables geode behavior for this item.
|}
 
</dd>
 
  
<dt>Player actions:</dt>
+
You can specify one or both fields:
<dd>
+
<ul>
 +
<li><samp>GeodeDrops</samp> can be set to the specific items to drop. Default none. This consists of a list of models with these fields:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
 
! field
 
! field
! effect
+
! purpose
 
|-
 
|-
| <samp>DefaultValidPlantableLocations</samp>
 
| ''(Optional)'' The internal names of the locations where crops can be planted and grown by default (see also [[#Custom planting restrictions|custom planting restrictions]]).
 
 
|-
 
|-
| <samp>AllowRainTotem</samp>
+
| ''common fields''
| ''(Optional)'' Whether a [[Rain Totem]] can be used to force rain in this context tomorrow.
+
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields supported by geode drops.
 +
 
 +
If set to an [[Modding:Item queries|item query]] which returns multiple items, one of them will be selected at random.
 +
|-
 +
| <samp>Chance</samp>
 +
| ''(Optional)'' The probability that the item will be dropped if the other fields match, as a decimal value between 0 (never) and 1 (always). Default 1.
 +
|-
 +
| <samp>SetFlagOnPickup</samp>
 +
| ''(Optional)'' The mail flag to set for the current player when this drop is picked up.
 
|-
 
|-
| <samp>MaxPassOutCost</samp>
+
| <samp>Precedence</samp>
| ''(Optional)'' When the player passes out (due to [[energy|exhaustion]] or at 2am) in this context, the maximum amount of [[gold]] lost. If omitted or set to <samp>-1</samp>, uses the same value as the <samp>Default</samp> context ({{price|1000}} by default).
+
| ''(Optional)'' The order in which this entry should be checked, where lower values are checked first. This can be a negative value. Geode drops with the same precedence are checked in the order listed. Default 0.
 +
 
 +
For consistency, vanilla drops mostly use these values:
 +
* <samp>-1000</samp>: special overrides like the [[Golden Helmet]];
 +
* <samp>0</samp>: normal items.
 +
|}</li>
 +
<li><samp>GeodeDropsDefaultItems</samp> chooses a predefined list of possible geode drops like [[clay]], [[coal]], [[Copper Ore|copper]], [[Iridium Ore|iridium]], etc. Default false.</li>
 +
</ul>
 +
 
 +
If both fields are specified, each geode will choose between them with an equal 50% chance. If <samp>GeodeDrops</samp> is specified but no entries match, the geode will use the <samp>GeodeDropsDefaultItems</samp> regardless of whether it's true.
 
|-
 
|-
| <samp>PassOutMail</samp>
+
| <samp>ArtifactSpotChances</samp>
| ''(Optional)'' When the player passes out (due to [[energy|exhaustion]] or at 2am) in this context, the possible [[Modding:Mail data|letter IDs]] to add to their mailbox (if they haven't received it before). If multiple letters are valid, one will be chosen randomly (unless one specifies <samp>SkipRandomSelection</samp>).
+
| ''(Optional)'' If this is an artifact (i.e. the <samp>Type</samp> field is <samp>Arch</samp>), the chance that it can be found by digging [[Artifact Spot|artifact spots]] in each location.
 +
 
 +
This consists of a string → model lookup, where:
 +
* the key is the internal location name;
 +
* the value is the probability the item will spawn if checked, as a decimal value between 0 (never) and 1 (always).
 +
|}
  
This consists of a list of models with these fields:
+
====Context tags & exclusions====
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
 
! field
 
! field
! effect
+
! purpose
 
|-
 
|-
| <samp>Mail</samp>
+
| <samp>ContextTags</samp>
| The [[Modding:Mail data|letter ID]] to add.
+
| ''(Optional)'' The custom [[Modding:Items#Context tags|context tags]] to add for this item (in addition to the tags added automatically based on the other object data). This is formatted as a list; for example:
 
+
<syntaxhighlight lang="json">
The game will look for an existing letter ID in <samp>Data/mail</samp> in this order (where {{t|billed}} is <samp>Billed</samp> if they lost [[gold]] or <samp>NotBilled</samp> otherwise, and {{t|gender}} is <samp>Female</samp> or <samp>Male</samp>):
+
"ContextTags": [ "color_yellow", "fish_ocean", "fish_upright", "season_summer" ]
* <samp>{{t|letter id}}_{{t|billed}}_{{t|gender}}</samp>
+
</syntaxhighlight>
* <samp>{{t|letter id}}_{{t|billed}}</samp>
 
* <samp>{{t|letter id}}</samp>
 
 
 
If no match is found in <samp>Data/mail</samp>, the game will send <samp>passedOut2</samp> instead.
 
 
 
If the mail ID starts with <samp>passedOut</samp>, <samp>{0}</samp> in the letter text will be replaced with the gold amount lost, and it won't appear in the [[collections]] page.
 
 
|-
 
|-
| <samp>MaxPassOutCost</samp>
+
| <samp>ExcludeFromRandomSale</samp>
| ''(Optional)'' The maximum amount of [[gold]] lost. This is applied after the context's <samp>MaxPassOutCost</samp> (i.e. the context's value is used to calculate the random amount, then this field caps the result). Defaults to unlimited.
+
| ''(Optional)'' Whether to exclude this item from shops when selecting random items to sell. Default false.
 
|-
 
|-
| <samp>Condition</samp>
+
| <samp>ExcludeFromFishingCollection</samp><br /><samp>ExcludeFromShippingCollection</samp>
| ''(Optional)'' A [[#Game state queries|game state query]] which indicates whether this entry is active. Defaults to always true.
+
| ''(Optional)'' Whether to exclude this item from the fishing/shipping collection and their respective effect on the [[perfection|perfection score]]. Default false, in which case the normal requirements apply (e.g. artifacts are always excluded from the shipping collection).
|-
 
| <samp>SkipRandomSelection</samp>
 
| ''(Optional)'' If true, send this mail if the <samp>Condition</samp> matches instead of choosing a random valid mail. Default false.
 
 
|}
 
|}
|-
 
| <samp>PassOutLocations</samp>
 
| ''(Optional)'' When the player passes out (due to [[energy|exhaustion]] or at 2am) in this context ''and'' they started the day in a different location context, the locations where they'll wake up. (If the player started the day in the same context, they'll wake up in the last bed they slept in instead.)
 
  
This consists of a list of models with these fields:
+
====Advanced====
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
 
! field
 
! field
! effect
+
! purpose
 
|-
 
|-
| <samp>Location</samp>
+
| <samp>CustomFields</samp>
| The internal location name.
+
| ''(Optional)'' The [[#Custom data fields|custom fields]] for this entry.  
|-
 
| <samp>Position</samp>
 
| The ''default'' tile position within the location, specified as an object with <samp>X</samp> and <samp>Y</samp> fields. If the location has any bed furniture, they'll be placed in the first bed found instead.
 
|-
 
| <samp>Condition</samp>
 
| ''(Optional)'' A [[#Game state queries|game state query]] which indicates whether this entry is active. Defaults to always applied.
 
 
|}
 
|}
  
If no locations are specified or none match, the player will wake up in their bed at home.
+
===Custom pants===
|-
+
{{/doc status|[[Modding:Items]]|done=false}}
| <samp>ReviveLocations</samp>
+
 
| ''(Optional)'' If the player just got knocked out in combat, the location names where they'll wake up.
+
You can now create/edit [[Tailoring#Pants|pants]] by editing the new <samp>Data/Pants</samp> asset, which replaces <samp>Data/clothingInformation</samp>. This consists of a string → model lookup, where...
 +
* The key is the unqualified [[#Custom items|item ID]].
 +
* The value is a model with the fields listed below.
  
This consists of a list of models with these fields:
+
====Basic pants data====
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
 
! field
 
! field
! effect
+
! purpose
 
|-
 
|-
| <samp>Location</samp>
+
| <samp>Name</samp>
| The internal location name.
+
| ''(Optional)'' The internal name for the item. Default <samp>Pants</samp>.
 
|-
 
|-
| <samp>Position</samp>
+
| <samp>DisplayName</samp><br /><samp>Description</samp>
| The tile position within the location, specified as an object with <samp>X</samp> and <samp>Y</samp> fields.
+
| ''(Optional)'' A [[Modding:Tokenizable strings|tokenizable string]] for the item's in-game display name and description. Defaults to the generic pants text (''Pants'' and ''A wearable pair of pants'').
 
|-
 
|-
| <samp>Condition</samp>
+
| <samp>Price</samp>
| ''(Optional)'' A [[#Game state queries|game state query]] which indicates whether this entry is active. Defaults to always applied.
+
| ''(Optional)'' The default price when the item is sold to the player in a shop. Default 50.
 
|}
 
|}
  
If the selected location has a standard [[Modding:Event data|event]] with the exact key <samp>PlayerKilled</samp> (with no <samp>/</samp> or preconditions in the key), that event will play when the player wakes up and the game will apply the lost items or [[gold]] logic. The game won't track this event, so it'll repeat each time the player is revived. If there's no such event, the player will wake up without an event, and no items or gold will be lost.
+
====Appearance====
 
 
If no locations are specified or none match, the player will wake up at [[Harvey's Clinic|Harvey's clinic]].
 
|}
 
</dd>
 
 
 
<dt>Season:</dt>
 
<dd>
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
 
! field
 
! field
! effect
+
! purpose
 +
|-
 +
| <samp>Texture</samp>
 +
| The asset name for the texture containing the pants' sprite. Defaults to <samp>Characters/Farmer/pants</samp>.
 +
|-
 +
| <samp>SpriteIndex</samp>
 +
| The pants' sprite index within the <samp>Texture</samp>, where 0 is the top-left set.
 +
|-
 +
| <samp>DefaultColor</samp>
 +
| ''(Optional)'' The dye color to apply to the sprite when the player hasn't [[dyeing|dyed]] it yet, if any. See [[#Color fields|color format]]. Default <samp>255 235 203</samp> (which matches the color of the cloth item).
 +
|-
 +
| <samp>CanBeDyed</samp>
 +
| ''(Optional)'' Whether the player can [[dyeing|dye]] these pants. Default false.
 
|-
 
|-
| <samp>SeasonOverride</samp>
+
| <samp>IsPrismatic</samp>
| ''(Optional)'' The season which is always active for locations within this context (one of <samp>spring</samp>, <samp>summer</samp>, <samp>fall</samp>, or <samp>winter</samp>). For example, setting <samp>summer</samp> will make it always [[summer]] there regardless of the calendar season. If not set, the calendar season applies.
+
| ''(Optional)'' Whether the pants continuously shift colors. This overrides <samp>DefaultColor</samp> and <samp>CanBeDyed</samp> if set. Default false.
 
|}
 
|}
</dd>
 
  
<dt>Weather:</dt>
+
====Other====
<dd>
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
 
! field
 
! field
! effect
+
! purpose
 +
|-
 +
| <samp>CanChooseDuringCharacterCustomization</samp>
 +
| ''(Optional)'' Whether these pants can be selected on the character customization screen (e.g. when creating a character). Default false.
 
|-
 
|-
| <samp>WeatherConditions</samp>
+
| <samp>CustomFields</samp>
| ''(Optional)'' The weather logic to apply for locations in this context (ignored if <samp>CopyWeatherFromLocation</samp> is set). Defaults to always sunny. If multiple are specified, the first matching weather is applied.
+
| The [[#Custom data fields|custom fields]] for this entry.
 +
|}
 +
 
 +
===Custom shirts===
 +
{{/doc status|[[Modding:Items]]|done=false}}
 +
 
 +
You can now create/edit [[Tailoring#Shirts|shirts]] by editing the new <samp>Data/Shirts</samp> asset, which replaces <samp>Data/clothingInformation</samp>. This consists of a string → model lookup, where...
 +
* The key is the unqualified [[#Custom items|item ID]].
 +
* The value is a model with the fields listed below.
  
This consists of a list of models with these fields:
+
====Basic shirt data====
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
 
! field
 
! field
! effect
+
! purpose
 
|-
 
|-
| <samp>Weather</samp>
+
| <samp>Name</samp>
| The [[#Custom weather|weather ID]] to set.
+
| ''(Optional)'' The internal name for the item. Default <samp>Shirt</samp>.
 
|-
 
|-
| <samp>Condition</samp>
+
| <samp>DisplayName</samp><br /><samp>Description</samp>
| ''(Optional)'' A [[#Game state queries|game state query]] which indicates whether to apply the weather. Defaults to always applied.
+
| ''(Optional)'' A [[Modding:Tokenizable strings|tokenizable string]] for the item's in-game display name and description. Defaults to the generic shirt text (''Shirt'' and ''A wearable shirt'').
|}
 
 
|-
 
|-
| <samp>CopyWeatherFromLocation</samp>
+
| <samp>Price</samp>
| ''(Optional)'' The <samp>Name</samp> (i.e. unique ID) of the location context from which to inherit weather.
+
| ''(Optional)'' The default price when the item is sold to the player in a shop. Default 50.
 
|}
 
|}
  
If a [[#Custom passive festivals|passive festival]] is active in any location within this context, the weather is sunny for the entire context regardless of these fields.
+
====Appearance====
 
 
</dd>
 
 
 
<dt>Music:</dt>
 
<dd>
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
 
! field
 
! field
! effect
+
! purpose
 
|-
 
|-
| <samp>DefaultMusic</samp>
+
| <samp>Texture</samp>
| ''(Optional)'' The [[#Custom audio|cue ID]] for the music to play when the player is in the location, unless overridden by a <samp>Music</samp> map property. Despite the name, this has a higher priority than the seasonal music fields below. Ignored if omitted.
+
| The asset name for the texture containing the shirt's sprite. Defaults to <samp>Characters/Farmer/shirts</samp>.
 
|-
 
|-
| <samp>DefaultMusicCondition</samp>
+
| <samp>SpriteIndex</samp>
| ''(Optional)'' A [[#Game state queries|game state query]] which returns whether the <samp>DefaultMusic</samp> field should be applied (if more specific music isn't playing). Defaults to always true.
+
| The shirt's sprite index within the <samp>Texture</samp>, where 0 is the top-left set.
 
|-
 
|-
| <samp>DefaultMusicDelayOneScreen</samp>
+
| <samp>DefaultColor</samp>
| ''(Optional)'' When the player warps and the music changes, whether to silence the music and play the ambience (if any) until the next warp (similar to the default valley locations). Default false.
+
| ''(Optional)'' The dye color to apply to the sprite when the player hasn't [[dyeing|dyed]] it yet, if any. See [[#Color fields|color format]]. Default none.
 
|-
 
|-
| <samp>SpringMusic</samp><br /><samp>SummerMusic</samp><br /><samp>FallMusic</samp><br /><samp>WinterMusic</samp>
+
| <samp>CanBeDyed</samp>
| ''(Optional)'' A list of [[#Custom audio|cue IDs]] to play before noon in this location unless it's raining, there's a <samp>Music</samp> map property, or the context has a <samp>DefaultMusic</samp> value. If multiple values are specified, the game will play one per day in sequence.
+
| ''(Optional)'' Whether the player can [[dyeing|dye]] this shirt. Default false.
 
|-
 
|-
| <samp>DayAmbience</samp><br /><samp>NightAmbience</samp>
+
| <samp>IsPrismatic</samp>
| ''(Optional)'' The [[#Custom audio|cue ID]] for the background ambience to play when there's no music active, depending on the [[Day Cycle|time of day]]. Both default to none.
+
| ''(Optional)'' Whether the shirt continuously shifts colors. This overrides <samp>DefaultColor</samp> and <samp>CanBeDyed</samp> if set. Default false.
 
|-
 
|-
| <samp>PlayRandomAmbientSounds</samp>
+
| <samp>HasSleeves</samp>
| ''(Optional)'' Whether to play random outdoor ambience sounds depending on factors like the season and time of day (e.g. birds, crickets, and mysterious groan sounds in the rain). This is unrelated to the <samp>DayAmbience</samp> and <samp>NightAmbience</samp> fields. Default true.
+
| ''(Optional)'' Whether to draw shirt sleeves. Default true.
 
|}
 
|}
</dd>
 
</dl>
 
  
===Custom map actions===
+
====Other====
C# mods can now handle custom <samp>Action</samp> & <samp>TouchAction</samp> [[Modding:Maps|map properties]] by calling <samp>GameLocation.RegisterTileAction</samp> & <samp>RegisterTouchAction</samp>, and passing a callback which receives the location, map property arguments, player who activated it, and tile position.
+
{| class="wikitable"
 +
|-
 +
! field
 +
! purpose
 +
|-
 +
| <samp>CanChooseDuringCharacterCustomization</samp>
 +
| ''(Optional)'' Whether this shirt can be selected on the character customization screen (e.g. when creating a character). Default false.
 +
|-
 +
| <samp>CustomFields</samp>
 +
| The [[#Custom data fields|custom fields]] for this entry.
 +
|}
 +
 
 +
===Custom tools===
 +
{{/doc status|[[Modding:Items]]|done=false}}
  
For example, let's say you want a locked gate which needs a custom key item. You can add a regular <code>TouchAction Example.ModId_UnlockGate</code> map property (e.g. by adding it directly in the map file, or using [[Modding:Content Patcher|Content Patcher]]'s <samp>EditMap</samp>, or using the [[Modding:Modder Guide/APIs/Content|content API]]). Then you can just handle the logic from your C# mod:
+
You can now create/edit [[tools]] by editing the new <samp>Data/Tools</samp> asset. This consists of a string → model lookup, where...
<syntaxhighlight lang="c#">
+
* The key is the unqualified [[#Custom items|item ID]].
internal class ModEntry : Mod
+
* The value is a model with the fields listed below.
{
 
    /// <inheritdoc />
 
    public override void Entry(IModHelper helper)
 
    {
 
        GameLocation.RegisterTouchAction("Example.ModId_UnlockGate", this.HandleUnlockGate);
 
    }
 
  
    private void HandleUnlockGate(GameLocation location, string[] args, Farmer player, Vector2 tile)
+
====Basic tool data====
    {
+
{| class="wikitable"
        const string mailFlag = "Example.ModId_GateUnlocked";
+
|-
        const string keyId = "Example.ModId_GateKey";
+
! field
 +
! purpose
 +
|-
 +
| <samp>ClassName</samp>
 +
| The name of the C# class to construct within the <code>StardewValley.Tools</code> namespace. The class must be a subclass of <samp>StardewValley.Tool</samp>, and have a constructor with no arguments. For example, given a value of <samp>Axe</samp>, the game will create <code>StardewValley.Tools.Axe</code> instances.
  
        // unlock gate if locked
+
The main values are:
        if (!player.mailReceived.Contains(mailFlag))
+
* main tools (<samp>Axe</samp>, <samp>FishingRod</samp>, <samp>Hoe</samp>, <samp>MeleeWeapon</samp>, <samp>MilkPail</samp>, <samp>Pan</samp>, <samp>Pickaxe</samp>, <samp>Shears</samp>, <samp>Wand</samp>, and <samp>WateringCan</samp>);
        {
+
* a special <samp>GenericTool</samp> type which applies the <samp>Data/Tools</samp> data and only has generic logic, so C# mods can patch in their own logic;
            if (!Game1.player.hasItemInInventory(keyId, 1))
+
* and two tools cut from the game which may not work correctly (<samp>Lantern</samp> and <samp>Raft</samp>).
            {
+
|-
                Game1.activeClickableMenu = new DialogueBox("This gate is locked. I wonder where the key is?");
+
| <samp>Name</samp>
                return;
+
| The internal name to set for the tool item.
            }
+
|-
 +
| <samp>DisplayName</samp><br /><samp>Description</samp>
 +
| A [[Modding:Tokenizable strings|tokenizable string]] for the tool's in-game display name and description.
 +
|-
 +
| <samp>AttachmentSlots</samp>
 +
| ''(Optional)'' The number of attachment slots to enable on the tool. Note that only <samp>FishingRod</samp> tools have the code to render and use attachment slots. Default <samp>-1</samp>, which keeps the default value set by the tool class.
 +
|-
 +
| <samp>SalePrice</samp>
 +
| ''(Optional)'' The default price when the item is sold to the player in a shop. Defaults to <samp>-1</samp>, in which case you should set the price manually in shops.
 +
|-
 +
| <samp>CustomFields</samp>
 +
| The [[#Custom data fields|custom fields]] for this entry.
 +
|}
  
            player.removeFirstOfThisItemFromInventory(keyId);
+
====Appearance====
            player.mailReceived.Add(mailFlag);
+
Note that drawing the tool correctly in the world (ie, while the player is trying to use it) probably still needs custom code.
        }
 
 
 
        // apply open-gate map edit
 
        IAssetDataForMap mapHelper = this.Helper.Content.GetPatchHelper(location.map).AsMap();
 
        mapHelper.PatchMap(
 
            this.Helper.Content.Load<Map>("assets/unlocked-gate.tmx"),
 
            targetArea: new Rectangle((int)tile.X - 1, (int)tile.Y - 1, 2, 2)
 
        );
 
    }
 
}
 
</syntaxhighlight>
 
 
 
===Custom map areas===
 
[[File:Modding map area.png|thumb|The valley map, with one map area highlighted.]]
 
 
 
You can now add/edit areas on the game menu's map UI, or even replace the entire map for a different world region, by editing the new <samp>Data/InGameMap</samp> asset. For example, this is used to show a different farm on the map depending on the current [[Farm Maps|farm type]].
 
 
 
====Concepts====
 
The game divides the map into three concepts:
 
 
 
* A '''map''' is one full world area rendered in one image, like the entire image shown at right.
 
* A '''map area''' is a smaller section of the map which is linked to one or more in-game areas. The map area might be edited/swapped depending on the context, have its own tooltip(s), or have its own player marker positions. For example, the highlighted area on the image shown at right is swapped depending on the current [[Farm Maps|farm type]].
 
* A '''group name''' is a unique key shared between all the map areas that are rendered on the same map. For example, if there was a separate map for [[Ginger Island]], all the map areas in the valley group would be hidden.
 
 
 
====Format====
 
The <samp>Data/InGameMap</samp> data asset consists of a string → model lookup, where the key matches the <samp>AreaID</samp> field and the value is a model with these fields:
 
  
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
 
! field
 
! field
! effect
+
! purpose
|-
 
| <samp>AreaID</samp>
 
| A unique identifier for the area. The ID should only contain alphanumeric/underscore/dot characters. For custom areas, this should be prefixed with your mod ID like <samp>Example.ModId_AreaName</samp>.
 
|-
 
| <samp>Group</samp>
 
| A unique group key shared between all areas drawn on the same map (see [[#Concepts|concepts]]). When the player is in an area for one group, all map areas with a different group key are hidden automatically. The base valley map added by the base game has the group key <samp>SDV</samp>. This should only contain alphanumeric/underscore/dot characters. For custom groups, this should be prefixed with your mod ID like <samp>Example.ModId_GroupName</samp>.
 
 
|-
 
|-
 
| <samp>Texture</samp>
 
| <samp>Texture</samp>
| The asset name for the texture to draw when the area is applied to the map.
+
| The asset name for the texture containing the tool's sprite.
 
 
If set to the exact string <samp>"MOD_FARM"</samp>, the game will apply the texture for the current farm type, regardless of whether it's a vanilla or mod farm type. (The vanilla <samp>DestRect</samp> for the farm area is <samp>"0 43 131 61"</samp>.)
 
 
 
'''Note:''' this field is required. To add an invisible area, you can set this to a valid texture (e.g. <samp>"LooseSprites\\map"</samp>) and omit <samp>SourceRect</samp> instead.
 
 
|-
 
|-
| <samp>SourceRect</samp>
+
| <samp>SpriteIndex</samp>
| The pixel area within the <samp>Texture</samp> to draw, formatted like <samp>"{{t|x}} {{t|y}} {{t|width}} {{t|height}}"</samp>. Omit this field to make the area invisible (''e.g.,'' to add zones or tooltips without changing the map).
+
| The tool's sprite index within the <samp>Texture</samp>, where 0 is the top row.
 
|-
 
|-
| <samp>DestRect</samp>
+
| <samp>MenuSpriteIndex</samp>
| The pixel area within the map which is covered by this area, formatted like <samp>"{{t|x}} {{t|y}} {{t|width}} {{t|height}}"</samp>.
+
| ''(Optional)'' The sprite index within the <samp>Texture</samp> for the item icon. Defaults to <samp>SpriteIndex</samp>.
|-
+
|}
| <samp>Zones</samp>
 
| The in-game locations to match with the map. Each zone can provide one or more of the following:
 
* match an in-game location to the world map area (via <samp>ValidAreas</samp>);
 
* match an in-game tile position to the world map pixel position (via <samp>MapTileCorners</samp> and <samp>MapImageCorners</samp>);
 
* add tooltips and scroll text for different portions of the world map (via <samp>DisplayName</samp>).
 
  
This consists of a list models with these fields:
+
====Upgrades====
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
 
! field
 
! field
! effect
+
! purpose
 
|-
 
|-
| <samp>ValidAreas</samp>
+
| <samp>UpgradeLevel</samp>
| A list of location names. Each location can be one of...
+
| ''(Optional)'' The tool upgrade level. Default <samp>-1</samp>, which keeps the default value set by the tool class.
* An internal location name (as shown by the {{nexus mod|679|Debug Mode}} mod). Any location within [[The Mines|the mines]] and the [[Skull Cavern]] will be <samp>Mines</samp> and <samp>SkullCave</samp> respectively, and festivals use the map asset name (e.g. <samp>Town-EggFestival</samp>). For example, the vanilla desert uses <code>"ValidAreas": [ "Desert", "SkullCave", "SandyHouse", "SandyShop", "Club" ]</code>.
 
* <samp>CONTEXT_Default</samp> for any location in the valley.
 
* <samp>CONTEXT_Island</samp> for any location on [[Ginger Island]].
 
 
|-
 
|-
| <samp>MapTileCorners</samp><br /><samp>MapImageCorners</samp>
+
| <samp>ApplyUpgradeLevelToDisplayName</samp>
| ''(Optional)'' The corner coordinates for the in-game location measured in tiles, and the equivalent map image area measured in pixels. Both use the form <samp>"{{t|top-left x}} {{t|top-left y}} {{t|bottom-right x}} {{t|bottom-right y}}"</samp>.
+
| ''(Optional)'' Whether to adjust the <samp>DisplayName</samp> for the usual upgrade levels. For example, the display name for a level one Axe changes to 'Copper Axe'. Default false.
  
These are used to calculate the position of a player within the map view, given their real position in-game. For example, let's say an area has tile positions <code>(0, 0)</code> through <code>(10, 20)</code>, and map pixel positions <code>(200, 200)</code> through <code>(300, 400)</code>. If the player is standing on tile <code>(5, 10)</code> in-game (in the exact middle of the location), the game would place their marker at pixel <code>(250, 300)</code> on the map (in the exact middle of the map area).
+
The display name format in English is:
 
+
{| class="wikitable"
If these are omitted, the player marker is simply placed in the center of the parent map area.
 
 
|-
 
|-
| <samp>DisplayName</samp>
+
! upgrade level
| ''(Optional)'' A [[#Tokenizable string format|tokenizable string]] for the scroll text (shown at the bottom of the map when the player is in this area). Defaults to the parent area's <samp>DisplayName</samp>. If this is the exact string <samp>FarmName</samp>, it shows the farm name instead.
+
! display name format
|}
 
 
|-
 
|-
| <samp>DisplayName</samp>
+
| 1
| ''(Optional)'' A [[#Tokenizable string format|tokenizable string]] for the tooltip (shown when the mouse is over the area) and scroll (shown at the bottom of the map when the player is in the location). If omitted or empty, the tooltip/scroll isn't shown. Defaults to empty.
+
| Copper {{t|display name}}
 
|-
 
|-
| <samp>Condition</samp>
+
| 2
| ''(Optional)'' A [[#Game state queries|game state query]] which checks whether the area should be applied (if the group is visible). Defaults to always applied.
+
| Steel {{t|display name}}
 
|-
 
|-
| <samp>DisplayAsUnknown</samp>
+
| 3
| ''(Optional)'' Whether to replace the tooltip for the area with <samp>???</samp> if the <samp>Condition</samp> isn't met. Default false.
+
| Gold {{t|display name}}
 
|-
 
|-
| <samp>IncludeInGroupDetection</samp>
+
| 4
| ''(Optional)'' Whether to use this area when the game is scanning areas to see which group the player is in. If this is false, it will be ignored even if the player is in the area. Default true.
+
| Iridium {{t|display name}}
 
|}
 
|}
 +
|-
 +
| <samp>ConventionalUpgradeFrom</samp>
 +
| ''(Optional)'' If set, prepends an upgrade for the given tool ID to the <samp>UpgradeFrom</samp> field. This applies these rules (based on the <samp>UpgradeLevel</samp> field, not the upgrade level of the specified tool ID):
  
====Example====
+
{| class="wikitable"
This [[Modding:Content Patcher|Content Patcher]] content pack adds a full world map for [[Ginger Island]], complete with tooltips and player marker positioning. If the player unlocked the [[Ginger Island#Beach Resort|beach resort]], it applies the beach resort texture on top of the base map.
+
|-
 +
! upgrade level
 +
! price
 +
! items needed
 +
|-
 +
| 1
 +
| {{price|2000}}
 +
| {{name|Copper Bar|5}}
 +
|-
 +
| 2
 +
| {{price|5000}}
 +
| {{name|Iron Bar|5}}
 +
|-
 +
| 3
 +
| {{price|10000}}
 +
| {{name|Gold Bar|5}}
 +
|-
 +
| 4
 +
| {{price|25000}}
 +
| {{name|Iridium Bar|5}}
 +
|}
  
{{#tag:syntaxhighlight|<nowiki>
+
For example, Iridium Axe specifies this value:
{
+
<syntaxhighlight lang="js">
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
+
"ConventionalUpgradeFrom": "(T)GoldAxe"
    "Changes": [
+
</syntaxhighlight>
        // add world map edits
+
|-
        {
+
| <samp>UpgradeFrom</samp>
            "Action": "EditData",
+
| ''(Optional)'' The requirements to buy this tool from Clint's [[Blacksmith#Upgrade Tools|blacksmith tool upgrade shop]]. If you specify multiple entries, the first one which matches will be applied.
            "Target": "Data/IngameMap",
 
            "Entries": {
 
                // the base world map image with tooltips/positioning
 
                "GingerIsland_BaseMap": {
 
                    "Group": "GingerIsland",
 
                    "AreaID": "GingerIsland_BaseMap",
 
                    "Texture": "Mods/Example.ModId/GingerIsland",
 
                    "SourceRect": "0 0 300 180",
 
                    "DestRect": "0 0 300 180",
 
                    "Zones": [
 
                        {
 
                            "ValidAreas": [ "IslandSouth" ],
 
                            "MapTileCorners": "0 0 42 45",
 
                            "MapImageCorners": "105 105 231 240",
 
                            "DisplayName": "{{i18n: map-names.island-south}}"
 
                        },
 
                        // ... list each map area here
 
                    ]
 
                },
 
 
 
                // add beach resort if unlocked
 
                "GingerIsland_Resort": {
 
                    "Group": "GingerIsland",
 
                    "AreaID": "GingerIsland_Resort",
 
                    "Texture": "Mods/Example.ModId/GingerIsland_Resort",
 
                    "SourceRect": "0 0 300 180",
 
                    "DestRect": "0 0 300 180",
 
                    "Condition": "PLAYER_HAS_FLAG Any Island_Resort"
 
                }
 
            }
 
        },
 
 
 
        // load textures
 
        {
 
            "Action": "Load",
 
            "Target": "Mods/Example.ModId/GingerIsland",
 
            "FromFile": "assets/ginger-island.png"
 
        }
 
    ]
 
}</nowiki>|lang=javascript}}
 
 
 
===Custom map layers===
 
You can now add any number of [[Modding:Maps|map layers]] by suffixing a vanilla layer name (i.e. <samp>Back</samp>, <samp>Buildings</samp>, <samp>Front</samp>, or <samp>AlwaysFront</samp>) with an offset. For example, <samp>Back-1</samp> will be drawn before/under <samp>Back</samp>, and <samp>Back2</samp> will be drawn after/over it. You can increment the number to add more layers.
 
 
 
This only affects layer rendering. Tile properties must still be set on the original layers.
 
 
 
===Custom minecarts===
 
You can now add/edit [[minecart]] destinations by editing the <samp>Data\MiscGameData</samp> data asset, which consists of a data model with two relevant fields (listed below).
 
 
 
Note that <samp>Data\MiscGameData</samp> contains a single global entry, it isn't a list or dictionary like other assets. For example, Content Patcher would edit <samp>MineCartCondition</samp> as its own entry.
 
  
 +
This consists of a list of models with these fields:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
 
! field
 
! field
! effect
+
! purpose
 
|-
 
|-
| <samp>MineCartCondition</samp>
+
| <samp>Price</samp>
| A [[#Game state queries|game state query]] which indicates whether minecarts in general are unlocked. You usually shouldn't change this value, unless you're changing the overall game progression (e.g. adding an alternative way to unlock minecart access).
+
| ''(Optional)'' The gold price to buy the upgrade. Defaults to 0.
 
|-
 
|-
| <samp>MineCartDestinations</samp>
+
| <samp>RequireToolId</samp>
| The destinations which the player can travel to from any minecart. This consists of a string → model lookup, where the key is a unique destination ID (only containing alphanumeric/underscore/dot characters, with custom entries prefixed with your mod ID like <samp>Example.ModId_DestinationId</samp>), and the value is a model with these fields:
+
| ''(Optional)'' If set, the [[#Custom items|qualified or unqualified item ID]] for the tool that must be in the player's inventory for the upgrade to appear. The tool will be destroyed when the upgrade is purchased.
{| class="wikitable"
 
|-
 
! field
 
! effect
 
|-
 
| <samp>Location</samp>
 
| The [[#Custom locations|location ID]] for the destination.
 
|-
 
| <samp>Tile</samp>
 
| The destination tile position within the location, specified as a model with <samp>X</samp> and <samp>Y</samp> fields.
 
|-
 
| <samp>Direction</samp>
 
| The direction the player should face after arrival (one of <samp>down</samp>, <samp>left</samp>, <samp>right</samp>, or <samp>up</samp>).
 
 
|-
 
|-
| <samp>DisplayName</samp>
+
| <samp>TradeItemId</samp>
| A [[#Tokenizable string format|tokenizable string]] for the destination name shown in the minecart menu. You can use the location's display name with the <samp>LocationName</samp> token (like <code>[LocationName Desert]</code> for the [[desert]]).
+
| ''(Optional)'' If set, the [[#Custom items|qualified or unqualified item ID]] for an extra item that must be traded to upgrade the tool. (For example, many vanilla tools need metal bars.)
 
|-
 
|-
| <samp>Network</samp>
+
| <samp>TradeItemAmount</samp>
| ''(Optional)'' An arbitrary ID which groups the destination (along with any others having the same ID) into a separate network. Destinations in a network are only visible if the destination list is opened for that network via the <samp>MinecartTransport {{o|network name}}</samp> [[Modding:Maps|action property]]. If omitted, the minecart is part of the implicit default network.
+
| ''(Optional)'' The number of <samp>TradeItemId</samp> required. Defaults to 1.
 
|-
 
|-
 
| <samp>Condition</samp>
 
| <samp>Condition</samp>
| ''(Optional)'' A [[#Game state queries|game state query]] which indicates whether this minecart destination is available. Defaults to always available.
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this upgrade is available. Defaults to always true.
|}
 
 
|}
 
|}
  
===Custom passive festivals===
+
For example, these are equivalent to the Steel Axe's upgrade settings:
You can now add or modify passive festivals by editing the <samp>Data/PassiveFestivalData</samp> asset.
+
<syntaxhighlight lang="js">
 +
"UpgradeFrom": [
 +
    {
 +
        "RequireToolId": "(T)CopperAxe",
 +
        "Price": 5000,
 +
        "TradeItemId": "(O)335", // Iron Bar
 +
        "TradeItemAmount": 5
 +
    }
 +
]
 +
</syntaxhighlight>
 +
 
 +
If you want the tool to always be available, you can just omit the conditions. For example:
 +
<syntaxhighlight lang="js">
 +
"UpgradeFrom": [
 +
    {
 +
        "Price": 5000
 +
    }
 +
]
 +
</syntaxhighlight>
  
(A ''passive festival'' is a [[festivals|festival]] like the [[Night Market]]. They replace a location for a period of time, the player can enter/leave them anytime, and time continues passing while at the festival.)
+
Note that Clint needs a few days to smith the new tool. If you want to sell the tool directly, [[#Custom shops|add it to a regular shop]] instead.
 +
|}
  
====Data format====
+
====Game logic====
The <samp>Data/PassiveFestivalData</samp> asset consists of a string → model lookup, where the key is the unique festival ID, and the value is a model with these fields:
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
 
! field
 
! field
! effect
+
! purpose
 
|-
 
|-
| <samp>ID</samp>
+
| <samp>CanBeLostOnDeath</samp>
| A key which uniquely identifies this festival. For custom festivals, the ID should only contain alphanumeric/underscore/dot characters, and should ideally be prefixed with your mod ID like <samp>Example.ModId_FestivalName</samp>.
+
| Whether the player can [[Adventurer's Guild#Item Recovery Service|lose this tool when they die]]. Default false.
 +
|}
 +
 
 +
====Extensibility====
 +
{| class="wikitable"
 
|-
 
|-
| <samp>DisplayName</samp>
+
! field
| A [[#Tokenizable string format|tokenizable string]] for the display name shown on the [[calendar]].
+
! purpose
 
|-
 
|-
| <samp>Season</samp>
+
| <samp>ModData</samp>
| The [[season]] when the festival becomes active.
+
| ''(Optional)'' The mod data values to set when the tool is created, accessible in C# code via the <samp>tool.modData</samp> dictionary. For example:
|-
+
<syntaxhighlight lang="js">
| <samp>StartDay</samp><br /><samp>EndDay</samp>
+
"ModData": {
| The days of month when the festival becomes active.
+
    "PowerLevel": 9000
 +
}
 +
</syntaxhighlight>
 
|-
 
|-
| <samp>StartTime</samp>
+
| <samp>SetProperties</samp>
| The time of day when the festival opens each day.
+
| ''(Optional)'' Set the value of arbitrary properties on the tool class. For example, this would disable the tool animation and require no stamina:
|-
 
| <samp>StartMessage</samp>
 
| A [[#Tokenizable string format|tokenizable string]] for the in-game [[wikipedia:Pop-up notification|toast notification]] shown when the festival begins each day.
 
|-
 
| <samp>MapReplacements</samp>
 
| The locations to swap for the duration of the festival. Despite the field name, this swaps '''locations''' (e.g. as added by <samp>CustomLocations</samp> using [[Modding:Content Patcher|Content Patcher]]), and not the location's map asset.
 
 
 
This is specified as a string → string lookup, where the key is the original location to replace and the value is the new location. Both use the internal location name, as shown by the {{nexus mod|679|Debug Mode}} mod. For example, this swaps the <samp>Beach</samp> location with <samp>BeachNightMarket</samp> during the [[Night Market]]:
 
 
<syntaxhighlight lang="js">
 
<syntaxhighlight lang="js">
"MapReplacements": {
+
"SetProperties": {
     "Beach": "BeachNightMarket"
+
     "InstantUse": true,
 +
    "IsEfficient": true
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>
|-
 
| <samp>Condition</samp>
 
| ''(Optional)'' A [[#Game state queries|game state query]] which indicates whether the festival is enabled (subject to the other fields like <samp>StartDay</samp> and <samp>EndDay</samp>). Defaults to always enabled.
 
|-
 
| <samp>ShowOnCalendar</samp>
 
| ''(Optional)'' Whether the festival appears on the [[calendar]], using the same iridium-star icon as the [[Calendar#Winter|Night Market]]. Default true.
 
|-
 
| <samp>DailySetupMethod</samp><br /><samp>CleanupMethod</samp>
 
| ''(Optional)'' A C# method which applies custom logic when the day starts (<samp>DailySetupMethod</samp>) and/or overnight after the last day of the festival (<samp>CleanupMethod</samp>).
 
 
These must be specified in the form <samp>{{t|full type name}}.{{t|method name}}</samp>. The methods must be static, take zero arguments, and return void.
 
 
|}
 
|}
  
====NPC schedules====
+
===Custom wild trees===
When a passive festival is active, NPCs will check for [[Modding:Schedule data|a schedule entry]] in this order:
+
{{/doc status|a new doc page|done=false}}
  
{| class="wikitable"
+
====Data format====
|-
+
You can now create/edit [[Trees|wild trees]] by editing the <samp>Data/WildTrees</samp> asset.
! syntax
 
! summary
 
|-
 
| <samp>{{t|festival ID}}_{{t|festival day}}</samp>
 
| Applies on the given date. The {{t|festival day}} is relative, so <samp>1</samp> matches the festival <samp>StartDay</samp>.<br /><small>Example: <samp>NightMarket_3</samp> or <samp>marriage_NightMarket_3</samp></small>
 
|-
 
| <samp>{{t|festival ID}}</samp>
 
| Applies if there's no date-specific entry.<br /><small>Example: <samp>NightMarket</samp> or <samp>marriage_NightMarket</samp></small>
 
|}
 
  
If the NPC is married to a player, they'll add a <samp>marriage_</samp> prefix to the keys (like <samp>marriage_{{t|festival ID}}_{{t|festival day}}</samp>) and ignore any entry without the prefix.
+
This consists of a string → model lookup, where...
 
+
* The asset key is a [[Modding:Common data field types#Unique string ID|unique string ID]] for the tree type. The vanilla tree IDs are <samp>1</samp> (oak), <samp>2</samp> (maple), <samp>3</samp> (pine), <samp>6</samp> (palm), <samp>7</samp> (mushroom), and <samp>8</samp> (mahogany).
===Custom planting restrictions===
+
* The asset value is a model with thee fields listed below.
You can now add [[Modding:Items#Context tags|context tags]] to a [[crops|crop seed]], [[Fruit Trees|fruit tree sapling]], or [[trees|wild tree seed]] to restrict where it can be planted. This is based on these tags:
 
  
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! tag
+
! field
 
! effect
 
! effect
 
|-
 
|-
| <samp>plantable_greenhouse</samp>
+
| <samp>Textures</samp>
| Can always be planted in a [[greenhouse]] (''i.e.,'' locations with <samp>IsGreenhouse</samp>), regardless of any other context tag.
+
| The texture to use as the tree's spritesheet in-game. If multiple textures are listed, the first matching one is used.
|-
 
| <samp>plantable_location_{{t|location name}}</samp><br /><samp>not_plantable_location_{{t|location name}}</samp>
 
| Must or must not be planted in one of these locations. This must be the internal location name (as shown by {{nexus mod|679|Debug Mode}}), lowercase and with any spaces replaced with underscores.
 
|-
 
| <samp>plantable_context_{{t|context ID}}</samp><br /><samp>not_plantable_context_{{t|context ID}}</samp>
 
| Must or must not be planted in one of these [[#Custom location contexts|location contexts]]. The context ID must be lowercase, with any spaces replaced with underscores.
 
|}
 
 
 
When multiple tags are specified, they're applied in this precedence order:
 
  
 +
This consists of a list of models with these fields:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! precedence
+
! field
! rule
+
! effect
! result
 
 
|-
 
|-
| 1
+
| <samp>Texture</samp>
| <samp>plantable_greenhouse</samp> matches
+
| The asset name for the tree's spritesheet.
| plantable
 
 
|-
 
|-
| 2
+
| <samp>Season</samp>
| <samp>plantable_location_*</samp> matches
+
| ''(Optional)'' If set, the specific season when this texture should apply. For more complex conditions, see <samp>Condition</samp>.
| plantable
 
 
|-
 
|-
| 2
+
| <samp>Condition</samp>
| <samp>not_plantable_location_*</samp> matches<br />''or'' <samp>not_plantable_context_*</samp> matches
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this texture should be applied for a tree. Defaults to always enabled.
| not plantable
+
 
|-
+
This is checked when the tree is created, a new day starts, or its texture is reloaded by a mod. More frequent conditions (like time of day) won't work as expected unless a mod manually triggers a tree update.
| 3
 
| <samp>plantable_context_*</samp> or <samp>plantable_location_*</samp> specified but didn't match<br /><small>(<samp>not_*</samp> doesn't affect this rule)
 
| not plantable
 
|-
 
| 4
 
| current location listed in the context's <samp>DefaultValidPlantableLocations</samp> field
 
| plantable
 
|-
 
| 5
 
| colspan="2"| ''defaults to normal planting logic''
 
 
|}
 
|}
 
For example:
 
{| class="wikitable"
 
 
|-
 
|-
! tags
+
| <samp>SeedItemId</samp>
! effect
+
| ''(Optional)'' The [[#Custom items|qualified item ID]] for the seed item. If omitted, the tree can't be planted and <samp>SeedOnShakeChance</samp> will be ignored.
! plantable
 
! reason
 
 
|-
 
|-
|rowspan="4"| ''none''
+
| <samp>SeedPlantable</samp>
| [[The Farm|Farm]]
+
| ''(Optional)'' Whether the seed can be planted by the player. If this is false, it can only be spawned automatically via map properties. Default true.
| ☑ plantable
 
|rowspan="4"| default behavior
 
 
|-
 
|-
| [[Greenhouse]]
+
| <samp>GrowthChance</samp>
| ☑ plantable
+
| ''(Optional)'' The probability each day that the tree will grow to the next stage without [[Tree Fertilizer|tree fertilizer]], as a value from 0 (will never grow) to 1 (will grow every day). Defaults to 0.2 (20% chance).
 
|-
 
|-
| location listed in its context's <samp>DefaultValidPlantableLocations</samp>
+
| <samp>FertilizedGrowthChance</samp>
| ☑ plantable
+
| ''(Optional)'' Equivalent to <samp>GrowthChance</samp>, but with [[Tree Fertilizer|tree fertilizer]]. Defaults to 1 (100% chance).
 
|-
 
|-
| [[Bus Stop]]
+
| <samp>SeedSpreadChance</samp>
|
+
| ''(Optional)'' The probability each day that the tree will plant a seed on a nearby tile, as a value from 0 (never) to 1 (always). This only applied in locations where trees plant seeds (e.g. farms in vanilla). Default 0.15 (15% chance).
 
|-
 
|-
|rowspan="2"| <samp>plantable_greenhouse, not_plantable_context_default</samp>
+
| <samp>SeedOnShakeChance</samp>
| [[The Farm|Farm]]
+
| ''(Optional)'' The probability each day that the tree will produce a seed that will drop when the tree is shaken, as a value from 0 (never) to 1 (always). Default 0.05 (5% chance).
| ☐
 
| matches <samp>not_plantable_context_default</samp>
 
 
|-
 
|-
| [[Greenhouse]]
+
| <samp>SeedOnChopChance</samp>
| ☑ plantable
+
| ''(Optional)'' The probability that a seed will drop when the player chops down the tree, as a value from 0 (never) to 1 (always). Default 0.75 (75% chance).
| overridden by <samp>plantable_greenhouse</samp>
 
 
|-
 
|-
|rowspan="3"| <samp>plantable_location_islandwest</samp>
+
| <samp>DropWoodOnChop</samp>
| [[Ginger Island|Island West]]
+
| ''(Optional)'' Whether to drop [[wood]] when the player chops down the tree. Default true.
| ☑ plantable
 
| matches <samp>plantable_location_islandwest</samp></samp>
 
 
|-
 
|-
| [[Ginger Island|Island South]]
+
| <samp>DropHardwoodOnLumberChop</samp>
| ☐
+
| ''(Optional)'' Whether to drop [[hardwood]] when the player chops down the tree, if they have the [[Skills#Foraging|Lumberjack profession]]. Default true.
|rowspan="2"| doesn't match <samp>plantable_location_islandwest</samp></samp>
 
 
|-
 
|-
| [[The Farm|Farm]]
+
| <samp>IsLeafy</samp>
|
+
| ''(Optional)'' Whether shaking or chopping the tree causes cosmetic leaves to drop from tree and produces a leaf rustle sound. When a leaf drops, the game will use one of the four leaf sprites in the tree's spritesheet in the slot left of the stump sprite. Default true.
 
|-
 
|-
|rowspan="3"| <samp>plantable_context_island</samp>
+
| <samp>IsLeafyInWinter</samp>
| [[Ginger Island|Island West]]
+
| ''(Optional)'' Whether <samp>IsLeafy</samp> also applies in winter. Default false.
| ☑ plantable
 
|rowspan="2"| matches <samp>plantable_context_island</samp>
 
 
|-
 
|-
| [[Ginger Island|Island South]]
+
| <samp>GrowsInWinter</samp>
| ☑ plantable
+
| ''(Optional)'' Whether the tree can grow in winter (subject to <samp>GrowthChance</samp> or <samp>FertilizedGrowthChance</samp>). Default false.
 
|-
 
|-
| [[The Farm|Farm]]
+
| <samp>IsStumpDuringWinter</samp>
| ☐
+
| ''(Optional)'' Whether the tree is reduced to a stump in winter and regrows in spring, like the vanilla [[Trees#Mushroom Tree|mushroom tree]]. Default false.
| doesn't match <samp>plantable_context_island</samp>
 
 
|-
 
|-
|rowspan="3"| <samp>not_plantable_context_island</samp>
+
| <samp>AllowWoodpeckers</samp>
| [[Ginger Island|Island West]]
+
| ''(Optional)'' Whether woodpeckers can spawn on the tree. Default true.
| ☐
 
|rowspan="2"| matches <samp>not_plantable_context_island</samp>
 
 
|-
 
|-
| [[Ginger Island|Island South]]
+
| <samp>UseAlternateSpriteWhenNotShaken</samp><br /><samp>UseAlternateSpriteWhenSeedReady</samp>
|
+
| ''(Optional)'' Whether to render a different tree sprite when the player hasn't shaken it on that day (<samp>UseAlternateSpriteWhenNotShaken</samp>) or it has a seed ready (<samp>UseAlternateSpriteWhenSeedReady</samp>). If either field is true, the tree spritesheet must be double-width with the alternate textures on the right. If both are true, the same alternate sprites are used for both. Default false.
 
|-
 
|-
| [[The Farm|Farm]]
+
| <samp>DebrisColor</samp>
| ☑ plantable
+
| ''(Optional)'' The color of the cosmetic wood chips when chopping the tree. This can be...
| default behavior
+
* a [[#Color fields|standard color format]];
 +
* or one of <samp>12</samp> (brown/woody), <samp>100001</samp> (white), <samp>100001</samp> (light green),  <samp>100002</samp> (light blue), <samp>100003</samp> (red), <samp>100004</samp> (yellow), <samp>100005</samp> (black), <samp>100006</samp> (gray), or <samp>100007</samp> (charcoal / dim gray).
 +
 
 +
Defaults to <samp>12</samp> (brown/woody).
 
|-
 
|-
|rowspan="3"| <samp>plantable_location_town, plantable_location_mountain</samp>
+
| <samp>SeedDropItems</samp>
| [[Pelican Town|Town]]
+
| ''(Optional)'' When a seed is dropped subject to <samp>SeedOnShakeChance</samp>, the item to drop instead of the item specified by <samp>SeedItemId</samp>. If this is empty or none match, the <samp>SeedItemId</samp> will be dropped instead.
| ☑ plantable
+
 
| matches <samp>plantable_location_town</samp>
+
This consists of a list of models with these fields:
 +
{| class="wikitable"
 
|-
 
|-
| [[The Mountain|Mountain]]
+
! field
| ☑ plantable
+
! effect
| matches <samp>plantable_location_mountain</samp>
 
 
|-
 
|-
| [[The Farm|Farm]]
+
| ''common fields''
| ☐
+
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields supported for chop drops.
| doesn't match any <samp>plantable_location_*</samp> tags
 
|}
 
  
===Custom weather===
+
If set to an [[Modding:Item queries|item query]] which returns multiple items, one of them will be selected at random.
You can now change the weather algorithm by editing [[#Custom location contexts|location context data]], and (with a C# mod) implement custom weathers.
+
|-
 
+
| <samp>Season</samp>
Fields like <samp>Game1.weather</samp> and <samp>Game1.weatherForTomorrow</samp> are now strings to support custom mod weather IDs. The change for vanilla weather has no effect on Content Patcher packs, since the new weather IDs match the ones Content Patcher was using before (i.e. <samp>Sun</samp>, <samp>Rain</samp>, <samp>Snow</samp>, <samp>Storm</samp>, and <samp>Wind</samp>). C# mods may also see a <samp>Festival</samp> weather, while Content Patcher packs will see <samp>Sun</samp> for it. The constants like <samp>Game1.weather_sunny</samp> have the new string values (with new constants like <samp>Game1.legacy_weather_sunny</samp> for the legacy values).
+
| ''(Optional)'' If set, the item only applies if the tree's location is in this season.
 
 
The base game will treat an invalid weather as sunny. C# mods can implement custom weather effects using [[Modding:Modder Guide/APIs/Events|normal SMAPI events]] like <samp>UpdateTicked</samp>, or by [[Modding:Modder Guide/APIs/Harmony|patching]] methods like <samp>Game1.ApplyWeatherForNewDay</samp> and <samp>Game1.populateDebrisWeatherArray</samp>.
 
 
 
===New map properties===
 
1.6 adds several new [[Modding:Maps|map properties]].
 
 
 
====Warps & map positions====
 
{| class="wikitable"
 
 
|-
 
|-
! property
+
| <samp>Chance</samp>
! explanation
+
| ''(Optional)'' The probability that the item will drop, as a value between 0 (never drops) and 1 (always drops). Default 1 (100% chance).
 
|-
 
|-
| <samp>DefaultWarpLocation {{t|x}} {{t|y}}</samp><br />''(valid in any location)''
+
| <samp>ContinueOnDrop</samp>
| The default arrival tile, used when a player or NPC is added to the location without a target tile (e.g. using [[Modding:Console commands|debug commands]] like <samp>debug warp</samp> or <samp>debug eventbyid</samp>).
+
| ''(Optional)'' If this item is dropped, whether to continue as if it hadn't been dropped for the remaining drop candidates. Default false.
 
|}
 
|}
 +
|-
 +
| <samp>ChopItems</samp>
 +
| ''(Optional)'' The additional items to drop when the tree is chopped down. All matching items are dropped.
  
====Audio====
+
This consists of a list of models with these fields:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! property
+
! field
! explanation
+
! effect
 
|-
 
|-
| <samp>MusicContext {{t|context}}</samp><br />''(valid in any location)''
+
| ''common fields''
| The music context for this location. The recommended values are <samp>Default</samp> or <samp>SubLocation</samp>. This only affects the music priority in split screen, where <samp>SubLocation</samp> has a lower priority than <samp>Default</samp>. For example, if player A is at a location with the <samp>Default</samp> music context, and player B is a location with the <samp>SubLocation</samp> context, the game will choose player A's music.
+
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields supported for chop drops.
 +
 
 +
If set to an [[Modding:Item queries|item query]] which returns multiple items, one of them will be selected at random.
 
|-
 
|-
| <samp>MusicIgnoreInRain T</samp><br />''(valid in any outdoor location)''
+
| <samp>Season</samp>
| If set to <samp>T</samp>, the <samp>Music</samp> property is ignored when it's raining in this location.
+
| ''(Optional)'' If set, the item only applies if the tree's location is in this season.
 
|-
 
|-
| <samp>MusicIgnoreInSpring T</samp><br /><samp>MusicIgnoreInSummer T</samp><br /><samp>MusicIgnoreInFall T</samp><br /><samp>MusicIgnoreInWinter T</samp><br />''(valid in any outdoor location)''
+
| <samp>Chance</samp>
| If set to <samp>T</samp>, the <samp>Music</samp> property is ignored in the given season.
+
| ''(Optional)'' The probability that the item will drop, as a value between 0 (never drops) and 1 (always drops). Default 1 (100% chance).
 
|-
 
|-
| <samp>MusicIgnoreInFallDebris T<br />''(valid in any outdoor location)''
+
| <samp>MinSize</samp><br /><samp>MaxSize</samp>
| If set to <samp>T</samp>, the <samp>Music</samp> property is ignored in fall during windy weather.
+
| ''(Optional)'' The minimum and/or maximum growth stage for the tree at which this item is produced. The possible values are <samp>Seed</samp>, <samp>Sprout</samp>, <samp>Sapling</samp>, <samp>Bush</samp>, and <samp>Tree</samp>. Both default to no limit.
 
|-
 
|-
| <samp>MusicIsTownTheme T</samp><br />''(valid in any location)''
+
| <samp>ForStump</samp>
| If set to <samp>T</samp>, uses the same behavior as [[Pelican Town]]'s music: it will start playing after the day music has finished, and will continue playing while the player travels through indoor areas, but will stop when entering another outdoor area that isn't marked with the same <samp>Music</samp> and <samp>MusicIsTownTheme</samp> properties.
+
| ''(Optional)'' Whether the item is only produced if the tree is a stump (<samp>true</samp>), not a stump (<samp>false</samp>), or both (<samp>null</samp>). Defaults to <samp>false</samp> (non-stumps only).
 
|}
 
|}
 +
|-
 +
| <samp>ShakeItems</samp>
 +
| The items produced by shaking the tree when it's fully grown. This only applies the first time the tree is shaken each day. All matching items are dropped.
  
====Crops====
+
This consists of a list of models with these fields:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! property
+
! field
! explanation
+
! effect
 
|-
 
|-
| <samp>AllowGiantCrops T</samp>
+
| ''common fields''
| If set with any non-blank value, [[Crops#Giant Crops|giant crops]] can grow in this location. (To plant the crop itself, you'll need [[#Custom planting restrictions|custom planting restrictions]] or the [[#Custom location contexts|<samp>DefaultValidPlantableLocations</samp> context field]].)
+
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields supported for shake items.
|}
 
  
====Fishing====
+
If set to an [[Modding:Item queries|item query]] which returns multiple items, one of them will be selected at random.
{| class="wikitable"
+
|-
 +
| <samp>Season</samp>
 +
| ''(Optional)'' If set, the item only applies if the tree's location is in this season.
 
|-
 
|-
! property
+
| <samp>Chance</samp>
! explanation
+
| ''(Optional)'' The probability that this entry is selected, as a value between 0 (never drops) and 1 (always drops). Default 1 (100% chance).
 +
|}
 
|-
 
|-
| <samp>CrabPotAreaCorners [{{t|corners}} {{t|area IDs}}]+</samp>
+
| <samp>TapItems</samp>
| The fish areas for [[Crab Pot|crab pots]] in this location, which can be used in [[Modding:Fish data|fish spawn data]]. For example, you can define "freshwater" and "ocean" areas which have different fish.
+
| The items produced by [[Tapper|tapping]] the tree. If multiple items can be produced, the first available one is selected.
  
This consists of a space-delimited list of these fields:
+
This consists of a list of models with these fields:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 1,881: Line 2,080:
 
! effect
 
! effect
 
|-
 
|-
| <samp>corners</samp>
+
| ''common fields''
| The tile area within the map, specified as a the top-left and bottom-right X/Y positions in the form <samp>{{t|top-left X}} {{t|top-left Y}} {{t|bottom-right X}} {{t|bottom-right Y}}</samp>. Any of the numbers can be set to <samp>-1</samp> to make it unbounded (e.g. <samp>15 -1 30 -1</samp> covers X positions 15 to 30, but the entire map vertically).
+
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields supported for tapper items.
 +
 
 +
If set to an [[Modding:Item queries|item query]] which returns multiple items, one of them will be selected at random.
 
|-
 
|-
| <samp>area IDs</samp>
+
| <samp>Season</samp>
| The area IDs described by these values. This is the value referenced in [[Modding:Fish data|fish spawn rules]] or other properties like <samp>DefaultCrabPotArea</samp>.
+
| ''(Optional)'' If set, the item only applies if the tree's location is in this season.
|}
 
 
 
You can add any number of areas by appending them (with a space) at the end of the field. The area list in the last field will end when it encounters a number. For example:
 
<pre>CrabPotAreaCorners 0 0 10 10 freshwater ocean 15 15 30 30 Example.ModId_CustomWater</pre>
 
 
|-
 
|-
| <samp>DefaultCrabPotArea {{t|area IDs}}</samp>
+
| <samp>Chance</samp>
| The area IDs used for tiles not covered by <samp>CrabPotAreaCorners</samp> (see that property for more info). If omitted, defaults to <samp>freshwater</samp>.
+
| ''(Optional)'' The probability that this entry is selected, as a value between 0 (never drops) and 1 (always drops). Default 1 (100% chance).
 
|-
 
|-
| <samp>DefaultFishingArea {{t|location key}} {{t|area ID}}</samp>
+
| <samp>DaysUntilReady</samp>
| The area ID used for tiles not covered by <samp>FishingAreaCorners</samp> (see that properties for more info). If omitted, only fish which spawn in the special <samp>-1</samp> area (any area) can be caught on those tiles.
+
| The number of days before the tapper is ready to empty.
 
|-
 
|-
| <Samp>FishingAreaCorners [{{t|corners}} {{t|location key}} {{t|area ID}}]+</samp>
+
| <samp>PreviousItemId</samp>
| The fish areas when fishing with [[Fishing Rod|fishing rod]] in this location, which can be used in [[Modding:Fish data|fish spawn data]]. For example, you can define "lake" and "river" areas which have different fish.
+
| ''(Optional)'' If set, the item only applies if the previous item produced by the tapper matches one of the given [[#Custom items|qualified item IDs]]. If an entry is null or an empty string, it matches when there's no previous item.
  
This consists of a space-delimited list of these fields:
+
For example: <code>"PreviousItemId": [ null ]</code> only applies when a tapper is first added to the tree, and <code>"PreviousItemsId": [ "(O)420" ]</code> applies if the player just collected a [[Red Mushroom|red mushroom]] (object #420) from it.
{| class="wikitable"
 
 
|-
 
|-
! field
+
| <samp>DaysUntilReadyModifiers</samp>
! effect
+
| ''(Optional)'' [[#Quantity modifiers|Quantity modifiers]] applied to the <samp>DaysUntilReady</samp> value. Default none.
 
|-
 
|-
| <samp>corners</samp>
+
| <samp>DaysUntilReadyModifiersMode</samp>
| The tile area within the map, specified as a the top-left and bottom-right X/Y positions in the form <samp>{{t|top-left X}} {{t|top-left Y}} {{t|bottom-right X}} {{t|bottom-right Y}}</samp>. Any of the numbers can be set to <samp>-1</samp> to make it unbounded (e.g. <samp>15 -1 30 -1</samp> covers X positions 15 to 30, but the entire map vertically).
+
| ''(Optional)'' [[#Quantity modifiers|Quantity modifier modes]] which indicate what to do if multiple modifiers in the <samp>DaysUntilReadyModifiersMode</samp> field apply at the same time. Default <samp>Stack</samp>.
 +
|}
 
|-
 
|-
| <samp>location key</samp>
+
| <samp>PlantableLocationRules</samp>
| The entry key in the <samp>Data/Locations</samp> data asset from which to get available fish.
+
| ''(Optional)'' The rules to decide which locations you can plant the seed in, if applicable. The first matching rule is used. This can override location checks (e.g. crops being limited to the farm), but not built-in requirements like crops needing dirt.
|-
+
 
| <samp>area ID</samp>
+
This consists of a list of models with these fields:
| The area ID described by these values. This is the value referenced in [[Modding:Fish data|fish spawn rules]] or other properties like <samp>DefaultFishingArea</samp>.
 
|}
 
  
You can add any number of areas by appending them (with a space) at the end of the field. For example (note that vanilla area IDs are numbers like <samp>1</samp> for legacy reasons):
 
<pre>FishingAreaCorners 0 0 10 10 Forest 1 15 15 30 30 Forest Example.ModId_Lake</pre>
 
|-
 
|style="max-width:30vw;"| <samp>LegendaryFishAreaCorners [{{t|corners}} {{t|anchor}} {{t|fish ID}} {{t|family ID}} {{t|min level}} {{t|min depth}} {{t|chance}} {{t|curiosity buff}} {{t|weather}} {{t|seasons}}]+
 
| The map areas where [[Fish#Legendary Fish|legendary fish]] can be caught in the location. This consists of a space-delimited list of these fields:
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 1,926: Line 2,116:
 
! effect
 
! effect
 
|-
 
|-
| <samp>corners</samp>
+
| <samp>Id</samp>
| The tile area within the map, specified as a the top-left and bottom-right X/Y positions in the form <samp>{{t|top-left X}} {{t|top-left Y}} {{t|bottom-right X}} {{t|bottom-right Y}}</samp>. Any of the numbers can be set to <samp>-1</samp> to make it unbounded (e.g. <samp>15 -1 30 -1</samp> covers X positions 15 to 30, but the entire map vertically).
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the list.
 
|-
 
|-
| <samp>anchor</samp>
+
| <samp>Result</samp>
| Whether to check the position of the player (<samp>player</samp>) or the fishing bobber (<samp>bobber</samp>).
+
| Indicates whether the seed can be planted in a location if this entry is selected. The possible values are:
 +
* <samp>Default</samp>: the seed can be planted if the location normally allows it. This can be used to stop processing further rules, and/or set a custom <samp>DeniedMessage</samp>.
 +
* <samp>Allow</samp>: the seed can be planted here, regardless of whether the location normally allows it.
 +
* <samp>Deny</samp>: the seed can't be planted here, regardless of whether the location normally allows it.
 
|-
 
|-
| <samp>fish ID</samp>
+
| <samp>Condition</samp>
| The unqualified [[#Custom items|item ID]] for the legendary fish that can be caught in this area.
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this entry applies. Default true.
 
|-
 
|-
| <samp>family ID</samp>
+
| <samp>PlantedIn</samp>
| One of:
+
| ''(Optional)'' The planting context to apply this rule for. The possible values are <samp>Ground</samp> (planted directly in the ground), <samp>GardenPot</samp> (planted in a [[Garden Pot|garden pot]]), or <samp>Any</samp>. Default <samp>Any</samp>.
* <samp>null</samp> to ignore this field.
+
 
* Or the unqualified [[#Custom items|item ID]] for the legendary fish that can be caught in this area when the [[Quests#Extended Family|Extended Family]] quest is active.
+
Note that trees can't be planted in garden pots.
 
|-
 
|-
| <samp>min level</samp>
+
| <samp>DeniedMessage</samp>
| The minimum [[Skills#Fishing|fishing level]] needed for this fish to appear.
+
| ''(Optional)'' If this rule prevents planting the seed, the tokenizable string to show to the player (or <samp>null</samp> to default to the normal behavior for the context). This also applies when the <samp>Result</samp> is <samp>Default</samp>, if that causes the planting to be denied.
 +
|}
 
|-
 
|-
| <samp>min depth</samp>
+
| <samp>CustomFields</samp>
| The minimum water depth (i.e. bobber's tile distance from the closest land) needed for this fish to appear.
+
| The [[#Custom data fields|custom fields]] for this entry.
|-
 
| <samp>chance</samp>
 
| The probability that the fish will appear each time the player fishes in the area, as a value between 0 (never) and 1 (always).
 
|-
 
| <samp>curiosity buff</samp>
 
| A flat increase to <samp>chance</samp> when the player fishes with a [[Curiosity Lure]].
 
|-
 
| <samp>weather</samp>
 
| The weather when the fish appears. One of <samp>sunny</samp>, <samp>rainy</samp>, <samp>both</samp>, or <samp>default</samp>. If <samp>default</samp>, it will use the weather from the [[Modding:Fish data|fish's <samp>Data\Fish</samp> entry]].
 
|-
 
| <samp>seasons</samp>
 
| A space-delimited list of seasons when the fish can be caught, like <samp>spring summer</samp>.
 
 
|}
 
|}
  
You can add any number of areas by appending them (with a space) at the end of the field. The season list in the last field will end when it encounters a number. For example:
+
====Spawning wild trees====
<pre>LegendaryFishAreaCorners 0 0 15 15 player 160 899 3 0 0.2 0.05 both fall 30 30 -1 -1 bobber 682 901 0 0 0.1 0.1 both spring summer fall winter</pre>
+
Custom trees can be added to the game in two ways:
|}
+
* Spawn them on [[Modding:Maps|map tiles]] when the location is created, using the new <samp>SpawnTree: wild {{t|tree ID}} {{o|growth stage on location created}} {{o|growth stage on day-update regrowth}}</samp> tile property. This must be added on the <samp>Paths</samp> layer, which must also have tile index 34 from the <samp>paths</samp> tilesheet.
 +
* Or give the player a seed item in the usual ways (e.g. from [[#Custom shops|a shop]], [[Modding:Mail data|mail letter]], etc).
 +
 
 +
===Default recipes===
 +
{{/doc status|[[Modding:Recipe data]]|done=false}}
 +
 
 +
You can now have [[Modding:Recipe data|crafting and cooking recipes]] that are learned automatically by setting the condition field to <samp>default</samp>. Any missing default recipes will be learned on day start.
  
====Building construction====
+
For example, here's the chest entry from <samp>Data/CraftingRecipes</samp>:
{| class="wikitable"
+
<syntaxhighlight lang="js">
 +
"Chest": "388 50/Home/130/true/default/"
 +
</syntaxhighlight>
 +
 
 +
===Global inventories===
 +
C# mods can now set a <samp>chest.GlobalInventoryId</samp> field to make it share a global inventory with every other chest having the same ID. This replaces the equivalent hardcoded logic for [[Junimo Chest|Junimo chests]], which now just default to a <samp>"JunimoChests"</samp> global inventory ID. For example, this can be used to have multiple Junimo chest networks or make other containers share inventory.
 +
 
 +
C# mods can also use this to store items for other mod purposes, by using <samp>Game1.player.team.globalInventories</samp> or <samp>Game1.player.team.GetOrCreateGlobalInventory(id)</samp> directly.
 +
 
 +
===Hats on aquarium fish===
 +
{{/doc status|[[Modding:Fish data]]|done=false}}
 +
 
 +
Custom [[Modding:Fish data|fish in aquariums]] can now wear [[hats]], just like vanilla [[Sea Urchin|sea urchins]]. This can be enabled by specifying a new field in <samp>Data/AquariumFish</samp>:
 +
 
 +
{| class="wikitable"
 
|-
 
|-
! property
+
! index
! explanation
+
! field
 +
! purpose
 
|-
 
|-
| <samp>CanBuildHere T</samp><br />''(valid in any outdoor location)''
+
| 7
| Whether to allow constructing buildings in this location. The game will adjust automatically to account for it (e.g. Robin will let you choose where to build). See [[#Build anywhere|''build anywhere'' in what's new]].
+
| hat position
|-
+
| The pixel position of the hat on the sprite, specified as an object with <samp>X</samp> and <samp>Y</samp> values.
| <samp>BuildConditions {{t|query}}</samp><br />''(valid in any outdoor location)''
 
| If <samp>CanBuildHere</samp> is set, an optional [[#Game state queries|game state query]] which indicates whether building is allowed currently.
 
|-
 
| <samp>LooserBuildRestrictions T</samp><br />''(valid in any outdoor location)''
 
| If set, tiles don't need to be marked <samp>Buildable T</samp> or <samp>Diggable T</samp> in their properties. Tiles can be blocked with <samp>Buildable F</samp> instead. The other restrictions still apply.
 
|-
 
| <samp>ValidBuildRect {{t|x}} {{t|y}} {{t|width}} {{t|height}}</samp><br />''(valid in any outdoor location)''
 
| The tile area within the map where buildings may be placed. If omitted, buildings may be placed in any open space in the map.
 
 
|}
 
|}
  
===Tile property changes===
+
===Context tag changes===
<ul>
+
{{/doc status|[[Modding:Items#Context tags]]|done=false}}
<li>Added new <samp>Action</samp> [[Modding:Maps|tile properties]]:
+
 
 +
====New context tags====
 +
1.6 adds several new [[Modding:Items#Context tags|item context tags]]:
 +
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! layer
+
! context tag
! property
+
! effect
! explanation
 
 
|-
 
|-
| <samp>Buildings</samp>
+
| <samp>campfire_item</samp>
| <samp>Action BuildingSilo</samp>
+
| Marks the item as a [[campfire]]. If the item also has the <samp>torch_item</samp> context tag, when it's placed in the world and turned on...
| If a building covers this tile, enables [[silo]] interactions on this tile subject to the building's <samp>HayCapacity</samp> field in <samp>Data/BuildingsData</samp>.
+
* campfire flames are drawn over it;
 +
* if the item is [[Modding:Items#Big craftables|big craftable]], light is emitted from its center instead of the top.
 
|-
 
|-
| <samp>Buildings</samp>
+
| <samp>fish_pond_ignore</samp>
| <samp>Action BuildingToggleAnimalDoor</samp>
+
| Prevents players from adding this fish to [[Fish Pond|fish ponds]], even if it would otherwise match an entry in <samp>Data/FishPondData</samp>.
| If a building covers this tile, opens or closes its animal door.
 
 
|-
 
|-
| <samp>Buildings</samp>
+
| <samp>geode_crusher_ignored</samp>
| <samp>Action Forge</samp>
+
| Prevents breaking this item open in a [[Geode Crusher|geode crusher]], even if the item has geode fields in [[#Custom objects|<samp>Data/Objects</samp>]].
| Opens the [[Forge]] menu.
 
 
|-
 
|-
| <samp>Buildings</samp>
+
| <samp>item_type_{{t|type}}</samp>
| <samp>Action ObeliskWarp {{t|location name}} {{t|x}} {{t|y}} {{o|whether to dismount}}</samp>
+
| For an [[Modding:Items#Objects|object-type item]], the type value from the 'type and category' field. (Non-object items always have the exact tag <samp>item_type_</samp> with nothing after the last underscore.) This is automatic and shouldn't be set manually. The tag is checked in a few places (''e.g.'' the [[museum]] to check if an item is an artifact or mineral), but most of the game won't be affected.
| Warps the player to the specified location name and position with the [[Warp Totem|Obelisk]] animation/sound effects.
 
 
|-
 
|-
| <samp>Buildings</samp>
+
| <samp>museum_donatable</samp><br /><samp>not_museum_donatable</samp>
| <samp>Action OpenShop {{t|shop id}} {{o|from direction}} {{o|open time}} {{o|close time}} {{o|owner tile area}}</samp>
+
| Set whether the item can be donated to the [[museum]], overriding the vanilla logic.
| Open the [[#Custom shops|shop]] with the given {{t|shop id}}. All arguments besides the ID are optional:
 
* {{o|from direction}}: if specified, the player must be standing in this direction relative to the shop (one of <samp>down</samp>, <samp>up</samp>, <samp>left</samp>, <samp>right</samp>, or <samp>none</samp>). Setting this to <samp>none</samp> disables the requirement. The default for most vanilla shops is <samp>down</samp>.
 
* {{o|open time}} and {{o|close time}}: the start & end times in 26-hour format when the shop is available. Interacting with the tile outside those times does nothing.
 
* {{o|owner tile area}}: if specified, the tile area which must contain one of the shop owners for the shop to be available. For a custom shop, these are defined by its <samp>ValidNPCs</samp> field. This can be specified in two forms: <samp>{{t|x}} {{t|y}}</samp> for a single tile, or <samp>{{t|x}} {{t|y}} {{t|width}} {{t|height}}</samp> for a multi-tile area.
 
 
|-
 
|-
| <samp>Buildings</samp>
+
| <samp>not_giftable</samp>
| <samp>Action PlayEvent {{t|event id}} {{o|check preconditions}} {{o|skip if seen}}</samp>
+
| Prevents players from gifting this item to NPCs, who'll ignore the item entirely (e.g. as if you were holding a tool).
| Immediately start an [[Modding:Event data|event]], subject to the conditions:
 
* {{o|check preconditions}}: whether to ignore the action if the [[Modding:Event data#Event preconditions|event's preconditions]] don't match (one of <samp>true</samp> or <samp>false</samp>). Default true.
 
* {{o|skip if seen}}: whether to ignore the action if the player has already seen the given event. Default true.
 
  
If the event is skipped, the action is silently ignored.
+
This only affects gift-giving, it doesn't affect non-gift logic like quest goals or special order objectives. If the NPC also has a <samp>reject_*</samp> dialogue for the item, the dialogue takes priority.
 +
|-
 +
| <samp>not_placeable</samp><br /><samp>placeable</samp>
 +
| Sets whether the item can be placed on the ground.
 +
|-
 +
| <samp>prevent_loss_on_death</samp>
 +
| Indicates the item can't be [[Adventurer's Guild#Item Recovery Service|lost when the player dies]].
 +
|-
 +
| <samp>sign_item</samp>
 +
| Marks the item as a [[Crafting#Signs|sign]], which lets player display items on it or place it on a [[Fish Pond|fish pond]] to show the fish count.
 +
|-
 +
| <samp>torch_item</samp>
 +
| Marks the item as a [[torch]], which lets the player turn it on/off to emit light.
  
For example, <code>Action PlayEvent 60367 false false</code> will replay the bus arrival event from the start of the game.
+
See also <samp>campfire_item</samp>.
 
|}
 
|}
</li>
+
 
<li>Added new <samp>TouchAction</samp> [[Modding:Maps|tile properties]]:
+
Context tags which affect [[#Custom machines|machine processing]]:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! layer
+
! context tag
! property
+
! effect
! explanation
 
 
|-
 
|-
| <samp>Back</samp>
+
| <samp>crystalarium_banned</samp>
| <samp>TouchAction PlayEvent {{t|event id}} {{o|check preconditions}} {{o|skip if seen}} {{o|fallback action}}</samp>
+
| When applied to a gem or mineral item, prevents players from placing it in a [[crystalarium]].
| Equivalent to <samp>Action PlayEvent</samp>. If the event is skipped, you can optionally specify another action to call instead after the other parameters, like <code>TouchAction PlayEvent 60367 true true TouchAction PlayEvent 520702 false false</code> to play another event instead.
+
|-
|}</li>
+
| <samp>keg_juice</samp><br /><samp>keg_wine</samp>
<li>Dropped support for non-string map & tile properties. Properties set to <samp>bool</samp>, <samp>int</samp>, or <samp>float</samp> will be converted to <samp>string</samp> when the game loads them.</li>
+
| Allows processing the item in a [[keg]] to produce a juice or wine variant.
</ul>
 
 
 
==What's new for buildings==
 
===Custom buildings===
 
You can now add custom buildings by editing the <samp>Data/BuildingsData</samp> asset. This consists of a string → model lookup, where the key is a unique building ID, and the value is a model with these fields:
 
 
 
====Required fields====
 
{| class="wikitable"
 
 
|-
 
|-
! field
+
| <samp>preserves_jelly</samp><br /><samp>preserves_pickle</samp>
! effect
+
| Allows processing the item in a [[Preserves Jar|preserves jar]] to produce a jelly or pickled variant.
 
|-
 
|-
| <samp>ID</samp>
+
| <samp>seedmaker_banned</samp>
| A key which uniquely identifies this building. This should match the asset key. The ID should only contain alphanumeric/underscore/dot characters, and should ideally be prefixed with your mod ID like <samp>Example.ModId_BuildingName</samp>.
+
| When applied to a seed item, prevents players from placing it in a [[Seed Maker|seed maker]].
 
|-
 
|-
| <samp>Name</samp><br /><samp>Description</samp>
+
| <samp>tapper_item</samp>
| A [[#Tokenizable string format|tokenizable string]] for the display name and description (e.g. shown in the construction menu).
+
| Marks the item as a [[tapper]] or [[Heavy Tapper|heavy tapper]].
 
|-
 
|-
| <samp>Texture</samp>
+
| <samp>tapper_multiplier_{{t|multiplier}}</samp>
| The asset name for the texture under the game's Content folder.
+
| The multiplier applied to the tapper production speed. For example, <samp>2</samp> will make items take half their base time (''i.e.'' each item will finish in <sup>base time</sup>/<sub>speed multiplier</sub>). Defaults to 1 if omitted.
 
|}
 
|}
  
====Construction====
+
And informational tags which have no effect on the game logic:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! context tag
 
! effect
 
! effect
 
|-
 
|-
| <samp>Builder</samp>
+
| <samp>fish_legendary</samp><br /><samp>fish_legendary_family</samp>
| ''(Optional)'' The NPC from whom you can request construction. The only recognized values are <samp>Carpenter</samp> ([[Carpenter's Shop|Robin]]) and [[Wizard's Tower#Buildings|<samp>Wizard</samp>]]. Defaults to <samp>Carpenter</samp>. If omitted, it won't appear in any menu.
+
| Marks the fish as a [[Fish#Legendary Fish|legendary fish]] or [[Quests#Extended Family|legendary fish family]]. These are purely informational; the legendary fish behavior is determined by data fields like <samp>CatchLimit</samp> or <samp>IsBossFish</samp> in [[#Custom locations|<samp>Data/Locations</samp>]].
 
|-
 
|-
| <samp>BuildCost</samp>
+
| <samp>geode</samp>
| ''(Optional)'' The gold cost to construct the building. Defaults to {{price|0}}.
+
| ''(Added automatically)'' Marks the item as a [[Minerals#Geodes|geode]] item, which can be broken open at [[Blacksmith|Clint's blacksmith shop]] or using a [[Geode Crusher|geode crusher]]. This is added automatically if the geode fields are present in [[#Custom objects|<samp>Data/Objects</samp>]].
 
|-
 
|-
| <samp>BuildMaterials</samp>
+
| <samp>id_{{t|item id}}</samp>
| ''(Optional)'' The materials you must provide to start construction, as a list of models with these fields:
+
| ''(Added automatically)'' The [[#Custom items|qualified item ID]], like <samp>id_(o)128</samp>. This can be used to match or exclude an item by ID using context tags. Any spaces in the ID are replaced with underscores, and single quotes are removed.
{| class="wikitable"
 
 
|-
 
|-
! field
+
| <samp>is_machine</samp>
! effect
+
| ''(Added automatically)'' Indicates the item has [[#Custom machines|machine logic]]. This is added automatically based on <samp>Data/Machines</samp>.
 
|-
 
|-
| <samp>ItemID</samp>
+
| <samp>machine_input</samp>
| The required item ID (qualified or unqualified).
+
| ''(Added automatically)'' Whether the item is a machine which accepts items from the player. This is added automatically based on the machine's fields in <samp>Data/Machines</samp>:
 +
* if <samp>HasInput</samp> is true;
 +
* ''or'' if any output rules have an <samp>ItemPlacedInMachine</samp> trigger.
 
|-
 
|-
| <samp>Amount</samp>
+
| <samp>machine_output</samp>
| The number of the item required.
+
| ''(Added automatically)'' Whether the item is a machine which produces items for the player to collect. This is added automatically based on the machine's fields in <samp>Data/Machines</samp>:
|}
+
* if <samp>HasOutput</samp> is true;
 +
* ''or'' if it has any output rules.
 +
|}
 +
 
 +
====ItemContextTagManager class====
 +
For C# mods, 1.6 adds a new <samp>ItemContextTagManager</samp> class which simplifies working with [[Modding:Items#Context tags|item context tags]] and reduces repeated code.
 +
 
 +
This provides a few utility methods:
 +
{| class="wikitable"
 +
|-
 +
! method
 +
! effect
 
|-
 
|-
| <samp>BuildDays</samp>
+
| <code>GetBaseContextTags(id)</code>
| ''(Optional)'' The number of days needed to complete construction (e.g. <samp>1</samp> for a building completed the next day). If set to 0, construction finishes instantly. Defaults to 0.
+
| Get the base context tags for an item based on its raw data in <samp>Data/Objects</samp> or <samp>Data/BigCraftables</samp>. This doesn't include dynamic tags added that are based on instance info (like quality), which you can get using <code>item.GetContextTags()</code>.
 
|-
 
|-
| <samp>BuildCondition</samp>
+
| <code>DoesTagQueryMatch(query, tags)</code>
| ''(Optional)'' A [[#Game state queries|game state query]] which indicates whether the building should be available in Robin's construction menu. Defaults to always available.
+
| Get whether a context tag query matches the given tags. For example, <code>ItemContextTagManager.DoesTagQueryMatch("bone_item, !fossil_item", item.GetContextTags())</code> returns true if the item is a bone item but not a fossil (like the [[Bone Flute]]).
 
|-
 
|-
| <samp>AdditionalPlacementTiles</samp>
+
| <code>DoAllTagsMatch(requiredTags, actualTags)</code><br /><code>DoAnyTagsMatch(requiredTags, actualTags)</code>
| ''(Optional)'' The extra tiles to treat as part of the building when placing it through Robin's menu. For example, the farmhouse uses this to make sure the stairs are clear. This consists of a list of models with these fields:
+
| Get whether every (<samp>DoAllTagsMatch</samp>) or at least one (<samp>DoAnyTagsMatch</samp) required tag matches the actual item tags. This supports negated required tags like <samp>"!fossil_item"</samp> too.
{| class="wikitable"
 
 
|-
 
|-
! field
+
| <code>DoesTagMatch(requiredTag, actualTags)</code>
! effect
+
| Get whether a single tag matches the actual item tags. This supports negated required tags like <samp>"!fossil_item"</samp> too.
 
|-
 
|-
| <samp>Tile</samp>
+
| <code>SanitizeContextTag(tag)</code>
| The tile position relative to the top-left corner of the building, specified as an object with <samp>X</samp> and <samp>Y</samp> fields.
+
| ''(Specialized)'' Replace characters that may appear in item names so they're valid in context tags. For example, <code>SanitizeContextTag("Sam's Boombox")</code> returns <samp>sams_boombox</samp>.
 
|}
 
|}
|-
+
 
| <samp>IndoorItems</samp>
+
====Other context tag changes====
| ''(Optional)'' The items to place in the building interior when it's constructed or upgraded. This consists of a list of models with these fields:
+
* Context tags are now case-insensitive.
 +
 
 +
===Inventory class===
 +
For C# mods, 1.6 adds a new <samp>Inventory</samp> class to manage a list of items. This is used for the <samp>Farmer.items</samp> and <samp>Chest.items</samp> fields. It implements <samp>IList&lt;Item&gt;</samp>, so most existing code should still work fine.
 +
 
 +
This has three main benefits:
 +
<ul>
 +
<li>It has methods to simplify many common operations. For example:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! method
 
! effect
 
! effect
 
|-
 
|-
| <samp>ItemID</samp>
+
| <code>HasAny()</code>
| The [[#Custom items|qualified item ID]] for the item to place.
+
| Get whether the inventory contains any items (ignoring empty slots).
 
|-
 
|-
| <samp>Tile</samp>
+
| <code>CountItemStacks()</code>
| The tile position at which to place the item, specified as an object with <samp>X</samp> and <samp>Y</samp> fields.
+
| Get the number of item stacks in the inventory (ignoring empty slots).
 
|-
 
|-
| <samp>Indestructible</samp>
+
| <code>ContainsId(id)</code>
| ''(Optional)'' Whether to prevent the player from destroying, picking up, or moving the item. Default false.
+
| Get whether the inventory contains any item with the given qualified or unqualified item ID.
|}
 
 
|-
 
|-
| <samp>AddMailOnBuild</samp>
+
| <code>ContainsId(id, minCount)</code>
| ''(Optional)'' A list of [[Modding:Mail data|letter IDs]] to send to all players when the building is constructed for the first time.
+
| Get whether the inventory contains items with the given qualified or unqualified item ID, and their combined stack size is at least <samp>minCount</samp>.
|}
 
 
 
====Upgrades====
 
{| class="wikitable"
 
 
|-
 
|-
! field
+
| <code>CountId(id)</code>
! effect
+
| Get the combined stack size of all items with the given qualified or unqualified item ID.
 
|-
 
|-
| <samp>BuildingToUpgrade</samp>
+
| <code>GetById(id)</code>
| ''(Optional)'' The ID of the building for which this is an upgrade, or omit to allow constructing it as a new building. For example, the [[Coop|Big Coop]] sets this to <samp>"Coop"</samp>. Any numbers of buildings can be an upgrade for the same building, in which case the player can choose one upgrade path.
+
| Get a list of items in the inventory with the given qualified or unqualified item ID.
 
|-
 
|-
| <samp>IndoorItemMoves</samp>
+
| <code>ReduceId(id, count)</code>
| ''(Optional)'' When applied as an upgrade to an existing building, the placed items in its interior to move when transitioning to the new map. This is a list of models with these fields:
+
| Remove the given number of items matching the given qualified or unqualified item ID. This reduces the stack size for matching items until a total of <samp>count</samp> have been removed, and clears any slots which reach a stack size of zero.
 +
|}</li>
 +
<li>Many common operations have been unified, so previously player-only methods can now be used with chests too.</li>
 +
<li>It has an internal index by item ID, so operations like <code>items.ContainsId("(O)128")</code> are much more efficient since they no longer iterate the list.</li>
 +
</ul>
 +
 
 +
This replaces some previous methods:
 +
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! game class
! effect
+
! old code
 +
! migration
 +
|-
 +
|rowspan="6"| <samp>Farmer</samp>
 +
| <code>getItemCount(id)</code><br /><code>GetTallyOfObject(id)</code><br /><code>GetTallyOfObject(id, isBigCraftable)</code><br /><code>hasItemInInventory(id, count)</code><br /><code>hasItemInList(list, id, count)</code>
 +
| &#32;
 +
* To check an item ID, use <code>items.CountId(id)</code> or <code>Items.ContainsId(id, count)</code>.
 +
* To check Golden Walnuts or Qi Gems, use the <samp>Game1.netWorldState.Value.GoldenWalnuts</samp> and <samp>Farmer.QiGems</samp> fields.
 +
* To check category matches or <samp>-777</samp> (seasonal wild seeds), the <samp>getItemCount</samp> and <samp>getItemCountInList</samp> still exist.
 +
|-
 +
| <code>hasItemInInventoryNamed(name)</code><br /><code>hasItemWithNameThatContains(name)</code>
 +
| In most cases, you should match items by ID instead (see the previous row).
 +
 
 +
If you really need to match items by name, you can replace it like this:
 +
<syntaxhighlight lang="c#">
 +
// exact name
 +
bool hasMatch = Game1.player.Items.Any(item => item?.Name == name);
 +
 
 +
// name contains
 +
bool hasMatch = Game1.player.Items.Any(item => item?.Name?.Contains(name) is true);
 +
</syntaxhighlight>
 +
|-
 +
| <code>areAllItemsNull()</code>
 +
| Use <code>!items.HasAny()</code>.
 
|-
 
|-
| <samp>Source</samp>
+
| <code>numberOfItemsInInventory()</code>
| The tile position on which any item will be moved.
+
| Use <code>items.CountItemStacks()</code> to count all items, or <code>Items.Count(p => p is Object)</code> to match this method's actual behavior.
 
|-
 
|-
| <samp>Destination</samp>
+
| <code>consumeObject(id, count)</code>
| The tile position to which to move the item.
+
| Use <code>items.ReduceId(id, count)</code>.
 
|-
 
|-
| <samp>Size</samp>
+
| <code>removeItemsFromInventory(id, count)</code>
| ''(Optional)'' The tile size of the area to move, specified as a model with <samp>X</samp> and <samp>Y</samp> fields. Defaults to a 1×1 area. If this is multiple tiles, the <samp>Source</samp> and <samp>Destination</samp> specify the top-left coordinate of the area.
+
| &#32;
|}
+
* To remove an item by ID, use <code>items.ReduceId(id, count)</code>.
 +
* To deduct Golden Walnuts or Qi Gems, change the <samp>Game1.netWorldState.Value.GoldenWalnuts</samp> and <samp>Farmer.QiGems</samp> fields.
 
|-
 
|-
| <samp>UpgradeSignTile</samp>
+
|rowspan="2"| <samp>Object</samp>
| ''(Optional)'' The tile position relative to the top-left corner of the building where the upgrade sign will be placed when Robin is building an upgrade, in the form <samp>"{{t|x}}, {{t|y}}"</samp>. Defaults to approximately <samp>"5, 1"</samp> if the building interior type is <samp>Shed</samp>, else <samp>"0, 0"</samp>.
+
| <code>ConsumeInventoryItem(player, id, count)</code>
 +
| This was somewhat specialized and shouldn't be called by mod code, but the equivalent would be <code>(Object.autoLoadChest ?? player.items).ReduceId(id, count)</code>. See also notes for <samp>Farmer.removeItemsFromInventory</samp>.
 
|-
 
|-
| <samp>UpgradeSignHeight</samp>
+
| <code>GetTallyOfObject(player, id)</code>
| ''(Optional)'' The pixel height of the upgrade sign when Robin is building an upgrade. Defaults to 0.
+
| This was somewhat specialized and shouldn't be called by mod code, but the equivalent would be <code>(Object.autoLoadChest ?? player.items).CountId(id)</code>. See also notes for <samp>Farmer.getTallyOfObject</samp>.
 
|}
 
|}
  
====Exterior behavior====
+
It implements a new <samp>IInventory</samp> interface, which lets mods pass their own implementations to code which works on inventories.
 +
 
 +
===Furniture changes===
 +
{{/doc status|[[Modding:Items#Furniture]]|done=false}}
 +
 
 +
<ul>
 +
<li>[[Modding:Items#Furniture|<samp>Data/furniture</samp>]] no longer has language variants. Translations were moved into <samp>Strings/Furniture</samp>.</li>
 +
<li>
 +
There are a few changes in [[Modding:Items#Furniture|<samp>Data/furniture</samp>]]:
 +
<ul>
 +
<li>Field index 6 is now placement restrictions and field index 7 is now display name. The display name field is no longer omitted in English.</li>
 +
<li>Field index 7 (display name) now allows [[Modding:Tokenizable strings|tokenizable strings]].</li>
 +
<li>Added new fields:
 +
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
 +
! index
 
! field
 
! field
 
! effect
 
! effect
 
|-
 
|-
| <samp>Size</samp>
+
| 8
| ''(Optional)'' The building's width and height when constructed, measured in tiles. Defaults to a 1 x 1 area.
+
| sprite index
 +
| The sprite index within the spritesheet texture to draw.
 
|-
 
|-
| <samp>CollisionMap</samp>
+
| 9
| ''(Optional)'' An ASCII text block which indicates which of the building's tiles the players can walk onto, where each character can be <samp>X</samp> (blocked) or <samp>O</samp> (passable). Defaults to all tiles blocked.
+
| texture
 
+
| ''(Optional)'' The asset name of the texture to draw. Defaults to <samp>TileSheets/furniture</samp>.
For example, a [[stable]] covers a 2x4 tile area with the front two tiles passable:
 
<pre>XXXX
 
XOOX</pre>
 
 
 
When the collision map is parsed, leading/trailing whitespace is trimmed (both for the entire map and for each line). In JSON, you can specify it in two forms:
 
<syntaxhighlight lang="js">
 
// single line with \n line breaks
 
"CollisionMap": "XXXX\nXOOX"
 
 
 
// multi-line with optional indentation
 
"CollisionMap": "
 
    XXXX
 
    XOOX
 
"
 
</syntaxhighlight>
 
 
|-
 
|-
| <samp>HumanDoor</samp>
+
| 10
| ''(Optional)'' The position of the door that can be clicked to warp into the building interior. This is measured in tiles relative to the top-left corner tile. Defaults to disabled.
+
| off limits for random sale
 +
| ''(Optional)'' Whether to prevent this furniture from appearing in randomly generated shop stocks and the furniture catalogue. Default false.
 
|-
 
|-
| <samp>AnimalDoor</samp>
+
| 11
| ''(Optional)'' The position and size of the door that animals use to enter/exit the building, if the building interior is an animal location, specified in the form <samp>"{{t|x}} {{t|y}} {{t|width}} {{t|height}}"</samp>. This is measured in tiles relative to the top-left corner tile. Defaults to disabled.
+
| context tags
|-
+
| ''(Optional)'' A space-delimited list of [[Modding:Items#Context tags|context tags]] which apply to this furniture. Default none.
| <samp>AnimalDoorOpenDuration</samp><br /><samp>AnimalDoorCloseDuration</samp>
+
|}</li>
| ''(Optional)'' The duration of the open/close animation for the animal door, measured in milliseconds. If omitted, the door switches to the open/closed state instantly.
+
</ul>
|-
+
</li>
| <samp>AnimalDoorOpenSound</samp><br /><samp>AnimalDoorCloseSound</samp>
+
</ul>
| ''(Optional)'' The sound which is played once each time the animal door is opened/closed. Disabled by default.
+
 
|}
+
===Other item changes for C# mods===
 +
* Placed object changes:
 +
** Every placed object now has a <samp>Location</samp> property set to the location which contains it. This removes location parameters from many object methods.
 +
** Setting an object's tile position through <samp>obj.TileLocation</samp> now recalculcates its collision box automatically. (Setting it through the <samp>tileLocation</samp> net field directly won't though.)
 +
** The <samp>obj.IsScarecrow()</samp> and <samp>GetScarecrowRadius()</samp> methods now work for non-bigcraftable objects too.
 +
* Clothing changes:
 +
** <samp>Clothes.clothesType</samp> is now an enum field.
 +
** Clothing is no longer gender-specific. This renames <samp>indexInTileSheetMale</samp> to <samp>indexInTileSheet</samp>, obsoletes <samp>indexInTileSheetFemale</samp>, and converts gender-variant clothing into regular items.
 +
** Removed unused <samp>ClothesType.ACCESSORY</samp> value.
 +
** <samp>Farmer.pants</samp> and <samp>Farmer.shirt</samp> now store the item ID instead of the sprite index.
 +
** In <samp>Data/TailoringRecipes</samp>, added a <samp>CraftingIdFeminine</samp> field which overrides <samp>CraftingId</samp> for female characters.
 +
* Crop changes:
 +
** Added <samp>Game1.cropData</samp> to read crop info without constantly reloading the <samp>Data/Crops</samp> asset.
 +
** Removed most crop fields which only mirror the data (like <samp>harvestMethod</samp> or <samp>seasonsToGrowIn</samp>). Mods can get the info through <samp>crop.GetData()</samp> instead.
 +
** Partly de-hardcoded fertilizer logic. Almost all fertilizer logic is now centralized into a new patchable set of <samp>HoeDirt</samp> methods (see list below). The only fertilizer logic that's still embedded elsewhere is the interaction errors in <samp>Utility.tryToPlaceItem</samp>.
 +
** HoeDirt.fertilizer.Value is now set to <samp>null</samp> when there is no fertilizer. Both qualified and unqualified IDs should be expected.
 +
** Removed <samp>crop.InferSeedIndex()</samp>. This was used to support old crops, which are now fixed by a save migration instead.
 +
* Tool changes:
 +
** Fixed various logic not handling custom tool upgrade levels.
 +
<ul>
 +
<li>Other item logic:<ul>
 +
<li>Simplified the constructors for many item types, particularly <samp>Object</samp>.</li>
 +
<li>[[Honey]] items now have their <samp>preserve</samp> field set to a new <samp>Honey</samp> type (instead of null).</li>
 +
<li>The <samp>Object.performObjectDropInAction</samp> method now applies the <samp>probe</samp> argument much more consistently. This only affects method calls with <samp>probe: true</samp>.</li>
 +
<li>The <samp>Item.salePrice()</samp> method now has option to get the price without [[Multiplayer#Profit margins|profit margins]].</li>
 +
<li>Added new fields & methods:
  
====Exterior appearance====
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! type
 +
! field/method
 
! effect
 
! effect
 
|-
 
|-
| <samp>SourceRect</samp>
+
| <samp>Chest</samp>
| ''(Optional)'' The building's pixel area within the <samp>Texture</samp>, in the form <samp>"{{t|x}} {{t|y}} {{t|width}} {{t|height}}"</samp> (like <samp>"0 0 112 128"</samp>). Defaults to the entire texture.
+
| <samp>GetItemsForPlayer()</samp>
 +
| Shortcut for <samp>chest.GetItemsForPlayer(Game1.player.UniqueMultiplayerID)</samp>.
 
|-
 
|-
| <samp>Skins</samp>
+
| rowspan="2"| <samp>Crop</samp>
| ''(Optional)'' The appearances which can be selected from Robin's menu (like stone/plank/log [[cabin]]s). If specified, it's assumed that one of the skins matches the default appearance specified by <samp>Texture</samp> (so you need at least two skins for the option to appear in-game). This consists of a list of models with these fields:
+
| <samp>GetHarvestMethod()</samp>
{| class="wikitable"
+
| Get the method used to harvest the crop (one of <samp>HarvestMethod.Grab</samp> or <samp>HarvestMethod.Scythe</samp>).
 
|-
 
|-
! field
+
| <samp>IsInSeason(location)</samp>
! effect
+
| Whether the crop can grow in the location's current season (or true if crops ignore seasons in the location, like the [[greenhouse]]).
 
|-
 
|-
| <samp>ID</samp>
+
| rowspan="8"| <samp>HoeDirt</samp>
| The unique ID for the skin.
+
| <samp>HasFertilizer()</samp>
 +
| Get whether the dirt has any fertilizer applied.
 
|-
 
|-
| <samp>Name</samp><br /><samp>Description</samp>
+
| <samp>CanApplyFertilizer(itemId)</samp>
| [[#Tokenizable string format|Tokenizable strings]] for the skin's display name and description.
+
| Get whether a player can apply the given fertilizer to this dirt.
 
|-
 
|-
| <samp>Texture</samp>
+
| <samp>CheckApplyFertilizerRules(itemId)</samp>
| The asset name for the texture under the game's Content folder.
+
| Get whether a player can apply the given fertilizer to this dirt, and the reason they can't if applicable.
|}
 
 
|-
 
|-
| <samp>FadeWhenBehind</samp>
+
| <samp>GetFertilizerSpeedBoost()</samp>
| ''(Optional)'' Whether the building should become semi-transparent when the player is behind it. Default true.
+
| Get the crop growth speed boost from fertilizers applied to this dirt.
 
|-
 
|-
| <samp>DrawOffset</samp>
+
| <samp>GetFertilizerWaterRetentionChance()</samp>
| ''(Optional)'' A pixel offset applied to the building sprite's placement in the world. Default 0.
+
| Get the water retention chance from fertilizers applied to this dirt, as a value between 0 (no change) and 1 (100% chance of staying watered).
 
|-
 
|-
| <samp>SeasonOffset</samp>
+
| <samp>GetFertilizerQualityBoostLevel()</samp>
| ''(Optional)'' A pixel offset to apply each season. This is applied to the <samp>SourceRect</samp> position by multiplying the offset by 0 (spring), 1 (summer), 2 (fall), or 3 (winter). Default 0, so all seasons use the same source rect.
+
| Get the quality boost level from fertilizers applied to this dirt, which influences the chance of producing a higher-quality crop.
 
|-
 
|-
| <samp>SortTileOffset</samp>
+
| <samp>GetFertilizerSourceRect()</samp>
| ''(Optional)'' A Y tile offset applied when figuring out render layering. For example, a value of <samp>2.5</samp> will treat the building as if it was 2.5 tiles further up the screen for the purposes of layering. Default 0.
+
| Get the pixel area within the dirt spritesheet to draw for any fertilizer applied to this dirt.
 +
 
 +
(This method existed before, but no longer requires the fertilizer ID argument.)
 
|-
 
|-
| <samp>DrawLayers</samp>
+
| <samp>isWatered()</samp>
| ''(Optional)'' A list of textures to draw over or behind the building, with support for conditions and animations. This consists of a list of models with these fields:
+
| Get whether the dirt is currently watered.
{| class="wikitable"
 
 
|-
 
|-
! field
+
|rowspan="5"| <samp>Item</samp>
! effect
+
| <samp>IsRecipe</samp><br /><samp>Quality</samp><br /><samp>Stack</samp></samp><br /><samp>sellToStorePrice(…)</samp>
 +
| Equivalent to the previous <samp>Object</samp> fields/methods, to simplify common code and avoid needing to special-case <samp>Object</samp> items.
 
|-
 
|-
| <samp>SourceRect</samp>
+
| <samp>appliesProfitMargins()</samp>
| The pixel area within the <samp>texture</samp> to draw, formatted like <samp>"{{t|x}} {{t|y}} {{t|width}} {{t|height}}"</samp>. If the overlay is animated via <samp>FrameCount</samp>, this is the area of the first frame.
+
| Get whether this item should apply [[Multiplayer#Profit margins|profit margins]] to shop prices.
 
|-
 
|-
| <samp>DrawPosition</samp>
+
| <samp>CanBeLostOnDeath()</samp>
| The tile position at which to draw the top-left corner of the texture, relative to the building's top-left corner tile.
+
| Get whether this item can be lost when the player dies, so it can be recovered from the [[Adventurer's Guild#Item Recovery Service|item recovery service]].
 
|-
 
|-
| <samp>Texture</samp>
+
| <samp>HasTypeId(id)</samp><br /><samp>HasTypeObject()</samp><br /><samp>HasTypeBigCraftable()</samp>
| ''(Optional)'' The asset name of the texture to draw. Defaults to the building's default <samp>Texture</samp> field.
+
| Get whether the item has the given [[#Custom items|type definition ID]]. These are null-safe and double as a null check:
 +
<syntaxhighlight lang="c#">
 +
if (item.HasTypeId(ItemRegistry.type_object))
 +
{
 +
    // item is non-null and has type (O)
 +
}
 +
</syntaxhighlight>
 +
<samp>HasTypeObject()</samp> and <samp>HasTypeBigCraftable()</samp> are shortcuts for passing <samp>ItemRegistry.type_object</samp> and <samp>ItemRegistry.type_bigCraftable</samp> respectively.
 
|-
 
|-
| <samp>DrawInBackground</samp>
+
| <samp>TryGetTempData</samp><br /><samp>SetTempData</samp>
| ''(Optional)'' Whether to draw the texture behind the building sprite (i.e. underlay) instead of over it.
+
| Get or set temporary item info that's not synchronized in multiplayer or written to the save file.
 +
 
 +
For example, the game uses this to pass spawn options to the fishing minigame:
 +
<syntaxhighlight lang="c#">
 +
if (spawn.IsBossFish)
 +
    fish.SetTempData(nameof(spawn.IsBossFish), true);
 +
 
 +
...
 +
 
 +
fish.TryGetTempData(nameof(SpawnFishData.IsBossFish), out bool bossFish);
 +
</syntaxhighlight>
 
|-
 
|-
| <samp>SortTileOffset</samp>
+
| <samp>FishingRod</samp>
| ''(Optional)'' A Y tile offset applied when figuring out render layering. For example, a value of <samp>2.5</samp> will treat the texture as if it was 2.5 tiles further up the screen for the purposes of layering. Default 0.
+
| <samp>CanUseBait()</samp><br /><samp>CanUseTackle()</samp><br /><samp>GetBait()</samp><br /><samp>GetTackle()</samp><br /><samp>HasMagicBait()</samp><br /><samp>HasCuriosityLure()</samp>
 +
| Simplifies working with the fishing rod's [[bait]] and [[tackle]].
 
|-
 
|-
| <samp>OnlyDrawIfChestHasContents</samp>
+
|rowspan="2"| <samp>Furniture</samp>
| ''(Optional)'' The name of a chest defined in the <samp>Chests</samp> field which must contain items. If it's empty, this overlay won't be rendered. Default none.
+
| <samp>SetPlacement</samp><br /><samp>SetHeldObject</samp>
 +
| Set the furniture's position and rotation (<samp>SetPlacement</samp>) or held object (<samp>SetHeldObject</samp>). The latter will initialize the held object's tile position to match the furniture instance.
 +
 
 +
These are used by the game to initialize furniture in one go. For example:
 +
<syntaxhighlight lang="c#">
 +
// oak table holding decorative bowl
 +
Furniture table = ItemRegistry
 +
    .Create<Furniture>("(F)1120")
 +
    .SetPlacement(5, 4, 0)
 +
    .SetHeldObject(ItemRegistry.Create<Furniture>("(F)1364"));
 +
</syntaxhighlight>
 
|-
 
|-
| <samp>FrameCount</samp><br /><samp>FramesPerRow</samp><br /><samp>FrameDuration</samp>
+
| <samp>IsTable()</samp>
| ''(Optional)'' If <samp>FrameCount</samp> is more than one, the building overlay will be animated automatically. For each frame, the <samp>SourceRect</samp> will be offset by its <samp>Width</samp> to the right up to <samp>FramesPerRow - 1</samp> times, and then down by its <samp>Height</samp>. Each frame will be rendered on-screen for <samp>FrameDuration</samp> milliseconds before switching to the next frame.
+
| Get whether this furniture is a table.
 
 
For example, if you set <samp>FrameCount</samp> to 6 and <samp>FramesPerRow</samp> to 3, the building will expect the frames to be laid out like this in the spritesheet (where frame 1 matches <samp>SourceRect</samp>):
 
<pre>
 
┌───┬───┬───┐
 
│ 1 │ 2 │ 3 │
 
├───┼───┼───┤
 
│ 4 │ 5 │ 6 │
 
└───┴───┴───┘
 
</pre>
 
 
|-
 
|-
| <samp>AnimalDoorOffset</samp>
+
|rowspan="2"| <samp>FruitTree</samp>
| ''(Optional)'' A pixel offset applied to the draw layer when the animal door is open. While the door is opening, the percentage open is applied to the offset (e.g. 50% open = 50% offset).
+
| <samp>GetQuality()</samp>
|}
+
| Get the quality of fruit currently being produced by the fruit tree.
 
|-
 
|-
| <samp>DrawShadow</samp>
+
| <samp>TryAddFruit()</samp>
| ''(Optional)'' Whether to draw an automatic shadow along the bottom edge of the building's sprite. Default true.
+
| Add a fruit item to the tree based on [[#Custom fruit trees|its data]].
|}
 
 
 
====Interior====
 
{| class="wikitable"
 
 
|-
 
|-
! field
+
| <samp>IndoorPot</samp>
! effect
+
| <samp>Water()</samp>
 +
| Simplifies watering dirt in the [[Garden Pot|garden pot]].
 
|-
 
|-
| <samp>IndoorMap</samp>
+
| <samp>Object</samp>
| ''(Optional)'' The name of the map asset under <samp>Maps</samp> to load for the building interior. For example, <samp>"Shed"</samp> will load the [[shed]]'s <samp>Maps/Shed</samp> map.
+
| <samp>GetBoundingBox()</samp><br /><samp>GetBoundingBoxAt(x, y)</samp>
 +
| Get the pixel collision area for the item placed in the world. These replace the former <samp>getBoundingBox(position)</samp> method.
 
|-
 
|-
| <samp>IndoorMapType</samp>
+
| <samp>Tool</samp>
| ''(Optional)'' The full name of the C# location class which will manage the building's interior location. This must be one of the vanilla types to avoid a crash when saving. There are too many to list here, but the most useful types are likely...
+
| <samp>isScythe()</samp>
* <samp>StardewValley.AnimalHouse</samp>;
+
| Equivalent to the previous <samp>MeleeWeapon</samp> method, to simplify common code and avoid needing to special-case <samp>MeleeWeapon</samp> items.
* <samp>StardewValley.Locations.Cabin</samp>;
 
* <samp>StardewValley.Locations.Cellar</samp>;
 
* <samp>StardewValley.Locations.DecoratableLocation</samp>;
 
* <samp>StardewValley.Locations.FarmCave</samp>;
 
* <samp>StardewValley.Locations.FarmHouse</samp>;
 
* <samp>StardewValley.Locations.Shed</samp>;
 
* and <samp>StardewValley.Locations.SlimeHutch</samp>.
 
Defaults to the generic <samp>StardewValley.GameLocation</samp> class.
 
 
|-
 
|-
| <samp>NonInstancedIndoorLocation</samp>
+
|rowspan="3"| <samp>Tree</samp>
| ''(Optional)'' The name of the existing global location to treat as the building's interior, like <samp>FarmHouse</samp> and <samp>Greenhouse</samp> for their buildings.
+
| <samp>CheckForNewTexture()</samp>
 
+
| Reset the tree's texture if it would change based on [[#Custom wild trees|its data]].
Each location can only be used by one building. If the location is already in use (e.g. because the player has two of this building), each subsequent building will use the <samp>IndoorMap</samp> and <samp>IndoorMapType</samp> instead. For example, the first greenhouse will use the global <samp>Greenhouse</samp> location, and any subsequent greenhouse will use a separate instanced location.
 
 
|-
 
|-
| <samp>MaxOccupants</samp>
+
| <samp>GetMaxSizeHere</samp>
| ''(Optional)'' The maximum number of animals who can live in this building.
+
| Get the maximum size the tree can grow in its current position (e.g. accounting for nearby trees blocking growth).
 
|-
 
|-
| <samp>ValidOccupantTypes</samp>
+
| <samp>IsGrowthBlockedByNearbyTree</samp>
| ''(Optional)'' A list of building IDs whose animals to allow in this building too. For example, <code>[ "Barn", "Coop" ]</code> will allow [[barn]] and [[coop]] animals in this building. Default none.
+
| Get whether growth is blocked because it's too close to another fully-grown tree.
 
|}
 
|}
 +
</li>
 +
<li>Modularized <samp>Object.CheckForAction</samp> to simplify mod patches.</li>
 +
<li>Reworked <samp>Item.getOne()</samp> implementation to avoid common pitfalls. (This only affects mods with custom item classes, or which patch <samp>Item.getOne</samp> or <samp>Item._GetOneFrom</samp>.)</li>
 +
<li>Fixed fruit trees forgetting the growth stage set in their constructor when they're updated overnight.</li>
 +
</ul>
  
====Item processing====
+
===Other item changes===
 +
* Added per-object display names (''e.g.'' for custom flavored items). See the <samp>ObjectDisplayName</samp> [[Modding:Item queries#Item spawn fields|item spawn field]], or <samp>object.displayNameFormat</samp> in C#.
 +
* [[Ginger Island#Gem Birds|Item pedestals]] are now normal item, so you can spawn them using a mod like CJB Item Spawner to display items.
 +
* Added optional <samp>Condition</samp> [[Modding:Game state queries|game state query]] field to <samp>Data/SpecialOrders</samp>.
 +
* Item data changes:
 +
** The display name field now exists in English too for <samp>Data/Boots</samp>, <samp>Data/Bundles</samp>, <samp>Data/CookingRecipes</samp>, <samp>Data/CraftingRecipes</samp>, <samp>Data/Furniture</samp>, <samp>Data/Hats</samp>, and <samp>Data/Weapons</samp>.
 +
** The randomly spawned [[The Farm#Stone|stones]], [[The Farm#Wood|twigs]], and [[weeds]] have been formalized into ''litter''. They all now have object type <samp>Litter</samp>, [[Modding:Items#Categories|category]] -999 (<samp>StardewValley.Object.litterCategory</samp>), a relevant display name/description (like ''Gold Stone'' & ''Break apart to obtain gold ore'' instead of ''Stone'' & ''...''), a price of 0 (not sellable), and edibility of -300 (inedible). This also adds all mine ore nodes to <samp>Data/Objects</samp>, so the game no longer creates invalid items to show their sprite. (Doing so in 1.6 will now show an Error Item sprite instead.)
 +
** [[Honey]] items now have the <samp>honey_item</samp> context tag.
 +
** Shirts no longer have a dynamic numeric ID range; every valid shirt is now listed in [[#Custom shirts|<samp>Data/Shirts</samp>]].
 +
** You can now apply a custom buff ID when the item is eaten, via <samp>Data/Objects</samp>'s <samp>Buff</samp> field.
 +
** The type field in <samp>Data/Objects</samp> is no longer checked using substring matching (e.g. the game now uses <code>data.Type == "Fish"</code> instead of <code>typeAndCategory.Contains("Fish")</code>), which may impact mods which depended on that undocumented behavior.
 +
* Crop changes:
 +
** Paddy crops now recheck for nearby water each day, so they'll update if you add/remove a building with water or change the map layout.
 +
** In <samp>Data/Crops</samp>, each harvest option is now self-contained. For example, you can set <samp>HarvestMinStack</samp> without <samp>ExtraHarvestChance</samp>.
 +
* Fish changes:
 +
** <samp>Data/Fish</samp> is no longer translated, so there's only one <samp>Data/Fish.xnb</samp> field. Fish display names are now taken from <samp>Data/Objects</samp>.
 +
** Added a new field (index 13) in <samp>Data/Fish</samp>, which sets whether the fish can be selected for the first-catch tutorial.
 +
* Recipe changes in <samp>Data/CookingRecipes</samp> and <samp>Data/CraftingRecipes</samp>:
 +
** These assets no longer have language variants.
 +
** The display name now supports [[Modding:Tokenizable strings|tokenizable strings]].
 +
** The display name can now be left blank to get it from the first item in the output list.
 +
* Other item logic:
 +
** Missing recipes that should already be unlocked are now added to the player automatically on save load.
 +
** <samp>Data/Bundles</samp> is now loaded later, so content packs can edit it reliably.</samp>
 +
** Chests with <samp>fridge: true</samp> are now treated as mini-fridges for the cooking menu.
 +
** Gift boxes can now contain multiple items.
 +
** Fixed furniture drawn over sitting players if it has no front texture.
 +
** Fixed tool being upgraded by Clint not affected by recursive item search logic.
 +
** Fixed <samp>tool.getOne()</samp> not copying the tool name.
 +
** Fixed cooking menu constantly creating hovered item if the item/recipe names don't match.
 +
 
 +
==What's new for locations & weather==
 +
===Custom locations===
 +
{{/doc status|[[Modding:Location data]]|done=true}}
 +
 
 +
You can now add/edit locations by editing the revamped <samp>Data/Locations</samp> asset. This makes nearly everything in the location configurable — display name, default warp arrival tile, how the location is created, artifact spots / fish / forage / weeds, music, etc.
 +
 
 +
See [[Modding:Location data]] for docs on the new data format.
 +
 
 +
===Custom location contexts===
 +
{{/doc status|[[Modding:Location data]] or a new doc page|done=false}}
 +
 
 +
====Vanilla contexts====
 +
* The game previously had two hardcoded location context enums: <samp>Default</samp> (for the valley) and <samp>Island</samp> (for [[Ginger Island]]). These have been replaced with data models which define the location context settings, loaded from the <samp>Data/LocationContexts</samp> asset.
 +
* [[The Desert|The desert]] is now part of a new <samp>Desert</samp> context (instead of <samp>Default</samp>). Some of the previously hardcoded desert logic (like always sunny weather) is now just part of the context data in <samp>Data/LocationContexts</samp>.
 +
 
 +
====Format====
 +
Custom contexts can be created by editing the new <samp>Data/LocationContexts</samp> asset, and setting the context name in the location's <samp>LocationContext</samp> [[Modding:Maps|map property]].
 +
 
 +
The data asset consists of a string → model lookup, where the key matches the <samp>Name</samp> field and the value is a model with these fields:
 +
 
 +
<dl style="margin-left: 2em;">
 +
<dt>Required fields:</dt>
 +
<dd>
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 2,319: Line 2,650:
 
! effect
 
! effect
 
|-
 
|-
| <samp>HayCapacity</samp>
+
| <samp>Name</samp>
| ''(Optional)'' The amount of hay that can be stored in this building. If built on the [[The Farm|farm]], this works just like [[silo]]s and contributes to the farm's available hay.
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for the location context.
|-
+
|}
| <samp>ItemConversions</samp>
+
</dd>
| ''(Optional)'' The item processing rules which take input items and convert them into output items using the inventories defined by <samp>Chests</samp>. This consists of a list of models with these fields:
+
 
 +
<dt>Player actions:</dt>
 +
<dd>
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 2,329: Line 2,662:
 
! effect
 
! effect
 
|-
 
|-
| <samp>RequiredTags</samp>
+
| <samp>AllowRainTotem</samp>
| A list of [[Modding:Items#Context tags|context tags]] to match against an input item. An item must have ''all'' of these tags to be accepted.
+
| ''(Optional)'' Whether a [[Rain Totem|rain totem]] can be used to force rain in this context tomorrow. If false, using a rain totem here will show a "''this item can't be used here''" message instead.
 
|-
 
|-
| <samp>SourceChest</samp>
+
| <samp>RainTotemAffectsContext</samp>
| The name of the inventory defined in <samp>Chests</samp> from which to take input items.
+
| ''(Optional)'' If set, using a rain totem here will change the weather in the given context ID. For example, rain totems in the desert change weather in the valley.
 
|-
 
|-
| <samp>DestinationChest</samp>
+
| <samp>MaxPassOutCost</samp>
| The name of the inventory defined in <samp>Chests</samp> in which to store output items.
+
| ''(Optional)'' When the player passes out (due to [[energy|exhaustion]] or at 2am) in this context, the maximum amount of [[gold]] lost. If omitted or set to <samp>-1</samp>, uses the same value as the <samp>Default</samp> context ({{price|1000}} by default).
 
|-
 
|-
| <samp>ProducedItems</samp>
+
| <samp>PassOutMail</samp>
| The output items produced when an input item is converted. This consists of a list of models with these fields:
+
| ''(Optional)'' When the player passes out (due to [[energy|exhaustion]] or at 2am) in this context, the possible [[Modding:Mail data|letter IDs]] to add to their mailbox (if they haven't received it before). If multiple letters are valid, one will be chosen randomly (unless one specifies <samp>SkipRandomSelection</samp>).
 +
 
 +
This consists of a list of models with these fields:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 2,345: Line 2,680:
 
! effect
 
! effect
 
|-
 
|-
| <samp>ItemID</samp>
+
| <samp>Id</samp>
| The [[#Custom items|qualified item ID]].
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry in the list.
 
|-
 
|-
| <samp>MinCount</samp><br /><samp>MaxCount</samp>
+
| <samp>Mail</samp>
| The minimum/maximum number of the item to produce.
+
| The [[Modding:Mail data|letter ID]] to add.
 +
 
 +
The game will look for an existing letter ID in <samp>Data/mail</samp> in this order (where {{t|billed}} is <samp>Billed</samp> if they lost [[gold]] or <samp>NotBilled</samp> otherwise, and {{t|gender}} is <samp>Female</samp> or <samp>Male</samp>):
 +
* <samp>{{t|letter id}}_{{t|billed}}_{{t|gender}}</samp>
 +
* <samp>{{t|letter id}}_{{t|billed}}</samp>
 +
* <samp>{{t|letter id}}</samp>
 +
 
 +
If no match is found in <samp>Data/mail</samp>, the game will send <samp>passedOut2</samp> instead.
 +
 
 +
If the mail ID starts with <samp>passedOut</samp>, <samp>{0}</samp> in the letter text will be replaced with the gold amount lost, and it won't appear in the [[collections]] page.
 
|-
 
|-
| <samp>Chance</samp>
+
| <samp>MaxPassOutCost</samp>
| ''(Optional)'' The probability that the item will be produced, as a value between 0 (never drops) and 1 (always drops). This has no effect on other output items (e.g. if there are ten outputs with 100% chance, all ten will be produced). Default 1 (100% chance).
+
| ''(Optional)'' The maximum amount of [[gold]] lost. This is applied after the context's <samp>MaxPassOutCost</samp> (i.e. the context's value is used to calculate the random amount, then this field caps the result). Defaults to unlimited.
 
|-
 
|-
 
| <samp>Condition</samp>
 
| <samp>Condition</samp>
| ''(Optional)'' If set, the output is only available if the given [[#Game state queries|game state query]] is true.
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this entry is active. Defaults to always true.
|}
 
 
|-
 
|-
| <samp>RequiredCount</samp>
+
| <samp>SkipRandomSelection</samp>
| ''(Optional)'' The number of the input item to consume. Default 1.
+
| ''(Optional)'' If true, send this mail if the <samp>Condition</samp> matches instead of choosing a random valid mail. Default false.
|-
 
| <samp>MaxDailyConversions</samp>
 
| ''(Optional)'' The maximum number of the input item which can be processed each day. Each conversion rule has its own separate maximum (e.g. if you have two rules each with a max of 1, then you can convert one of each daily). Set to -1 to allow unlimited conversions. Default 1.
 
 
|}
 
|}
 
|-
 
|-
| <samp>Chests</samp>
+
| <samp>PassOutLocations</samp>
| ''(Optional)'' The input/output inventories that can be accessed from a tile on the building exterior. The allowed items are defined by the separate <samp>ItemConversions</samp> field. This is a list of models with these fields:
+
| ''(Optional)'' When the player passes out (due to [[energy|exhaustion]] or at 2am) in this context ''and'' they started the day in a different location context, the locations where they'll wake up. (If the player started the day in the same context, they'll wake up in the last bed they slept in instead.)
 +
 
 +
If the selected location doesn't contain a bed and doesn't have the [[#New map properties|<samp>AllowWakeUpWithoutBed</samp> map property]], the player will wake up in the farmhouse instead.
 +
 
 +
This consists of a list of models with these fields:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 2,372: Line 2,716:
 
! effect
 
! effect
 
|-
 
|-
| <samp>Name</samp>
+
| <samp>Id</samp>
| A name for this chest, referenced from the <samp>ItemConversions</samp> field. Each chest must have a unique name within one building's chest list (but they don't need to be globally unique).
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry in the list.
 
|-
 
|-
| <samp>Type</samp>
+
| <samp>Location</samp>
| The inventory type. This must be one of:
+
| The internal location name.
* <samp>Chest</samp>: show a normal chest UI on click.
 
* <samp>Collect</samp>: provides items for the player to collect. Clicking the tile will do nothing (if empty), grab the item directly (if it only contains one item), else show a grab-only inventory UI.
 
* <samp>Load</samp>: lets the player add items for the building to process.
 
 
|-
 
|-
| <samp>Sound</samp>
+
| <samp>Position</samp>
| ''(Optional)'' The sound to play once when the player clicks the chest.
+
| The ''default'' tile position within the location, specified as an object with <samp>X</samp> and <samp>Y</samp> fields. If the location has any bed furniture, they'll be placed in the first bed found instead.
 
|-
 
|-
| <samp>InvalidItemMessage</samp><br /><samp>InvalidCountMessage</samp><br /><samp>ChestFullMessage</samp>
+
| <samp>Condition</samp>
| ''(Optional)'' A [[#Tokenizable string format|tokenizable string]] to show when the player tries to add an item to the chest when...
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this entry is active. Defaults to always applied.
* it isn't a supported item;
+
|}
* it's supported but they don't have enough in their inventory;
+
 
* the chest has no more room to accept it.
+
If no locations are specified or none match, the player will wake up in their bed at home.
If omitted, the player interaction is ignored with no message shown.
 
 
|-
 
|-
| <samp>DisplayTile</samp>
+
| <samp>ReviveLocations</samp>
| ''(Optional)'' The chest's position on the building exterior, measured in tiles from the top-left corner of the building, specified in the form <samp>"{{t|x}}, {{t|y}}"</samp>. This affects the position of the 'item ready to collect' bubble. If omitted, the bubble is disabled.
+
| ''(Optional)'' If the player just got knocked out in combat, the location names where they'll wake up.
|-
 
| <samp>DisplayHeight</samp>
 
| ''(Optional)'' If <samp>DisplayTile</samp> is set, the chest's tile height like <samp>1.5</samp>.
 
|}
 
|}
 
  
====Tile interactions====
+
This consists of a list of models with these fields:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 2,405: Line 2,740:
 
! effect
 
! effect
 
|-
 
|-
| <samp>ActionTiles</samp>
+
| <samp>Id</samp>
| ''(Optional)'' A list of tiles which the player can click to trigger an <samp>Action</samp> [[Modding:Maps|map tile property]]. This consists of a list of models with these fields:
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry in the list.
 +
|-
 +
| <samp>Location</samp>
 +
| The internal location name.
 +
|-
 +
| <samp>Position</samp>
 +
| The tile position within the location, specified as an object with <samp>X</samp> and <samp>Y</samp> fields.
 +
|-
 +
| <samp>Condition</samp>
 +
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this entry is active. Defaults to always applied.
 +
|}
 +
 
 +
If the selected location has a standard [[Modding:Event data|event]] with the exact key <samp>PlayerKilled</samp> (with no <samp>/</samp> or preconditions in the key), that event will play when the player wakes up and the game will apply the lost items or [[gold]] logic. The game won't track this event, so it'll repeat each time the player is revived. If there's no such event, the player will wake up without an event, and no items or gold will be lost.
 +
 
 +
If no locations are specified or none match, the player will wake up at [[Harvey's Clinic|Harvey's clinic]].
 +
|}
 +
</dd>
 +
 
 +
<dt>Season:</dt>
 +
<dd>
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 2,412: Line 2,766:
 
! effect
 
! effect
 
|-
 
|-
| <samp>Tile</samp>
+
| <samp>SeasonOverride</samp>
| The tile position, relative to the building's top-left corner tile.
+
| ''(Optional)'' The season which is always active for locations within this context (one of <samp>spring</samp>, <samp>summer</samp>, <samp>fall</samp>, or <samp>winter</samp>). For example, setting <samp>summer</samp> will make it always [[summer]] there regardless of the calendar season. If not set, the calendar season applies.
|-
 
| <samp>Action</samp>
 
| The [[#Tokenizable string format|tokenizable string]] for the action to perform, excluding the <samp>Action</samp> prefix. For example, <samp>"Dialogue Hi there @!"</samp> to show a messagebox like "''Hi there <player name>!''". The tokenizable string is expected before the action is raised. See the [[Modding:Maps#Tile properties 2|list of tile properties]] for useful <samp>Action</samp> values.
 
 
|}
 
|}
|-
+
</dd>
| <samp>DefaultAction</samp>
+
 
| ''(Optional)'' The default tile action if the clicked tile isn't in <samp>ActionTiles</samp>. Default none.
+
<dt>Weather:</dt>
|-
+
<dd>
| <samp>TileProperties</samp>
 
| ''(Optional)'' The [[Modding:Maps|map tile properties]] to set. This consists of a list of models with these fields:
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 2,429: Line 2,778:
 
! effect
 
! effect
 
|-
 
|-
| <samp>LayerName</samp>
+
| <samp>WeatherConditions</samp>
| The name of the map layer whose tiles to change.
+
| ''(Optional)'' The weather logic to apply for locations in this context (ignored if <samp>CopyWeatherFromLocation</samp> is set). Defaults to always sunny. If multiple are specified, the first matching weather is applied.
|-
+
 
| <samp>Tiles</samp>
+
This consists of a list of models with these fields:
| The tile properties to set on the layer, as a list of models with these fields:
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 2,439: Line 2,787:
 
! effect
 
! effect
 
|-
 
|-
| <samp>Tile</samp>
+
| <samp>Id</samp>
| The tile position, relative to the building's top-left corner tile.
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry in the list.
 
|-
 
|-
| <samp>Key</samp>
+
| <samp>Weather</samp>
| The tile property name to set.
+
| The [[#Custom weather|weather ID]] to set.
 
|-
 
|-
| <samp>Value</samp>
+
| <samp>Condition</samp>
| ''(Optional)'' The tile property value to set, or omit to set a null value.
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether to apply the weather. Defaults to always applied.
|}
 
 
|}
 
|}
 
|-
 
|-
| <samp>AdditionalTilePropertyRadius</samp>
+
| <samp>CopyWeatherFromLocation</samp>
| ''(Optional)'' When checking whether the player clicked on a <samp>TileProperties</samp> tile, an added distance around the building at which tile locations may be placed. Default 0, so only tile properties within the normal building bounds will work.
+
| ''(Optional)'' The <samp>Name</samp> (i.e. unique ID) of the location context from which to inherit weather.
 
|}
 
|}
  
====Advanced====
+
If a [[#Custom passive festivals|passive festival]] is active in any location within this context, the weather is sunny for the entire context regardless of these fields.
 +
 
 +
</dd>
 +
 
 +
<dt>Music:</dt>
 +
<dd>
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 2,460: Line 2,812:
 
! effect
 
! effect
 
|-
 
|-
| <samp>BuildingType</samp>
+
| <samp>DefaultMusic</samp>
| ''(Optional)'' The full name of the C# type to instantiate for the building instance. Defaults to a generic <samp>Building</samp> instance. Note that using a non-vanilla building type will cause a crash when trying to write the building to the save file.
+
| ''(Optional)'' The [[#Custom audio|cue ID]] for the music to play when the player is in the location, unless overridden by a <samp>Music</samp> map property. Despite the name, this has a higher priority than the seasonal music fields below. Ignored if omitted.
 
|-
 
|-
| <samp>ModData</samp>
+
| <samp>DefaultMusicCondition</samp>
| ''(Optional)'' A string → string lookup of arbitrary <samp>modData</samp> values to attach to the building when it's constructed.
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which returns whether the <samp>DefaultMusic</samp> field should be applied (if more specific music isn't playing). Defaults to always true.
 
|-
 
|-
| <samp>ConvertBuildingOffset</samp>
+
| <samp>DefaultMusicDelayOneScreen</samp>
| ''(Optional)'' Only used when migrating pre-1.6 buildings to 1.6, specifically to adjust for the barn's footprint being reduced by one tile in the back.
+
| ''(Optional)'' When the player warps and the music changes, whether to silence the music and play the ambience (if any) until the next warp (similar to the default valley locations). Default false.
 
|-
 
|-
| <samp>UpgradeOffset</samp><br /><samp>ValidBuildLocations</samp>
+
| <samp>Music</samp>
| ''(Optional)'' '''Unused.'''
+
| ''(Optional)'' A list of [[#Custom audio|cue IDs]] to play before noon in this location unless it's raining, there's a <samp>Music</samp> map property, or the context has a <samp>DefaultMusic</samp> value. If multiple values are specified, the game will play one per day in sequence.
|}
 
  
===Build anywhere===
+
This consists of a list of models with these fields:
Buildings and animals are no longer hardcoded to the [[The Farm|farm]] location. You can allow building construction for any location using the [[#Map/tile property changes|new <samp>CanBuildHere</samp> and related map properties]]. The game will adjust accordingly (e.g. Robin will let you choose where to construct the building).
 
 
 
==What's new for NPCs==
 
===Custom NPC data===
 
[[Modding:NPC data|Custom NPCs were already possible]], but 1.6 extends that with a new <samp>Data/AdditionalNPCData</samp> data asset to customize previously hardcoded game logic and specify some data for NPCs that aren't in <samp>Data/NPCDispositions</samp>.
 
 
 
This consists of a string → model lookup, where the key is the internal NPC name (i.e. the same key as <samp>Data/NPCDispositions</samp> if any), and the value is a model with these fields:
 
 
 
<dl style="margin-left: 2em;">
 
<dt>Main info:</dt>
 
<dd>
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 2,490: Line 2,830:
 
! effect
 
! effect
 
|-
 
|-
| <samp>ID</samp>
+
| <samp>Id</samp>
| The internal NPC name. This should match the entry key.
+
| ''(Optional)'' A [[Modding:Common data field types#Unique string ID|unique string ID]] which identifies this entry within the list. Defaults to the <samp>Track</samp> value.
 
|-
 
|-
| <samp>DisplayName</samp>
+
| <samp>Track</samp>
| ''(Optional)'' A [[#Tokenizable string format|tokenizable string]] for the NPC's display name. Defaults to the display name in <samp>Data/NPCDispositions</samp> (if any), else the internal NPC name.
+
| The [[Modding:Migrate to Stardew Valley 1.6#Custom audio|audio track ID]] to play.
 
|-
 
|-
| <samp>Size</samp>
+
| <samp>Condition</samp>
| ''(Optional)'' The pixel size of the individual sprites in their overworld sprite spritesheet. Specified as a model with <samp>X</samp> and <samp>Y</samp> fields. Defaults to <samp>(16, 32)</samp>.
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this entry applies. Default true.
 +
|}
 
|-
 
|-
| <samp>UnlockConditions</samp>
+
| <samp>DayAmbience</samp><br /><samp>NightAmbience</samp>
| ''(Optional)'' A [[#Game state queries|game state query]] which indicates whether the NPC should be added to the world, checked when loading a save and when ending each day. This only affects whether the NPC is added when missing; returning false won't remove an NPC that's already been added. Defaults to true.
+
| ''(Optional)'' The [[#Custom audio|cue ID]] for the background ambience to play when there's no music active, depending on the [[Day Cycle|time of day]]. Both default to none.
 
|-
 
|-
| <samp>TextureName</samp>
+
| <samp>PlayRandomAmbientSounds</samp>
| ''(Optional)'' The '''last segment''' of the NPC's portrait and sprite asset names. For example, set to <samp>Abigail</samp> to use <samp>Portraits/Abigail</samp> and <samp>Characters/Abigail</samp> respectively. Defaults to the internal NPC name.
+
| ''(Optional)'' Whether to play random outdoor ambience sounds depending on factors like the season and time of day (e.g. birds, crickets, and mysterious groan sounds in the rain). This is unrelated to the <samp>DayAmbience</samp> and <samp>NightAmbience</samp> fields. Default true.
|-
 
| <samp>Breather</samp>
 
| ''(Optional)'' Whether the chest on the NPC's overworld sprite puffs in and out as they breath. Default true.</samp>.
 
 
|}
 
|}
 
</dd>
 
</dd>
  
<dt>Spawn info:</dt>
+
<dt>Advanced:</dt>
 
<dd>
 
<dd>
 
{| class="wikitable"
 
{| class="wikitable"
Line 2,517: Line 2,855:
 
! effect
 
! effect
 
|-
 
|-
| <samp>ForceSpawn</samp>
+
| <samp>CustomFields</samp>
| ''(Optional)'' Whether to add this NPC to the world even if they don't have an entry in <samp>Data/NPCDispositions</samp>. If true, you must specify <samp>DefaultLocation</samp> to avoid errors. Defaults to false.
+
| The [[#Custom data fields|custom fields]] for this entry.
|-
 
| <samp>DefaultLocation</samp>
 
| ''(Optional)'' The internal name for the home location where this NPC spawns and returns each day. Defaults to the value specified in <samp>Data/NPCDispositions</samp> (if any), else causes an error.
 
|-
 
| <samp>DefaultTile</samp>
 
| ''(Optional)'' The tile position within the home location where this NPC spawns and returns each day. Specified as a model with <samp>X</samp> and <samp>Y</samp> fields. Defaults to the tile specified in <samp>Data/NPCDispositions</samp> (if any), else <samp>(0, 0)</samp>.
 
|-
 
| <samp>Direction</samp>
 
| ''(Optional)'' The default direction the NPC faces when they start each day. The possible values are <samp>down</samp>, <samp>left</samp>, <samp>right</samp>, and <samp>up</samp>. Defaults to the value specified in <samp>Data/NPCDispositions</samp> (if any), else <samp>up</samp>.
 
 
|}
 
|}
 
</dd>
 
</dd>
 +
</dl>
 +
 +
===Custom garbage cans===
 +
{{/doc status|a new doc page|done=false}}
 +
 +
====Format====
 +
You can now add or edit [[Garbage Can|garbage cans]] on any map by editing the new <samp>Data/GarbageCans</samp> asset (see examples below).
 +
 +
The asset consists of a data model with these fields:
  
<dt>Social features:</dt>
 
<dd>
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 2,538: Line 2,874:
 
! effect
 
! effect
 
|-
 
|-
| <samp>SocializeConditions</samp>
+
| <samp>DefaultBaseChance</samp>
| ''(Optional)'' A [[#Game state queries|game state query]] which indicates whether to enable social features (like birthdays, gift giving, [[friendship]], and an entry in the social tab). Defaults to true (except for monsters, horses, pets, and Junimos).
+
| The probability that an item will be found when searching garbage cans, as a value between 0 (never) and 1 (always). If the probability check fails, only items that set <samp>IgnoreBaseChance</samp> can spawn. This can be overridden by the per-garbage-can <samp>BaseChance</samp> field. Default 0.2.
 
|-
 
|-
| <samp>Visibility</samp>
+
| <samp>BeforeAll</samp><br /><samp>AfterAll</samp>
| ''(Optional)'' Determines how the NPC is shown on the [[friendship|social tab]] when unlocked. Possible values:
+
| The items to prepend (<samp>BeforeAll</samp>) or append (<samp>AfterAll</samp>) to the <samp>GarbageCans</samp> → <samp>Items</samp> field for all garbage cans. These work exactly like the items in that field (e.g. subject to the garbage can's base chance).
 +
|-
 +
| <samp>GarbageCans</samp>
 +
| The data for individual garbage cans. This consists of a string → model lookup with these fields:
 +
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! value
+
! field
 
! effect
 
! effect
 
|-
 
|-
| <samp>HiddenAlways</samp>
+
| ''entry key''
| They never appear in the social tab.
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this garbage can.
 
|-
 
|-
| <samp>Hidden</samp>
+
| <samp>BaseChance</samp>
| Until the player meets them, they don't appear on the social tab.
+
| ''(Optional)'' If set, overrides the root <samp>DefaultBaseChance</samp> field for this garbage can. Defaults to <samp>DefaultBaseChance</samp>.
 
|-
 
|-
| <samp>Default</samp>
+
| <samp>Items</samp>
| Until the player meets them, their name on the social tab is replaced with "???".
+
| ''(Optional)'' The items to try spawning when the player searches the garbage can. The first matching item in <samp>BeforeAll</samp> + <samp>Items</samp> + <samp>AfterAll</samp> will be spawned, and any further items will be ignored. Defaults to none.
|-
 
| <samp>Friend</samp>
 
| They always appear in the social tab (including their name).
 
|}
 
  
Defaults to <samp>Default</samp>.
+
This consists of a list of models with these fields:
|-
 
| <samp>ExcludeFromIntroductionsQuest</samp>
 
| ''(Optional)'' Whether this NPC will be ignored for the [[Quests#List of Story Quests|''introductions'' quest]]. Default false if the NPC is in <samp>Data/NPCDispositions</samp>, else true.
 
|}
 
</dd>
 
 
 
<dt>[[Secrets#Gift Log|Hidden gift log emote]]:</dt>
 
<dd>
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 2,575: Line 2,903:
 
! effect
 
! effect
 
|-
 
|-
| <samp>HiddenProfileEmoteSound</samp>
+
| ''common fields''
| ''(Optional)'' For the [[Secrets#Gift Log|hidden gift log emote]], the [[#Custom audio|cue ID]] for the sound played when clicking the sprite. Defaults to <samp>drumkit6</samp>.
+
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields supported by garbage cans.
 +
 
 +
If set to an [[Modding:Item queries|item query]] which returns multiple items, one of them will be selected at random.
 +
|-
 +
| <samp>IgnoreBaseChance</samp>
 +
| ''(Optional)'' Whether this item can spawn even if the <samp>BaseChance</samp> probability check didn't pass. Default false.
 +
|-
 +
| <samp>IsMegaSuccess</samp>
 +
| ''(Optional)'' Whether to treat this item as a 'mega success' if it's selected, which plays a special <samp>crit</samp> sound and bigger animation. Default false.
 
|-
 
|-
| <samp>HiddenProfileEmoteDuration</samp>
+
| <samp>IsDoubleMegaSuccess</samp>
| ''(Optional)'' For the [[Secrets#Gift Log|hidden gift log emote]], how long the animation plays measured in milliseconds. Defaults to 4000 (4 seconds).
+
| ''(Optional)'' Whether to treat this item as an 'double mega success' if it's selected, which plays an explosion sound and dramatic animation. Default false.
 
|-
 
|-
| <samp>HiddenProfileEmoteStartFrame</samp>
+
| <samp>AddToInventoryDirectly</samp>
| ''(Optional)'' For the [[Secrets#Gift Log|hidden gift log emote]], the index within the NPC's overworld sprite spritesheet at which the animation starts. If omitted for a vanilla NPC, the game plays a default animation specific to that NPC; if omitted for a custom NPC, the game just shows them walking while facing down.
+
| ''(Optional)'' Whether to add the item to the player's inventory directly, opening an item grab menu if they don't have room in their inventory. If false, the item will be dropped on the ground next to the garbage can instead. Default false.
 
|-
 
|-
| <samp>HiddenProfileEmoteFrameCount</samp>
+
| <samp>CreateMultipleDebris</samp>
| ''(Optional)'' For the [[Secrets#Gift Log|hidden gift log emote]], the number of frames in the animation. The first frame corresponds to <samp>HiddenProfileEmoteStartFrame</samp>, and each subsequent frame will use the next sprite in the spritesheet. Default 1.
+
| ''(Optional)'' Whether to split the spawned item into multiple stacks which each have a stack size of one. This has no effect if <samp>AddToInventoryDirectly</samp> is enabled. Default false.
 +
|}
 +
|}
  
This has no effect if <samp>HiddenProfileEmoteStartFrame</samp> isn't set.
+
If the garbage can being searched doesn't have its own entry under <samp>GarbageCans</samp>, the game will just use the <samp>BeforeAll</samp> and <samp>AfterAll</samp> fields.
 
|-
 
|-
| <samp>HiddenProfileEmoteFrameDuration</samp>
+
| <samp>CustomFields</samp>
| ''(Optional)'' For the [[Secrets#Gift Log|hidden gift log emote]], how long each animation frame is shown on-screen before switching to the next one, measured in milliseconds. Default 200.
+
| The [[#Custom data fields|custom fields]] for this entry.
 
 
This has no effect if <samp>HiddenProfileEmoteStartFrame</samp> isn't set.
 
 
|}
 
|}
</dd>
 
</dl>
 
  
===Custom farm animals===
+
====Example new garbage can====
You can now create and edit [[Animals|farm animals]] via the new <samp>Data/AdditionalFarmAnimalData</samp> asset. This supercedes <samp>Data/FarmAnimals</samp>, which is ignored if the animal exists in <samp>Data/AdditionalFarmAnimalData</samp> (except for the [[perfection]] summit event, which only uses the original animals in <samp>Data/FarmAnimals</samp>).
+
You can add garbage cans using only [[Modding:Content Patcher|Content Patcher]] or [[Modding:Modder Guide/APIs/Content|SMAPI's content API]]. For example, this content pack adds a new garbage can entry with the ID <samp>Example.ModId_Carpenter</samp>:
  
This consists of a string → model lookup, where the key matches the <samp>ID</samp> field, and the value is a model with these fields:
+
{{#tag:syntaxhighlight|<nowiki>
 
+
{
====Main info====
+
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
{| class="wikitable"
+
    "Changes": [
|-
+
        {
! field
+
            "Action": "EditData",
! effect
+
            "Target": "Data/GarbageCans",
|-
+
            "TargetField": [ "GarbageCans" ],
| <samp>ID</samp>
+
            "Entries": {
| The unique farm animal ID. For custom farm animals, this should be prefixed with your mod ID like <samp>Example.ModId_FarmAnimalName</samp>.
+
                "{{ModId}}_Carpenter": {
|-
+
                    "Items": [
| <samp>DisplayName</samp>
+
                        // 25% chance of pufferfish
| A [[#Tokenizable string format|tokenizable string]] for the animal type's display name.
+
                        {
|-
+
                            "ID": "{{ModId}}_Pufferfish",
| <samp>House</samp>
+
                            "Condition": "RANDOM 0.25",
| The [[#Custom buildings|building ID]] for the main building type that houses this animal. The animal will also be placeable in buildings whose <samp>ValidOccupantTypes</samp> field contains this value.
+
                            "ItemId": "(O)128"
|}
+
                        },
 +
 
 +
                        // else guaranteed random House Plant item
 +
                        {
 +
                            "ID": "{{ModId}}_RandomHousePlant",
 +
                            "ItemID": "RANDOM_ITEMS (F) 1376 1390"
 +
                        }
 +
                    ]
 +
                }
 +
            }
 +
        }
 +
    ]
 +
}</nowiki>|lang=javascript}}
 +
 
 +
Then you'd place an <code>Action: Garbage Example.ModId_Carpenter</code> [[Modding:Maps|map tile property]] to mark a tile as a garbage can using this data.
 +
 
 +
====Example change for existing garbage can====
 +
You can edit an existing garbage cans using only [[Modding:Content Patcher|Content Patcher]] or [[Modding:Modder Guide/APIs/Content|SMAPI's content API]]. For example, this content pack adds pufferfish to the Saloon garbage can, and moves it above the dish of the day.
 +
 
 +
Note that this uses <samp>TargetField</samp> to 'move into' the item list for the saloon, and then treat those items as the entry list being edited. Specifying an ID which isn't in the list will add a new entry, just like when editing a regular list asset.
 +
 
 +
{{#tag:syntaxhighlight|<nowiki>
 +
{
 +
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
 +
    "Changes": [
 +
        {
 +
            "Action": "EditData",
 +
            "Target": "Data/GarbageCans",
 +
            "TargetField": [ "GarbageCans", "Saloon", "Items" ],
 +
            "Entries": {
 +
                // 25% chance of pufferfish
 +
               
 +
                "{{ModId}}_Pufferfish":{
 +
                    "ID": "{{ModId}}_Pufferfish",
 +
                    "Condition": "RANDOM 0.25",
 +
                    "ItemId": "(O)128"
 +
                }
 +
            },
 +
            "MoveEntries": [
 +
                { "ID": "{{ModId}}_Pufferfish", "BeforeId": "Base_DishOfTheDay" }
 +
            ]
 +
        }
 +
    ]
 +
}</nowiki>|lang=javascript}}
  
====Animal shop====
+
====Changes for C# mods====
These fields affect how this farm animal type is shown in [[Marnie's Ranch|Marnie's animal shop]]. Animals are automatically listed if they have a valid <samp>PurchasePrice</samp> value.
+
Previously garbage cans were tracked by <samp>Town.garbageChecked</samp>, an array of boolean fields. That approach doesn't work in Stardew Valley 1.6, since we're no longer limited to a specific set of garbage cans in the town map. This has been replaced by <samp>Game1.netWorldState.Value.CheckedGarbage</samp>, which is a hash set of garbage can IDs.
  
 +
To migrate code:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! action
! effect
+
! code in 1.5.6
 +
! code in 1.6
 
|-
 
|-
| <samp>PurchasePrice</samp>
+
| check if a garbage can was searched
| ''(Optional if not purchaseable)'' Half the cost to purchase the animal (the actual price is double this value), or a negative value to disable purchasing this animal type. Default -1.
+
| <syntaxhighlight lang="js">
 +
Town town = (Town)Game1.getLocationFromName("Town");
 +
if (town.garbageChecked[5])
 +
  ...
 +
</syntaxhighlight>
 +
| <syntaxhighlight lang="js">
 +
if (Game1.netWorldState.Value.CheckedGarbage.Contains("Saloon"))
 +
  ...
 +
</syntaxhighlight>
 
|-
 
|-
| <samp>ShopTexture</samp>
+
| mark a garbage can searched
| ''(Optional if not purchaseable)'' The asset name for the icon texture to show in shops. Defaults to <samp>LooseSprites/Cursors</samp> or <samp>LooseSprites/Cursors2</samp> based on the animal's position within the loaded data (but using the default isn't recommended if it's purchaseable).
+
| <syntaxhighlight lang="js">
|-
+
Town town = (Town)Game1.getLocationFromName("Town");
| <samp>ShopSourceRect</samp>
+
town.garbageChecked[5] = true;
| ''(Optional if not purchaseable)'' The pixel area within the <samp>ShopTexture</samp> to draw, specified as an object with <samp>X</samp>, <samp>Y</samp>, <samp>Width</samp>, and <samp>Height</samp> fields. This should be 32 pixels wide and 16 high. Ignored if <samp>ShopTexture</samp> isn't set.
+
</syntaxhighlight>
|-
+
| <syntaxhighlight lang="js">
| <samp>RequiredBuilding</samp>
+
Game1.netWorldState.Value.CheckedGarbage.Add("Saloon");
| ''(Optional)'' The building that needs to be built on the farm for this animal to be available to purchase. Buildings that are upgraded from this building are valid too. Default none.
+
</syntaxhighlight>
|-
+
|}
| <samp>UnlockCondition</samp>
 
| ''(Optional)'' A [[#Game state queries|game state query]] which indicates whether the farm animal is available in the shop menu. Default always unlocked.
 
|-
 
| <samp>ShopDisplayName</samp>
 
| ''(Optional)'' A [[#Tokenizable string format|tokenizable string]] for the display name shown in the shop menu. Defaults to the <samp>DisplayName</samp> field.
 
|-
 
| <samp>ShopDescription</samp>
 
| ''(Optional)'' A [[#Tokenizable string format|tokenizable string]] for the tooltip description shown in the shop menu. Defaults to none.
 
|-
 
| <samp>ShopMissingBuildingDescription</samp>
 
| ''(Optional)'' A [[#Tokenizable string format|tokenizable string]] which overrides <samp>ShopDescription</samp> if the <samp>RequiredBuilding</samp> isn't built. Defaults to none.
 
|-
 
| <samp>Genders</samp>
 
| ''(Optional)'' The possible genders for the animal type. Currently this only affects the text shown after purchasing the animal, like "''Great! I'll send little &lt;name&gt; to [his/her] new home right away''". Default <samp>Female</samp>.
 
  
The possible values are:
+
To migrate former vanilla trash can IDs:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! value
+
! position
! effect
+
! ID in 1.5.6
 +
! ID in 1.6
 
|-
 
|-
| <samp>Male</samp><br /><samp>Female</samp>
+
| Near [[Jodi]] and [[Kent]]'s house
| Farm animals of this type are always male or always female.
+
| <code>0</code>
 +
| <code>JodiAndKent</code>
 
|-
 
|-
| <samp>MaleOrFemale</samp>
+
| Near [[Emily]] and [[Haley]]'s house
| The gender of each animal is randomized based on its internal unique ID.
+
| <code>1</code>
|}
+
| <code>EmilyAndHaley</code>
 
|-
 
|-
| <samp>AlternatePurchaseTypes</samp>
+
| Near [[Lewis]]' house
| ''(Optional)'' The possible variants for this farm animal (e.g. chickens can be Brown Chicken, Blue Chicken, or White Chicken). This consists of a list of models with these fields:
+
| <code>2</code>
{| class="wikitable"
+
| <code>Mayor</code>
 
|-
 
|-
! field
+
| Near [[Museum]]
! effect
+
| <code>3</code>
 +
| <code>Museum</code>
 
|-
 
|-
| <samp>AnimalIDs</samp>
+
| Near [[Blacksmith|Clint's blacksmith]]
| A list of animal IDs to spawn instead of the main <samp>ID</samp> field. If multiple are listed, one is chosen at random on purchase.
+
| <code>4</code>
 +
| <code>Blacksmith</code>
 
|-
 
|-
| <samp>Condition</samp>
+
| Near [[The Stardrop Saloon|the Saloon]]
| ''(Optional)'' A [[#Game state queries|game state query]] which indicates whether this variant entry is available. Default always enabled.
+
| <code>5</code>
|}
+
| <code>Saloon</code>
 
 
If multiple are listed, the first available variant is returned. Default none.
 
|}
 
 
 
====Hatching====
 
{| class="wikitable"
 
 
|-
 
|-
! field
+
| Near [[Evelyn]] and [[George]]'s house
! effect
+
| <code>6</code>
 +
| <code>Evelyn</code>
 
|-
 
|-
| <samp>EggItemIDs</samp>
+
| Near [[JojaMart]]
| ''(Optional)'' A list of the [[#Custom items| object IDs]] that can be placed in the incubator/ostrich incubator to hatch the animal (Todo : determine if the incubator also needs data to be added for this to work).
+
| <code>7</code>
|-
+
| <code>JojaMart</code>
| <samp>IncubationTime</samp>
 
| ''(Optional)'' The time needed for the egg to hatch. Default : todo
 
|-
 
| <samp>IncubatorParentSheetOffset</samp>
 
| ''(Optional)'' (Todo : sprite index of the incubator when the egg is hatching ?).  Default : todo
 
|-
 
| <samp>BirthText</samp>
 
| ''(Optional)'' A [[#Tokenizable string format|tokenizable string]] for the tooltip description shown when entering the building after the egg hatched.  Default : todo
 
 
|}
 
|}
  
====Growth====
+
===Custom map actions===
{| class="wikitable"
+
{{/doc status|[[Modding:Maps]]|done=false}}
|-
+
 
! field
+
C# mods can now handle custom <samp>Action</samp> & <samp>TouchAction</samp> [[Modding:Maps|map properties]] by calling <samp>GameLocation.RegisterTileAction</samp> & <samp>RegisterTouchAction</samp>, and passing a callback which receives the location, map property arguments, player who activated it, and tile position.
! effect
 
|-
 
| <samp>DaysToMature</samp>
 
| ''(Optional)'' The number of days until a freshly purchased/born animal becomes an adult and begins producing items. Default 1.
 
|-
 
| <samp>CanGetPregnant</samp>
 
| ''(Optional)'' Whether an animal can [[Animals#Animal Births|produce a child]] (regardless of gender). Default false.
 
|}
 
  
====Produce====
+
For example, let's say you want a locked gate which needs a custom key item. You can add a regular <code>TouchAction Example.ModId_UnlockGate</code> map property (e.g. by adding it directly in the map file, or using [[Modding:Content Patcher|Content Patcher]]'s <samp>EditMap</samp>, or using the [[Modding:Modder Guide/APIs/Content|content API]]). Then you can just handle the logic from your C# mod:
{| class="wikitable"
+
<syntaxhighlight lang="c#">
|-
+
internal class ModEntry : Mod
! field
+
{
! effect
+
    /// <inheritdoc />
|-
+
    public override void Entry(IModHelper helper)
| <samp>ProduceItemIDs</samp><br /><samp>DeluxeProduceItemIDs</samp>
+
    {
| ''(Optional)'' A pair of string condition and string of the [[#Custom items|''unqualified'' object ID]] of the produced items.  The list of items is first filtered via condition checking, and then one is randomly picked from the remaining, valid items. If set, the deluxe item overrides the default one if the <samp>Deluxe*</samp> fields match. Both default to none.
+
        GameLocation.RegisterTouchAction("Example.ModId_UnlockGate", this.HandleUnlockGate);
|-
+
    }
| <samp>DaysToProduce</samp>
 
| ''(Optional)'' The number of days between item productions. For example, setting <samp>1</samp> will produce an item every other day. Default 1.
 
|-
 
| <samp>ProduceOnMature</samp>
 
| ''(Optional)'' Whether an item is produced on the day the animal becomes an adult. Default false.
 
|-
 
| <samp>QualityBoostProfession</samp>
 
| ''(Optional)'' The internal ID of a [[Skills|profession]] which increases the chance of higher-quality produce. This has the same effect as the [[Skills#Farming|Coopmaster and Shepherd professions]], and doesn't stack with them. Defaults to the Coopmaster profession for an animal whose <samp>House</samp> value is <samp>Coop</samp>, else the Shepherd profession.
 
|-
 
| <samp>ProduceSpeedProfession</samp>
 
| ''(Optional)'' The internal ID of a [[Skills|profession]] which reduces the <samp>DaysToProduce</samp> by one. Defaults to none.
 
|-
 
| <samp>ProduceSpeedBoostFriendship</samp>
 
| ''(Optional)'' The minimum friendship points needed to reduce the <samp>DaysToProduce</samp> by one. Default to no reduction based on friendship.
 
|-
 
| <samp>DeluxeProduceMinimumFriendship</samp>
 
| ''(Optional)'' The minimum friendship points needed to produce the <samp>DeluxeProduceItemID</samp>. Default 200.
 
|-
 
| <samp>DeluxeProduceCareDivisor</samp><br /><samp>DeluxeProduceLuckMultiplier</samp>
 
| ''(Optional)'' Modifiers which change the probability of producing the <samp>DeluxeProduceItemID</samp>, based on this formula:
 
<pre>
 
if happiness > 200:
 
  happiness_modifier = happiness * 1.5
 
else if happiness > 100:
 
  happiness_modifier = 0
 
else
 
  happiness_modifier = happiness - 100
 
  
((friendship + happiness_modifier) / DeluxeProduceCareDivisor) + (daily_luck * DeluxeProduceLuckMultiplier)
+
    private void HandleUnlockGate(GameLocation location, string[] args, Farmer player, Vector2 tile)
</pre>
+
    {
 +
        const string mailFlag = "Example.ModId_GateUnlocked";
 +
        const string keyId = "Example.ModId_GateKey";
  
Specifically:
+
        // unlock gate if locked
* <samp>DeluxeProduceCareDivisor</samp> reduces the bonus from friendship and happiness, so a lower value ''increases'' the probability of producing the deluxe item. Default 1200.
+
        if (!player.mailReceived.Contains(mailFlag))
* <samp>DeluxeProduceLuckMultiplier</samp> increases the effect of [[Luck|daily luck]]. Default 0.
+
        {
 +
            if (!Game1.player.Items.ContainsId(id, count))
 +
            {
 +
                Game1.activeClickableMenu = new DialogueBox("This gate is locked. I wonder where the key is?");
 +
                return;
 +
            }
  
For example, given a friendship of 102 and happiness of 150, the probability with the default field values will be <code>((102 + 0) / 1200) + (daily_luck * 0) = (102 / 1200) = 0.085</code> or 8.5%.
+
            player.removeFirstOfThisItemFromInventory(keyId);
 +
            player.mailReceived.Add(mailFlag);
 +
        }
  
See [[Animals#Produce]] for more info on the calculation.
+
        // apply open-gate map edit
|-
+
        // NOTE: this is a quick example which changes the location's current map. If another mod reloads the map
| <samp>HarvestType</samp>
+
        // (e.g. a content pack editing it), the change will be lost. For persistent changes, you should use the
| ''(Optional)'' How produced item are collected from the animal. The valid values are:
+
        // AssetRequested event to apply the change when the map is reloaded.
{| class="wikitable"
+
        IAssetDataForMap mapHelper = this.Helper.GameContent.GetPatchHelper(location.map).AsMap();
|-
+
        mapHelper.PatchMap(
! value
+
            this.Helper.Content.Load<Map>("assets/unlocked-gate.tmx"),
! effect
+
            targetArea: new Rectangle((int)tile.X - 1, (int)tile.Y - 1, 2, 2)
|-
+
        );
| <samp>DropOvernight</samp>
+
    }
| The item is placed on the ground in the animal's home building overnight.
+
}
|-
+
</syntaxhighlight>
| <samp>HarvestWithTool</samp>
 
| The item is collected from the animal directly based on the <samp>HarvestTool</samp> field.
 
|}
 
  
Default <samp>DropOvernight</samp>.
+
As another example, let's say you want the gate to unlock when the player presses the action key. You can add a regular <code>Action Example.ModId_UnlockGate</code> map property (e.g. by adding it directly in the map file, or using [[Modding:Content Patcher|Content Patcher]]'s <samp>EditMap</samp>, or using the [[Modding:Modder Guide/APIs/Content|content API]]). Then you can just handle the logic from your C# mod:
|-
+
<syntaxhighlight lang="c#">
| <samp>HarvestTool</samp>
+
internal class ModEntry : Mod
| ''(Optional)'' The [[#Custom items|tool ID]] with which the item can be collected from the animal, if the <samp>HarvestType</samp> is set to <samp>HarvestWithTool</samp>. The values recognized by the vanilla tools are <samp>MilkPail</samp> and <samp>Shears</samp>. Default none.
+
{
 +
    /// <inheritdoc />
 +
    public override void Entry(IModHelper helper)
 +
    {
 +
        GameLocation.RegisterTileAction("Example.ModId_UnlockGate", this.HandleUnlockGate);
 +
    }
  
|}
+
    private bool HandleUnlockGate(GameLocation location, string[] args, Farmer player, Microsoft.Xna.Framework.Point point)
 +
    {
 +
        const string mailFlag = "Example.ModId_GateUnlocked";
 +
        const string keyId = "Example.ModId_GateKey";
  
====Audio & sprite====
+
        // unlock gate if locked
{| class="wikitable"
+
        if (!player.mailReceived.Contains(mailFlag))
|-
+
        {
! field
+
            if (!Game1.player.Items.ContainsId(id, count))
! effect
+
            {
|-
+
                Game1.activeClickableMenu = new DialogueBox("This gate is locked. I wonder where the key is?");
| <samp>Sound</samp>
+
                return false;
| ''(Optional)'' The [[#Custom audio|audio cue ID]] for the sound produced by the animal (e.g. when pet). Default none.
+
            }
|-
+
 
| <samp>BabySound</samp>
+
            player.removeFirstOfThisItemFromInventory(keyId);
| ''(Optional)'' Overrides <samp>Sound</samp> field when the animal is a baby. Has no effect if <samp>Sound</samp> isn't specified. Default none.
+
            player.mailReceived.Add(mailFlag);
|-
+
        }
| <samp>Texture</samp>
+
 
| ''(Optional)'' The asset name for the texture animal's spritesheet. Defaults to <samp>Animals/{{t|ID}}</samp> (like <samp>Animals/Goat</samp> for a [[goat]]).
+
        // apply open-gate map edit
|-
+
        // NOTE: this is a quick example which changes the location's current map. If another mod reloads the map
| <samp>HarvestedTexture</samp>
+
        // (e.g. a content pack editing it), the change will be lost. For persistent changes, you should use the
| ''(Optional)'' Overrides <samp>Texture</samp> if the animal doesn't currently have an item ready to collect (like the [[sheep]]'s sheared sprite). Default none.
+
        // AssetRequested event to apply the change when the map is reloaded.
|-
+
        IAssetDataForMap mapHelper = this.Helper.GameContent.GetPatchHelper(location.map).AsMap();
| <samp>BabyTexture</samp>
+
        mapHelper.PatchMap(
| ''(Optional)'' Overrides <samp>Texture</samp> and <samp>HarvestedTexture</samp> when the animal is a baby. Default none.
+
            this.Helper.Content.Load<Map>("assets/unlocked-gate.tmx"),
|-
+
            targetArea: new Rectangle((int)point.X - 1, (int)point.Y - 1, 2, 2)
| <samp>UseFlippedRightForLeft</samp>
+
        );
| ''(Optional)'' When the animal is facing left, whether to use a flipped version of their right-facing sprite. Default false.
+
 
|-
+
        return true;
| <samp>SpriteWidth</samp><br /><samp>SpriteHeight</samp>
+
    }
| ''(Optional)'' The pixel height & width of the animal's sprite (before the in-game pixel zoom). Both default to 16.
+
}
|}
+
</syntaxhighlight>
 +
 
 +
===Custom map layers===
 +
{{/doc status|[[Modding:Maps]]|done=false}}
 +
 
 +
You can now add any number of [[Modding:Maps|map layers]] by suffixing a vanilla layer name (i.e. <samp>Back</samp>, <samp>Buildings</samp>, <samp>Front</samp>, or <samp>AlwaysFront</samp>) with an offset. For example, <samp>Back-1</samp> will be drawn before/under <samp>Back</samp>, and <samp>Back2</samp> will be drawn after/over it. You can increment the number to add more layers.
 +
 
 +
This only affects layer rendering. Tile properties must still be set on the original layers.
 +
 
 +
===Custom minecarts===
 +
{{/doc status|a new doc page|done=false}}
 +
 
 +
You can now extend [[minecart]]s by editing the <samp>Data\Minecarts</samp> data asset.
 +
 
 +
This consists of a string → model lookup, where...
 +
* The key is a [[Modding:Common data field types#Unique string ID|unique string ID]] for the minecart network. When you interact with a minecart, the destinations listed for its network are shown.
 +
* The value is a model with the fields listed below.
  
====Behavior====
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 2,818: Line 3,176:
 
! effect
 
! effect
 
|-
 
|-
| <samp>CanSwim</samp>
+
| <samp>Destinations</samp>
| ''(Optional)'' Whether animals on the farm can swim in water once they've been pet. Default false.
+
| The destinations which the player can travel to from minecarts in this network. This consists of a list of model with these fields:
 +
{| class="wikitable"
 
|-
 
|-
| <samp>BabiesFollowAdults</samp>
+
! field
| ''(Optional)'' Whether baby animals can follow nearby adults. This only applies for animals whose <samp>House</samp> field is <samp>Coop</samp>. Default false.
+
! effect
 +
|-
 +
| <samp>Id</samp>
 +
| A [[Modding:Common data field types#Unique string ID|unique string ID]] for this destination within the network.
 
|-
 
|-
| <samp>Pessimism</samp>
+
| <samp>DisplayName</samp>
| ''(Optional)'' An amount subtracted from the [[Animals#Mood|mood boost]] when a player pets the animal, before the [[Skills#Farming|Coopmaster or Shepherd profession]] bonus is applied. Default -1 (i.e. ''improves'' mood by one 1 point).
+
| A [[Modding:Tokenizable strings|tokenizable string]] for the destination name shown in the minecart menu. You can use the location's display name with the <samp>LocationName</samp> token (like <code>[LocationName Desert]</code> for the [[desert]]).
 
|-
 
|-
| <samp>Price</samp>
+
| <samp>TargetLocation</samp>
| ''(Optional)'' The price when [[Animals#Selling Animals|the player sells the animal]], before the frienship boost. Default 0.
+
| The [[#Custom locations|location ID]] for the destination.
|}
 
 
 
====Other====
 
{| class="wikitable"
 
 
|-
 
|-
! field
+
| <samp>TargetTile</samp>
! effect
+
| The destination tile position within the location, specified as a model with <samp>X</samp> and <samp>Y</samp> fields.
 
|-
 
|-
| <samp>StatToIncrementOnProduce</samp>
+
| <samp>TargetDirection</samp>
| ''(Optional)'' The game stat counters to increment when the animal produces an item. Default none. This consists of a list of models with these fields:
+
| The direction the player should face after arrival (one of <samp>down</samp>, <samp>left</samp>, <samp>right</samp>, or <samp>up</samp>).
{| class="wikitable"
 
 
|-
 
|-
! field
+
| <samp>Condition</samp>
! effect
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this minecart destination is available. Defaults to always available.
 
|-
 
|-
| <samp>StatName</samp>
+
| <samp>Price</samp>
| The name of the stat counter field on <samp>Game1.stats</samp>.
+
| ''(Optional)'' The gold price that must be paid each time to use this destination. Default none.
 
|-
 
|-
| <samp>RequiredTags</samp>
+
| <samp>BuyTicketMessage</samp>
| ''(Optional)'' A comma-delimited list of [[Modding:Items#Context tags|context tags]] required on the main input item. The stat is only incremented if the item has ''all'' of these. You can negate a tag with <samp>!</samp> (like <code>bone_item,!fossil_item</code> for bone items that aren't fossils). Defaults to always enabled.
+
| ''(Optional)'' If the destination costs money to use, a [[Modding:Tokenizable strings|tokenizable string]] for the purchase confirmation message shown. If present, <code>{0}</code> is replaced with the purchase price. Defaults to the network's <samp>BuyTicketMessage</samp> field.
|}
 
 
|-
 
|-
| <samp>MeatID</samp>
+
| <samp>CustomFields</samp>
| ''(Optional)'' No effect. Default none.
+
| ''(Optional)'' The [[#Custom data fields|custom fields]] for this entry.
 
|}
 
|}
 +
|-
 +
| <samp>UnlockCondition</samp>
 +
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this minecart network is unlocked. Default always enabled.
 +
|-
 +
| <samp>LockedMessage</samp>
 +
| ''(Optional)'' A [[Modding:Tokenizable strings|tokenizable string]] for the message shown when interacting with a minecart when the <samp>UnlockCondition</samp> false. Defaults to an "''Out of order''" translation.
 +
|-
 +
| <samp>ChooseDestinationMessage</samp>
 +
| ''(Optional)'' A [[Modding:Tokenizable strings|tokenizable string]] for the message shown when listing destinations to choose from. Defaults to a "''Choose destination:''" translation.
 +
|-
 +
| <samp>BuyTicketMessage</samp>
 +
| ''(Optional)'' When a destination costs money to use, a [[Modding:Tokenizable strings|tokenizable string]] for the purchase confirmation message shown. If present, <code>{0}</code> is replaced with the purchase price. Defaults to a "''Buy a ticket for {0}g?''" translation.
 +
|}
 +
 +
====Open a minecart menu====
 +
You can use an <samp>Action: MinecartTransport {{o|network ID}} {{o|exclude destination ID}}</samp> [[Modding:Maps|map property]] to open the minecart menu. When the player interacts with the tile, it'll open the menu for the {{o|network ID}} network (default <samp>Default</samp>). if {{o|exclude destination ID}} is specified, the matching destination will be hidden from the list (usually because you're at that minecart). For example, the [[Bus Stop|bus stop]] minecart uses <code>Action: MinecartTransport Default Bus</code>.
 +
 +
From a C# mod, you can call <code>Game1.currentLocation.ShowMineCartMenu(networkId, excludeDestinationId)</code> which works the same way (except that <samp>networkId</samp> is required).
 +
 +
====Example====
 +
This [[Modding:Content Patcher|Content Patcher]] content pack adds the [[Railroad]] as a minecart destination, complete with a map edit adding a decorative minecart. It is available after the [[Random Events|Earthquake]] has occurred and minecarts have been unlocked.
 +
 +
{{#tag:syntaxhighlight|<nowiki>
 +
{
 +
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
 +
    "Changes": [
 +
        // add minecart destination
 +
        {
 +
            "Action": "EditData",
 +
            "Target": "Data/Minecarts",
 +
            "TargetField": [ "Default", "Destinations" ], // for the "Default" network, edit the "Destinations" field
 +
            "Entries": {
 +
                "Railroad": {
 +
                    "Id": "Railroad",
 +
                    "DisplayName": "[LocationName Railroad]",
 +
                    "Condition": "LOCATION_ACCESSIBLE Railroad",
  
===Custom pets===
+
                    "TargetLocation": "Railroad",
====Format====
+
                    "TargetTile": { "X": 16, "Y": 39 },
You can now create and edit [[Animals#Cat or Dog|pet]]s and pet breeds via the new <samp>Data/PetsData</samp> asset. This consists of a string → model lookup, where the key matches the <samp>ID</samp> field, and the value is a model with these fields:
+
                    "TargetDirection": "down",
 +
                }
 +
            }
 +
        },
 +
 
 +
        // add decorative minecart
 +
        {
 +
            "Action": "EditMap",
 +
            "Target": "Maps/Railroad",
 +
            "FromFile": "assets/Custom_Railroad_Minecart.tmx",
 +
            "ToArea": { "X": 15, "Y": 35, "Width": 4, "Height": 5 }
 +
        }
 +
    ]
 +
}</nowiki>|lang=javascript}}
 +
 
 +
===Custom passive festivals===
 +
{{/doc status|[[Modding:Festival data]] or a new doc page|done=false}}
 +
 
 +
You can now add or modify passive festivals by editing the <samp>Data/PassiveFestivals</samp> asset.
 +
 
 +
(A ''passive festival'' is a [[festivals|festival]] like the [[Night Market]]. They replace a location for a period of time, the player can enter/leave them anytime, and time continues passing while at the festival.)
  
 +
====Data format====
 +
The <samp>Data/PassiveFestivals</samp> asset consists of a string → model lookup, where...
 +
* The key is a [[Modding:Common data field types#Unique string ID|unique string ID]] for the festival.
 +
* The value is a model with the fields listed below.
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 2,864: Line 3,280:
 
! effect
 
! effect
 
|-
 
|-
| <samp>ID</samp>
+
| <samp>DisplayName</samp>
| The unique pet ID. (This is for the pet type like <samp>Cat</samp> or <samp>Dog</samp>, not the breed.) For custom pets, this should be prefixed with your mod ID like <samp>Example.ModId_PetName</samp>.
+
| A [[Modding:Tokenizable strings|tokenizable string]] for the display name shown on the [[calendar]].
 
|-
 
|-
| <samp>BarkSound</samp>
+
| <samp>Season</samp>
| The [[#Custom audio|cue ID]] for the pet's occasional 'bark' sound.
+
| The [[season]] when the festival becomes active.
 
|-
 
|-
| <samp>ContentSound</samp>
+
| <samp>StartDay</samp><br /><samp>EndDay</samp>
| The [[#Custom audio|cue ID]] for the sound which the pet makes when you pet it.
+
| The days of month when the festival becomes active.
 
|-
 
|-
| <samp>Behaviors</samp>
+
| <samp>StartTime</samp>
| The pet's possible actions and behaviors, defined as the states in a state machine. Essentially the pet will be in one state at any given time, which also determines which state they can transition to next. For example, a cat can transition from <samp>Walk</samp> to <samp>BeginSitDown</samp>, but it can't skip instantly from <samp>Walk</samp> to <samp>SitDownLick</samp>.
+
| The time of day when the festival opens each day.
 
 
This consists of a list of models with these fields:
 
 
 
<dl>
 
<dt>Required fields:</dt>
 
<dd>
 
{| class="wikitable"
 
 
|-
 
|-
! field
+
| <samp>StartMessage</samp>
! effect
+
| A [[Modding:Tokenizable strings|tokenizable string]] for the in-game [[wikipedia:Pop-up notification|toast notification]] shown when the festival begins each day.
 
|-
 
|-
| <samp>Name</samp>
+
| <samp>MapReplacements</samp>
| A unique name for the state. This only needs to be unique within the pet type (e.g. <samp>Cat</samp> and <samp>Dog</samp> can have different behaviors with the same name).
+
| The locations to swap for the duration of the festival. Despite the field name, this swaps '''locations''' (e.g. as added by <samp>CustomLocations</samp> using [[Modding:Content Patcher|Content Patcher]]), and not the location's map asset.
|}
 
</dd>
 
  
<dt>Direction:</dt>
+
This is specified as a string → string lookup, where the key is the original location to replace and the value is the new location. Both use the internal location name, as shown by the {{nexus mod|679|Debug Mode}} mod. For example, this swaps the <samp>Beach</samp> location with <samp>BeachNightMarket</samp> during the [[Night Market]]:
<dd>
+
<syntaxhighlight lang="js">
{| class="wikitable"
+
"MapReplacements": {
 +
    "Beach": "BeachNightMarket"
 +
}
 +
</syntaxhighlight>
 
|-
 
|-
! field
+
| <samp>Condition</samp>
! effect
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether the festival is enabled (subject to the other fields like <samp>StartDay</samp> and <samp>EndDay</samp>). Defaults to always enabled.
 
|-
 
|-
| <samp>Direction</samp>
+
| <samp>ShowOnCalendar</samp>
| ''(Optional)'' The specific direction to face at the start of this state (one of <samp>left</samp>, <samp>right</samp>, <samp>up</samp>, or <samp>down</samp>).  
+
| ''(Optional)'' Whether the festival appears on the [[calendar]], using the same iridium-star icon as the [[Calendar#Winter|Night Market]]. Default true.
 
|-
 
|-
| <samp>RandomizeDirection</samp>
+
| <samp>DailySetupMethod</samp><br /><samp>CleanupMethod</samp>
| ''(Optional)'' Whether to point the pet in a random direction at the start of this state (overriding the <samp>Direction</samp> if specified). Default false.
+
| ''(Optional)'' A C# method which applies custom logic when the day starts (<samp>DailySetupMethod</samp>) and/or overnight after the last day of the festival (<samp>CleanupMethod</samp>).
 +
 
 +
These must be specified in the form <samp>{{t|full type name}}: {{t|method name}}</samp> (like <samp>ExampleMod.Namespace.Type, ExampleMod: MethodName</samp>). The methods must be static, take zero arguments, and return void.
 
|-
 
|-
| <samp>IsSideBehavior</samp>
+
| <samp>CustomFields</samp>
| ''(Optional)'' Whether to constrain <samp>RandomizeDirection</samp> to left and right. If false, it will choose any of the four cardinal directions. Default false.
+
| The [[#Custom data fields|custom fields]] for this entry.
 
|}
 
|}
</dd>
 
  
<dt>Movement:</dt>
+
====NPC schedules====
<dd>
+
When a passive festival is active, NPCs will check for [[Modding:Schedule data|a schedule entry]] in this order:
 +
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! syntax
! effect
+
! summary
 
|-
 
|-
| <samp>WalkInDirection</samp>
+
| <samp>{{t|festival ID}}_{{t|festival day}}</samp>
| ''(Optional)'' Whether to walk in the pet's facing direction. Default false.
+
| Applies on the given date. The {{t|festival day}} is relative, so <samp>1</samp> matches the festival <samp>StartDay</samp>.<br /><small>Example: <samp>NightMarket_3</samp> or <samp>marriage_NightMarket_3</samp></small>
 
|-
 
|-
| <samp>MoveSpeed</samp>
+
| <samp>{{t|festival ID}}</samp>
| ''(Optional)'' Override's the pet's <samp>MoveSpeed</samp> field while this state is active. Default -1 (which uses the pet's <samp>MoveSpeed</samp> value).
+
| Applies if there's no date-specific entry.<br /><small>Example: <samp>NightMarket</samp> or <samp>marriage_NightMarket</samp></small>
 
|}
 
|}
</dd>
 
  
<dt>Audio:</dt>
+
If the NPC is married to a player, they'll add a <samp>marriage_</samp> prefix to the keys (like <samp>marriage_{{t|festival ID}}_{{t|festival day}}</samp>) and ignore any entry without the prefix.
<dd>
+
 
 +
===Custom weather===
 +
{{/doc status|[[Modding:Weather data]]|done=false}}
 +
 
 +
You can now change the weather algorithm by editing [[#Custom location contexts|location context data]], and (with a C# mod) implement custom weathers.
 +
 
 +
Fields like <samp>Game1.weather</samp> and <samp>Game1.weatherForTomorrow</samp> are now strings to support custom mod weather IDs. The change for vanilla weather has no effect on Content Patcher packs, since the new weather IDs match the ones Content Patcher was using before (i.e. <samp>Sun</samp>, <samp>Rain</samp>, <samp>Snow</samp>, <samp>Storm</samp>, and <samp>Wind</samp>). C# mods may also see a <samp>Festival</samp> weather, while Content Patcher packs will see <samp>Sun</samp> for it. The constants like <samp>Game1.weather_sunny</samp> have the new string values (with new constants like <samp>Game1.legacy_weather_sunny</samp> for the legacy values).
 +
 
 +
The base game will treat an invalid weather as sunny. C# mods can implement custom weather effects using [[Modding:Modder Guide/APIs/Events|normal SMAPI events]] like <samp>UpdateTicked</samp>, or by [[Modding:Modder Guide/APIs/Harmony|patching]] methods like <samp>Game1.ApplyWeatherForNewDay</samp> and <samp>Game1.populateDebrisWeatherArray</samp>.
 +
 
 +
===Custom world maps===
 +
{{/doc status|[[Modding:World map]]|done=true}}
 +
 
 +
[[File:Modding map area.png|thumb|The default world map, with the farm map area highlighted.]]
 +
 
 +
You can now change the world map shown in the game menu by editing the <samp>Data/WorldMap</samp> asset. This lets you...
 +
* add custom maps for certain locations;
 +
* apply texture overlays;
 +
* add/edit tooltips;
 +
* set real-time player marker positioning;
 +
* etc.
 +
 
 +
The game's default map is fully defined in <samp>Data/WorldMap</samp>, including all the display text and conditional changes.
 +
 
 +
===New map properties===
 +
{{/doc status|[[Modding:Maps]]|done=false}}
 +
 
 +
1.6 adds several new [[Modding:Maps|map properties]].
 +
 
 +
====Building construction====
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! property
! effect
+
! explanation
 
|-
 
|-
| <samp>SoundOnStart</samp>
+
| <samp>CanBuildHere T</samp><br />''(valid in any outdoor location)''
| ''(Optional)'' The [[#Custom audio|audio cue ID]] for the sound to play when the state starts. If set to <samp>BARK</samp>, the pet's <samp>BarkSound</samp> (or breed's <samp>BarkOverride</samp>) field is used. Defaults to none.
+
| Whether to allow constructing buildings in this location. The game will adjust automatically to account for it (e.g. Robin will let you choose where to build). See [[#Build anywhere|''build anywhere'' in what's new]].
 +
|-
 +
| <samp>BuildConditions {{t|query}}</samp><br />''(valid in any outdoor location)''
 +
| If <samp>CanBuildHere</samp> is set, an optional [[Modding:Game state queries|game state query]] which indicates whether building is allowed currently.
 +
|-
 +
| <samp>LooserBuildRestrictions T</samp><br />''(valid in any outdoor location)''
 +
| If set, tiles don't need to be marked <samp>Buildable T</samp> or <samp>Diggable T</samp> in their properties. Tiles can be blocked with <samp>Buildable F</samp> instead. The other restrictions still apply.
 +
|-
 +
| <samp>ValidBuildRect {{t|x}} {{t|y}} {{t|width}} {{t|height}}</samp><br />''(valid in any outdoor location)''
 +
| The tile area within the map where buildings may be placed. If omitted, buildings may be placed in any open space in the map.
 +
|}
 +
 
 +
====Crops====
 +
{| class="wikitable"
 +
|-
 +
! property
 +
! explanation
 
|-
 
|-
| <samp>SoundRange</samp><br /><samp>SoundRangeFromBorder</samp>
+
| <samp>AllowGiantCrops T</samp>
| ''(Optional)'' When set, the <samp>SoundOnStart</samp> is only audible if the pet is within this many tiles away from the player (<samp>SoundRange</samp>) or past the border of the screen (<samp>SoundRangeFromBorder</samp>). Default -1 (no distance check).
+
| If set with any non-blank value, [[Crops#Giant Crops|giant crops]] can grow in this location (if crops are also allowed per the [[#Custom crops|crop data]] or [[#Custom location contexts|<samp>PlantableLocations</samp> context field]]).
 
|-
 
|-
| <samp>SoundIsVoice</samp>
+
| <samp>DirtDecayChance {{t|chance}}</samp>
| ''(Optional)'' Whether to mute the <samp>SoundOnStart</samp> when the 'mute animal sounds' option is set. Default false.
+
| The probability that each dirt tile will disappear overnight if it doesn't contain a crop, as a value between 0 (never) and 1 (always). Defaults to 0 (greenhouses), 0.1 (farms), and 1 (anywhere else).
 
|}
 
|}
</dd>
 
  
<dt>Behavior transitions:</dt>
+
====Farmhouse interior====
<dd>
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! property
! effect
+
! explanation
 
|-
 
|-
| <samp>AnimationEndBehaviorChanges</samp><br /><samp>TimeoutBehaviorChanges</samp><br /><samp>PlayerNearbyBehaviorChanges</samp><br /><samp>RandomBehaviorChanges</samp><br /><samp>JumpLandBehaviorChanges</samp>
+
| <samp>FarmHouseStarterGift [{{t|id}} {{o|count}}]+</samp>
| ''(Optional)'' A list of possible behavior transitions to start when the criteria are achieved. If multiple transitions are listed, a random one will be selected. If omitted, it won't affect behavior transitions.
+
| The items that should appear in the initial gift box placed in the farmhouse when the save is created. This consists of one or more pairs of item ID (which can be qualified or unqualified) and count. The count is optional on the last entry.
 +
 
 +
For example, this will add 10 pufferfish (object 128) and a blobfish mask (hat 56):
 +
<pre>FarmHouseStarterGift (O)128 10 (H)56 1</pre>
  
These are triggered when this behavior's animation finishes (<samp>AnimationEndBehaviorChanges</samp>), when the set duration ends (<samp>TimeoutBehaviorChanges</samp>), when the player is within 2 tiles of the pet (<samp>PlayerNearbyBehaviorChanges</samp>), randomly at the start of each frame based on the <samp>RandomBehaviorChangeChance</samp> field (<samp>RandomBehaviorChanges</samp>), and when the pet finishes a jump (<samp>JumpLandBehaviorChanges</samp>).
+
If omitted, the default items (usually a 15 parsnip seeds) are added instead.
 +
|}
  
These consist of a list of models with these fields:
+
====Warps & map positions====
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! property
! effect
+
! explanation
 
|-
 
|-
| <samp>Behavior</samp><br /><samp>LeftBehavior</samp><br /><samp>RightBehavior</samp><br /><samp>UpBehavior</samp><br /><samp>DownBehavior</samp>
+
| <samp>AllowWakeUpWithoutBed {{t|allow}}</samp>
| The name of the behavior to start. The pet will check for a behavior field matching its current facing direction first, then try the <samp>Behavior</samp>. If none are specified, the current behavior will continue unchanged.
+
| Whether the player can wake up in this location without a bed, similar to the island farmhouse. This is typically used with <samp>PassOutLocations</samp> in [[#Custom location contexts|<samp>Data/LocationContexts</samp>]].
 
|-
 
|-
| <samp>OutsideOnly</samp>
+
| <samp>DefaultWarpLocation {{t|x}} {{t|y}}</samp><br />''(valid in any location)''
| ''(Optional)'' Whether the transition can only happen if the pet is outside. Default false.
+
| The default arrival tile, used when a player or NPC is added to the location without a target tile (e.g. using [[Modding:Console commands|debug commands]] like <samp>debug warp</samp> or <samp>debug eventbyid</samp>).
 
|-
 
|-
| <samp>Weight</samp>
+
| <samp>PetBowlLocation {{t|x}} {{t|y}}</samp><br />''(valid in the farm)''
| ''(Optional)'' The option's weight when randomly choosing a behavior, relative to other behaviors in the list (e.g. <samp>2</samp> is twice as likely as <samp>1</samp>). Default 1.
+
| The default position of the pet bowl
|}
 
 
|-
 
|-
| <samp>Duration</samp><br /><samp>MinimumDuration</samp><br /><samp>MaximumDuration</samp>
+
| <samp>SpouseRoomPosition {{t|x}} {{t|y}}</samp><br />''(valid in farmhouse)''
| ''(Optional)'' The millisecond duration until the pet transitions to a behavior in the <samp>TimeoutBehaviorChanges</samp> field, if set. You must specify either a specific duration, or an inclusive minimum-to-maximum range in which the game will choose a random duration. If omitted, the behavior won't have a duration limit.
+
| The top-left position at which to place the [[Marriage#Spouse Rooms|spouse room]].
 
|-
 
|-
| <samp>RandomBehaviorChangeChance</samp>
+
| <samp>TravelingCartPosition {{t|x}} {{t|y}}</samp><br />''(valid in the forest)''
| ''(Optional)'' The random probability at the start of each frame that the pet will transition to a behavior in the <samp>RandomBehaviorChanges</samp> field, if set. Specified as a value between 0 (never) and 1 (always). Default 0.
+
| The top-left position at which to place the [[Traveling Cart]]. This is the top-left corner of the collision box, so the roof will extend two tiles above this tile.
 
|}
 
|}
</dd>
 
  
<dt>Animation and per-frame sounds:</dt>
+
===Other map property changes===
<dd>
+
{{/doc status|[[Modding:Maps]]|done=false}}
 +
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! map property
! effect
+
! changes
 
|-
 
|-
| <samp>Animation</samp>
+
| <samp>Arch</samp><br /><samp>asdf</samp><br /><samp>Debris</samp><br /><samp>Fish</samp>
| ''(Optional)'' The animation frames to play while this state is active. This consists of a list of models with these fields:
+
| Removed (these were unused).
{| class="wikitable"
 
 
|-
 
|-
! field
+
| <samp>FarmHouseFlooring</samp><br /><samp>FarmHouseFurniture</samp><br /><samp>FarmHouseStarterSeedsPosition</samp><br /><samp>FarmHouseWallpaper</samp>
! effect
+
| These now work independently. For example, you can now use <samp>FarmHouseFlooring</samp> without needing to set <samp>FarmHouseFurniture</samp> too.
 
|-
 
|-
| <samp>Frame</samp>
+
| <samp>Music</samp>
| The frame index in the animation. This should be an incremental number starting at 0.
+
| Deprecated; use the music fields in [[#Custom locations|<samp>Data/Locations</samp>]] instead. This property is only applied if the location has no music in <samp>Data/Locations</samp>. This was removed from all vanilla maps.
 
|-
 
|-
| <samp>Duration</samp>
+
| <samp>NPCWarp</samp><br /><samp>Warp</samp>
| The millisecond duration for which the frame should be kept on-screen before continuing to the next frame.
+
| Now fault-tolerant. They'll automatically ignore extra spaces, log an informative warning if parsing still fails, and continue with the next warp if possible.
 
|-
 
|-
| <samp>HitGround</samp>
+
| <samp>Stumps</samp>
| ''(Optional)'' Whether to play the footstep sound for the tile under the pet when the frame starts. Default false.
+
| Now works in all locations.
 
|-
 
|-
| <samp>Jump</samp>
+
| <samp>UniquePortrait</samp><br /><samp>UniqueSprite</samp>
| ''(Optional)'' Whether the pet should perform a small hop when the frame starts, including a 'dwop' sound. Default false.
+
| Deprecated; use [[#Custom NPC appearance|custom NPC appearances]] instead. These properties will override NPC appearances. This was removed from all vanilla maps.
|-
 
| <samp>Sound</samp>
 
| ''(Optional)'' The [[#Custom audio|audio cue ID]] for the sound to play when the state starts. If set to <samp>BARK</samp>, the pet's <samp>BarkSound</samp> (or breed's <samp>BarkOverride</samp>) field is used. Defaults to none.
 
|-
 
| <samp>SoundRange</samp><br /><samp>SoundRangeFromBorder</samp><br /><samp>SoundIsVoice</samp>
 
| See description for the equivalent behavior fields, but applies to the frame's <samp>Sound</samp> field instead.
 
 
|}
 
|}
 +
 +
===Tile property changes===
 +
{{/doc status|[[Modding:Maps]]|done=false}}
 +
 +
<ul>
 +
<li>You can now override a tile index property by setting it as a tile property.</li>
 +
<li>Added new [[Modding:Maps|tile properties]]:
 +
{| class="wikitable"
 +
! layer
 +
! property
 +
! explanation
 
|-
 
|-
| <samp>Shake</samp>
+
| <samp>Paths</samp>
| ''(Optional)'' The millisecond duration for which to shake the pet when the state starts. Default 0.
+
| <samp>SpawnTree {{t|category}} {{t|ID}} {{t|Growth stage}} {{t|Regrowth stage}}</samp>
|-
+
| Spawns a tree when the map is created. {{t|category}} may be either <samp>wild</samp> or <samp>fruit</samp>. <samp>wild</samp> will spawn a [[Trees|wild tree]], while <samp>fruit</samp> will spawn a [[Fruit Trees|fruit tree]].  
| <samp>LoopMode</samp>
 
| ''(Optional)'' What to do when the last animation frame is reached while the behavior is still active. The possible values are <samp>Hold</samp> (keep the last frame visible until the animation ends), <samp>Loop</samp> (restart from the first frame), or <samp>None</samp> (equivalent to <samp>Loop</samp>). Default <samp>None</samp>.
 
|-
 
| <samp>AnimationMinimumLoops</samp><br /><samp>AnimationMaximumLoops</samp>
 
| ''(Optional)'' The minimum and maximum number of times to play the animation. Both must be specified to have any effect. The game will choose an inclusive random value between them. Both default to -1 (don't repeat animation).
 
 
|}
 
|}
</dd>
+
</li>
</dl>
+
<li>Added new <samp>Action</samp> [[Modding:Maps|tile properties]]:
|-
 
| <samp>Breeds</samp>
 
| The cosmetic breeds which can be selected in the character customization menu when creating a save. This consists of a list of models with these fields:
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! layer
! effect
+
! property
 +
! explanation
 
|-
 
|-
| <samp>ID</samp>
+
| <samp>Buildings</samp>
| The unique ID for the breed within the pet type.
+
| <samp>Action BuildingSilo</samp>
 +
| If a building covers this tile, enables [[silo]] interactions on this tile subject to the building's <samp>HayCapacity</samp> field in <samp>Data/Buildings</samp>.
 
|-
 
|-
| <samp>Texture</samp>
+
| <samp>Buildings</samp>
| The asset name for the breed spritesheet for the pet's in-game sprite. This should be 128 pixels wide, and 256 (cat) or 288 (dog) pixels high.
+
| <samp>Action BuildingToggleAnimalDoor</samp>
 +
| If a building covers this tile, opens or closes its animal door.
 
|-
 
|-
| <samp>IconTexture</samp>
+
| <samp>Buildings</samp>
| The asset name for the breed icon texture, shown on the character customization screen and in-game menu. This should be a 16x16 pixel icon.
+
| <samp>Action Dialogue</samp>
 +
| &#32;
 +
* The message can now be a [[Modding:Tokenizable strings|tokenizable string]].
 +
* Fixed the cursor not changing to the inspection icon when hovering on an <samp>Action Dialogue</samp> tile.
 
|-
 
|-
| <samp>IconSourceRect</samp>
+
| <samp>Buildings</samp>
| The icon's pixel area within the <samp>IconTexture</samp>, in the form <samp>"{{t|x}} {{t|y}} {{t|width}} {{t|height}}"</samp> (like <samp>"0 0 16 16"</samp>).
+
| <samp>Action Forge</samp>
 +
| Opens the [[Forge]] menu.
 
|-
 
|-
| <samp>BarkOverride</samp>
+
| <samp>Buildings</samp>
| ''(Optional)'' Override the pet's <samp>BarkSound</samp> field for this breed, if set.
+
| <samp>Action None</samp>
 +
| Does nothing. This is used to mark the tile interactive if the click will be handled separately.
 
|-
 
|-
| <samp>VoicePitch</samp>
+
| <samp>Buildings</samp>
| ''(Optional)'' The [[wikipedia:Pitch (music)|pitch]] applied to the pet's bark sound, measured as a decimal value relative to 1. Defaults to 1.
+
| <samp>Action ObeliskWarp {{t|location name}} {{t|x}} {{t|y}} {{o|whether to dismount}}</samp>
|}
+
| Warps the player to the specified location name and position with the [[Warp Totem|Obelisk]] animation/sound effects.
 
|-
 
|-
| <samp>MoveSpeed</samp>
+
| <samp>Buildings</samp>
| ''(Optional)'' How quickly the pet can move. Default 2.
+
| <samp>Action OpenShop {{t|shop id}} {{o|from direction}} {{o|open time}} {{o|close time}} {{o|owner tile area}}</samp>
 +
| Open the [[#Custom shops|shop]] with the given {{t|shop id}}. All arguments besides the ID are optional:
 +
* {{o|from direction}}: if specified, the player must be standing in this direction relative to the shop (one of <samp>down</samp>, <samp>up</samp>, <samp>left</samp>, <samp>right</samp>, or <samp>none</samp>). Setting this to <samp>none</samp> disables the requirement. The default for most vanilla shops is <samp>down</samp>.
 +
* {{o|open time}} and {{o|close time}}: the start & end times in 26-hour format when the shop is available. Interacting with the tile outside those times does nothing.
 +
* {{o|owner tile area}}: if specified, the tile area which must contain one of the shop owners for the shop to be available. For a custom shop, these are defined by its <samp>Owners</samp> field. This can be specified in two forms: <samp>{{t|x}} {{t|y}}</samp> for a single tile, or <samp>{{t|x}} {{t|y}} {{t|width}} {{t|height}}</samp> for a multi-tile area.
 
|-
 
|-
| <samp>SleepOnBedChance</samp><br /><samp>SleepNearBedChance</samp><br /><samp>SleepOnRugChance</samp>
+
| <samp>Buildings</samp>
| ''(Optional)'' The percentage chances for the locations where the pet will sleep each night, as a decimal value between 0 (never) and 1 (always). Each value is checked in the order listed at left until a match is found. If none of them match, the pet will choose a random empty spot in the farmhouse; if none was found, it'll sleep next to its pet bowl outside.
+
| <samp>Action PlayEvent {{t|event id}} {{o|check preconditions}} {{o|skip if seen}} {{o|fallback action}}</samp>
|-
+
| Immediately start an [[Modding:Event data|event]], subject to the conditions:
| <samp>RepeatContentSoundAfter</samp>
+
* {{o|check preconditions}}: whether to ignore the action if the [[Modding:Event data#Event preconditions|event's preconditions]] don't match (one of <samp>true</samp> or <samp>false</samp>). Default true.
| ''(Optional)'' The number of milliseconds until the <samp>ContentSound</samp> is repeated once. This is used by the dog, who pants twice when pet. Defaults to -1 (disabled).
+
* {{o|skip if seen}}: whether to ignore the action if the player has already seen the given event. Default true.
|}
 
  
====Pet bowl====
+
If the event doesn't start for any reason (including the preceding conditions):
The pet bowl is now a building which can be constructed or moved. Each pet is assigned to an available pet bowl.
+
* If {{o|fallback action}} is specified, it'll be run as an action. This can be any <samp>Action</samp> tile property (without the "Action " prefix), like <code>Action PlayEvent 60367 true true PlayEvent 520702 false false</code> to play a different event.
 
+
* Otherwise the action is silently ignored.
For C# mods, each pet now has a <samp>guid</samp> field populated with a unique ID, and each pet bowl has a <samp>petGuid</samp> field which tracks its owner (see the <samp>PetBowl::HasPet()</samp> and <samp>PetBowl::FindPet()</samp> methods).
 
 
 
===Custom monster eradication goals===
 
You can now add/edit [[Adventurer's Guild]] monster eradication goals by editing the new <samp>Data/MonsterSlayerQuestData</samp> data asset. This consists of a string → model lookup, where the key is a unique ID for the monster eradication goal, and the value is a model with these fields:
 
  
 +
For example, <code>Action PlayEvent 60367 false false</code> will replay the bus arrival event from the start of the game.
 +
|}
 +
</li>
 +
<li>Added new <samp>TouchAction</samp> [[Modding:Maps|tile properties]]:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! layer
! effect
+
! property
 +
! explanation
 +
|-
 +
| <samp>Back</samp>
 +
| <samp>TouchAction PlayEvent {{t|event id}} {{o|check preconditions}} {{o|skip if seen}} {{o|fallback action}}</samp>
 +
| Equivalent to <samp>Action PlayEvent</samp>, but activated on touch. Note that {{o|fallback action}} is an <samp>Action</samp> tile property, ''not'' a <samp>TouchAction</samp> tile property.
 +
|}</li>
 +
<li>Changed existing tile properties:
 +
{| class="wikitable"
 
|-
 
|-
| <samp>ID</samp>
+
! layer
| A key which uniquely identifies this goal. The ID should only contain alphanumeric/underscore/dot characters, and custom goal IDs should ideally be prefixed with your mod ID like <samp>Example.ModId_GoalName</samp>.
+
! property
 +
! reason
 
|-
 
|-
| <samp>DisplayName</samp>
+
|rowspan="4"| <samp>Back</samp>
| A [[#Tokenizable string format|tokenizable string]] for the goal's display name, shown on the board in the Adventurer's Guild.
+
| <samp>NoSpawn</samp>
 +
| Added <samp>NoSpawn false</samp> form, which disables any previous <samp>NoSpawn</samp> property on the tile. For example, this can be used to enable spawning on a tile which has a <samp>NoSpawn</samp> tile index property.
 
|-
 
|-
| <samp>Targets</samp>
+
| <samp>TouchAction Bus</samp>
| A list of [[Modding:Monster data#Monster IDs|monster IDs]] that are counted towards the <samp>Count</samp>.
+
| Removed. This wasn't used by the game or mods.
|-
 
| <samp>Count</samp>
 
| The total number of monsters (matching the <samp>Targets</samp>) which must be defeated to complete this goal.
 
 
|-
 
|-
| <samp>RewardItemID</samp>
+
| <samp>TouchAction Emote</samp>
| ''(Optional)'' The [[#Custom items|qualified item ID]] for the item that can be collected from [[Gil]] when this goal is completed. There's no reward item if omitted.
+
| Fixed error if the specified NPC isn't found.
 
|-
 
|-
| <samp>RewardItemPrice</samp>
+
| <samp>Treasure</samp>
| ''(Optional)'' The price of the <samp>RewardItemID</samp> in [[Marlon]]'s shop, or -1 to disable buying it from Marlon. Default -1.
+
| Added <samp>Treasure Item {{t|item ID}}</samp> form which accepts a [[#Custom items|qualified or unqualified item ID]].
 
|-
 
|-
| <samp>RewardMail</samp>
+
|rowspan="2"| <samp>Buildings</samp>
| ''(Optional)'' The [[Modding:Mail data|mail flag ID]] to set for all players when [[Gil]]'s reward menu is opened and this goal is complete. The players won't see a letter in their mailbox, even if it matches a letter ID. None is set if omitted.
+
| <samp>Action ItemChest</samp><br /><samp>Action Minecart</samp><br /><samp>Action RemoveChest</samp>
 +
| Removed. These weren't used by the game or mods.
 
|-
 
|-
| <samp>RewardMailDialogue</samp>
+
| <samp>Action Kitchen</samp>
| ''(Optional)'' A [[#Tokenizable string format|tokenizable string]] for [[Gil]]'s dialogue when the <samp>RewardMail</samp> is set. This has no effect if <samp>RewardMail</samp> isn't set. No extra dialogue is shown if omitted.
+
| Now works in any location (including those without a fridge).
 
|}
 
|}
 +
</li>
 +
</ul>
  
===Custom shops===
+
===Other location/map changes===
====Format====
+
{{/doc status|[[Modding:Maps]] and other pages as needed|done=false}}
You can now create and edit shops via the new <samp>Data/Shops</samp> asset. This consists of a list of models with these fields:
 
  
 +
* Farm data:
 +
** Added <samp>SpawnMonstersByDefault</samp> field to <samp>Data/AdditionalFarms</samp> to set the default value of the 'spawn monsters at night' [[Options#Advanced Game Options|advanced save option]].
 +
** Fixed crash on new-save screen if the farm type's tooltip has no description.
 +
* General location data:
 +
** All locations can now have animals. The <samp>IAnimalLocation</samp> is now obsolete and implemented by <samp>GameLocation</samp>.
 +
** Added new [[Modding:Fish data|fishing areas]] to simplify compatibility between fish & map mods (specifically for hilltop farm, wilderness farm, town, and desert).
 +
** Added a descriptive error when a required location or layer isn't found. Mods can use <samp>map.RequireLayer</samp> and <samp>Game1.RequireLocation</samp> to get a location with similar error-checking.
 +
** Added <samp>WarpPathfindingCache</samp> for C# mods, which modularizes the NPC warp route logic. You can edit its <samp>IgnoreLocationNames</samp>, <samp>OverrideTargetNames</samp>, and <samp>GenderRestrictions</samp> fields if needed for custom locations.
 +
** Game logic which checks tile indexes is now more fault-tolerant, so it won't crash if an expected tile was edited.
 +
** Finished migrating <samp>DecoratableLocation</samp> flooring/wallpaper areas to string IDs (started in Stardew Valley 1.5.5).
 +
* General map changes:
 +
** Added validation for [[Modding:Maps|map properties and tile properties]]. If the format is invalid, the game will now log a detailed error and skip it.
 +
** Removed unused [[Modding:Maps#Paths layer|path tiles]] in <samp>Maps/paths</samp> and all map files.
 +
* Location context data:
 +
** Building interiors now inherit their parent's location context by default.
 +
** Added <samp>Game1.locationContextData</samp> to cache the data from <samp>Data/LocationContexts</samp>.
 +
** Added constants for the vanilla context IDs like <samp>LocationContexts.IslandId</samp>.
 +
** Added validation for required location context IDs (and <samp>LocationContexts.Require(id)</samp> for mod logic).
 +
** Removed the <samp>Name</samp> field in <samp>Data/LocationContexts</samp>, which duplicated the ID.
 +
<ul>
 +
<li>Added methods to simplify common operations:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! type
 +
! method
 
! effect
 
! effect
 
|-
 
|-
| <samp>ID</samp>
+
|rowspan="7"| <samp>Building</samp>
| A unique ID for the shop. For a custom shop, you should use a globally unique ID which includes your mod ID like <samp>ExampleMod.Id_ShopName</samp>.
+
| <samp>GetParentLocation</samp>
 
+
| Get the location which contains this building.
The vanilla shop IDs are:
+
|-
{| class="wikitable"
+
| <samp>IsInCurrentLocation</samp>
 +
| Get whether the building is in the same location as the current player.
 +
|-
 +
| <samp>HasIndoors</samp>
 +
| Get whether the building has an interior location.
 
|-
 
|-
! ID
+
| <samp>GetIndoors</samp>
! shop
+
| Get the location within this building, if applicable.
! is fully editable¹
 
 
|-
 
|-
| <samp>AdventureShop</samp>
+
| <samp>HasIndoorsName</samp>
| [[Adventurer's Guild]]
+
| Get whether the building has an interior location and its unique name matches the given value (like <code>building.HasIndoorsName("FarmHouse")</code>).
| ☑ yes
 
 
|-
 
|-
| <samp>AnimalShop</samp>
+
| <samp>GetIndoorsName</samp>
| [[Marnie's Ranch]]
+
| Get the unique name of the location within this building, if applicable.
| ☑ yes
 
 
|-
 
|-
| <samp>Blacksmith</samp>
+
| ...
| [[Blacksmith|Clint's blacksmith shop]]
+
| ''see also [[#Other building changes|other building changes]] for non-location methods.''
| ☑ yes
 
 
|-
 
|-
| <samp>Dwarf</samp>
+
|rowspan="7"|<samp>Cabin</samp><br /><samp>FarmHouse</samp>
| [[Dwarf#Shop|Dwarf's shop]]
+
| <samp>GetCellar</samp>
| ☑ yes
+
| Get the [[cellar]] location linked to this cabin, if any.
 
|-
 
|-
| <samp>FishShop</samp>
+
| <samp>CanAssignFarmhand</samp><br /><samp>AssignFarmhand</samp>
| [[Fish Shop|Willy's fish shop]]
+
| ''(Cabin only)'' Check whether the cabin is available to assign to a farmhand, or perform the assignment.
| ☐ no
 
 
|-
 
|-
| <samp>HatMouse</samp>
+
| <samp>HasOwner</samp>
| [[Abandoned House|Abandoned house shop]]
+
| Get whether the home has an assigned player, regardless of whether they've finished creating their character.
| ☑ yes
 
 
|-
 
|-
| <samp>Hospital</samp>
+
| <samp>OwnerId</samp>
| [[Harvey's Clinic]]
+
| Get the unique ID of the player who owns this home, if any.
| ☑ yes
 
 
|-
 
|-
| <samp>Joja</samp>
+
| <samp>IsOwnedByCurrentPlayer</samp>
| [[Joja Mart]]
+
| Get whether the cabin belongs to the current player.
| ☐ no
 
 
|-
 
|-
| <samp>Saloon</samp>
+
| <samp>IsOwnerActivated</samp>
| [[Saloon|The Stardrop Saloon]]
+
| Get whether the home has an assigned player and they've finished creating their character.
| ☐ no
 
 
|-
 
|-
| <samp>Sandy</samp>
+
| <samp>HasNpcSpouse</samp>
| [[Oasis|Sandy's Oasis shop]]
+
| Get whether the player who owns this home is married to any NPC (when used like <samp>HasNpcSpouse()</samp>) or a specific NPC (like <samp>HasNpcSpouse(name)</samp>). This also replaces <samp>shouldShowSpouseRoom()</samp>.
| ☐ no
 
 
|-
 
|-
| <samp>SeedShop</samp>
+
|rowspan="2"| <samp>Farm</samp>
| [[Pierre's General Store|Pierre's general store]]
+
| <samp>GetStarterFarmhouseLocation</samp>
| ☑ yes
+
| Get the default tile position for the farmhouse. (See also <samp>farm.GetMainFarmHouseEntry()</samp>.)
 
|-
 
|-
| <samp>ShadowShop</samp>
+
| <samp>GetStarterPetBowlLocation</samp>
| [[Krobus|Krobus' shop]]
+
| Get the default tile position for the pet bowl.
| ☐ no
 
 
|-
 
|-
| <samp>Traveler</samp>
+
|rowspan="19"| <samp>GameLocation</samp>
| [[Traveling Cart|Traveling cart]]
+
| <samp>AddDefaultBuildings</samp>
| ☐ no
+
| Can be overridden to add custom buildings when the location is created and/or loaded. These can either be re-added whenever they're missing (like the vanilla farmhouse), or only built once on save creation (like the vanilla pre-built cabins).
|}
 
  
¹ The 'is fully editable' column shows whether the shop is fully defined in <samp>Data/Shops</samp>. If not, the shop can be extended via <samp>Data/Shops</samp> but its base shop inventory is defined in-code.
+
This replaces the former <samp>farm.AddModularShippingBin()</samp> method.
 
|-
 
|-
| <samp>ItemGroups</samp>
+
| <samp>GetFridge</samp><br /><samp>GetFridgePosition</samp>
| The items to list in the shop inventory. This consists of a list of models with these fields:
+
| Get the fridge's chest or tile position, if the location has one.
{| class="wikitable"
 
 
|-
 
|-
! field
+
| <samp>GetSeason</samp><br /><samp>GetSeasonIndex</samp><br /><samp>GetSeasonKey</samp>
! effect
+
| Get the local season that applies within the location as an enum, number (like <samp>0</samp> for spring), or string (like <samp>spring</samp>) respectively. For example, it's always summer on [[Ginger Island]].
 
|-
 
|-
| <samp>Items</samp>
+
| <samp>GetWeather</samp><br /><samp>IsDebrisWeatherHere</samp><br /><samp>IsLightningHere</samp><br /><samp>IsRainingHere</samp><br /><samp>IsSnowingHere</samp>
| The items to add to the shop inventory if the <samp>Condition</samp> matches. This costs of a list of values with these fields:
+
| Get the current weather in this location's context, regardless of whether the player is indoors and sheltered from it.
{| class="wikitable"
 
 
|-
 
|-
! field
+
| <samp>InDesertContext</samp><br /><samp>InIslandContext</samp><br /><samp>InValleyContext</samp>
! effect
+
| Get whether this location is within the <samp>Island</samp> or <samp>Default</samp> location context respectively.
 
|-
 
|-
| <samp>ItemID</samp>
+
| <samp>IsActiveLocation</samp>
| One of the [[#Custom items|qualified item ID]] (like <samp>(O)128</samp> for a [[pufferfish]]), or <samp>SEEDSHOP_RANDOM_WALLPAPERS</samp> (random wallpapers), or <samp>SEEDSHOP_PLAYER_ITEMS</samp> (items the player has recently sold to Pierre's store).
+
| Get whether this location is actively synced to the current player (see [[Modding:Modder Guide/Game Fundamentals#Farmhand shadow world|farmhand shadow world]]).
 
|-
 
|-
| <samp>IsRecipe</samp>
+
| <samp>IsTemporary</samp>
| ''(Optional)'' Whether to add the crafting/cooking recipe for the item, instead of the item itself. Default false.
+
| Get whether this is a temporary location for a festival or minigame. This is cached based on the location name (e.g. locations starting with <samp>Temp</samp> or some other specific names).
 
|-
 
|-
| <samp>Price</samp>
+
| <samp>GetLocationContextId</samp>
| ''(Optional)'' The price to purchase the item from the shop. Defaults to the item's normal price, or zero if <samp>TradeItemID</samp> is specified.
+
| Get the ID of the location context in <samp>Data/LocationContexts</samp> which contains this building.
 
|-
 
|-
| <samp>TradeItemID</samp><br /><samp>TradeItemAmount</samp>
+
| <samp>GetContainingBuilding</samp>
| ''(Optional)'' The [[#Custom items|item ID]] and amount must be traded to purchase this item. Defaults to no item and 1 respectively.
+
| Get the building instance which contains this location (like the cabin for a cabin interior), if applicable.
 
 
If both <samp>Price</samp> and <samp>TradeItemID</samp> are specified, the player will have to provide both to get the item.
 
 
|-
 
|-
| <samp>IgnorePriceMultiplier</samp>
+
| <samp>GetParentLocation</samp>
| ''(Optional)'' Whether to ignore the <samp>PriceMultiplier</samp> value set for the shop. Default false.
+
| Get the parent location which contains this one (like the farm for a cabin interior), or <samp>null</samp> if it has no parent.
 
|-
 
|-
| <samp>Stack</samp>
+
| <samp>GetRootLocation</samp>
| ''(Optional)'' The item's stack size after it's purchased. For example, setting this to <samp>5</samp> will give the player five items when they purchase it once. This is only applied after the item is purchased, so it has no effect on the price or <samp>Stock</samp> limit. Default 1.
+
| Get the parent location which contains this one (like the farm for a cabin interior), or the location itself if it has no parent.
 
|-
 
|-
| <samp>Stock</samp>
+
| <samp>GetInstancedBuildingInteriors</samp>
| ''(Optional)'' The maximum number of the item which can be purchased in one day. Default unlimited.
+
| Get all building interiors within this location which are instanced to the building (i.e. not in <samp>Game1.locations</samp> separately).
 
|-
 
|-
| <samp>LimitStock</samp>
+
| <samp>GetMapPropertySplitBySpaces</samp><br /><samp>GetTilePropertySplitBySpaces</samp>
| ''(Optional)'' If <samp>Stock</samp> is set, how the limit is applied in multiplayer. This has no effect on recipes.
+
| Get the value of a map/tile property and split it into individual words. If the map/tile property isn't defined, returns an empty array.
  
The possible values are:
+
For example:
{| class="wikitable"
+
<syntaxhighlight lang="c#">
 +
string[] fields = Game1.currentLocation.GetMapPropertySplitBySpaces("ScreenshotRegion");
 +
</syntaxhighlight>
 
|-
 
|-
! value
+
| <samp>HasMapPropertyWithValue</samp>
! effect
+
| Get whether a map property is defined and has a non-empty value.
 +
 
 +
For example:
 +
<syntaxhighlight lang="c#">
 +
bool canUseCasks = Game1.currentLocation.HasMapPropertyWithValue("CanCaskHere");
 +
</syntaxhighlight>
 
|-
 
|-
| <samp>Global</samp>
+
| <samp>StoreHayInAnySilo</samp>
| The limit applies to every player in the world. For example, if the <samp>Stock</samp> was <samp>1</samp> and a player bought it, no other players could buy one.
+
| Add hay to any silo with free space (preferring silos in the current location, then the farm, then anywhere).
|0
 
 
|-
 
|-
| <samp>Player</samp>
+
| <samp>TryGetMapProperty</samp>
| Each player has a separate <samp>Stock</samp> limit. For example, if the <samp>Stock</samp> was <samp>1</samp>, each player could buy one.
+
| Get a map property value as a string, if it's defined.
|-
+
 
| <samp>None</samp>
+
For example:
| Ignore the <samp>Stock</samp> value. This is used for items that adjust their own stock via code (e.g. by checking mail).
+
<syntaxhighlight lang="c#">
|}
+
if (this.TryGetMapProperty("Warps", out string warps))
 
+
{
Default <samp>Global</samp>.
+
    // ...
|}
+
}
 +
</syntaxhighlight>
 
|-
 
|-
| <samp>Condition</samp>
+
| <samp>TryGetMapPropertyAs</samp>
| ''(Optional)'' A [[#Game state queries|game state query]] which indicates whether the item should be added. If omitted, the item is always added.
+
| Get a map property and parse it into into a <samp>bool</samp>, <samp>double</samp>, <samp>Point</samp>, <samp>Rectangle</samp>, or <samp>Vector2</samp> value.
  
Special case: if the player found [[Pierre's Missing Stocklist]], season conditions are ignored in [[Pierre's General Store]].
+
For example:
|}
+
<syntaxhighlight lang="c#">
 +
if (!this.TryGetMapPropertyAs("MailboxLocation", out Point position))
 +
{
 +
    position = new Point(68, 16); // default value
 +
}
 +
</syntaxhighlight>
 
|-
 
|-
| <samp>SalableItemTags</samp>
+
| <samp>removeObjectsAndSpawned</samp>
| ''(Optional)'' A list of [[Modding:Items#Context tags|context tags]] for items which the player can sell to to this shop. Default none.
+
| Remove all objects, bushes, resource clumps, and terrain features within a tile area.
 
|-
 
|-
| <samp>ValidNPCs</samp>
+
| <samp>OnBuildingConstructed</samp><br /><samp>OnBuildingMoved</samp><br /><samp>OnBuildingDemolished</samp>
| ''(Optional)'' The NPCs who can run the shop. If the [[#Map/tile property changes|<samp>Action OpenShop</samp> property]] specifies the {{o|owner tile area}}, at least one of the listed NPCs must be within that area; else if the {{o|owner tile area}} was omitted, the first entry in the list is used. The selected NPC's portrait will be shown in the shop UI.
+
| These methods are called for all players when any player constructs, moves, or demolishes a building.
 
 
If omitted, the shop is opened regardless of any NPCs being nearby and no portrait is shown.
 
 
 
This consists of a list of models with these fields:
 
{| class="wikitable"
 
 
|-
 
|-
! field
+
|rowspan="3"| <samp>LibraryMuseum</samp>
! effect
+
| <samp>HasDonatedArtifacts()</samp>
 +
| Get whether any items have been donated to the [[museum]].
 
|-
 
|-
| <samp>Name</samp>
+
| <samp>HasDonatedArtifactAt(tile)</samp>
| ''(Optional)'' The internal name of the NPC which must be in range to use this entry. Omit to let any NPC in range run the shop.
+
| Get whether any donated item is currently placed at the given tile position within the [[museum]].
 
|-
 
|-
| <samp>ShownNPC</samp>
+
| <samp>HasDonatedArtifact(itemId)</samp>
| ''(Optional)'' The internal name of the NPC to show in the shop menu portrait, ''or'' the asset name of the portrait spritesheet to display. Omit to use the NPC matched via <samp>Name</samp>. '''Note''' : Currently it seems to require the <samp>Name</samp> field to be displayed.
+
| Get whether an artifact with the given qualified or unqualified item ID has been donated to the [[museum]].
 
|-
 
|-
| <samp>Dialogues</samp>
+
|rowspan="2"| <samp>MineShaft</samp>
| ''(Optional)'' A list of possible dialogues if this entry is selected. Each day one dialogue will be randomly chosen to show in the shop UI. Each dialogue consists of a model with these fields:
+
| <samp>GetLevelName</samp>
{| class="wikitable"
+
| Get the location name for a generated [[The Mines|mine]] or [[Skull Cavern]] level.
 +
 
 +
For example:
 +
<syntaxhighlight lang="c#">
 +
string locationName = MineShaft.GetLevelName(10); // returns "UndergroundMine10"
 +
Game1.warpFarmer(locationName, 0, 0, false);
 +
</syntaxhighlight>
 
|-
 
|-
! field
+
| <samp>IsGeneratedLevel</samp>
! effect
+
| Get whether a location or location name is a generated [[The Mines|mine]] or [[Skull Cavern]] level.
 +
 
 +
For example:
 +
<syntaxhighlight lang="c#">
 +
string locationName = "UndergroundMine10";
 +
bool isMine = MineShaft.IsGeneratedLevel(locationName, out int level); // returns true, 10
 +
</syntaxhighlight>
 
|-
 
|-
| <samp>Dialogue</samp>
+
| <samp>VolcanoDungeon</samp>
| The dialogue text to show, as a [[#Tokenizable string format|tokenizable string]]. The resulting text is parsed using the [[Modding:Dialogue|dialogue format]].
+
| <samp>GetLevelName</samp><br /><samp>IsGeneratedLevel</samp>
|-
+
| Equivalent to the matching <samp>MineShaft</samp> methods, but for the [[Volcano Dungeon]].
| <samp>Condition</samp>
 
| ''(Optional)'' A [[#Game state queries|game state query]] which indicates whether the dialogue should be available. If omitted, the dialogue is always available.
 
|} '''Note''' : Currently it seems to require the <samp>Name</samp> field to be displayed.
 
 
|}
 
|}
|-
+
</li>
| <samp>PriceMultiplier</samp>
+
</ul>
| ''(Optional)'' A multiplier applied to the price when buying items from the shop, like <samp>1.5</samp> for a 50% markup. Defaults to 1.
+
* Added map/tile property <samp>TryAdd</samp>/<samp>TryGetValue</samp> extensions in <samp>StardewValley.Extensions</samp> for string property values. For example, this lets you do <samp>map.Properties.TryGetValue(key, out string value)</samp>.
 +
* <samp>MineShaft.tryToAddMonster</samp> now returns whether a monster was added.
 +
* <samp>Game1.GetNumberBuildingsConstructed</samp> and <samp>location.getNumberBuildingsConstructed</samp> now have overloads to count all building types and/or specify whether to count under-construction buildings.
 +
* Fixed <samp>location.refurbishMapPortion</samp> copying <samp>Back</samp> source properties to the <samp>Building</samp> target layer.
 +
* Fixed door warps in custom indoor locations not consistently detected by the game.
  
'''Note:''' this is only applied to items in <samp>ItemGroups</samp> which explicitly set a price.
+
==What's new for buildings==
|}
+
===Custom buildings===
 +
{{/doc status|[[Modding:Blueprint data]]|done=false}}
  
====Open a custom shop====
+
You can now add custom buildings by editing the <samp>Data/Buildings</samp> asset. This consists of a string → model lookup, where...
You can place an [[#Map/tile property changes|<samp>Action OpenShop</samp> tile property]] on the map, which will open the given shop ID when the player clicks it.
+
* The key is a [[Modding:Common data field types#Unique string ID|unique string ID]] for the building type.
 
+
* The value is a model with the fields listed below.
In C# code, you can get the inventory for a custom shop using <code>Utility.GetShopStock("shop id here")</code>, or open a shop menu using <code>Game1.activeClickableMenu = new ShopMenu(new(), who: "shop id here")</code>. The ID of the opened shop is stored in the shop menu's <samp>storeContext</samp> field.
 
 
 
==What's new for everything else==
 
===Buff overhaul===
 
1.6 rewrites buffs to work more consistently and be more extensible:
 
 
 
* Buff logic is unified into <samp>Game1.player.buffs</samp>, which is the single source of truth for buff data. This replaces the previous <samp>player.added*</samp> and <samp>player.appliedBuffs</samp> fields, <samp>BuffsDisplay</samp> logic, enchantment stat bonuses, and boots/ring attribute changes on (un)equip.
 
* This also removes limitations on buff types (e.g. buffs can add weapon bonuses and weapons can add attribute buffs) and buffable equipment (e.g. equipped tools can have buffs too).
 
* Buff effects are now fully recalculated when they change, to fix a range of longstanding bugs like attribute drift and double-debuffs. Just like before, the buffs are managed locally; only the buff IDs and aggregate attribute effects are synced.
 
 
 
'''For C# mods:'''
 
* Each buff now has a unique string ID. You can apply a new buff with the same ID to replace it (so you no longer need to manually find and remove previous instances of the buff).
 
* You can add standard buff effects to any equipment by overriding <samp>Item.AddEquipmentEffects</samp>, or add custom behaviour/buffs by overriding <samp>Item.onEquip</samp> and <samp>Item.onUnequip</samp>.
 
* You can add custom food or drink buffs by overriding <samp>Item.GetFoodOrDrinkBuffs()</samp>.
 
* The <samp>Buff</samp> constructor now supports a custom icon texture, sprite index, display name, description, and millisecond duration to fully support custom buffs.
 
* You can change how buff attributes are displayed (or add new attributes) by extending the <samp>BuffsDisplay.displayAttributes</samp> list.
 
 
 
For example, here's how to add a custom buff which adds +3 speed:
 
 
 
<syntaxhighlight lang="c#">
 
Buff buff = new Buff(
 
    buff_id: "Example.ModId/ZoomZoom",
 
    display_name: "Zoom Zoom", // can optionally specify description text too
 
    icon_texture: this.Helper.Content.Load<Texture2D>("assets/zoom.png"),
 
    icon_sheet_index: 0,
 
    duration: 30_000, // 30 seconds
 
    buff_effects: new BuffEffects()
 
    {
 
        speed = { 10 } // shortcut for buff.speed.Value = 10
 
    }
 
);
 
Game1.player.applyBuff(buff);
 
</syntaxhighlight>
 
 
 
You can also implement your own custom effects in code by checking if the buff is active, like <code>Game1.player.hasBuff("Example.ModId/ZoomZoom")</code>.
 
 
 
===Custom audio===
 
You can now add custom [[Modding:Audio|music tracks or sound effects]] (called ''cues'') to the game by editing the <samp>Data/AudioCueModificationData</samp> asset. This can be used both to add new music cues, and to replace existing cues with new audio. These are added to the game's soundbank, so they can be used anywhere normal audio can be used (e.g. the <samp>Music</samp> [[Modding:Maps|map property]]).
 
 
 
====Format====
 
The <samp>Data/AudioCueModificationData</samp> asset consists of a string → model lookup, where the key matches the <samp>ID</samp>, and the value is a model with these fields:
 
  
 +
====Required fields====
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 3,328: Line 3,793:
 
! effect
 
! effect
 
|-
 
|-
| <samp>ID</samp>
+
| <samp>Name</samp><br /><samp>Description</samp>
| A unique cue ID, used when playing the sound in-game. The ID should only contain alphanumeric/underscore/dot characters. For custom locations, this should be prefixed with your mod ID like <samp>Example.ModId_AudioName</samp>.
+
| A [[Modding:Tokenizable strings|tokenizable string]] for the display name and description (e.g. shown in the construction menu).
 
|-
 
|-
| <samp>FilePaths</samp>
+
| <samp>Texture</samp>
| ''(Optional if editing a cue, required if adding a new one)'' A list of file paths (not asset names) from which to load the audio, relative to the game's <samp>Content</samp> folder. Each file can be <samp>.ogg</samp> or <samp>.wav</samp>. If you list multiple paths, a random one will be chosen each time it's played.
+
| The asset name for the texture under the game's Content folder.
|-
+
|}
| <samp>Category</samp>
 
| ''(Optional)'' The [[Modding:Audio#Category list|audio category]], which determines which volume slider in the game options applies. This should be one of <samp>Default</samp>, <samp>Music</samp>, <samp>Sound</samp>, <samp>Ambient</samp>, or <samp>Footsteps</samp> (see [[Modding:Audio#Category list|a description of each category]]). Default <samp>Default</samp>.
 
|-
 
| <samp>StreamedVorbis</samp>
 
| ''(Optional)'' Whether the audio should be streamed from disk when it's played, instead of being loaded into memory ahead of time. This is only possible for [[wikipedia:Vorbis|Ogg Vorbis]] (<samp>.ogg</samp>) files, which otherwise will be decompressed in-memory on load. Default false.
 
  
This is a tradeoff between memory usage and performance, so you should consider which value is best for each audio cue:
+
====Construction====
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! value
+
! field
 
! effect
 
! effect
 
|-
 
|-
| <samp>true</samp>
+
| <samp>Builder</samp>
| Reduces memory usage when the audio cue isn't active, but increases performance impact when it's played. Playing the audio multiple times will multiply the memory and performance impact while they're active, since each play will stream a new instance. Recommended for longer audio cues (like music or ambient noise), or cues that are rarely used in a specific scenario (e.g. a sound that only plays once in an event).
+
| ''(Optional)'' The NPC from whom you can request construction. The vanilla values are [[Carpenter's Shop|<samp>Robin</samp>]] and [[Wizard's Tower#Buildings|<samp>Wizard</samp>]], but you can specify a different name if a C# mod opens a construction menu for them. Defaults to <samp>Robin</samp>. If omitted, it won't appear in any menu.
 
|-
 
|-
| <samp>false</samp>
+
| <samp>BuildCost</samp>
| Increases memory usage (since it's fully loaded into memory), but reduces performance impact when it's played. It can be played any number of times without affecting memory or performance (it'll just play the cached audio). Recommended for sound effects, or short audio cues that are played occasionally.
+
| ''(Optional)'' The gold cost to construct the building. Defaults to {{price|0}}.
|}
 
 
|-
 
|-
| <samp>Looped</samp>
+
| <samp>BuildMaterials</samp>
| ''(Optional)'' Whether the audio cue loops continuously until stopped. Default false.
+
| ''(Optional)'' The materials you must provide to start construction, as a list of models with these fields:
|-
 
| <samp>UseReverb</samp>
 
| ''(Optional)'' Whether to apply a [[wikipedia:Reverberation|reverb]] effect to the audio. Default false.
 
|}
 
 
 
This describes a '''change''' applied to the soundbank. For example, you can specify only <samp>ID</samp> and <samp>Category</samp> to change the category for an existing music cue without overwriting other values.
 
 
 
====Example====
 
This content pack adds a new music cue to the game, and plays it when the player enters the bus stop:
 
 
 
{{#tag:syntaxhighlight|<nowiki>
 
{
 
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
 
    "Changes": [
 
        // add music cue
 
        {
 
            "Action": "EditData",
 
            "Target": "Data/AudioCueModificationData",
 
            "Entries": {
 
                "Example.ModId_Music": {
 
                    "ID": "Example.ModId_Music",
 
                    "Category": "Music",
 
                    "FilePaths": [ "{{AbsoluteFilePath: assets/music.ogg}}" ],
 
                    "StreamedVorbis": true,
 
                    "Looped": true
 
                }
 
            }
 
        },
 
 
 
        // add to bus stop
 
        {
 
            "Action": "EditMap",
 
            "Target": "Maps/BusStop",
 
            "MapProperties": {
 
                "Music": "Example.ModId_Music"
 
            }
 
        }
 
    ]
 
}</nowiki>|lang=javascript}}
 
 
 
====Limitations====
 
* As hinted by the unusual asset name (<samp>Data/AudioCueModificationData</samp> instead of <samp>Data/AudioCues</samp>), this is a list of changes applied to the current audio cues for the remainder of the game session. That means:
 
** You can't remove an audio cue once it's added.
 
** You can't undo a change by removing it from the data asset. For example, if you change an audio cue's category, it won't revert to the original value when you remove it from the asset. To undo a change, you'd need to add a new entry which sets the original values.
 
* The game will crash if it tries to play an audio cue that doesn't exist.
 
 
 
===Custom giant crops===
 
You can now add/edit [[Crops#Giant Crops|giant crops]] by editing the <samp>Data/GiantCrops</samp> data asset. This consists of a string → model lookup, where the key matches the <samp>ID</samp> and the value is a model with these fields:
 
 
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 3,409: Line 3,819:
 
! effect
 
! effect
 
|-
 
|-
| <samp>ID</samp>
+
| <samp>Id</samp>
| The unqualified item ID produced by the underlying crop (''i.e.'' the [[Modding:Crop data|'index of harvest' field in <samp>Data/Crops</samp>]]). The giant crop has a chance of growing when there's a grid of fully-grown crops which produce this item ID in a grid of <samp>TileSize</samp> tiles.
+
| ''(Optional)'' The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the current list. Defaults to the <samp>ItemId</samp> if not specified.
 
|-
 
|-
| <samp>Texture</samp>
+
| <samp>ItemId</samp>
| The asset name for the texture containing the giant crop's sprite.
+
| The required item ID (qualified or unqualified).
 
|-
 
|-
| <samp>Corner</samp>
+
| <samp>Amount</samp>
| ''(Optional)'' The top-left pixel position of the sprite within the <samp>Texture</samp>, specified as a model with <samp>X</samp> and <samp>Y</samp> fields. Defaults to (0, 0).
+
| The number of the item required.
 +
|}
 
|-
 
|-
| <samp>TileSize</samp>
+
| <samp>BuildDays</samp>
| ''(Optional)'' The area in tiles occupied by the giant crop, specified as a model with <samp>X</samp> and <samp>Y</samp> fields. This affects both its sprite size (which should be 16 pixels per tile) and the grid of crops needed for it to grow. Note that giant crops are drawn with an extra tile's height. Defaults to (3, 3).
+
| ''(Optional)'' The number of days needed to complete construction (e.g. <samp>1</samp> for a building completed the next day). If set to 0, construction finishes instantly. Defaults to 0.
 
|-
 
|-
| <samp>Chance</samp>
+
| <samp>BuildCondition</samp>
| ''(Optional)'' The percentage chance a given grid of crops will grow into the giant crop each night, as a value between 0 (never) and 1 (always).  Default 0.01.
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether the building should be available in the construction menu. Defaults to always available.
 
|-
 
|-
| <samp>HarvestedItemID</samp>
+
| <samp>BuildMenuDrawOffset</samp>
| ''(Optional)'' The item ID which is harvested when you break the giant crop. Defaults to the <samp>ID</samp>.
+
| ''(Optional)'' A pixel offset to apply to the building sprite when drawn in the construction menu. Default none.
 
|-
 
|-
| <samp>MinYields</samp>
+
| <samp>AdditionalPlacementTiles</samp>
| ''(Optional)'' The minimum number of the <samp>HarvestedItemID</samp> to drop when the giant crop is broken.
+
| ''(Optional)'' The extra tiles to treat as part of the building when placing it through the construction menu. For example, the farmhouse uses this to make sure the stairs are clear. This consists of a list of models with these fields:
|-
 
| <samp>MaxYields</samp>
 
| ''(Optional)'' The maximum number of the <samp>HarvestedItemID</samp> to drop when the giant crop is broken. Default 21.
 
|}
 
 
 
===Custom wedding event===
 
The [[Marriage#The Wedding|wedding]] event can now be changed by editing the <samp>Data\MiscGameData</samp> data asset, which consists of a data model with two relevant fields (listed below).
 
 
 
Note that <samp>Data\MiscGameData</samp> contains a single global entry, it isn't a list or dictionary like other assets. For example, Content Patcher would edit <samp>WeddingEvent</samp> as its own entry.
 
 
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 3,444: Line 3,845:
 
! effect
 
! effect
 
|-
 
|-
| <samp>WeddingEvent</samp>
+
| <samp>TileArea</samp>
| The [[Modding:Event data|event]] script which plays the wedding. The default script automatically handles marrying either an NPC or player, but mods can edit it conditionally to run a custom script (e.g. if the player is marrying their custom NPC).
+
| The tile area relative to the top-left corner of the building, specified as an object with <samp>X</samp>, <samp>Y</samp>, <samp>Width</samp>, and <samp>Height</samp> fields.
 +
|-
 +
| <samp>OnlyNeedsToBePassable</samp>
 +
| ''(Optional)'' Whether this area allows tiles that would normally not be buildable, so long as they are passable. For example, this is used to ensure that an entrance is accessible. Default false.
 +
|}
 
|-
 
|-
| <samp>WeddingContextualAttendees</samp>
+
| <samp>IndoorItems</samp>
| The other NPCs which should attend the wedding (unless they're the spouse). This consists of a string → model lookup, where the key is the internal NPC name, and the value is a model with these fields:
+
| ''(Optional)'' The items to place in the building interior when it's constructed or upgraded. This consists of a list of models with these fields:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 3,454: Line 3,859:
 
! effect
 
! effect
 
|-
 
|-
| <samp>ID</samp>
+
| <samp>Id</samp>
| The internal NPC name.
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the current list.
 
|-
 
|-
| <samp>Setup</samp>
+
| <samp>ItemId</samp>
| The NPC's tile position and facing direction when they attend. This is equivalent to field index 2 in the [[Modding:Event data#Basic format|event basic data]].
+
| The [[#Custom items|qualified item ID]] for the item to place.
 
|-
 
|-
| <samp>Celebration</samp>
+
| <samp>Tile</samp>
| ''(Optional)'' The [[Modding:Event data|event script]] to run during the celebration, like <samp>faceDirection Pierre 3 true</samp> which makes Pierre turn to face left. This can contain any number of script commands.
+
| The tile position at which to place the item, specified as an object with <samp>X</samp> and <samp>Y</samp> fields.
 
|-
 
|-
| <samp>Condition</samp>
+
| <samp>Indestructible</samp>
| ''(Optional)'' A [[#Game state queries|game state query]] which indicates whether the NPC should attend. Defaults to true.
+
| ''(Optional)'' Whether to prevent the player from destroying, picking up, or moving the item. Default false.
 
|}
 
|}
 +
|-
 +
| <samp>MagicalConstruction</samp>
 +
| ''(Optional)'' Whether the building is magical. This changes the carpenter menu to a mystic theme while this building's blueprint is selected, and completes the construction instantly when placed.
 +
|-
 +
| <samp>AddMailOnBuild</samp>
 +
| ''(Optional)'' A list of [[Modding:Mail data|letter IDs]] to send to all players when the building is constructed for the first time.
 
|}
 
|}
  
===Game state queries===
+
====Upgrades====
A ''game state query'' is a vanilla way to specify conditions for some content like [[#Custom shops|shop data]], inspired by [[Modding:Content Patcher|Content Patcher]]'s conditions. A query consists of a comma-delimited list of conditions in the form {{t|type}} {{o|arguments}}, where {{t|type}} is case-sensitive. The type can be prefixed with <code>!</code> to negate it. The query is true if it's null/blank, or if every listed condition exists and is true. For example, <code>!SEASON Spring, WEATHER Here sunny</code> is true on sunny non-[[spring]] days.
+
{| class="wikitable"
 
 
====Conditions====
 
; Date & time
 
:{| class="wikitable"
 
 
|-
 
|-
! Condition
+
! field
 
! effect
 
! effect
 
|-
 
|-
| <samp>DAY_OF_MONTH {{t|day}}</samp>
+
| <samp>BuildingToUpgrade</samp>
| The day of month.
+
| ''(Optional)'' The ID of the building for which this is an upgrade, or omit to allow constructing it as a new building. For example, the [[Coop|Big Coop]] sets this to <samp>"Coop"</samp>. Any numbers of buildings can be an upgrade for the same building, in which case the player can choose one upgrade path.
 
|-
 
|-
| <samp>DAY_OF_WEEK {{t|day}}</samp>
+
| <samp>IndoorItemMoves</samp>
| The day of week, formatted as an integer between 0 (Sunday) through 6 (Saturday).
+
| ''(Optional)'' When applied as an upgrade to an existing building, the placed items in its interior to move when transitioning to the new map. This is a list of models with these fields:
|-
+
{| class="wikitable"
| <samp>DAYS_PLAYED {{t|count}}</samp>
 
| Whether at least {{t|count}} days have been played in the current save (including the current one). This always increments in sync with the date in the base game, but when mods change the in-game date, they may or may not update this value.
 
 
|-
 
|-
| <samp>IS_FESTIVAL_DAY {{o|day offset}}</samp>
+
! field
| Whether there's a festival today, with an optional {{o|day offset}} (e.g. 1 for tomorrow).
+
! effect
 
|-
 
|-
| <samp>IS_PASSIVE_FESTIVAL_OPEN {{t|id}}</samp>
+
| <samp>Id</samp>
| Whether a [[#Custom passive festivals|passive festival]] with the given ID is active today, and the current time is within its opening hours.
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the current list.
 
|-
 
|-
| <samp>IS_PASSIVE_FESTIVAL_TODAY {{t|id}}</samp>
+
| <samp>Source</samp>
| Whether a [[#Custom passive festivals|passive festival]] with the given ID is active today.
+
| The tile position on which any item will be moved.
 
|-
 
|-
| <samp>SEASON {{t|season}}</samp>
+
| <samp>Destination</samp>
| The season (one of <samp>spring</samp>, <samp>summer</samp>, <samp>fall</samp>, or <samp>winter</samp>).
+
| The tile position to which to move the item.
 +
|-
 +
| <samp>Size</samp>
 +
| ''(Optional)'' The tile size of the area to move, specified as a model with <samp>X</samp> and <samp>Y</samp> fields. Defaults to a 1×1 area. If this is multiple tiles, the <samp>Source</samp> and <samp>Destination</samp> specify the top-left coordinate of the area.
 +
|}
 
|-
 
|-
| <samp>TIME {{t|min}} {{t|max}}</samp>
+
| <samp>UpgradeSignTile</samp>
| Whether the current time is between {{t|min}} and {{t|max}} inclusively, specified in [[Modding:Modder Guide/Game Fundamentals#Time format|26-hour time]]. Each value can be set to 0 or less to ignore it (''e.g.'' <samp>TIME 900 -1</samp> for 9am or later).
+
| ''(Optional)'' The tile position relative to the top-left corner of the building where the upgrade sign will be placed when Robin is building an upgrade, in the form <samp>"{{t|x}}, {{t|y}}"</samp>. Defaults to approximately <samp>"5, 1"</samp> if the building interior type is <samp>Shed</samp>, else <samp>"0, 0"</samp>.
 
|-
 
|-
| <samp>YEAR</samp>
+
| <samp>UpgradeSignHeight</samp>
| Whether the year is equal '''or more than''' the given value. For example, <code>YEAR 2</code> is true in year 2 and all later years.
+
| ''(Optional)'' The pixel height of the upgrade sign when Robin is building an upgrade. Defaults to 0.
 
|}
 
|}
  
; World
+
====Exterior behavior====
:{| class="wikitable"
+
{| class="wikitable"
 
|-
 
|-
! Condition
+
! field
 
! effect
 
! effect
 
|-
 
|-
| <samp>CAN_BUILD_CABIN</samp>
+
| <samp>Size</samp>
| Whether players can build more [[cabin]]s (i.e. they haven't reached the maximum number of player slots yet).
+
| ''(Optional)'' The building's width and height when constructed, measured in tiles. Defaults to a 1 x 1 area.
 
|-
 
|-
| <samp>CAN_BUILD_FOR_CABINS {{t|building ID}}</samp>
+
| <samp>CollisionMap</samp>
| Whether there are fewer of the given building constructed than there are cabins.
+
| ''(Optional)'' An ASCII text block which indicates which of the building's tiles the players can walk onto, where each character can be <samp>X</samp> (blocked) or <samp>O</samp> (passable). Defaults to all tiles blocked.
 +
 
 +
For example, a [[stable]] covers a 2x4 tile area with the front two tiles passable:
 +
<pre>XXXX
 +
XOOX</pre>
 +
 
 +
When the collision map is parsed, leading/trailing whitespace is trimmed (both for the entire map and for each line). In JSON, you can specify it in two forms:
 +
<syntaxhighlight lang="js">
 +
// single line with \n line breaks
 +
"CollisionMap": "XXXX\nXOOX"
 +
 
 +
// multi-line with optional indentation
 +
"CollisionMap": "
 +
    XXXX
 +
    XOOX
 +
"
 +
</syntaxhighlight>
 
|-
 
|-
| <samp>FARM_CAVE {{t|type}}</samp>
+
| <samp>HumanDoor</samp>
| The current [[The Farm#The Cave|farm cave]] (one of <samp>Bats</samp>, <samp>Mushrooms</samp>, or <samp>None</samp>).
+
| ''(Optional)'' The position of the door that can be clicked to warp into the building interior. This is measured in tiles relative to the top-left corner tile. Defaults to disabled.
 
|-
 
|-
| <samp>FARM_NAME {{t|name}}</samp>
+
| <samp>AnimalDoor</samp>
| The name of the farm.
+
| ''(Optional)'' The position and size of the door that animals use to enter/exit the building, if the building interior is an animal location, specified as an object with <samp>X</samp>, <samp>Y</samp>, <samp>Width</samp>, and <samp>Height</samp> fields. This is measured in tiles relative to the top-left corner tile. Defaults to disabled.
 
|-
 
|-
| <samp>FARM_TYPE {{t|type}}</samp>
+
| <samp>AnimalDoorOpenDuration</samp><br /><samp>AnimalDoorCloseDuration</samp>
| The [[Farm Maps|farm type]]. The {{t|type}} is one of <samp>1</samp> (standard), <samp>2</samp> (riverland), <samp>3</samp> (forest), <samp>4</samp> (hilltop), <samp>4</samp> (combat), <samp>5</samp> (four corners), <samp>6</samp> (beach), or the ID for a custom farm type.
+
| ''(Optional)'' The duration of the open/close animation for the animal door, measured in milliseconds. If omitted, the door switches to the open/closed state instantly.
 
|-
 
|-
| <samp>IS_CUSTOM_FARM_TYPE</samp>
+
| <samp>AnimalDoorOpenSound</samp><br /><samp>AnimalDoorCloseSound</samp>
| Whether the [[Farm Maps|farm type]] is a custom one created by a mod. (This returns false for mods which edit/replace a vanilla farm type.)
+
| ''(Optional)'' The sound which is played once each time the animal door is opened/closed. Disabled by default.
|-
 
| <samp>IS_COMMUNITY_CENTER_COMPLETE</samp>
 
| Whether the [[Community Center|community center]] has been repaired.
 
|-
 
| <samp>IS_HOST</samp>
 
| Whether the current player is the main/host player.
 
|-
 
| <samp>IS_JOJA_MART_COMPLETE</samp>
 
| Whether the [[Joja Warehouse|Joja warehouse]] has been built.
 
|-
 
| <samp>LOCATION_ACCESSIBLE {{t|name}}</samp>
 
| Whether the given location is accessible (one of <samp>CommunityCenter</samp>, <samp>JojaMart</samp>, or <samp>Railroad</samp>). Returns true for any other name, regardless of whether it's accessible.
 
|-
 
| <samp>LOCATION_CONTEXT {{t|location}}</samp>
 
| The location context name for the [[#Target location|given location]].
 
|-
 
| <samp>LOCATION_IS_MINES {{t|location}}</samp><br /><samp>LOCATION_IS_SKULL_CAVE {{t|location}}</samp>
 
| Whether the [[#Target location|given location]] is in [[The Mines|the mines]] or [[Skull Cavern]].
 
|-
 
| <samp>LOCATION_SEASON {{t|location}} {{t|season}}</samp>
 
| Whether the [[#Target location|given location]] is in the given season (one of <samp>spring</samp>, <samp>summer</samp>, <samp>fall</samp>, or <samp>winter</samp>). This accounts for the <samp>SeasonOverride</samp> field in the [[#Custom location contexts|location's context data]].
 
|-
 
| <samp>WEATHER {{t|location}} {{t|weather}}</samp>
 
| The weather ID in the [[#Target location|given location]]. The weather can be one of <samp>Festival</samp>, <samp>Rain</samp>, <samp>Snow</samp>, <samp>Storm</samp>, <samp>Sun</samp>, <samp>Wind</samp>, or a [[#Custom weather|custom weather ID]].
 
|-
 
| <samp>WORLD_STATE {{t|id}}</samp>
 
| Whether any world state flag with the given {{t|id}} is set.
 
 
|}
 
|}
  
; Player info & progress
+
====Exterior appearance====
:{| class="wikitable"
+
{| class="wikitable"
 
|-
 
|-
! Condition
+
! field
 
! effect
 
! effect
 
|-
 
|-
| <samp>MINE_LOWEST_LEVEL_REACHED {{t|level}}</samp>
+
| <samp>SourceRect</samp>
| Whether any player has reached at least level {{t|level}} in [[The Mines|the mines]].
+
| ''(Optional)'' The building's pixel area within the <samp>Texture</samp>, specified as an object with <samp>X</samp>, <samp>Y</samp>, <samp>Width</samp>, and <samp>Height</samp> fields. Defaults to the entire texture.
 
|-
 
|-
| <samp>PLAYER_COMBAT_LEVEL {{t|player}} {{t|level}}</samp><br /><samp>PLAYER_FARMING_LEVEL {{t|player}} {{t|level}}</samp><br /><samp>PLAYER_FISHING_LEVEL {{t|player}} {{t|level}}</samp><br /><samp>PLAYER_FORAGING_LEVEL {{t|player}} {{t|level}}</samp><br /><samp>PLAYER_MINING_LEVEL {{t|player}} {{t|level}}</samp>
+
| <samp>Skins</samp>
| The [[skills|skill levels]] for the [[#Target player|specified player(s)]].
+
| ''(Optional)'' The appearances which can be selected from Robin's menu (like stone/plank/log [[cabin]]s), in addition to the default appearance based on <samp>Texture</samp>. This consists of a list of models with these fields:
 +
{| class="wikitable"
 
|-
 
|-
| <samp>PLAYER_CURRENT_MONEY {{t|player}} {{t|amount}}</samp>
+
! field
| Whether the [[#Target player|specified player(s)]] currently have at least {{t|amount}} gold.
+
! effect
 
|-
 
|-
| <samp>PLAYER_FARMHOUSE_UPGRADE {{t|player}} {{t|level}}</samp>
+
| <samp>Id</samp>
| Whether the [[#Target player|specified player(s)]] have upgraded their [[farmhouse]] or [[cabin]] to at least the given level (see [https://github.com/Pathoschild/StardewMods/blob/develop/ContentPatcher/docs/author-tokens-guide.md#FarmhouseUpgrade possible levels]).
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for the skin.
 
|-
 
|-
| <samp>PLAYER_GENDER {{t|player}} {{t|gender}}</samp>
+
| <samp>Name</samp><br /><samp>Description</samp>
| Whether the [[#Target player|specified player(s)]] are <samp>Male</samp> or <samp>Female</samp>.
+
| [[Modding:Tokenizable strings|Tokenizable strings]] for the skin's display name and description.
 
|-
 
|-
| <samp>PLAYER_HAS_ACHIEVEMENT {{t|player}} {{t|achievement id}}</samp>
+
| <samp>Texture</samp>
| Whether the [[#Target player|specified player(s)]] have unlocked a specific achievement ID. The valid IDs are listed in [[Modding:Achievement data|<samp>Data/Achievements</samp>]], plus a few Steam achievement IDs that aren't listed.
+
| The asset name for the texture under the game's Content folder.
 
|-
 
|-
| <samp>PLAYER_HAS_ALL_ACHIEVEMENTS {{t|player}}</samp>
+
| <samp>Condition</samp>
| Whether the [[#Target player|specified player(s)]] have unlocked every achievement listed in [[Modding:Achievement data|<samp>Data/Achievements</samp>]]. This doesn't count the extra Steam achievement IDs that aren't listed in that file.
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this skin should be available to apply. This doesn't change buildings which already have it applied. Defaults to always true.
 
|-
 
|-
| <samp>PLAYER_HAS_CAUGHT_FISH {{t|player}} {{t|id}}</samp>
+
| <samp>BuildDays</samp><br /><samp>BuildCost</samp><br /><samp>BuildMaterials</samp>
| Whether the [[#Target player|specified player(s)]] have caught at least one fish with the given ID.
+
| ''(Optional)'' If set, overrides the equivalent field in the building data.
 
|-
 
|-
| <samp>PLAYER_HAS_CONVERSATION_TOPIC {{t|player}} {{t|id}}</samp>
+
| <samp>ShowAsSeparateConstructionEntry</samp>
| Whether the [[#Target player|specified player(s)]] have a [[Modding:Dialogue#Conversation topics|conversation topic]] with the ID {{t|id}} active.
+
| ''(Optional)'' Whether this skin should be shown as a separate building option in the construction menu (like cabins). Default false.
 
|-
 
|-
| <samp>PLAYER_HAS_CRAFTING_RECIPE {{t|player}} {{t|recipe name}}</samp><br /><samp>PLAYER_HAS_COOKING_RECIPE {{t|player}} {{t|recipe name}}</samp>
+
| <samp>Metadata</samp>
| Whether the [[#Target player|specified player(s)]] know the crafting/cooking recipe identified by its internal name (spaces allowed). For example, <code>PLAYER_HAS_CRAFTING_RECIPE CURRENT Field Snack</code>.
+
| ''(Optional)'' Equivalent to the <samp>Metadata</samp> field on the building. Properties defined in this field are added to the building's metadata when this skin is active, overwriting the previous property with the same name if applicable. Default none.
 +
|}
 
|-
 
|-
| <samp>PLAYER_HAS_DIALOGUE_ANSWER {{t|player}} {{t|id}}</samp>
+
| <samp>FadeWhenBehind</samp>
| Whether the [[#Target player|specified player(s)]] have chosen the given dialogue answer in a previous dialogue.
+
| ''(Optional)'' Whether the building should become semi-transparent when the player is behind it. Default true.
 
|-
 
|-
| <samp>PLAYER_HAS_FLAG {{t|player}} {{t|id}}</samp>
+
| <samp>DrawOffset</samp>
| Whether the [[#Target player|specified player(s)]] have the given [[Modding:Mail data|mail flag]] set (with spaces allowed in the {{t|id}}).
+
| ''(Optional)'' A pixel offset applied to the building sprite's placement in the world. Default 0.
 
|-
 
|-
| <samp>PLAYER_HAS_ITEM {{t|player}} {{t|item}}</samp>
+
| <samp>SeasonOffset</samp>
| Whether the [[#Target player|specified player(s)]] have at least one of a normal item (not bigcraftable, furniture, etc) in their inventory. The {{t|item}} can be <samp>858</samp> (Qi Gems), <samp>73</samp> (Walnuts), or the unqualified item ID.
+
| ''(Optional)'' A pixel offset to apply each season. This is applied to the <samp>SourceRect</samp> position by multiplying the offset by 0 (spring), 1 (summer), 2 (fall), or 3 (winter). Default 0, so all seasons use the same source rect.
 
|-
 
|-
| <samp>PLAYER_HAS_ITEM_NAMED {{t|player}} {{t|item name}}</samp>
+
| <samp>SortTileOffset</samp>
| Whether the [[#Target player|specified player(s)]] have at least one item in their inventory with the given {{t|item name}} (spaces allowed).
+
| ''(Optional)'' A Y tile offset applied when figuring out render layering. For example, a value of <samp>2.5</samp> will treat the building as if it was 2.5 tiles further up the screen for the purposes of layering. Default 0.
 
|-
 
|-
| <samp>PLAYER_HAS_PROFESSION {{t|profession id}}</samp>
+
| <samp>DrawLayers</samp>
| Whether the [[#Target player|specified player(s)]] have the given [[Skills|profession]] ID.
+
| ''(Optional)'' A list of textures to draw over or behind the building, with support for conditions and animations. This consists of a list of models with these fields:
 +
{| class="wikitable"
 
|-
 
|-
| <samp>PLAYER_HAS_READ_LETTER {{t|player}} {{t|id}}</samp>
+
! field
| Whether the [[#Target player|specified player(s)]] have read a letter, where {{t|id}} is the internal mail ID (spaces allowed). For example, <code>PLAYER_HAS_READ_LETTER Any Visited_Island</code>.
+
! effect
 
|-
 
|-
| <samp>PLAYER_HAS_SECRET_NOTE {{t|player}} {{t|id}}</samp>
+
| <samp>Id</samp>
| Whether the [[#Target player|specified player(s)]] have read a secret note, where {{t|id}} is the secret note's integer ID.
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the current list.
 
|-
 
|-
| <samp>PLAYER_HAS_SEEN_EVENT {{t|player}} {{t|id}}</samp>
+
| <samp>SourceRect</samp>
| Whether the [[#Target player|specified player(s)]] have seen the event with given {{t|id}}.
+
| The pixel area within the <samp>texture</samp> to draw, formatted like <samp>"{{t|x}} {{t|y}} {{t|width}} {{t|height}}"</samp>. If the overlay is animated via <samp>FrameCount</samp>, this is the area of the first frame.
 
|-
 
|-
| <samp>PLAYER_LOCATION_CONTEXT {{t|player}} {{t|location context}}</samp>
+
| <samp>DrawPosition</samp>
| Whether the [[#Target player|specified player(s)]] are in the given [[#Custom location contexts|location context]].
+
| The tile position at which to draw the top-left corner of the texture, relative to the building's top-left corner tile.
 
|-
 
|-
| <samp>PLAYER_LOCATION_NAME {{t|player}} {{t|location name}}</samp><br /><samp>PLAYER_LOCATION_UNIQUE_NAME {{t|player}} {{t|location name}}</samp>
+
| <samp>Texture</samp>
| Whether the [[#Target player|specified player(s)]] are in the given location, using the name or unique instanced name (you can see both names in-game using the {{nexus mod|679|Debug Mode}} mod). The {{t|location name}} value doesn't recognize [[#Target location|target location keywords]] like <samp>Here</samp>.
+
| ''(Optional)'' The asset name of the texture to draw. Defaults to the building's default <samp>Texture</samp> field.
 
|-
 
|-
| <samp>PLAYER_MOD_DATA {{t|player}} {{t|key}} {{t|value}}</samp>
+
| <samp>DrawInBackground</samp>
| Whether the [[#Target player|specified player(s)]] have a <samp>player.modData</samp> entry added by a mod with the given {{t|key}} and {{t|value}}.
+
| ''(Optional)'' Whether to draw the texture behind the building sprite (i.e. underlay) instead of over it.
 
|-
 
|-
| <samp>PLAYER_MONEY_EARNED {{t|player}} {{t|amount}}</samp>
+
| <samp>SortTileOffset</samp>
| Whether the [[#Target player|specified player(s)]] have earned at least {{t|amount}} gold.
+
| ''(Optional)'' A Y tile offset applied when figuring out render layering. For example, a value of <samp>2.5</samp> will treat the texture as if it was 2.5 tiles further up the screen for the purposes of layering. Default 0.
|}
 
 
 
; Player relationships
 
:{| class="wikitable"
 
 
|-
 
|-
! Condition
+
| <samp>OnlyDrawIfChestHasContents</samp>
! effect
+
| ''(Optional)'' The ID of a chest defined in the <samp>Chests</samp> field which must contain items. If it's empty, this overlay won't be rendered. Default none.
 
|-
 
|-
| <samp>PLAYER_HAS_CHILDREN {{t|player}} {{t|count}}</samp>
+
| <samp>FrameCount</samp><br /><samp>FramesPerRow</samp><br /><samp>FrameDuration</samp>
| Whether the [[#Target player|specified player(s)]] have least {{t|count}} children.
+
| ''(Optional)'' If <samp>FrameCount</samp> is more than one, the building overlay will be animated automatically. For each frame, the <samp>SourceRect</samp> will be offset by its <samp>Width</samp> to the right up to <samp>FramesPerRow - 1</samp> times, and then down by its <samp>Height</samp>. Each frame will be rendered on-screen for <samp>FrameDuration</samp> milliseconds before switching to the next frame.
 +
 
 +
For example, if you set <samp>FrameCount</samp> to 6 and <samp>FramesPerRow</samp> to 3, the building will expect the frames to be laid out like this in the spritesheet (where frame 1 matches <samp>SourceRect</samp>):
 +
<pre>
 +
┌───┬───┬───┐
 +
│ 1 │ 2 │ 3 │
 +
├───┼───┼───┤
 +
│ 4 │ 5 │ 6 │
 +
└───┴───┴───┘
 +
</pre>
 
|-
 
|-
| <samp>PLAYER_HAS_PET {{t|player}}</samp>
+
| <samp>AnimalDoorOffset</samp>
| Whether the [[#Target player|specified player(s)]] have a [[Animals#Cat or Dog|pet]].
+
| ''(Optional)'' A pixel offset applied to the draw layer when the animal door is open. While the door is opening, the percentage open is applied to the offset (e.g. 50% open = 50% offset).
|-
 
| <samp>PLAYER_HEARTS {{t|player}} {{t|npc}} {{t|heart level}}</samp>
 
| Whether the [[#Target player|specified player(s)]] have a friend with at least {{t|heart level}} hearts of [[friendship]]. The {{t|npc}} can be an NPC's internal name, <samp>Any</samp> (check every NPC), or <samp>AnyDateable</samp> (check every romanceable NPC).
 
|-
 
| <samp>PLAYER_HAS_MET {{t|player}} {{t|npc}}</samp><br /><samp>PLAYER_IS_UNMET {{t|player}} {{t|npc}}</samp><br />
 
| Whether the [[#Target player|specified player(s)]] have talked to or not talked to an NPC at least once. The {{t|npc}} is an NPC's internal name.
 
|-
 
| <samp>PLAYER_IS_DATING {{t|player}} {{t|npc}}</samp><br /><samp>PLAYER_IS_ENGAGED {{t|player}} {{t|target}}</samp><br /><samp>PLAYER_IS_MARRIED {{t|player}} {{t|target}}</samp><br /><samp>PLAYER_IS_DIVORCED {{t|player}} {{t|npc}}</samp>
 
| Whether the [[#Target player|specified player(s)]] have this relationship status with an NPC. The player is dating after giving the NPC a [[bouquet]], and engaged after giving a [[Mermaid's Pendant]] but before the marriage. The {{t|npc}} can be an NPC's internal name, or <samp>Any</samp> (check every romanceable NPC).
 
|-
 
| <samp>PLAYER_IS_ROOMMATE {{t|player}} {{t|target}}</samp>
 
| Whether the [[#Target player|specified player(s)]] have a roommate. The {{t|target}} can be an NPC's internal name, <samp>Any</samp> (with any NPC), or <samp>Player</samp> (always false).
 
|-
 
| <samp>PLAYER_PREFERRED_PET {{t|player}} {{t|pet}}</samp>
 
| Whether the preferred pet for the [[#Target player|specified player(s)]] is <samp>Cat</samp> or <samp>Dog</samp>.
 
 
|}
 
|}
 
; Randomization
 
:{| class="wikitable"
 
 
|-
 
|-
! Condition
+
| <samp>DrawShadow</samp>
! effect
+
| ''(Optional)'' Whether to draw an automatic shadow along the bottom edge of the building's sprite. Default true.
|-
 
| <samp>RANDOM {{t|value}}</samp>
 
| A random probability check. For example, <code>RANDOM 0.4</code> is true 40% of the time. This recalculates the result each time it's called.
 
|-
 
| <samp>PICKED_VALUE_TICK {{t|min}} {{t|min}} {{t|value}} {{o|seed offset}}</samp><br /><samp>PICKED_VALUE_DAYS {{t|min}} {{t|max}} {{t|value}} {{o|seed offset}}</samp>
 
| Whether a random value between {{t|min}} and {{t|max}} is equal to {{t|value}}. For example, <samp>PICKED_VALUE_TICK 1 10 2</samp> has a 10% chance (check if 2 is equal to a random number between 1 and 10).
 
 
 
This always choose the same value for the current tick (if <samp>PICKED_VALUE_TICK</samp>) or in-game day (if <samp>PICKED_VALUE_DAYS</samp>). To have a different synchronized value, specify {{o|seed offset}} with an offset number (e.g. three options in a list would use offset 0, 1, and 2).
 
|-
 
| <samp>PICKED_VALUE {{t|min}} {{t|max}} {{t|value}}</samp><br /><samp>PICKED_VALUE_CHANCE {{t|chance}}</samp><br /><samp>PICKED_VALUE_SUMMER_RAIN_CHANCE {{t|chance}}</samp>
 
| '''Not recommended for mods, except in shop dialogue and weather conditions.'''<br />These are specialized to to replicate older vanilla behavior, and depend on <code>GameStateQuery.PickRandomValue(random)</code> being called first. The game only calls that method when opening a shop menu for [[#Custom shops|shop data with dialogue]] or when checking [[#Custom weather|weather conditions]].
 
 
|}
 
|}
  
; For items only
+
====Interior====
: These are used with queries that check an item. For vanilla content, these are only supported for [[#Custom machines|custom machine]] conditions. For custom queries, C# mods can specify the <samp>target_item</samp> parameter when calling <samp>GameStateQuery.CheckConditions</samp>. In any other context, they'll always return false.
+
{| class="wikitable"
:{| class="wikitable"
 
 
|-
 
|-
! Condition
+
! field
 
! effect
 
! effect
 
|-
 
|-
| <samp>ITEM_HAS_TAG {{t|tags}}</samp>
+
| <samp>IndoorMap</samp>
| Whether the item has all of the given space-delimited tags. For example, <code>ITEM_HAS_TAG bone_item marine_item</code> will only match items with both tags.
+
| ''(Optional)'' The name of the map asset under <samp>Maps</samp> to load for the building interior. For example, <samp>"Shed"</samp> will load the [[shed]]'s <samp>Maps/Shed</samp> map.
 
|-
 
|-
| <samp>ITEM_ID {{t|item ID}}</samp>
+
| <samp>IndoorMapType</samp>
| Whether the item has the given [[#Custom items|''unqualified'' item ID]].
+
| ''(Optional)'' The full name of the C# location class which will manage the building's interior location. This must be one of the vanilla types to avoid a crash when saving. There are too many to list here, but the most useful types are likely...
|-
+
* <samp>StardewValley.AnimalHouse</samp>;
| <samp>ITEM_QUALITY {{t|quality}}</samp>
+
* <samp>StardewValley.Locations.Cabin</samp>;
| Whether the item's quality is {{t|quality}} or higher. The possible values for {{t|quality}} are <samp>0</samp> (normal), <samp>1</samp> (silver), <samp>2</samp> (gold), or <samp>4</samp> (iridium).
+
* <samp>StardewValley.Locations.Cellar</samp>;
 +
* <samp>StardewValley.Locations.DecoratableLocation</samp>;
 +
* <samp>StardewValley.Locations.FarmCave</samp>;
 +
* <samp>StardewValley.Locations.FarmHouse</samp>;
 +
* <samp>StardewValley.Shed</samp>;
 +
* and <samp>StardewValley.SlimeHutch</samp>.
 +
Defaults to the generic <samp>StardewValley.GameLocation</samp> class.
 
|-
 
|-
| <samp>ITEM_STACK {{t|count}}</samp>
+
| <samp>NonInstancedIndoorLocation</samp>
| Whether the item stack contains at least {{t|count}} items. Note that this only applies to the target item, it doesn't include other stacks in the inventory.
+
| ''(Optional)'' The name of the existing global location to treat as the building's interior, like <samp>FarmHouse</samp> and <samp>Greenhouse</samp> for their buildings.
|}
 
  
; Immutable
+
Each location can only be used by one building. If the location is already in use (e.g. because the player has two of this building), each subsequent building will use the <samp>IndoorMap</samp> and <samp>IndoorMapType</samp> instead. For example, the first greenhouse will use the global <samp>Greenhouse</samp> location, and any subsequent greenhouse will use a separate instanced location.
:{| class="wikitable"
 
 
|-
 
|-
! Condition
+
| <samp>MaxOccupants</samp>
! effect
+
| ''(Optional)'' The maximum number of animals who can live in this building.
 
|-
 
|-
| <samp>TRUE</samp>
+
| <samp>AllowAnimalPregnancy</samp>
| A condition which always matches.
+
| ''(Optional)'' Whether animals can get pregnant and produce offspring in this building. Default false.
 
|-
 
|-
| <samp>FALSE</samp>
+
| <samp>ValidOccupantTypes</samp>
| A condition which never matches.
+
| ''(Optional)'' A list of building IDs whose animals to allow in this building too. For example, <code>[ "Barn", "Coop" ]</code> will allow [[barn]] and [[coop]] animals in this building. Default none.
 
|}
 
|}
  
====Target location====
+
====Item processing====
Some conditions have a {{t|location}} argument. This can be one of...
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! value
+
! field
! result
+
! effect
 
|-
 
|-
| <samp>Here</samp>
+
| <samp>HayCapacity</samp>
| The current player's location (regardless of the [[#Target player|target player]]).
+
| ''(Optional)'' The amount of hay that can be stored in this building. If built on the [[The Farm|farm]], this works just like [[silo]]s and contributes to the farm's available hay.
 
|-
 
|-
| <samp>Target</samp>
+
| <samp>ItemConversions</samp>
| This value depends on the context:
+
| ''(Optional)'' The item processing rules which take input items and convert them into output items using the inventories defined by <samp>Chests</samp>. This consists of a list of models with these fields:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! context
+
! field
 
! effect
 
! effect
 
|-
 
|-
| <samp>Data/MachinesData</samp>
+
| <samp>Id</samp>
| The location containing the machine.
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this rule within the current list.
 
|-
 
|-
| ''custom queries''
+
| <samp>RequiredTags</samp>
| C# mods may specify a <samp>target_location</samp> parameter when calling <samp>GameStateQuery.CheckConditions</samp>.
+
| A list of [[Modding:Items#Context tags|context tags]] to match against an input item. An item must have ''all'' of these tags to be accepted.
 
|-
 
|-
| ''any other''
+
| <samp>SourceChest</samp>
| If the [[#Target player|player <samp>Target</samp>]] is set, that player's location. Otherwise equivalent to <samp>Here</samp>.
+
| The ID of the inventory defined in <samp>Chests</samp> from which to take input items.
|}
+
|-
 +
| <samp>DestinationChest</samp>
 +
| The ID of the inventory defined in <samp>Chests</samp> in which to store output items.
 
|-
 
|-
| ''any other''
+
| <samp>ProducedItems</samp>
| The [[#Custom locations|location ID]] (i.e. internal name) for the location to check.
+
| The output items produced when an input item is converted. This consists of a list of models with these fields:
|}
 
 
 
====Target player====
 
Some conditions have a {{t|player}} argument. This can be one of...
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! value
+
! field
! result
+
! effect
 
|-
 
|-
| <samp>Any</samp>
+
| ''common fields''
| At least one player must match the condition, regardless of whether they're online.
+
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields supported by machine output.
 +
 
 +
If set to an [[Modding:Item queries|item query]] which returns multiple items, one of them will be selected at random.
 
|-
 
|-
| <samp>All</samp>
+
| <samp>Chance</samp>
| Every player must match the condition, regardless of whether they're online.
+
| ''(Optional)'' The probability that the item will be produced, as a value between 0 (never drops) and 1 (always drops). Default 1 (100% chance).
 +
|}
 
|-
 
|-
| <samp>Current</samp>
+
| <samp>RequiredCount</samp>
| The local player.
+
| ''(Optional)'' The number of the input item to consume. Default 1.
 
|-
 
|-
| <samp>Host</samp>
+
| <samp>MaxDailyConversions</samp>
| The main player.
+
| ''(Optional)'' The maximum number of the input item which can be processed each day. Each conversion rule has its own separate maximum (e.g. if you have two rules each with a max of 1, then you can convert one of each daily). Set to -1 to allow unlimited conversions. Default 1.
 +
|}
 
|-
 
|-
| <samp>Target</samp>
+
| <samp>Chests</samp>
| This value depends on the context:
+
| ''(Optional)'' The input/output inventories that can be accessed from a tile on the building exterior. The allowed items are defined by the separate <samp>ItemConversions</samp> field. This is a list of models with these fields:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! context
+
! field
 
! effect
 
! effect
 
|-
 
|-
| <samp>Data/LocationContexts</samp>
+
| <samp>Id</samp>
| For the <samp>PassOutLocations</samp> field only, the player whose pass-out location to get.
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this chest within the current list.
 +
 
 +
This is referenced from the <samp>ItemConversions</samp> field.
 +
|-
 +
| <samp>Type</samp>
 +
| The inventory type. This must be one of:
 +
* <samp>Chest</samp>: show a normal chest UI on click.
 +
* <samp>Collect</samp>: provides items for the player to collect. Clicking the tile will do nothing (if empty), grab the item directly (if it only contains one item), else show a grab-only inventory UI.
 +
* <samp>Load</samp>: lets the player add items for the building to process.
 
|-
 
|-
| <samp>Data/MiscGameData</samp>
+
| <samp>Sound</samp>
| For the <samp>WeddingContextualAttendees</samp> field only, the attendee player (if the attendee is a player).
+
| ''(Optional)'' The sound to play once when the player clicks the chest.
 
|-
 
|-
| <samp>Data/WildTrees</samp>
+
| <samp>InvalidItemMessage</samp><br /><samp>InvalidCountMessage</samp><br /><samp>ChestFullMessage</samp>
| For the <samp>AdditionalChopDrops</samp> field only, the last player who chopped the tree.
+
| ''(Optional)'' A [[Modding:Tokenizable strings|tokenizable string]] to show when the player tries to add an item to the chest when...
 +
* it isn't a supported item;
 +
* it's supported but they don't have enough in their inventory;
 +
* the chest has no more room to accept it.
 +
If omitted, the player interaction is ignored with no message shown.
 
|-
 
|-
| ''custom queries''
+
| <samp>InvalidItemMessageCondition</samp>
| C# mods may specify a <samp>target_farmer</samp> parameter when calling <samp>GameStateQuery.CheckConditions</samp>.
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether <samp>InvalidItemMessage</samp> should be shown. This can use item-related queries like <samp>ITEM_TYPE</samp>. Defaults to always true.
 
|-
 
|-
| ''any other''
+
| <samp>DisplayTile</samp>
| Equivalent to <samp>Current</samp>.
+
| ''(Optional)'' The chest's position on the building exterior, measured in tiles from the top-left corner of the building, specified in the form <samp>"{{t|x}}, {{t|y}}"</samp>. This affects the position of the 'item ready to collect' bubble. If omitted, the bubble is disabled.
 +
|-
 +
| <samp>DisplayHeight</samp>
 +
| ''(Optional)'' If <samp>DisplayTile</samp> is set, the chest's tile height like <samp>1.5</samp>.
 
|}
 
|}
|-
 
| ''any other''
 
| The unique multiplayer ID for the player to check.
 
 
|}
 
|}
  
====Using queries elsewhere====
+
====Tile interactions====
C# code can use the <samp>GameStateQuery</samp> class to work with queries, like <code>GameStateQuery.CheckConditions(query)</code>.
+
{| class="wikitable"
 
+
|-
You can also use game state queries in [[Modding:Event data|event preconditions]] using the new <samp>G</samp> condition flag, like <code>some_event_id/G !SEASON Spring, WEATHER Here sunny</code>.
+
! field
 
+
! effect
====Extensibility====
+
|-
C# mods can define custom conditions by calling <code>GameStateQuery.RegisterQueryType("condition name", (string[] fields) => ...)</code>. To avoid conflicts, prefixing custom condition names with your mod ID (like <samp>Example.ModId_SomeCondition</samp>) is strongly recommended.
+
| <samp>ActionTiles</samp>
 
+
| ''(Optional)'' A list of tiles which the player can click to trigger an <samp>Action</samp> [[Modding:Maps|map tile property]]. This consists of a list of models with these fields:
===Tokenizable string format===
 
Stardew Valley 1.6 adds support for literal strings that contain tokens (currently only supported for [[#Custom map areas|custom map areas]] and [[#Custom shops|custom shops]]).
 
 
 
====Literal text====
 
Previously you often needed to load text from a [[Modding:Modder Guide/Game Fundamentals#String keys|string key]] in data assets. With this new format, you can use the literal text directly in the asset instead (including Content Patcher tokens):
 
 
 
<syntaxhighlight lang="js">
 
// before
 
"Dialogue": "Strings\\StringsFromCSFiles:ShopMenu.cs.11488",
 
 
 
// after: literal text supported
 
"Dialogue": "Welcome to Pierre's!",
 
 
 
// after: literal text with Content Patcher tokens
 
"Dialogue": "Welcome to Pierre's, {{PlayerName}}! {{i18n: translatable-text}}",
 
</syntaxhighlight>
 
 
 
====Tokens====
 
You can inject tokens using square brackets. For example, <code>"[LocalizedText Strings\StringsFromCSFiles:ShopMenu.cs.11488] This is raw text"</code> will show something like "''Welcome to Pierre's! This is raw text''". Here are the supported tokens:
 
 
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! token format
+
! field
! output
+
! effect
 
|-
 
|-
| <samp>[ArticleFor {{t|word}}]</samp>
+
| <samp>Id</samp>
| The grammatical article (''a'' or ''an'') for the given word when playing in English, else blank. For example, <code>[ArticleFor apple] apple</code> will output ''an apple''.
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the current list.
 
|-
 
|-
| <samp>[CharacterName {{t|name}}]</samp>
+
| <samp>Tile</samp>
| The translated display name for an NPC, given their internal name.
+
| The tile position, relative to the building's top-left corner tile.
 
|-
 
|-
| <samp>[DataString {{t|asset name}} {{t|key}} {{t|index}}]</samp>
+
| <samp>Action</samp>
| Parses the data asset identified by {{t|asset name}}, finds the entry matching {{t|key}}, splits the slash-delimited string, and returns the value with index {{t|index}} (starting from 0).
+
| The [[Modding:Tokenizable strings|tokenizable string]] for the action to perform, excluding the <samp>Action</samp> prefix. For example, <samp>"Dialogue Hi there @!"</samp> to show a messagebox like "''Hi there <player name>!''". The tokenizable string is expected before the action is raised. See the [[Modding:Maps#Tile properties 2|list of tile properties]] for useful <samp>Action</samp> values.
 
+
|}
For example, <samp>[DataString Data\Blueprints Silo 8]</samp> matches the word "Silo" from this entry in <samp>Data\Blueprints</samp>:
 
<syntaxhighlight lang="js">
 
  "Silo": "390 100 330 10 334 5/3/3/-1/-1/-2/-1/null/Silo/Allows you to cut and store grass for feed./Buildings/none/48/128/-1/null/Farm/100/false"
 
</syntaxhighlight>
 
 
|-
 
|-
| <samp>[DayOfMonth]</samp>
+
| <samp>DefaultAction</samp>
| The numeric day of month, like <samp>5</samp> on spring 5.
+
| ''(Optional)'' The default tile action if the clicked tile isn't in <samp>ActionTiles</samp>. Default none.
 
|-
 
|-
| <samp>[EscapedText {{t|text}}]</samp>
+
| <samp>TileProperties</samp>
| Replaces spaces in the given text with a special character that lets you pass them into other space-delimited tokens. The characters are automatically turned back into spaces when displayed.
+
| ''(Optional)'' The [[Modding:Maps|map tile properties]] to set. This consists of a list of models with these fields:
 +
{| class="wikitable"
 
|-
 
|-
| <samp>[FarmerUniqueID]</samp>
+
! field
| The target player's unique internal multiplayer ID
+
! effect
 
|-
 
|-
| <samp>[FarmName]</samp>
+
| <samp>Id</samp>
| The farm name for the current save (without the injected "Farm" text).
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the current list.
 
|-
 
|-
| <samp>[GenderedText {{t|male text}} {{t|female text}}</samp>
+
| <samp>Name</samp>
| Depending on the target player's gender, show either the male text or female text. If the text contains spaces, you'll need to escape them using <samp>EscapedText</samp>.
+
| The tile property name to set.
 
|-
 
|-
| <samp>[LocalizedText {{t|string key}}]</samp>
+
| <samp>Value</samp>
| Translation text loaded from the given [[Modding:Modder Guide/Game Fundamentals#String keys|string key]]. If the translation has placeholder tokens like <samp>{0}</samp>, you can add the values after the string key.
+
| ''(Optional)'' The tile property value to set, or omit to set a null value.
 
|-
 
|-
| <samp>[LocationName {{t|location ID}}]</samp>
+
| <samp>Layer</samp>
| The translation display name for a location given its ID (''i.e.'' the same ID as in <samp>Data/AdditionalLocationData</samp>).
+
| The name of the map layer whose tiles to change.
 
|-
 
|-
| <samp>[PositiveAdjective]</samp>
+
| <samp>TileArea</samp>
| A random adjective from the <samp>Strings\Lexicon</samp> data asset's <samp>RandomPositiveAdjective_PlaceOrEvent</samp> entry.
+
| The tiles to which to add the property, relative to the top-left corner of the building's collision box. This is specified as an object with <samp>X</samp>, <samp>Y</samp>, <samp>Width</samp>, and <samp>Height</samp> fields.
 +
|}
 
|-
 
|-
| <samp>[Season]</samp>
+
| <samp>AdditionalTilePropertyRadius</samp>
| The current season name, like ''spring''.
+
| ''(Optional)'' When checking whether the player clicked on a <samp>TileProperties</samp> tile, an added distance around the building at which tile locations may be placed. Default 0, so only tile properties within the normal building bounds will work.
|-
 
| <samp>[SpouseFarmerText {{t|spouse is farmer text}} {{t|spouse is NPC text}}</samp>
 
| Show a different text depending on whether the target player's spouse is a player or NPC. If the text contains spaces, you'll need to escape them using <samp>EscapedText</samp>.
 
|-
 
| <samp>[SpouseGenderedText {{t|male text}} {{t|female text}}]</samp>
 
| Equivalent to <samp>GenderedText</samp>, but based on the gender of the player's NPC or player spouse instead.
 
|-
 
| <samp>[SuggestedItem]</samp>
 
| '''(For shops only.)''' The name of a random item currently available in the shop stock.
 
 
|}
 
|}
  
When passing an input argument for tokens like <samp>ArticleFor</samp>, the input can contain its own nested tokens. For example, <code>"[ArticleFor [SuggestedItem]] [SuggestedItem]"</code> would output something like ''an Apple''.
+
====Advanced====
 
 
If you're using [[Modding:Content Patcher|Content Patcher]], you can use its tokens anywhere in the string (including within square brackets); they'll be expanded before the game parses the string. For example, <code><nowiki>"{{Spouse}} would love [ArticleFor [SuggestedItem]] [SuggestedItem]!"</nowiki></code> would output something like "''Alexa would love an Apple!''".
 
 
 
===String event & response IDs===
 
[[Modding:Event data|Event IDs]] and [[Modding:Dialogue#Response IDs|dialogue response IDs]] are now strings, so mods can use a unique key like <samp>Example.ModId_EventName</samp> (instead of hoping no other mod uses the same number). Prefixing the mod ID is recommended to simplify troubleshooting and avoid conflicts. For best compatibility, custom IDs should only contain alphanumeric/underscore/dot characters.
 
 
 
===New C# utility methods===
 
Stardew Valley 1.6 adds several new methods to the <samp>Utility</samp> class. Here are some of the most useful ones for mods:
 
 
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! method
+
! field
 
! effect
 
! effect
 
|-
 
|-
| <samp>GetDataAtIndex</samp><br /><samp>GetIntAtIndex</samp><br /><samp>GetFloatAtIndex</samp><br /><samp>GetStringAtIndex</samp>
+
| <samp>Metadata</samp>
| Parse a value from an array with optional field indexes.
+
| ''(Optional)'' A list of custom properties applied to the building, which can optionally be overridden per-skin in the <samp>Skins</samp> field. Default none.
  
For example, code like this:
+
The base game recognizes these properties:
 +
{| class="wikitable"
 +
|-
 +
! property
 +
! description
 +
|-
 +
| <samp>ChimneyPosition: {{t|x}} {{t|y}}</samp>
 +
| ''(Optional)'' The pixel position at which to place a chimney on the building exterior, relative to the top-left corner of the sprite. This will apply the same logic as the farmhouse chimney (e.g. producing smoke if there's a lit fireplace inside the building).
 +
|-
 +
| <samp>ChimneyPosition{{o|upgrade level}}: {{t|x}} {{t|y}}</samp>
 +
| ''(Optional, for farmhouses/cabins only)'' Override <samp>ChimneyPosition</samp> for the given upgrade level, starting from 0 for the initial farmhouse/cabin. If there's no override for the current upgrade level, the highest override for a lower upgrade level is used (if any). For example, <samp>ChimneyPosition3</samp> would be used for the third house upgrade (and the fourth if there's no <samp>ChimneyPosition4</samp>).
 +
|}
 +
 
 +
This can also contain arbitrary custom properties, which C# mods can read using <samp>building.GetMetadata(key)</samp>.
 +
|-
 +
| <samp>BuildingType</samp>
 +
| ''(Optional)'' The full name of the C# type to instantiate for the building instance. Defaults to a generic <samp>Building</samp> instance.
 +
 
 +
'''⚠ Caution:''' this is meant to support vanilla building types like <samp>StardewValley.Shed</samp>. Setting this to a non-vanilla type will cause a crash when it's written to the save file, and may cause crashes in multiplayer. If you need custom behavior, consider handling it in C# based on the building type instead of creating a custom subclass; otherwise you'll need a framework mod like {{nexus mod|1348|SpaceCore}} to handle serialization and multiplayer sync.
 +
|-
 +
| <samp>ModData</samp>
 +
| ''(Optional)'' A string → string lookup of arbitrary <samp>modData</samp> values to attach to the building when it's constructed.
 +
|-
 +
| <samp>CustomFields</samp>
 +
| The [[#Custom data fields|custom fields]] for this entry.
 +
|}
 +
 
 +
===Build anywhere===
 +
{{/doc status|[[Modding:Blueprint data]] and [[Modding:Maps]]|done=false}}
  
<syntaxhighlight lang="c#">
+
* You can now allow building construction for any location using the [[#Map/tile property changes|new <samp>CanBuildHere</samp> and related map properties]]. The game will adjust accordingly (e.g. Robin will let you choose where to construct the building).
string[] rawEffects = fields.Length > Object.objectInfoBuffTypesIndex && fields[Object.objectInfoBuffTypesIndex].Length > 0
+
* Buildings and animals are no longer hardcoded to the [[The Farm|farm]] location (except [[cabin]]s and the [[farmhouse]] which still are).
    ? fields[Object.objectInfoBuffTypesIndex].Split(' ')
+
* Scything hay will now add hay to silos in any location, and animals will be auto-fed from hay in any location.
    : new string[0];
 
  
int farming = rawEffects.Length > Buffs.farming && int.TryParse(rawEffects[Buffs.farming], out int _farming)
+
===Other building changes===
    ? _farming
+
{{/doc status|[[Modding:Blueprint data]]|done=false}}
    : 0;
 
</syntaxhighlight>
 
  
Can now be rewritten like this:
+
: ''See also: [[#Other location/map changes|other location changes]] for location-related building changes.''
  
 +
; General building changes
 +
* Building display names & descriptions are now in <samp>Strings/Buildings</samp> for reuse.
 +
* Removed <samp>Data/Blueprints</samp>. This has been replaced by <samp>Data/Buildings</samp> (building data) and <samp>Strings/Buildings</samp> (display names & descriptions).
 +
<ul>
 +
<li>Added methods to simplify common operations:
 +
{| class="wikitable"
 +
|-
 +
! type
 +
! method
 +
! effect
 +
|-
 +
|rowspan="7"| <samp>Building</samp>
 +
| <samp>CreateInstanceFromId</samp>
 +
| Create a building instance from its type ID in <samp>Data/Buildings</samp>. For example:
 
<syntaxhighlight lang="c#">
 
<syntaxhighlight lang="c#">
string[] rawEffects = Utility.GetDataAtIndex(fields, Object.objectInfoBuffTypesIndex, "").Split(' ');
+
Building shippingBin = Building.CreateInstanceFromId("Shipping Bin", Vector2.Zero); // creates an instance of StardewValley.Buildings.ShippingBin
int farming = Utility.GetIntAtIndex(rawEffects, Buffs.farming);
 
 
</syntaxhighlight>
 
</syntaxhighlight>
 
|-
 
|-
| <samp>GetItemDataForItemID</samp>
+
| <samp>GetData</samp><br /><samp>TryGetData</samp>
| Get metadata about a given [[#Custom items|item ID]] like its display name, description, spritesheet index & source rectangle, etc.
+
| Get the data for the building's type from <samp>Data/Building</samp>.
 
|-
 
|-
| <samp>GetDescriptionForItemID</samp><br /><samp>GetDisplayNameForItemID</samp><br /><samp>GetSourceRectForItemID</samp><br /><samp>GetTextureForItemID</samp><br /><samp>GetParentSheetIndexForItemID</samp>
+
| <samp>GetMetadata</samp>
| Get specific details about a given [[#Custom items|item ID]] from <samp>GetItemDataForItemID</samp>.
+
| Get a value from [[#Custom buildings|the <samp>Metadata</samp> field in <samp>Data/Buildings</samp>]] for this building.
 
|-
 
|-
| <samp>StringToDirection</samp>
+
| <samp>GetPaintDataKey</samp>
| Converts a string direction (one of <samp>down</samp>, <samp>left</samp>, <samp>right</samp>, or <samp>up</samp>) into a direction code recognized by various game methods (''i.e.'' <samp>Game1.down</samp>, etc). If the string contains a number, the numeric value is returned (even if it's not a valid direction). If it's any other unrecognized value, the method returns -1.
+
| Get the key in <samp>Data/PaintData</samp> for this building, if it has any.
 +
|-
 +
| <samp>ReloadBuildingData</samp>
 +
| Apply the latest data in <samp>Data/Buildings</samp> to this building.
 +
|-
 +
| <samp>FinishConstruction</samp>
 +
| If the building is being constructed or upgrade, instantly finish doing so.
 +
|-
 +
| <samp>UpdateTransparency</samp>
 +
| Update the building transparency on tick for the local player's position.
 +
 
 +
This method mainly exists to let mods override/patch the transparency logic.
 +
|-
 +
| <samp>Farm</samp>
 +
| <samp>GetMainFarmHouse</samp>
 +
| Get the main [[farmhouse]] building.
 +
|-
 +
| <samp>GameLocation</samp>
 +
| <samp>OnParentBuildingUpgraded</samp>
 +
| Called when the building containing this location is upgraded, if applicable.
 
|}
 
|}
 +
</li>
 +
</ul>
 +
* Added building <samp>id</samp> field, which uniquely identifies each building in the world.
 +
 +
; [[Junimo Hut|Junimo hut]] changes
 +
* The <samp>JunimoHut.cropHarvestRange</samp> field is now per-building and editable.
  
===Other changes===
+
; [[Fish Pond|Fish pond]] changes
 
<ul>
 
<ul>
<li>Added new [[Modding:Console commands|debug commands]]:
+
<li>In <samp>Data/FishPondData</samp>, added a <samp>Precedence</samp> field which sets the order in which entries are checked for a match (with lower values checked first). This ensures that the fallback entries are checked after specific fish. For consistency, vanilla entries use these values:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! command
+
! precedence
! description
+
! used for
 
|-
 
|-
| <samp>bsm</samp>
+
| 0<br /><small>(default value)</small>
| If the player is standing right under a building, open a menu to change the building appearance.
+
| specific fish
 
|-
 
|-
| <samp>testwedding</samp>
+
| 100
| Immediately play the [[Marriage#The Wedding|wedding]] event.
+
| custom groups (e.g. desert fish)
 
|-
 
|-
| <samp>qualifiedid</samp>
+
| 500
| Print the held item's display name and [[#Custom items|qualified item ID]].
+
| broad fish type (e.g. ocean fish)
|}</li>
 
<li>Added new [[Modding:Dialogue|dialogue]] commands:
 
{| class="wikitable"
 
 
|-
 
|-
! command
+
| 1000
! description
+
| fallback (e.g. fish category)
|-
+
|}
| <samp>$f {{t|response IDs}}</samp>
+
</li>
| Forget any number of space-delimited [[Modding:Dialogue#Response IDs|dialogue response IDs]] previously answered by the player.
+
<li>In <samp>Data/FishPondData</samp>, the reward <samp>ItemId</samp> can now be an [[Modding:Item queries|item query]].</li>
|-
+
<li>[[Legendary Fish|Legendary fish]] can now be added to [[Fish Pond|fish ponds]] if they have an entry in <samp>Data/FishPondData</samp>.</li>
| <samp>$v {{t|event id}} {{o|check preconditions}} {{o|skip if seen}}</samp>
+
</ul>
| Immediately start an [[Modding:Event data|event]] and end the current dialogue, subject to the conditions:
+
 
* {{o|check preconditions}}: whether to ignore the command if the [[Modding:Event data#Event preconditions|event's preconditions]] don't match (one of <samp>true</samp> or <samp>false</samp>). Default true.
+
==What's new for NPCs==
* {{o|skip if seen}}: whether to ignore the command if the player has already seen the given event. Default true.
+
===Custom NPCs===
 +
{{/doc status|[[Modding:NPC data]]|done=false}}
 +
 
 +
[[Modding:NPC data|Custom NPC data]] has been overhauled in 1.6. The new <samp>Data/Characters</samp> asset (which replaces <samp>Data/NPCDispositions</samp> + <samp>Data/spousePatios</samp> + <samp>Data/spouseRooms</samp>) uses a data model format that's easier to edit and understand, and has a lot of fields to customize previously-hardcoded data.
  
If the event is skipped, the dialogue continues to the next line instead.
+
====Format====
 +
This consists of a string → model lookup, where...
 +
* The key is a [[Modding:Common data field types#Unique string ID|unique string ID]] for the NPC like <samp>Example.ModId_NpcName</samp>, which will be used as the internal <samp>Name</samp> (not <samp>DisplayName</samp>).
 +
* The value is a model with the following fields.
  
For example, <code>$v 60367 false false</code> will replay the bus arrival event from the start of the game.
+
<dl style="margin-left: 2em;">
|}
+
<dt>Basic info:</dt>
</li>
+
<dd>
<li>Added new [[Modding:Event data|event]] commands:
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! command
 
! description
 
|-
 
| <samp>temporaryAnimatedSprite ...</samp>
 
| Add a temporary animated sprite to the event, using these space-delimited fields:
 
{| class="wikitable"
 
|-
 
! index
 
 
! field
 
! field
 
! effect
 
! effect
 
|-
 
|-
| 0
+
| <samp>DisplayName</samp>
| <samp>texture</samp>
+
| A [[Modding:Tokenizable strings|tokenizable string]] for the NPC's display name.
| The asset name for texture to draw.
+
|-
 +
| <samp>Language</samp>
 +
| ''(Optional)'' The language spoken by the NPC. One of <samp>Default</samp> (the default language understood by the player) or <samp>Dwarvish</samp> (which the player can only understand after finding the [[Dwarvish Translation Guide|Dwarvish translation guide]]). Default <samp>Default</samp>.
 
|-
 
|-
| 1&ndash;4
+
| <samp>Gender</samp>
| <samp>rectangle</samp>
+
| ''(Optional)'' The NPC's gender identity. One of <samp>Female</samp>, <samp>Male</samp>, or <samp>Undefined</samp>. Default <samp>Undefined</samp>.
| The pixel area within the <samp>texture</samp> to draw, in the form <samp>{{t|x}} {{t|y}} {{t|width}} {{t|height}}</samp>.
 
 
|-
 
|-
| 5
+
| <samp>Age</samp>
| <samp>interval</samp>
+
| ''(Optional)'' The general age of the NPC. One of <samp>Child</samp>, <samp>Teen</samp>, or <samp>Adult</samp>. Default <samp>Adult</samp>.
| The millisecond duration for each frame in the animation.
+
 
 +
This affects generated dialogue lines (e.g. a child might say "stupid" and an adult might say "depressing"), generic dialogue (e.g. a child might respond to dumpster diving with "''Eww... What are you doing?''" and a teen would say "''Um... Why are you digging in the trash?''"), and the gift they choose as [[Feast of the Winter Star]] gift-giver. Children are also excluded from item delivery quests.
 +
|-
 +
| <samp>Manner</samp>
 +
| ''(Optional)'' A measure of the character's general politeness, which affects some generic dialogue lines. One of <samp>Neutral</samp>, <samp>Polite</samp>, or <samp>Rude</samp>. Default <samp>Neutral</samp>.
 
|-
 
|-
| 6
+
| <samp>SocialAnxiety</samp>
| <samp>frames</samp>
+
| ''(Optional)'' A measure of the character's comfort with social situations, which affects some generic dialogue lines. One of <samp>Neutral</samp>, <samp>Outgoing</samp>, or <samp>Shy</samp>. Default <samp>Neutral</samp>.
| The number of frames in the animation.
 
 
|-
 
|-
| 7
+
| <samp>Optimism</samp>
| <samp>loops</samp>
+
| ''(Optional)'' A measure of the character's overall optimism. One of <samp>Neutral</samp>, <samp>Negative</samp>, or <samp>Positive</samp>. Default <samp>Neutral</samp>.
| The number of times to repeat the animation.
 
 
|-
 
|-
| 8&ndash;9
+
| <samp>BirthSeason</samp>
| <samp>tile</samp>
+
| ''(Optional if non-social)'' The season name (case-sensitive) for the NPC's birthday. One of <samp>spring</samp>, <samp>summer</samp>, <samp>fall</samp>, or <samp>winter</samp>. Default none.
| The tile position at which to draw the sprite, in the form <samp>{{t|x}} {{t|y}}</samp>.
 
 
|-
 
|-
| 10
+
| <samp>BirthDay</samp>
| <samp>flicker</samp>
+
| ''(Optional if non-social)'' The day number for the NPC's birthday. Default 0.
| '''[TODO: document what this does]''' (one of <samp>true</samp> or <samp>false</samp>).
 
 
|-
 
|-
| 11
+
| <samp>HomeRegion</samp>
| <samp>flip</samp>
+
| ''(Optional)'' The region of the world in which the NPC lives (one of <samp>Desert</samp>, <samp>Town</samp>, or <samp>Other</samp>). For example, only <samp>Town</samp> NPCs are counted for the introductions [[Quests#List of Story Quests|quest]], can be selected as a secret santa for the [[Feast of the Winter Star]], or get a friendship boost from the [[Luau]]. Default <samp>Other</samp>.
| Whether to flip the sprite horizontally when it's drawn (one of <samp>true</samp> or <samp>false</samp>).
 
 
|-
 
|-
| 12
+
| <samp>IsDarkSkinned</samp>
| <samp>sort tile Y</samp>
+
| ''(Optional)'' Whether the NPC has dark skin, which affects the chance of children with the player having dark skin too. Default false.
| The tile Y position to use in the layer depth calculation, which affects which sprite is drawn on top if two sprites overlap.
+
|}
 +
</dd>
 +
 
 +
<dt>Social features:</dt>
 +
<dd>
 +
{| class="wikitable"
 
|-
 
|-
| 13
+
! field
| <samp>alpha fade</samp>
+
! effect
| '''[TODO: document what this does]'''
 
 
|-
 
|-
| 14
+
| <samp>CanSocialize</samp>
| <samp>scale</samp>
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether to enable social features (like birthdays, gift giving, [[friendship]], and an entry in the social tab). Default true.
| A multiplier applied to the sprite size (in addition to the normal 4× pixel zoom).
 
 
|-
 
|-
| 15
+
| <samp>CanBeRomanced</samp>
| <samp>scale change</samp>
+
| ''(Optional)'' Whether the NPC can be dated and romanced. This enables romance features for this NPC (like a 'single' label in the social menu, bouquet gifting, and marriage). Default false.
| '''[TODO: document what this does]'''
 
 
|-
 
|-
| 16
+
| <samp>CanReceiveGifts</samp>
| <samp>rotation</samp>
+
| ''(Optional)'' Whether players can give gifts to this NPC. Default true.
| The rotation to apply to the sprite, measured in [[wikipedia:radians|radians]].
+
 
 +
The NPC must also be social per <samp>CanSocialize</samp> and have an entry in <samp>Data/NPCGiftTastes</samp> to be giftable, regardless of this value.
 
|-
 
|-
| 17
+
| <samp>CanCommentOnPurchasedShopItems</samp>
| <samp>rotation change</samp>
+
| ''(Optional)'' Whether this NPC can comment on items that a player sold to a shop which then resold it to them. If null (or omitted), this will default to true if their <samp>HomeRegion</samp> is set to <samp>Town</samp>.
| '''[TODO: document what this does]'''
+
 
 +
The NPC must also be social per <samp>CanSocialize</samp> to allow it, regardless of this value.
 
|-
 
|-
| 18+
+
| <samp>CanGreetNearbyCharacters</samp>
| ''flags''
+
| ''(Optional)'' Whether this NPC can show a speech bubble greeting nearby players or NPCs, and or be greeted by other NPCs. Default true.
| Any combination of these space-delimited flags:
+
|-
* <samp>hold_last_frame</samp>: after playing the animation once, freeze the last frame as long as the sprite is shown.
+
| <samp>CanVisitIsland</samp>
* <samp>ping_pong</samp>: '''[TODO: document what this does]'''
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether the NPC can visit the [[Ginger Island]] resort once it's unlocked. Default true.
* <samp>motion {{t|x}} {{t|y}}</samp>: '''[TODO: document what this does]'''
 
* <samp>acceleration {{t|x}} {{t|y}}</samp>: '''[TODO: document what this does]'''
 
* <samp>acceleration_change {{t|x}} {{t|y}}</samp>: '''[TODO: document what this does]'''
 
|}
 
|}
 
</li>
 
<li>Unknown [[Modding:Dialogue|dialogue]] commands starting with <samp>$</samp> are no longer parsed as a portrait number if they're not numeric.</li>
 
<li>Fixed <samp>ebi</samp> [[Modding:Console commands|debug command]] not playing events correctly if called from the same location as the event.</li>
 
<li>Added <samp>silence</samp> [[Modding:Audio|audio cue]]. This is different from <samp>none</samp> in that it suppresses both town music and ambient sounds.</li>
 
<li>The [[desert]] no longer assumes the player arrived by bus unless their previous location was the [[Bus Stop|bus stop]].</li>
 
</ul>
 
 
 
==Breaking changes for C# mods==
 
'''This section only describes how this update may break existing mods. See the ''what's new'' sections above for more info, including new functionality mods can use.'''
 
 
 
See also [[#Breaking changes for content packs|''Breaking changes for content packs'']], which affect C# mods too.
 
 
 
===Item ID changes===
 
: ''See also: [[#Custom items|custom items in what's new]].''
 
 
 
The [[#Custom items|main <samp>Item</samp> properties have changed]]. To migrate existing code:
 
<ul>
 
<li>Don't use <samp>ParentSheetIndex</samp> to compare items. For example, <samp>item.ParentSheetIndex == 0</samp> will match both [[weeds]] and any custom item whose sprite is the first one in its custom spritesheet. You should compare items using [[#Custom items|their new <samp>ItemID</samp> and <samp>QualifiedItemID</samp> properties instead. Here's how to migrate various common forms:
 
  
 +
The NPC must also be social per <samp>CanSocialize</samp> to visit the island, regardless of this value.
 +
|-
 +
| <samp>LoveInterest</samp>
 +
| ''(Optional)'' Unused.
 +
|-
 +
| <samp>Calendar</samp>
 +
| ''(Optional)'' Determines when the NPC's birthday is shown in the [[calendar]]. Possible values:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! old code
+
! value
! new code
+
! effect
 +
|-
 +
| <samp>HiddenAlways</samp>
 +
| They never appear in the calendar.
 
|-
 
|-
 +
| <samp>HiddenUntilMet</samp>
 +
| Until the player meets them, they don't appear in the calendar.
 
|-
 
|-
| <samp>item.ParentSheetIndex == 848</samp>
+
| <samp>AlwaysShown</samp>
| <samp>item.QualifiedItemID == "(O)848"</samp>
+
| They always appear in the calendar.
 +
|}
 +
 
 +
Defaults to <samp>AlwaysShown</samp>.
 
|-
 
|-
| <samp>IsNormalObjectAtParentSheetIndex(item, 74)</samp>
+
| <samp>SocialTab</samp>
| <samp>item.QualifiedItemID == "(O)74"</samp>
+
| ''(Optional)'' Determines how the NPC is shown on the [[friendship|social tab]] when unlocked. Possible values:
 +
{| class="wikitable"
 
|-
 
|-
| <samp>!item.bigCraftable && item.ParentSheetIndex == 128</samp>
+
! value
| <samp>item.QualifiedItemID == "(O)128"</samp>
+
! effect
 
|-
 
|-
| <samp>item is Boots && item.ParentSheetIndex == 505</samp>
+
| <samp>HiddenAlways</samp>
| <samp>item.QualifiedItemID == "(B)505"</samp>
+
| They never appear in the social tab.
|}</li>
+
|-
<li>Don't assume item sprites are in the vanilla spritesheets. For example, instead of rendering <samp>Game1.objectSpriteSheet</samp> for an object, call <code>Utility.GetTextureForItemID(item.QualifiedItemID)</code> to get its texture.</li>
+
| <samp>HiddenUntilMet</samp>
<li>Creating items works just like before, except that you now specify the item's <samp>ItemID</samp> (_not_ <samp>QualifiedItemID</samp>) instead of its <samp>ParentSheetIndex</samp>. This is the same value for vanilla items. For example:
+
| Until the player meets them, they don't appear on the social tab.
 
+
|-
<syntaxhighlight lang="c#">
+
| <samp>UnknownUntilMet</samp>
new Object("634", 1);                      // vanilla item
+
| Until the player meets them, their name on the social tab is replaced with "???".
new Object("Example.ModId_Watermelon", 1); // custom item
+
|-
</syntaxhighlight>
+
| <samp>AlwaysShown</samp>
 +
| They always appear in the social tab (including their name).
 +
|}
  
You can also use a new utility method to construct items from their <samp>QualifiedItemID</samp>:
+
Defaults to <samp>UnknownUntilMet</samp>.
 +
|-
 +
| <samp>SpouseAdopts</samp>
 +
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether the player will need to adopt children with this spouse, instead of either the player or NPC giving birth. If null, defaults to true for same-gender and false for opposite-gender spouses.
  
<syntaxhighlight lang="c#">
+
The <samp>Target</samp> player is the one they're married to.
Item item = Utility.CreateItemByID("(B)505"); // Rubber Boots
+
|-
</syntaxhighlight></li>
+
| <samp>SpouseWantsChildren</samp>
</ul>
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether the spouse will ask to have children. Defaults to true.
  
===Other ID changes===
+
The <samp>Target</samp> player is the one they're married to.
Many other things in the game now have unique string IDs too (including [[#Buff overhaul|buffs]], [[#String event IDs|events]], and fruit trees). To migrate existing code:
+
|-
 +
| <samp>SpouseGiftJealousy</samp>
 +
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether the [[Marriage#Jealousy|spouse will get jealous of gifts to other NPCs]]. Defaults to true.
  
* When referencing numeric IDs, you usually just need to convert them into a string (like <code>Game1.player.hasBuff("1590166")</code> or <code>Game1.player.eventsSeen.Contains("1590166")</code>).
+
The <samp>Target</samp> player is the one they're married to, and the <samp>Target</samp> item is the one that was gifted.
* When creating buffs, see [[#Buff overhaul|buff overhaul]] for how to create buffs now.
+
|-
 
+
| <samp>SpouseGiftJealousyFriendshipChange</samp>
===Building and animal changes===
+
| ''(Optional)'' The [[Friendship|friendship point]] effect when the <samp>SpouseGiftJealously</samp> is triggered. Default -30.
: ''See also: [[#Build anywhere|build anywhere in what's new]].''
+
|-
 +
| <samp>SpouseRoom</samp>
 +
| ''(Optional)'' The [[Marriage#Spouse Rooms|NPC's spouse room]] in the farmhouse when the player marries them, if applicable. If this is omitted for a marriageable NPC, they'll use Abigail's spouse room by default.
  
* Since all locations now allow buildings and animals, mod code which handles <samp>BuildableGameLocation</samp> and <samp>IAnimalLocation</samp> won't detect all buildable locations. You can replace them with <samp>location.IsBuildableLocation()</samp> (or just access <samp>location.buildings</samp> directly) and <samp>location.animals.Any()</samp> instead. Mods should no longer have any reference at all to <samp>BuildableGameLocation</samp> and <samp>IAnimalLocation</samp>.
+
This consists of a model with these fields:
* Since buildings can be built anywhere, you can no longer assume a building is on the farm. You can check the new <samp>building.buildingLocation</samp> field instead.
 
* You should review direct references to the farm (like <code>Game1.getFarm()</code> or <code>Game1.getLocationFromName("Farm")</code>) to see if it needs to be rewritten to allow location.
 
* <code>Utility.numSilos()</code> should no longer be used to calculate available hay, since it doesn't account for custom buildings with hay storage. Use <code>Game1.getFarm().GetHayCapacity()</code> instead.
 
* The <samp>Cat</samp> and <samp>Dog</samp> classes are now unused; all pets are now <samp>Pet</samp> directly.
 
 
 
===Player changes===
 
: ''See also: [[#Buff overhaul|buff overhaul in what's new]].''
 
 
 
<ul>
 
<li>Several <samp>Game1.player</samp> / <samp>Farmer</samp> fields changed as part of the [[#Buff overhaul|buff overhaul]]:
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! old field
+
! field
! how to migrate
+
! effect
 
|-
 
|-
| <samp>appliedBuffs</samp><br /><samp>appliedSpecialBuffs</samp>
+
| <samp>MapAsset</samp>
| Use <code>Game1.player.hasBuff(id)</code> instead.
+
| ''(Optional)'' The asset name for the spouse room map. The <samp>Map/</samp> prefix is added automatically and shouldn't be included. Defaults to <samp>spouseRooms</samp>.
 
|-
 
|-
| <samp>attack</samp><br /><samp>immunity</samp>
+
| <samp>MapSourceRect</samp>
| Use <samp>Attack</samp> and <samp>Immunity</samp> instead.
+
| ''(Optional)'' The tile area within the <samp>MapAsset</samp> containing the spouse's room. This should usually be a 6x9 tile area, though the game will try to adjust to a different size. Specified as a model with <samp>X</samp>, <samp>Y</samp>, <samp>Width</samp>, and <samp>Height</samp> fields. Defaults to <samp>(0, 0, 6, 9)</samp>.
|-
+
|}
| <samp>addedCombatLevel</samp><br /><samp>addedFarmingLevel</samp><br /><samp>addedFishingLevel</samp><br /><samp>addedForagingLevel</samp><br /><samp>addedLuckLevel</samp><br /><samp>addedMiningLevel</samp><br /><samp>attackIncreaseModifier</samp><br /><samp>critChanceModifier</samp><br /><samp>critPowerModifier</samp><br /><samp>knockbackModifier</samp><br /><samp>resilience</samp><br /><samp>weaponPrecisionModifier</samp><br /><samp>weaponSpeedModifier</samp>
 
| Use equivalent properties under <samp>Game1.player.buffs</samp> instead (e.g. <samp>Game1.player.buffs.CombatLevel</code>).
 
 
|-
 
|-
| <samp>addedSpeed</samp><br /><samp>CombatLevel</samp><br /><samp>CraftingTime</samp><br /><samp>FarmingLevel</samp><br /><samp>FishingLevel</samp><br /><samp>ForagingLevel</samp><br /><samp>LuckLevel</samp><br /><samp>MagneticRadius</samp><br /><samp>MaxStamina</samp><br /><samp>MiningLevel</samp><br /><samp>Stamina</samp>
+
| <samp>SpousePatio</samp>
| These are now readonly and can't be set directly. You can change them by [[#Buff overhaul|adding a buff]], equipment bonus, etc instead.
+
| ''(Optional)'' The [[Marriage#Spouse Outside Area|NPC's patio area]] on the farm when the player marries them, if any. Default none.
|}</li>
 
<li>Buffs are now recalculated automatically, and you can reset a buff by just reapplying it. See [[#Buff overhaul|buff overhaul]] for more info.</li>
 
<li>Buff logic has been centralized into <samp>Game1.player.buffs</samp>. This replaces a number of former fields/methods like <samp>Game1.buffsDisplay</samp>.</li>
 
</ul>
 
 
 
===Collision changes===
 
The game's tile collision logic has been overhauled and merged into a simpler set of methods on <samp>GameLocation</samp> instances:
 
  
 +
This consists of a model with these fields:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! method
+
! field
 
! effect
 
! effect
 
|-
 
|-
| <samp>CanSpawnCharacterHere</samp>
+
| <samp>MapAsset</samp>
| Get whether NPCs can be placed on the given tile (e.g. it's within the map bounds and tile is walkable), '''and''' there's no placed object (even if walkable like flooring) and the <samp>NoFurniture</samp> [[Modding:Maps|tile property]] isn't set.
+
| ''(Optional)'' The asset name for the patio area. The <samp>Map/</samp> prefix is added automatically and shouldn't be included. Defaults to <samp>spousePatios</samp>.
 
|-
 
|-
| <samp>CanItemBePlacedHere</samp>
+
| <samp>MapSourceRect</samp>
| Get whether items can be placed on the given tile in non-floating form (e.g. it's within the map bounds and not blocked by a non-walkable item). If the <samp>item_is_passable</samp> argument is true, this ignores players/NPCs on the tile.
+
| ''(Optional)'' The tile area within the <samp>MapAsset</samp> containing the spouse's patio area. This must be a 4x4 tile area. Specified as a model with <samp>X</samp>, <samp>Y</samp>, <samp>Width</samp>, and <samp>Height</samp> fields. Defaults to <samp>(0, 0, 4, 4)</samp>.
 
|-
 
|-
| <samp>isBuildable</samp>
+
| <samp>SpriteAnimationFrames</samp>
| Get whether buildings can be placed on the given tile.
+
| ''(Optional)'' The spouse's animation frames when they're in the patio. Each frame is an array containing [0] the sprite index in their spritesheet, and [1] the optional duration in milliseconds (default 100). If omitted or empty, the NPC won't be animated.
 +
 
 +
For example, here is Abigail playing the flute:
 +
<syntaxhighlight lang="js">
 +
"SpriteAnimationFrames": [
 +
    [16, 500], // show index 16 for 500ms
 +
    [17, 500],
 +
    [18, 500],
 +
    [19]      // if duration is omitted, defaults to 100ms
 +
]
 +
</syntaxhighlight>
 
|-
 
|-
| <samp>IsTilePassable</samp>
+
| <samp>SpriteAnimationPixelOffset</samp>
| Get whether the tile can be walked on (ignoring collisions with in-game objects, NPCs, etc).
+
| ''(Optional)'' The pixel offset to apply to the NPC's sprite when they're animated in the patio, specified as a model with <samp>X</samp> and <samp>Y</samp> fields. This is ignored if the NPC isn't animated via <samp>SpriteAnimationFrames</samp>. Default none.
 +
|}
 
|-
 
|-
| <samp>IsTileOccupiedBy</samp>
+
| <samp>SpouseFloors</samp><br /><samp>SpouseWallpapers</samp>
| Get whether the tile contains a player, object, NPC/monster/pet/etc, terrain feature, building, etc. You can specify <code>ignore_passables: false</code> to ignore objects which can be walked over (like flooring), and override <samp>collision_mask</samp> to change the collision logic (e.g. <code>collision_mask: GameLocation.CollisionMask.All & ~GameLocation.CollisionMask.Farmers</code> to ignore players on the tile).
+
| ''(Optional)'' The floors and wallpapers which the NPC may randomly apply to the farmhouse when married to the player. If omitted or empty, the NPC will randomly choose a base floor (0–39) or wallpaper (0–111).
 
|-
 
|-
| <samp>IsTileBlockedBy</samp>
+
| <samp>IntroductionsQuest</samp>
| Equivalent to calling both <samp>IsTilePassable</samp> and <samp>IsTileOccupiedBy</samp>.
+
| ''(Optional)'' Whether to include this NPC in [[Quests#List of Story Quests|the ''introductions'' quest]]. If <samp>null</samp> (or omitted), this will default to true if the <samp>HomeRegion</samp> field is set to <samp>Town</samp>.
 
|-
 
|-
| <samp>IsLocationSpecificOccupantOnTile</samp><br /><samp>IsLocationSpecificPlacementRestriction</samp>
+
| <samp>ItemDeliveryQuests</samp>
| Generally shouldn't be used directly. Checks for location-specific collisions (e.g. ladders in [[The Mines|the mines]] or parrot platforms on [[Ginger Island]]).
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this NPC can give item delivery quests. If <samp>null</samp> (or omitted), this will default to true if the <samp>HomeRegion</samp> field is set to <samp>Town</samp>.
|}
 
  
===Check for obsolete code===
+
The NPC must also be social per <samp>CanSocialize</samp> to allow it, regardless of this value.
Perform a full rebuild of your mod (in Visual Studio, click ''Build > Rebuild Solution''), then check the Error List pane for any warnings like "'''X' is obsolete''". Anything from the vanilla game code which is marked obsolete won't work anymore and is only kept for save migrations. Usually the warning will include an explanation of what you should use instead.
+
|-
 +
| <samp>PerfectionScore</samp>
 +
| ''(Optional)'' Whether to include this NPC when checking whether the player has max friendships with every NPC for the perfection score. Default true.
  
==Breaking changes for content packs==
+
The NPC must also be social per <samp>CanSocialize</samp> to be counted, regardless of this value.
'''This section only describes how this update may break existing mods. See the ''what's new'' sections above for more info, including new functionality mods can use.'''
+
|-
 
+
| <samp>EndSlideShow</samp>
===Standardized data fields===
+
| ''(Optional)'' How the NPC appears in the end-game perfection slide show. Possible values:
1.6 standardizes the number of fields in data assets, and fixes inconsistencies between English and localized files. '''This is a major breaking change for content packs, and for C# mods which edit data assets.'''
+
{| class="wikitable"
 +
|-
 +
! value
 +
! effect
 +
|-
 +
| <samp>Hidden</samp>
 +
| The NPC doesn't appear in the slide show.
 +
|-
 +
| <samp>MainGroup</samp>
 +
| The NPC is added to the main group of NPCs which walk across the screen.
 +
|-
 +
| <samp>TrailingGroup</samp>
 +
| The NPC is added to the trailing group of NPCs which follow the main group.
 +
|}
  
Three examples illustrate the standardization:
+
Defaults to <samp>MainGroup</samp>.
 +
|-
 +
| <samp>FriendsAndFamily</samp>
 +
| ''(Optional)'' The NPC's closest friends and family, as a dictionary where the key is the other NPC's internal name and the value is an optional tokenizable string for the name to use in dialogue text (like 'mom'). Default none.
  
<ul>
+
This affects generic dialogue for revealing likes and dislikes to family members, and may affect <samp>inlaw_&lt;NPC&gt;</samp> dialogues. This isn't necessarily comprehensive.
<li><samp>Data/CookingRecipes</samp> had four fields in English, and a fifth field in other languages for the display name. The display name field is now required in English too.</li>
+
|}
<li><samp>Data/BigCraftables</samp> had an optional 9th field which indicates whether it's a lamp, and a 10th field for the display name. Even if it's empty, the 9th field is now required (note the extra <samp>/</samp> before the last field):
+
</dd>
<syntaxhighlight lang="json">
 
// before
 
"151": "Marble Brazier/500/-300/Crafting -9/Provides a moderate amount of light./true/true/0/Marble Brazier", // 9 fields
 
  
// after
+
<dt>Dumpster diving:</dt>
"151": "Marble Brazier/500/-300/Crafting -9/Provides a moderate amount of light./true/true/0//Marble Brazier" // 10 fields
+
<dd>
</syntaxhighlight></li>
+
{| class="wikitable"
<li><samp>Data/ObjectInformation</samp> had several optional fields at the end. These are now required even if empty:
+
|-
<syntaxhighlight lang="json">
+
! field
// before
+
! effect
"0": "Weeds/0/-1/Basic/Weeds/A bunch of obnoxious weeds."
+
|-
 +
| <samp>DumpsterDiveEmote</samp>
 +
| ''(Optional)'' The emote ID to show above the NPC's head when they see a player rummaging through trash. See [[Modding:event data#Emotes|emote IDs]]. If omitted or <samp>null</samp>, the default depends on the NPC's age: a child will show sad (28), a teen will show a question mark (8), and an adult will show angry (12).
 +
|-
 +
| <samp>DumpsterDiveFriendshipEffect</samp>
 +
| ''(Optional)'' The friendship point change if this NPC sees a player rummaging through trash. Default -25.
 +
|}</dd>
  
// after
+
<dt>Festivals:</dt>
"0": "Weeds/0/-1/Basic/Weeds/A bunch of obnoxious weeds.///"
+
<dd>
</syntaxhighlight></li>
+
{| class="wikitable"
</ul>
+
|-
 +
! field
 +
! effect
 +
|-
 +
| <samp>FlowerDanceCanDance</samp>
 +
| ''(Optional)'' Whether players can ask the NPC to dance at the Flower Dance festival. The possible values are <samp>true</samp> (can always ask), <samp>false</samp> (can never ask), or <samp>null</samp> (can ask if they're romanceable). Default <samp>null</samp>.
  
Existing mods which add entries without the now-required fields may cause errors and crashes. XNB mods which change data are likely universally broken.
+
If the NPC can dance, you should also add the [[Modding:NPC data#Overworld_sprites|dance sprite frames]] and <samp>FlowerDance_Decline</samp> [[Modding:Dialogue|dialogue text]]. You can optionally set the <samp>FlowerDance_Accept</samp> dialogue too (though NPCs have a default accept dialogue if not).
 +
|-
 +
| <samp>WinterStarParticipant</samp>
 +
| ''(Optional)''  A [[Modding:Game state queries|game state query]] which indicates whether this NPC can give and receive gifts at the [[Feast of the Winter Star]]. If <samp>null</samp> (or omitted), this will default to true if the <samp>HomeRegion</samp> field is set to <samp>Town</samp>.
 +
|-
 +
| <samp>WinterStarGifts</samp>
 +
| At the [[Feast of the Winter Star]], the possible gifts this NPC can give to players. A matching entry is selected at random.
  
The exception is fields which only exist for modding, like the texture + index overrides for [[#Custom items|custom items]]. These can typically be omitted.
+
This consists of a list of models with these fields:
 +
{| class="wikitable"
 +
|-
 +
! field
 +
! effect
 +
|-
 +
| ''common fields''
 +
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields.
  
===Event ID changes===
+
If set to an [[Modding:Item queries|item query]] which returns multiple items, one of them will be selected at random.
: ''See also: [[#String event IDs|string event IDs in what's new]].''
+
|}
 +
|}
  
Events now have unique string IDs.
+
<dt>Spawn rules:</dt>
 
+
<dd>
When creating an event:
+
{| class="wikitable"
<ul>
+
|-
<li>New events should use a globally unique ID in the form <samp>Your.ModId_EventName</samp>. Existing events should be fine as-is, but it may be worth migrating them to avoid future conflicts.</li>
+
! field
<li>Every non-fork event '''must''' have a precondition in its key (even if it's empty). For example, change <code>"Your.ModId_EventName": "..."</code> to <code>"Your.ModId_EventName/": "..."</code>. This is needed for the game to distinguish between events and fork scripts.
+
! effect
 
+
|-
<syntaxhighlight lang="js">
+
| <samp>UnlockConditions</samp>
"Example.ModId_EventName/": "...", // event: loaded automatically by the game
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether the NPC should be added to the world, checked when loading a save and when ending each day. This only affects whether the NPC is added when missing; returning false won't remove an NPC that's already been added. Defaults to true.
"SomeFork": "..."                  // event fork: ignored unless it's loaded through an event script
+
|-
</syntaxhighlight></li>
+
| <samp>SpawnIfMissing</samp>
</ul>
+
| ''(Optional)'' Whether to add this NPC to the world if they're missing (if the <samp>UnlockConditions</samp> match and <samp>HomeLocation</samp> is valid). Default true.
 
+
|-
===XNB impact===
+
| <samp>Home</samp>
Here's a summary of the XNB files which changed in Stardew Valley 1.6.
+
| ''(Optional)'' The default place where this NPC spawns and returns each day. If there are multiple entries, the first matching one is used.
 
 
This doesn't include...
 
* new files (since they won't impact existing mods);
 
* changes in non-English files;
 
* new fields when the vanilla entries didn't change (e.g. optional [[#Custom items|custom item fields]]).
 
 
 
Shorthand:
 
* 'broken' means removing new content or potentially important changes, or potentially causing significant display bugs. This is a broad category — the game may work fine without it or crash, depending how it uses that specific content.
 
* 'mostly unaffected' means mods will only be affected if they edit specific entries or fields.
 
* Blank means no expected impact for the vast majority of mods.
 
 
 
XNB mods are disproportionately affected since (a) they replace the entire file and (b) they're loaded through the MonoGame content pipeline which is less tolerant of format changes.
 
  
 +
This consists of a list of models with these fields:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! content file
+
! field
! changes
+
! effect
! XNB
 
! Content Patcher
 
 
|-
 
|-
| <samp>Buildings/houses</samp>
+
| <samp>ID</samp>
| fixed missing pixels
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the current list.
| ✘ will remove changes
 
| ✓ mostly unaffected
 
 
|-
 
|-
| <samp>Data/AquariumFish</samp>
+
| <samp>Location</samp>
| [[#Custom items|changed key type]], [[#Standardized data fields|standardized fields]]
+
| ''(Optional)'' The internal name for the home location where this NPC spawns and returns each day. Default none.
| '''✘ broken'''
 
| '''✘ likely broken'''
 
 
|-
 
|-
| <samp>Data/BigCraftablesInformation</samp>
+
| <samp>Tile</samp>
| [[#Custom items|changed key type]], [[#Standardized data fields|standardized fields]]
+
| ''(Optional)'' The tile position within the home location where this NPC spawns and returns each day. Specified as a model with <samp>X</samp> and <samp>Y</samp> fields. Defaults to <samp>(0, 0)</samp>.
| '''✘ broken'''
 
| '''✘ likely broken'''
 
 
|-
 
|-
| <samp>Data/Boots</samp>
+
| <samp>Direction</samp>
| [[#Custom items|changed key type]], added display name
+
| ''(Optional)'' The default direction the NPC faces when they start each day. The possible values are <samp>down</samp>, <samp>left</samp>, <samp>right</samp>, and <samp>up</samp>. Defaults to <samp>up</samp>.
| '''✘ broken'''
 
| '''✘ likely broken'''
 
 
|-
 
|-
| <samp>Data/ClothingInformation</samp>
+
| <samp>Condition</samp>
| [[#Custom items|changed key type]], [[#Standardized data fields|standardized fields]]
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this entry can be selected. Default true.
| '''✘ broken'''
+
|}
| '''✘ likely broken'''
+
|}
 +
</dd>
 +
 
 +
<dt>Appearance & sprite:</dt>
 +
<dd>
 +
{| class="wikitable"
 +
|-
 +
! field
 +
! effect
 
|-
 
|-
| <samp>Data/CookingRecipes</samp>
+
| <samp>TextureName</samp>
| added display name
+
| ''(Optional)'' The '''last segment''' of the NPC's portrait and sprite asset names. For example, set to <samp>Abigail</samp> to use <samp>Portraits/Abigail</samp> and <samp>Characters/Abigail</samp> respectively. Defaults to the internal NPC name.
| '''✘ broken'''
 
| '''✘ likely broken'''
 
 
|-
 
|-
| <samp>Data/CraftingRecipes</samp>
+
| <samp>Appearance</samp>
| added display name
+
| ''(Optional)'' The portrait/sprite textures to use.
| '''✘ broken'''
+
 
| '''✘ likely broken'''
+
This can list any number of appearance options. They'll be sorted by <samp>Precedence</samp> value (with lower values taking priority), then filtered to those whose fields match. If multiple matching appearances have precedence, one entry is randomly chosen based on their relative weight. This randomization is stable per day, so the NPC always makes the same choice until the next day. If a portrait/sprite can't be loaded (or no appearances match), the NPC will use the default asset based on <samp>TextureName</samp>.
 +
 
 +
The NPC rechecks this field each time they change location.
 +
 
 +
This consists of a list of models with these fields:
 +
{| class="wikitable"
 
|-
 
|-
| <samp>Data/Crops</samp>
+
! field
| [[#Custom items|changed key type]]
+
! effect
| '''✘ broken'''
 
|
 
 
|-
 
|-
| <samp>Data/Events/IslandSouth</samp>
+
| <samp>Id</samp>
| fixed typo
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the current list.
| ✘ will remove changes
 
| ✓ mostly unaffected
 
 
|-
 
|-
| <samp>Data/Fish</samp>
+
| <samp>Season</samp>
| [[#Custom items|changed key type]]
+
| ''(Optional)'' The season in which this appearance should be used (one of <samp>spring</samp>, <samp>summer</samp>, <samp>fall</samp>, or <samp>winter</samp>), or omit for any season. Defaults to any season.
| '''✘ broken'''
 
|
 
 
|-
 
|-
| <samp>Data/FishPondData</samp>
+
| <samp>Indoors</samp><br /><samp>Outdoors</samp>
| [[#Custom items|changed <samp>ItemID</samp> field type]]
+
| ''(Optional)'' Whether this appearance should be used when indoors and/or outdoors. Both default to true.
| '''✘ broken'''
 
|
 
 
|-
 
|-
| <samp>Data/fruitTrees</samp>
+
| <samp>Condition</samp>
| [[#Custom items|changed key type]]
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this entry can be selected. Default true.
| '''✘ broken'''
 
|
 
 
|-
 
|-
| <samp>Data/Furniture</samp>
+
| <samp>Portrait</samp><br /><samp>Sprite</samp>
| [[#Custom items|changed key type]], [[#Standardized data fields|standardized fields]], added display name
+
| ''(Optional)'' The asset name for the portraits and/or sprites texture to load. If omitted or it can't be loaded, it will default to the default asset per the <samp>Texture</samp> field.
| '''✘ broken'''
 
| '''✘ likely broken'''
 
 
|-
 
|-
| <samp>Data/hats</samp>
+
| <samp>IsIslandAttire</samp>
| [[#Custom items|changed key type]], [[#Standardized data fields|standardized fields]], added display name
+
| ''(Optional)'' Whether this is island beach attire worn at the resort. Default false.
| '''✘ broken'''
+
 
| '''✘ likely broken'''
+
This is mutually exclusive: NPCs will never wear it in other contexts if it's true, and will never wear it as island attire if it's false.
 
|-
 
|-
| <samp>Data/ObjectContextTags</samp>
+
| <samp>Precedence</samp>
| added new entries & tags
+
| ''(Optional)'' The order in which this entry should be checked, where lower values are checked first. This can be a negative value. Default 0.
| '''✘ broken'''
 
| mostly unaffected<br /><small>(for content packs using best practices like appending<br />values, or which only edit their own items)</small>
 
 
|-
 
|-
| <samp>Data/ObjectInformation</samp>
+
| <samp>Weight</samp>
| [[#Custom items|changed key type]], [[#Standardized data fields|standardized fields]]
+
| ''(Optional)'' If multiple entries with the same <samp>Precedence</samp> match, the relative weight to use when randomly choosing one. Default 1.
| '''✘ broken'''
+
 
| '''✘ likely broken'''
+
For example, let's say two appearance entries match: one has a weight of 2, and the other has a weight of 1. Their probability of being chosen is 2/3 and 1/3 respectively.
 +
|}
 +
 
 +
'''Note:''' the default textures based on <samp>TextureName</samp> must still exist, even if you use this field to override them.
 
|-
 
|-
| <samp>Data/weapons</samp>
+
| <samp>MugShotSourceRect</samp>
| [[#Custom items|changed key type]], added display name
+
| ''(Optional)'' The 16x24-pixel area in the character's sprite texture to show as their mug shot icon in the calendar, social menu, and other contexts. Defaults to part of their first sprite.
| '''✘ broken'''
 
| '''✘ likely broken'''
 
 
|-
 
|-
| <samp>LooseSprites/Cursors2</samp>
+
| <samp>Size</samp>
| new sprite in empty area
+
| ''(Optional)'' The pixel size of the individual sprites in their overworld sprite spritesheet. Specified as a model with <samp>X</samp> and <samp>Y</samp> fields. Defaults to <samp>(16, 32)</samp>.
| '''✘ broken'''
+
 
|
+
'''Note:''' sizes bigger than 16×32 will cause issues like broken spawning, pathfinding, misalignment in the [[perfection]] end-game slide show, etc.
 
|-
 
|-
| <samp>Maps/AbandonedJojaMart</samp>
+
| <samp>Breather</samp>
| [[#Other changes|changed map & tile properties to string]]
+
| ''(Optional)'' Whether the chest on the NPC's overworld sprite puffs in and out as they breathe. Default true</samp>.
|
 
|
 
 
|-
 
|-
| <samp>Maps/AnimalShop</samp>
+
| <samp>BreathChestRect</samp>
| added <samp>Music</samp> map property
+
| ''(Optional)'' A [[Modding:Common data field types#Rectangle|rectangle]] pixel area within the spritesheet which expands and contracts to simulate breathing, relative to the top-left corner of the source rectangle for their current sprite. Omit to calculate it automatically. This should be omitted for most NPCs, unless they have a non-standard size.
| '''✘ broken'''
 
|
 
 
|-
 
|-
| <samp>Maps/Backwoods</samp><br /><samp>Maps/Backwoods_GraveSite</samp><br /><samp>Maps/Backwoods_Staircase</samp><br /><samp>Maps/Barn</samp><br /><samp>Maps/Barn2</samp>
+
| <samp>BreathChestPosition</samp>
| [[#Other changes|changed map & tile properties to string]]
+
| ''(Optional)'' A [[Modding:Common data field types#Point|point]] pixel offset to apply to the NPC's <samp>BreathChestPosition</samp> when drawn over the NPC. Omit to calculate it automatically. This should be omitted for most NPCs, unless they have a non-standard size.
|
 
|
 
 
|-
 
|-
| <samp>Maps/Barn3</samp>
+
| <samp>Shadow</samp>
| [[#Other changes|changed map & tile properties to string]], added <samp>AutoFeed</samp> map property
+
| ''(Optional)'' The options for the shadow to draw under the NPC, or omit to apply the default shadow behavior.
| '''✘ broken'''
+
 
|
+
This consists of a model with these fields:
 +
 
 +
{| class="wikitable"
 
|-
 
|-
| <samp>Maps/BathHouse_Pool</samp>
+
! field
| added <samp>Music</samp> map property
+
! effect
| '''✘ broken'''
 
|
 
 
|-
 
|-
| <samp>Maps/Beach</samp>
+
| <samp>Visible</samp>
| added <samp>DefaultCrabPotArea</samp> + <samp>LegendaryFishAreaCorners</samp> + <samp>Music</samp> + <samp>MusicIgnoreInRain</samp> map properties
+
| ''(Optional)'' Whether the shadow should be drawn. Default true.
| '''✘ broken'''
 
|
 
 
|-
 
|-
| <samp>Maps/Beach-NightMarker</samp>
+
| <samp>Offset</samp>
| added <samp>DefaultCrabPotArea</samp> + <samp>DefaultFishingArea</samp> map properties
+
| ''(Optional)'' A [[Modding:Common data field types#Point|point]] pixel offset applied to the shadow position. Default zero.
| '''✘ broken'''
 
|
 
 
|-
 
|-
| <samp>Maps/BoatTunnel</samp>
+
| <samp>Scale</samp>
| [[#Other changes|changed map & tile properties to string]], added <samp>DefaultCrabPotArea</samp> map property
+
| ''(Optional)'' The scale at which to draw the shadow. Default 1.
| '''✘ broken'''
+
 
|
+
This is a multiplier applied to the default shadow scale, which can change based on factors like whether the NPC is jumping. For example, <samp>0.5</samp> means half the size it'd be drawn if you didn't specify a scale.
 +
|}
 
|-
 
|-
| <samp>Maps/Cabin</samp><br /><samp>Maps/Cabin1</samp><br /><samp>Maps/Cabin1_marriage</samp><br /><samp>Maps/Cabin2</samp><br /><samp>Maps/Cabin2_marriage</samp>
+
| <samp>EmoteOffset</samp>
| [[#Other changes|changed map & tile properties to string]]
+
| ''(Optional)'' A [[Modding:Common data field types#Point|point]] pixel offset applied to emote drawn over the NPC. Default zero.
|
 
|
 
 
|-
 
|-
| <samp>Maps/Caldera</samp>
+
| <samp>ShakePortraits</samp>
| added <samp>Music</samp> map property
+
| ''(Optional)'' The portrait indexes which should shake when displayed. Default none.
| '''✘ broken'''
 
|
 
 
|-
 
|-
| <samp>Maps/Club</samp>
+
| <samp>KissSpriteIndex</samp>
| added <samp>LocationContext</samp> map property
+
| ''(Optional)'' If the NPC can be married, the sprite index within their <samp>Texture</samp> to use when kissing a player. Default 28.
| '''✘ broken'''
 
|
 
 
|-
 
|-
| <samp>Maps/Coop</samp><br /><samp>Maps/Coop2</samp>
+
| <samp>KissSpriteFacingDirection</samp>
| [[#Other changes|changed map & tile properties to string]]
+
| ''(Optional)'' Whether the character is facing right (true) or left (false) in their <samp>KissSpriteIndex</samp>. The sprite will be flipped as needed to face the player. Default true.
|
+
|}
|
+
</dd>
 +
 
 +
<dt>[[Secrets#Gift Log|Hidden gift log emote]]:</dt>
 +
<dd>
 +
{| class="wikitable"
 
|-
 
|-
| <samp>Maps/Coop3</samp>
+
! field
| [[#Other changes|changed map & tile properties to string]], added <samp>AutoFeed</samp> map property
+
! effect
| '''✘ broken'''
 
|
 
 
|-
 
|-
| <samp>Maps/Desert</samp>
+
| <samp>HiddenProfileEmoteSound</samp>
| added <samp>LocationContext</samp> map property
+
| ''(Optional)'' For the [[Secrets#Gift Log|hidden gift log emote]], the [[#Custom audio|cue ID]] for the sound played when clicking the sprite. Defaults to <samp>drumkit6</samp>.
| '''✘ broken'''
 
|
 
 
|-
 
|-
| <samp>Maps/ElliottHouse</samp>
+
| <samp>HiddenProfileEmoteDuration</samp>
| added <samp>Music</samp> map property
+
| ''(Optional)'' For the [[Secrets#Gift Log|hidden gift log emote]], how long the animation plays measured in milliseconds. Defaults to 4000 (4 seconds).
| '''✘ broken'''
 
|
 
 
|-
 
|-
| <samp>Maps/Farm</samp><br /><samp>Maps/Farm_Combat</samp>
+
| <samp>HiddenProfileEmoteStartFrame</samp>
| [[#Other changes|changed map & tile properties to string]], updated farmhouse area for moveable farmhouse
+
| ''(Optional)'' For the [[Secrets#Gift Log|hidden gift log emote]], the index within the NPC's overworld sprite spritesheet at which the animation starts. If omitted for a vanilla NPC, the game plays a default animation specific to that NPC; if omitted for a custom NPC, the game just shows them walking while facing down.
| ✘ corrupted visuals when farmhouse is moved
 
|
 
 
|-
 
|-
| <samp>Maps/Farm_Fishing</samp><br /><samp>Maps/Farm_Foraging</samp><br /><samp>Maps/Farm_FourCorners</samp>
+
| <samp>HiddenProfileEmoteFrameCount</samp>
| [[#Other changes|changed map & tile properties to string]], added <samp>DefaultFishingArea</samp> map property, updated farmhouse area for moveable farmhouse
+
| ''(Optional)'' For the [[Secrets#Gift Log|hidden gift log emote]], the number of frames in the animation. The first frame corresponds to <samp>HiddenProfileEmoteStartFrame</samp>, and each subsequent frame will use the next sprite in the spritesheet. Default 1.
| '''✘ broken'''
+
 
|
+
This has no effect if <samp>HiddenProfileEmoteStartFrame</samp> isn't set.
 
|-
 
|-
| <samp>Maps/Farm_Greenhouse_Dirt</samp><br /><samp>Maps/Farm_Greenhouse_Dirt_FourCorners</samp>
+
| <samp>HiddenProfileEmoteFrameDuration</samp>
| [[#Other changes|changed map & tile properties to string]]
+
| ''(Optional)'' For the [[Secrets#Gift Log|hidden gift log emote]], how long each animation frame is shown on-screen before switching to the next one, measured in milliseconds. Default 200.
|
+
 
|
+
This has no effect if <samp>HiddenProfileEmoteStartFrame</samp> isn't set.
 +
|}
 +
</dd>
 +
 
 +
<dt>Advanced:</dt>
 +
<dd>
 +
{| class="wikitable"
 
|-
 
|-
| <samp>Maps/Farm_Island</samp>
+
! field
| [[#Other changes|changed map & tile properties to string]], added <samp>DefaultFishingArea</samp> + <samp>DefaultCrabPotArea</samp> map properties, updated farmhouse area for moveable farmhouse
+
! effect
| '''✘ broken'''
 
|
 
 
|-
 
|-
| <samp>Maps/Farm_Mining</samp>
+
| <samp>CustomFields</samp>
| [[#Other changes|changed map & tile properties to string]], added <samp>DefaultFishingArea</samp> map property, updated farmhouse area for moveable farmhouse
+
| The [[#Custom data fields|custom fields]] for this entry.
| '''✘ broken'''
 
|
 
 
|-
 
|-
| <samp>Maps/FarmHouse</samp><br /><samp>Maps/FarmHouse_Bedroom_Normal</samp><br /><samp>Maps/FarmHouse_Bedroom_Open</samp><br /><samp>Maps/FarmHouse_Cellar</samp><br /><samp>Maps/FarmHouse_ChildBed_0</samp><br /><samp>Maps/FarmHouse_ChildBed_1</samp><br /><samp>Maps/FarmHouse_CornerRoom_Add</samp><br /><samp>Maps/FarmHouse_CornerRoom_Remove</samp><br /><samp>Maps/FarmHouse_SouthernRoom_Add</samp><br /><samp>Maps/FarmHouse_SouthernRoom_Remove</samp><br /><samp>Maps/FarmHouse1</samp><br /><samp>Maps/FarmHouse1_marriage</samp><br /><samp>Maps/FarmHouse2</samp><br /><samp>Maps/FarmHouse2_marriage</samp>
+
| <samp>FormerCharacterNames</samp>
| [[#Other changes|changed map & tile properties to string]]
+
| ''(Optional)'' The former NPC names which may appear in save data. If matched, the game will rename the NPC and update related data (e.g. friendship).
|
+
 
|
+
A former name is only applied if:
 +
# it doesn't match a current ID in <samp>Data/Characters</samp>;
 +
# the save has an NPC with the former name;
 +
# the save doesn't already have an NPC with the new name.
 +
 
 +
For example:
 +
<syntaxhighlight lang="js">
 +
"FormerCharacterNames": [ "SomeOldName" ]
 +
</syntaxhighlight>
 +
 
 +
Former names can have any format, but they must be '''globally''' unique. They can't match the ID or <samp>FormerCharacterNames</samp> of any other NPC in <samp>Data/Characters</samp> (whether vanilla or custom).
 
|-
 
|-
| <samp>Maps/Forest</samp>
+
| <samp>FestivalVanillaActorIndex</samp>
| added <samp>DefaultFishingArea</samp> + <samp>FishingAreaCorners</samp> + <samp>LegendaryFishAreaCorners</samp> map properties
+
| ''(Optional, Specialized)'' The NPC's index in the <samp>Maps/characterSheet</samp> tilesheet, if applicable. This is used for placing vanilla NPCs in festivals from the map; custom NPCs should use the <samp>&lt;layer&gt;_additionalCharacters</samp> field in the festival data instead.
| '''✘ broken'''
+
|}
|
+
</dd>
|-
+
</dl>
| <samp>Maps/Greenhouse</samp>
+
 
| [[#Other changes|changed map & tile properties to string]]
+
====Examples====
|
+
For example, this content pack adds a new ''Amabel'' NPC with full social features:
|
+
 
|-
+
{{#tag:syntaxhighlight|<nowiki>
| <samp>Maps/Hospital</samp>
+
{
| added <samp>Music</samp> and <samp>MusicIgnoreInRain</samp> map properties
+
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
| '''✘ broken'''
+
    "Changes": [
|
+
        {
|-
+
            "Action": "EditData",
| <samp>Maps/Island_W</samp>
+
            "Target": "Data/Characters",
| added <samp>LegendaryFishAreaCorners</samp> and <samp>FishingAreaCorners</samp> map property
+
            "Entries": {
| '''✘ broken'''
+
                "{{ModId}}_Amabel": {
|
+
                    "DisplayName": "Amabel", // this would normally use {{i18n:}} to support translations
|-
+
                    "BirthSeason": "Fall",
| <samp>Maps/IslandFarmHouse</samp>
+
                    "BirthDay": 14,
| [[#Other changes|changed map & tile properties to string]]
+
                    "HomeRegion": "Town",
|
+
                    "Gender": "Female",
|
+
                    "Age": "Teen",
|-
+
                    "Manner": "Rude",
| <samp>Maps/JojaMart</samp>
+
                    "SocialAnxiety": "Outgoing",
| added <samp>Music</samp> and <samp>MusicContext</samp> map properties
+
                    "Optimism": "Neutral",
| '''✘ broken'''
+
 
|
+
                    "CanBeRomanced": true,
|-
+
                    "LoveInterest": "Abigail",
| <samp>Maps/LeahHouse</samp><br /><samp>Maps/LeoTreeHouse</samp>
+
 
| added <samp>Music</samp> map property
+
                    "Home": [
| '''✘ broken'''
+
                        {
|
+
                            "Id": "Default",
|-
+
                            "Location": "SeedShop",
| <samp>Maps/MarnieBarn</samp><br /><samp>Maps/Mine</samp>
+
                            "Tile": { "X": 1, "Y": 9 },
| [[#Other changes|changed map & tile properties to string]]
+
                            "Direction": "Left"
|
+
                        }
|
+
                    ]
 +
                }
 +
            }
 +
        }
 +
    ]
 +
}</nowiki>|lang=javascript}}
 +
 
 +
You can also add non-social NPCs which don't have birthdays or friendship points, accept gifts, give quests, etc:
 +
{{#tag:syntaxhighlight|<nowiki>
 +
{
 +
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
 +
    "Changes": [
 +
        {
 +
            "Action": "EditData",
 +
            "Target": "Data/Characters",
 +
            "Entries": {
 +
                "{{ModId}}_Belwick": {
 +
                    "DisplayName": "Belwick", // this would normally use {{i18n:}} to support translations
 +
 
 +
                    "SocialTab": "HiddenAlways",
 +
                    "CanSocialize": "FALSE",
 +
                    "IntroductionsQuest": false,
 +
                    "PerfectionScore": false,
 +
                    "EndSlideShow": true
 +
                }
 +
            }
 +
        }
 +
    ]
 +
}</nowiki>|lang=javascript}}
 +
 
 +
===Custom NPC appearance===
 +
{{/doc status|[[Modding:NPC data]]|done=false}}
 +
 
 +
Each NPC can now have any number of custom portraits/sprites in <samp>Data/Characters</samp> with arbitrary conditions. This lets mods add features like indoor/outdoor outfits without the performance impact of reloading textures. If multiple outfits apply, the game will choose between them with a day-stable randomization.
 +
 
 +
For example, you can load indoor/outdoor outfits for a custom NPC to swap between automatically:
 +
<syntaxhighlight lang="js">
 +
// add base indoor/outdoor sprites
 +
{
 +
    "Action": "Load",
 +
    "Target": "Characters/Johnny_Indoor, Characters/Johnny_Outdoor, Portraits/Johnny_Indoor, Portraits/Johnny_Outdoor",
 +
    "FromFile": "assets/{{Target}}.png"
 +
},
 +
 
 +
// apply any overlays needed
 +
{
 +
    "Action": "EditImage",
 +
    "Target": "Characters/Johnny_Indoor, Portraits/Johnny_Indoor",
 +
    "FromFile": "assets/overlays/{{Target}}_married.png",
 +
    "When": {
 +
        "Spouse": "Johnny"
 +
    }
 +
},
 +
 
 +
// add NPC
 +
{
 +
    "Action": "EditData",
 +
    "Target": "Data/Characters",
 +
    "Entries": {
 +
        "SomeMod.Id_Johnny": {
 +
            ...,
 +
            "Appearance": [
 +
                {
 +
                    "Id": "Outdoors",
 +
                    "Indoors": false,
 +
                    "Portrait": "Portraits/Johnny_Outdoor",
 +
                    "Sprite": "Characters/Johnny_Outdoor"
 +
                },
 +
                {
 +
                    "Id": "Default",
 +
                    "Portrait": "Portraits/Johnny_Indoor",
 +
                    "Sprite": "Characters/Johnny_Indoor"
 +
                }
 +
            ]
 +
        }
 +
    }
 +
}
 +
</syntaxhighlight>
 +
 
 +
See the <samp>Appearance</samp> field in [[#Custom NPCs|custom NPC data]] for more info.
 +
 
 +
===Custom farm animals===
 +
{{/doc status|[[Modding:Animal data]]|done=true}}
 +
 
 +
You can now create and edit [[Animals|farm animals]] by editing the revamped <samp>Data/FarmAnimals</samp> asset. This changes to a data model, adds built-in support for custom animals, and allows far more customizability per animal (like its size, growth, produce, appearance and sounds, etc).
 +
 
 +
===Custom pets===
 +
{{/doc status|a new doc page|done=false}}
 +
 
 +
====Format====
 +
You can now create and customize [[Animals#Cat or Dog|pet]]s & pet breeds by editing the new <samp>Data/Pets</samp> asset.
 +
 
 +
This consists of a string → model lookup, where...
 +
* The key is a [[Modding:Common data field types#Unique string ID|unique string ID]] for the pet (not the pet breed). The vanilla IDs are <samp>Cat</samp> and <samp>Dog</samp>.
 +
* The value is a model with the fields listed below.
 +
 
 +
=====Basic info=====
 +
{| class="wikitable"
 
|-
 
|-
| <samp>Maps/Mountain</samp>
+
! field
| [[#Other changes|changed map & tile properties to string]], added <samp>LegendaryFishAreaCorners</samp> map property
+
! effect
| '''✘ broken'''
 
|
 
 
|-
 
|-
| <samp>Maps/MovieTheater</samp><br /><samp>Maps/MovieTheaterScreen</samp>
+
| <samp>DisplayName</samp>
| [[#Other changes|changed map & tile properties to string]]
+
| A [[Modding:Tokenizable strings|tokenizable string]] for the pet type's display name (e.g. "cat" or "dog"). For example, the vanilla adoption events show this when Marnie asks if you want to adopt the cat/dog.
|
+
|}
|
+
 
 +
=====Audio & sprites=====
 +
{| class="wikitable"
 
|-
 
|-
| <samp>Maps/paths</samp>
+
! field
| added icon for [[#Custom wild trees|custom wild tree spawn]]
+
! effect
|
 
|
 
 
|-
 
|-
| <samp>Maps/Saloon</samp>
+
| <samp>BarkSound</samp>
| added <samp>Music</samp> map property
+
| The [[#Custom audio|cue ID]] for the pet's occasional 'bark' sound.
| '''✘ broken'''
 
|
 
 
|-
 
|-
| <samp>Maps/SandyHouse</samp>
+
| <samp>ContentSound</samp>
| added <samp>LocationContext</samp> and <samp>Music</samp> map properties
+
| The [[#Custom audio|cue ID]] for the sound which the pet makes when you pet it.
| '''✘ broken'''
 
|
 
 
|-
 
|-
| <samp>Maps/ScienceHouse</samp>
+
| <samp>RepeatContentSoundAfter</samp>
| added <samp>Music</samp> map property
+
| ''(Optional)'' The number of milliseconds until the <samp>ContentSound</samp> is repeated once. This is used by the dog, who pants twice when pet. Defaults to -1 (disabled).
| '''✘ broken'''
 
|
 
 
|-
 
|-
| <samp>Maps/Sewer</samp>
+
| <samp>EmoteOffset</samp>
| added <samp>LegendaryFishAreaCorners</samp> map property
+
| ''(Optional)'' A pixel offset for the emote drawn above the pet sprite, specified as an object with <samp>X</samp> and <samp>Y</samp> fields. For example, this affects the heart emote shown after petting it. Default none.
| '''✘ broken'''
+
|}
|
+
 
 +
=====Events=====
 +
{| class="wikitable"
 
|-
 
|-
| <samp>Maps/Shed</samp>
+
! field
| added <samp>FloorIDs</samp> and <samp>WallIDs</samp> [[Modding:Maps|map properties]]
+
! effect
| '''✘ broken'''
 
|
 
 
|-
 
|-
| <samp>Maps/SkullCave</samp>
+
| <samp>EventOffset</samp>
| added <samp>LocationContext</samp> map property
+
| ''(Optional)'' The pixel offset for the pet when shown in events like Marnie's adoption event, specified as an object with <samp>X</samp> and <samp>Y</samp> fields. Default none.
| '''✘ broken'''
 
|
 
 
|-
 
|-
| <samp>Maps/spousePatios</samp>
+
| <samp>AdoptionEventLocation</samp><br /><samp>AdoptionEventId</samp>
| [[#Other changes|changed map & tile properties to string]]
+
| ''(Optional)'' If both fields are set, the location and [[Modding:Event data|event ID]] which lets the player adopt this pet. This forces the event to play after 20 days if its preconditions haven't been met yet. Default <samp>Farm</samp> and none respectively.
|
 
|
 
 
|-
 
|-
| <samp>Maps/Sunroom</samp>
+
| <samp>SummitPerfectionEvent</samp>
| [[#Other changes|changed map & tile properties to string]], added <samp>Music</samp> and <samp>MusicIgnoreInRain</samp> properties
+
| ''(Optional)'' How to render the pet during the summit [[perfection]] slideshow. If this isn't set, the pet won't be shown in the slideshow.
| '''✘ broken'''
+
 
|
+
This consists of a model with these fields:
 +
 
 +
{| class="wikitable"
 +
|-
 +
! field
 +
! effect
 +
|-
 +
| <samp>SourceRect</samp>
 +
| The source rectangle within the pet's texture to draw.
 +
|-
 +
| <samp>AnimationLength</samp>
 +
| The number of frames to show starting from the <samp>SourceRect</samp>.
 
|-
 
|-
| <samp>Maps/Town</samp>
+
| <samp>Motion</samp>
| added <samp>LegendaryFishAreaCorners</samp> and multiple <samp>Music*</samp> map properties
+
| The motion to apply to the pet sprite.
| '''✘ broken'''
 
|
 
 
|-
 
|-
| <samp>Maps/Mines/Volcano_SetPieces_32</samp>
+
| <samp>Flipped</samp>
| [[#Other changes|changed map & tile properties to string]]
+
| ''(Optional)'' Whether to flip the pet sprite left-to-right. Default false.
|
 
|
 
 
|-
 
|-
| <samp>Maps/Woods</samp>
+
| <samp>PingPong</samp>
| added <samp>Music</samp> and <samp>MusicIgnoreInRain</samp> map properties
+
| ''(Optional)'' Whether to apply the 'ping pong' effect to the pet sprite animation. Default false.
| '''✘ broken'''
+
|}
|
 
 
|}
 
|}
 +
 +
=====Gifts=====
 +
{| class="wikitable"
 +
|-
 +
! field
 +
! effect
 +
|-
 +
| <samp>GiftChance</samp>
 +
| ''(Optional)'' The random probability each day that the pet will give the player a gift from the <samp>Gifts</samp> list when they interact with the pet. Specified as a value between 0 (never) and 1 (always). Default .2 (20% chance).
 +
|-
 +
| <samp>Gifts</samp>
 +
| ''(Optional)'' The list of gifts that this pet can give if the <samp>GiftChance</samp> is successful. Default none.
 +
 +
This consists of a list of models with these fields:
 +
 +
{| class="wikitable"
 +
|-
 +
! field
 +
! effect
 +
|-
 +
| <samp>Id</samp>
 +
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the list.
 +
|-
 +
| <samp>QualifiedItemID</samp>
 +
| The [[Modding:Common data field types#Item ID|qualified item ID]] for the gift item to create.
 +
|-
 +
| <samp>Stack</samp>
 +
| ''(Optional)'' The stack size of the gift item to produce. Default 1.
 +
|-
 +
| <samp>MinimumFriendshipThreshold</samp>
 +
| ''(Optional)'' The friendship level that this pet must be at before it can give this gift. Defaults to 1000 (max friendship).
 +
|-
 +
| <samp>Weight</samp>
 +
| ''(Optional)'' The option's weight when randomly choosing a gift, relative to other gifts in the list (e.g. <samp>2</samp> is twice as likely as <samp>1</samp>). Default 1.
 +
|}
 +
|}
 +
 +
=====Behavior=====
 +
{| class="wikitable"
 +
|-
 +
! field
 +
! effect
 +
|-
 +
| <samp>Id</samp>
 +
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the list.
 +
|-
 +
| <samp>MoveSpeed</samp>
 +
| ''(Optional)'' How quickly the pet can move. Default 2.
 +
|-
 +
| <samp>SleepOnBedChance</samp><br /><samp>SleepNearBedChance</samp><br /><samp>SleepOnRugChance</samp>
 +
| ''(Optional)'' The percentage chances for the locations where the pet will sleep each night, as a decimal value between 0 (never) and 1 (always). Each value is checked in the order listed at left until a match is found. If none of them match, the pet will choose a random empty spot in the farmhouse; if none was found, it'll sleep next to its pet bowl outside.
 +
|-
 +
| <samp>Behaviors</samp>
 +
| The pet's possible actions and behaviors, defined as the states in a state machine. Essentially the pet will be in one state at any given time, which also determines which state they can transition to next. For example, a cat can transition from <samp>Walk</samp> to <samp>BeginSitDown</samp>, but it can't skip instantly from <samp>Walk</samp> to <samp>SitDownLick</samp>.
 +
 +
This consists of a list of models with these fields:
 +
 +
<dl>
 +
<dt>Required fields:</dt>
 +
<dd>
 +
{| class="wikitable"
 +
|-
 +
! field
 +
! effect
 +
|-
 +
| <samp>Id</samp>
 +
| A unique ID for the state. This only needs to be unique within the pet type (e.g. <samp>Cat</samp> and <samp>Dog</samp> can have different behaviors with the same ID).
 +
|}
 +
</dd>
 +
 +
<dt>Direction:</dt>
 +
<dd>
 +
{| class="wikitable"
 +
|-
 +
! field
 +
! effect
 +
|-
 +
| <samp>Direction</samp>
 +
| ''(Optional)'' The specific direction to face at the start of this state (one of <samp>left</samp>, <samp>right</samp>, <samp>up</samp>, or <samp>down</samp>), unless overridden by <samp>RandomizeDirection</samp>.
 +
|-
 +
| <samp>RandomizeDirection</samp>
 +
| ''(Optional)'' Whether to point the pet in a random direction at the start of this state (overriding the <samp>Direction</samp> if specified). Default false.
 +
|-
 +
| <samp>IsSideBehavior</samp>
 +
| ''(Optional)'' Whether to constrain the pet's facing direction to left and right while the state is active. Default false.
 +
|}
 +
</dd>
 +
 +
<dt>Movement:</dt>
 +
<dd>
 +
{| class="wikitable"
 +
|-
 +
! field
 +
! effect
 +
|-
 +
| <samp>WalkInDirection</samp>
 +
| ''(Optional)'' Whether to walk in the pet's facing direction. Default false.
 +
|-
 +
| <samp>MoveSpeed</samp>
 +
| ''(Optional)'' Overrides the pet's <samp>MoveSpeed</samp> field while this state is active. Default -1 (which uses the pet's <samp>MoveSpeed</samp> value).
 +
|}
 +
</dd>
 +
 +
<dt>Audio:</dt>
 +
<dd>
 +
{| class="wikitable"
 +
|-
 +
! field
 +
! effect
 +
|-
 +
| <samp>SoundOnStart</samp>
 +
| ''(Optional)'' The [[#Custom audio|audio cue ID]] for the sound to play when the state starts. If set to <samp>BARK</samp>, the pet's <samp>BarkSound</samp> (or breed's <samp>BarkOverride</samp>) field is used. Defaults to none.
 +
|-
 +
| <samp>SoundRange</samp><br /><samp>SoundRangeFromBorder</samp>
 +
| ''(Optional)'' When set, the <samp>SoundOnStart</samp> is only audible if the pet is within this many tiles away from the player (<samp>SoundRange</samp>) or past the border of the screen (<samp>SoundRangeFromBorder</samp>). Default -1 (no distance check).
 +
|-
 +
| <samp>SoundIsVoice</samp>
 +
| ''(Optional)'' Whether to mute the <samp>SoundOnStart</samp> when the 'mute animal sounds' option is set. Default false.
 +
|}
 +
</dd>
 +
 +
<dt>Behavior transitions:</dt>
 +
<dd>
 +
{| class="wikitable"
 +
|-
 +
! field
 +
! effect
 +
|-
 +
| <samp>AnimationEndBehaviorChanges</samp><br /><samp>TimeoutBehaviorChanges</samp><br /><samp>PlayerNearbyBehaviorChanges</samp><br /><samp>RandomBehaviorChanges</samp><br /><samp>JumpLandBehaviorChanges</samp>
 +
| ''(Optional)'' A list of possible behavior transitions to start when the criteria are achieved. If multiple transitions are listed, a random one will be selected. If omitted, it won't affect behavior transitions.
 +
 +
These are triggered when this behavior's animation finishes (<samp>AnimationEndBehaviorChanges</samp>), when the set duration ends (<samp>TimeoutBehaviorChanges</samp>), when the player is within 2 tiles of the pet (<samp>PlayerNearbyBehaviorChanges</samp>), randomly at the start of each frame based on the <samp>RandomBehaviorChangeChance</samp> field (<samp>RandomBehaviorChanges</samp>), and when the pet finishes a jump (<samp>JumpLandBehaviorChanges</samp>).
 +
 +
These consist of a list of models with these fields:
 +
{| class="wikitable"
 +
|-
 +
! field
 +
! effect
 +
|-
 +
| <samp>Behavior</samp><br /><samp>LeftBehavior</samp><br /><samp>RightBehavior</samp><br /><samp>UpBehavior</samp><br /><samp>DownBehavior</samp>
 +
| The ID of the behavior to start. The pet will check for a behavior field matching its current facing direction first, then try the <samp>Behavior</samp>. If none are specified, the current behavior will continue unchanged.
 +
|-
 +
| <samp>OutsideOnly</samp>
 +
| ''(Optional)'' Whether the transition can only happen if the pet is outside. Default false.
 +
|-
 +
| <samp>Weight</samp>
 +
| ''(Optional)'' The option's weight when randomly choosing a behavior, relative to other behaviors in the list (e.g. <samp>2</samp> is twice as likely as <samp>1</samp>). Default 1.
 +
|}
 +
|-
 +
| <samp>Duration</samp><br /><samp>MinimumDuration</samp><br /><samp>MaximumDuration</samp>
 +
| ''(Optional)'' The millisecond duration until the pet transitions to a behavior in the <samp>TimeoutBehaviorChanges</samp> field, if set. You must specify either a specific duration, or an inclusive minimum-to-maximum range in which the game will choose a random duration. If omitted, the behavior won't have a duration limit.
 +
|-
 +
| <samp>RandomBehaviorChangeChance</samp>
 +
| ''(Optional)'' The random probability at the start of each frame that the pet will transition to a behavior in the <samp>RandomBehaviorChanges</samp> field, if set. Specified as a value between 0 (never) and 1 (always). Default 0.
 +
|}
 +
</dd>
 +
 +
<dt>Animation and per-frame sounds:</dt>
 +
<dd>
 +
{| class="wikitable"
 +
|-
 +
! field
 +
! effect
 +
|-
 +
| <samp>Animation</samp>
 +
| ''(Optional)'' The animation frames to play while this state is active. This consists of a list of models with these fields:
 +
{| class="wikitable"
 +
|-
 +
! field
 +
! effect
 +
|-
 +
| <samp>Frame</samp>
 +
| The frame index in the animation. This should be an incremental number starting at 0.
 +
|-
 +
| <samp>Duration</samp>
 +
| The millisecond duration for which the frame should be kept on-screen before continuing to the next frame.
 +
|-
 +
| <samp>HitGround</samp>
 +
| ''(Optional)'' Whether to play the footstep sound for the tile under the pet when the frame starts. Default false.
 +
|-
 +
| <samp>Jump</samp>
 +
| ''(Optional)'' Whether the pet should perform a small hop when the frame starts, including a 'dwop' sound. Default false.
 +
|-
 +
| <samp>Sound</samp>
 +
| ''(Optional)'' The [[#Custom audio|audio cue ID]] for the sound to play when the animation starts or loops. If set to <samp>BARK</samp>, the pet's <samp>BarkSound</samp> (or breed's <samp>BarkOverride</samp>) field is used. Defaults to none.
 +
|-
 +
| <samp>SoundRange</samp><br /><samp>SoundRangeFromBorder</samp><br /><samp>SoundIsVoice</samp>
 +
| See description for the equivalent behavior fields, but applies to the frame's <samp>Sound</samp> field instead.
 +
|}
 +
|-
 +
| <samp>Shake</samp>
 +
| ''(Optional)'' The millisecond duration for which to shake the pet when the state starts. Default 0.
 +
|-
 +
| <samp>LoopMode</samp>
 +
| ''(Optional)'' What to do when the last animation frame is reached while the behavior is still active. The possible values are <samp>Hold</samp> (keep the last frame visible until the animation ends), <samp>Loop</samp> (restart from the first frame), or <samp>None</samp> (equivalent to <samp>Loop</samp>). Default <samp>None</samp>.
 +
|-
 +
| <samp>AnimationMinimumLoops</samp><br /><samp>AnimationMaximumLoops</samp>
 +
| ''(Optional)'' The minimum and maximum number of times to play the animation. Both must be specified to have any effect. The game will choose an inclusive random value between them. Both default to -1 (don't repeat animation).
 +
|}
 +
</dd>
 +
</dl>
 +
|}
 +
 +
=====Breeds=====
 +
{| class="wikitable"
 +
|-
 +
! field
 +
! effect
 +
|-
 +
| <samp>Breeds</samp>
 +
| The cosmetic breeds which can be selected in the character customization menu when creating a save. This consists of a list of models with these fields:
 +
{| class="wikitable"
 +
|-
 +
! field
 +
! effect
 +
|-
 +
| <samp>ID</samp>
 +
| The unique ID for the breed within the pet type.
 +
|-
 +
| <samp>Texture</samp>
 +
| The asset name for the breed spritesheet for the pet's in-game sprite. This should be 128 pixels wide, and 256 (cat) or 288 (dog) pixels high.
 +
|-
 +
| <samp>IconTexture</samp>
 +
| The asset name for the breed icon texture, shown on the character customization screen and in-game menu. This should be a 16x16 pixel icon.
 +
|-
 +
| <samp>IconSourceRect</samp>
 +
| The icon's pixel area within the <samp>IconTexture</samp>, specified as an object with <samp>X</samp>, <samp>Y</samp>, <samp>Width</samp>, and <samp>Height</samp> fields.
 +
|-
 +
| <samp>BarkOverride</samp>
 +
| ''(Optional)'' Override the pet's <samp>BarkSound</samp> field for this breed, if set.
 +
|-
 +
| <samp>VoicePitch</samp>
 +
| ''(Optional)'' The [[wikipedia:Pitch (music)|pitch]] applied to the pet's bark sound, measured as a decimal value relative to 1. Defaults to 1.
 +
|}
 +
|}
 +
 +
=====Advanced=====
 +
{| class="wikitable"
 +
|-
 +
! field
 +
! effect
 +
|-
 +
| <samp>CustomFields</samp>
 +
| The [[#Custom data fields|custom fields]] for this entry.
 +
|}
 +
 +
====Other changes====
 +
* The pet bowl is now a building which can be constructed or moved. Each pet is assigned to an available pet bowl. For C# mods, each pet now has a <samp>guid</samp> field populated with a unique ID, and each pet bowl has a <samp>petGuid</samp> field which tracks its owner (see the <samp>PetBowl::HasPet()</samp> and <samp>PetBowl::FindPet()</samp> methods).
 +
* In the [[Modding:Event data#Basic format|event character setup]], you can now use <samp>pet</samp> to add a pet of the player's selected type. Its actor name will be <samp>PetActor</samp> in other event commands. This supersedes <samp>cat</samp> (with name <samp>Cat</samp>) and <samp>dog</samp> (with name <samp>Dog</samp>), though those still work too.
 +
* For C# mods:
 +
** All pets now use a generic <samp>Pet</samp> class, instead of <samp>Cat</samp> or <samp>Dog</samp>. The pet type is tracked by the pet's <samp>petType</samp> field.
 +
** The player's preferred pet type is tracked by <samp>Game1.player.whichPetType</samp>. The former <samp>catPerson</samp> field is now readonly and checks that field.
 +
** Added <samp>Pet.type_cat</samp> and <samp>Pet.type_dog</samp> constants for the default pet types.
 +
 +
===Custom monster eradication goals===
 +
{{/doc status|a new doc page|done=false}}
 +
 +
: ''See also: [[#Monster eradication goal flag changes|Monster eradication goal flag changes]].''
 +
 +
You can now add/edit [[Adventurer's Guild]] monster eradication goals by editing the new <samp>Data/MonsterSlayerQuests</samp> data asset.
 +
 +
This consists of a string → model lookup, where...
 +
* The key is a [[Modding:Common data field types#Unique string ID|unique string ID]] for the monster eradication goal.
 +
* The value is a model with the fields listed below.
 +
 +
{| class="wikitable"
 +
|-
 +
! field
 +
! effect
 +
|-
 +
| <samp>DisplayName</samp>
 +
| A [[Modding:Tokenizable strings|tokenizable string]] for the goal's display name, shown on the board in the Adventurer's Guild.
 +
|-
 +
| <samp>Targets</samp>
 +
| A list of [[Modding:Monster data#Monster IDs|monster IDs]] that are counted towards the <samp>Count</samp>.
 +
|-
 +
| <samp>Count</samp>
 +
| The total number of monsters (matching the <samp>Targets</samp>) which must be defeated to complete this goal.
 +
|-
 +
| <samp>RewardItemId</samp>
 +
| ''(Optional)'' The [[#Custom items|qualified ID]] for the item that can be collected from [[Gil]] when this goal is completed. Default none.
 +
|-
 +
| <samp>RewardItemPrice</samp>
 +
| ''(Optional)'' The price of the <samp>RewardItemId</samp> in [[Marlon]]'s shop after the goal is completed, or -1 to disable buying it from Marlon. Default -1.
 +
|-
 +
| <samp>RewardDialogue</samp><br /><samp>RewardDialogueFlag</samp>
 +
| ''(Optional)'' A [[Modding:Tokenizable strings|tokenizable string]] for custom [[Gil]] dialogue shown when talking to him after completing the goal, and an optional [[Modding:Mail data|mail flag]] to set when the player has seen the dialogue. Both default to none.
 +
 +
If there are reward items, they're shown after this dialogue.
 +
 +
If <samp>RewardDialogue</samp> is used without <samp>RewardDialogueFlag</samp>, then this dialogue will be shown each time the reward menu is opened after completing the goal, until the player collects the reward items. If the <samp>RewardItems</samp> isn't set, this can safely be omitted since the goal will be marked collected immediately.
 +
 +
This doesn't send a letter; see <samp>RewardMail</samp> or <samp>RewardMailAll</samp> for that.
 +
|-
 +
| <samp>RewardFlag</samp><br /><samp>RewardFlagAll</samp>
 +
| ''(Optional)'' The [[Modding:Mail data|mail flag ID]] to set for the current player (<samp>RewardFlag</samp>) or all players (<samp>RewardFlagAll</samp>) when talking to [[Gil]] after completing the goal. Default none.
 +
 +
Note that <samp>RewardFlag</samp> is usually not needed, since the game will also set a <samp>Gil_{{t|goal ID}}</samp> flag regardless.
 +
 +
This doesn't send a letter; see <samp>RewardMail</samp> or <samp>RewardMailAll</samp> for that.
 +
|-
 +
| <samp>RewardMail</samp><br /><samp>RewardMailAll</samp>
 +
| ''(Optional)'' The mail letter ID to add to the mailbox tomorrow for the current player (<samp>RewardMail</samp>) or all players (<samp>RewardMailAll</samp>). Default none.
 +
|-
 +
| <samp>CustomFields</samp>
 +
| The [[#Custom data fields|custom fields]] for this entry.
 +
|}
 +
 +
===Custom phone calls===
 +
{{/doc status|a new doc page|done=false}}
 +
 +
Mods can now extend the [[telephone]] with custom calls (both incoming calls, and phone numbers which the player can call).
 +
 +
====Incoming calls====
 +
You can add or customize incoming calls by editing the <samp>Data/IncomingPhoneCalls</samp> asset.
 +
 +
This consists of a string → model lookup, where...
 +
* The key is a [[Modding:Common data field types#Unique string ID|unique string ID]] for the incoming call data.
 +
* The value is a model with the fields listed below.
 +
 +
{| class="wikitable"
 +
|-
 +
! field
 +
! effect
 +
|-
 +
| <samp>Dialogue</samp>
 +
| The dialogue text to show when the player answers the phone. This can use the full [[Modding:Dialogue|dialogue format]] (including questions and different dialogue based on the selected answer).
 +
|-
 +
| <samp>FromNpc</samp>
 +
| ''(Optional)'' The internal name of the NPC making the call. If specified, that NPC's name and portrait will be shown.
 +
|-
 +
| <samp>FromPortrait</samp>
 +
| ''(Optional)'' The asset name for the portrait spritesheet to display (like <samp>Portraits/Abigail</samp>). If <samp>FromNpc</samp> is specified too, this overrides the portrait from that NPC. If both <samp>FromNpc</samp> and <samp>FromDisplayName</samp> are null, this portrait will be shown with the display name "???".
 +
|-
 +
| <samp>FromDisplayName</samp>
 +
| ''(Optional)'' A [[Modding:Tokenizable strings|tokenizable string]] for the calling NPC's display name. If <samp>FromNpc</samp> is specified too, this overrides the display name from that NPC.
 +
|-
 +
| <samp>MaxCalls</samp>
 +
| ''(Optional)'' The maximum number of times a player can receive this phone call, or <samp>-1</samp> for no limit. Default 1.
 +
|-
 +
| <samp>TriggerCondition</samp><br /><samp>RingCondition</samp>
 +
| ''(Optional)'' If set, a game state query which indicates whether to trigger this phone call (<samp>TriggerCondition</samp>) or whether the phone rings when this call is received (<samp>RingCondition</samp>).
 +
 +
Whether a player receives this call depends on both fields: <samp>TriggerCondition</samp> is checked on the main player before sending the call to all players, then <samp>RingCondition</samp> is checked on each player to determine whether the phone rings for them.
 +
|-
 +
| <samp>IgnoreBaseChance</samp>
 +
| ''(Optional)'' Whether to ignore the 1% base chance when checking whether to trigger an incoming call. If true, the game will check if this call can be received regardless of the base chance. Default false.
 +
|-
 +
| <samp>SimpleDialogueSplitBy</samp>
 +
| ''(Optional, specialized)'' If set, marks the call as having a simple dialogue string without an NPC name and portrait, with lines split into multiple boxes by this substring. For example, <code>"SimpleDialogueSplitBy": "#"</code> will split <code>Box A#Box B#Box C</code> into three consecutive dialogue boxes.
 +
 +
You should omit this in most cases, and use the regular dialogue format in <samp>Dialogue</samp> to split lines if needed. This is mainly intended to support some older vanilla phone calls.
 +
|-
 +
| <samp>CustomFields</samp>
 +
| The [[#Custom data fields|custom fields]] for this entry.
 +
|}
 +
 +
====Custom handlers in C#====
 +
C# mods can implement <samp>StardewValley.PhoneCalls.IPhoneHandler</samp> and add it to <samp>Phone.PhoneHandlers</samp> for full control over both incoming and outgoing calls:
 +
 +
<syntaxhighlight lang="c#">
 +
/// <summary>The mod entry point.</summary>
 +
internal sealed class ModEntry : Mod
 +
{
 +
    /// <inheritdoc />
 +
    public override void Entry(IModHelper helper)
 +
    {
 +
        Phone.PhoneHandlers.Add(new CustomPhoneHandler());
 +
    }
 +
}
 +
 +
/// <summary>A custom phone handler.</summary>
 +
internal sealed class CustomPhoneHandler : IPhoneHandler
 +
{
 +
    ...
 +
}
 +
</syntaxhighlight>
 +
 +
See <samp>StardewValley.PhoneCalls.DefaultPhoneHandler</samp> in the [[Modding:Modder Guide/Get Started#decompile|decompiled game code]] for an example implementation.
 +
 +
===Custom shops===
 +
{{/doc status|[[Modding:Shops]]|done=true}}
 +
 +
You can now create and edit shops via the new <samp>Data/Shops</samp> asset. See [[Modding:Shops]] for documentation and examples.
 +
 +
===Dialogue changes===
 +
{{/doc status|[[Modding:Dialogue]]|done=false}}
 +
 +
<ul>
 +
<li>Added new [[Modding:Dialogue|dialogue]] keys:
 +
{| class="wikitable"
 +
|-
 +
! asset
 +
! key format
 +
! description
 +
|-
 +
|rowspan="22"| <samp>Characters/Dialogue/&lt;name&gt;</samp>
 +
|-
 +
| <samp>AcceptBirthdayGift_{{t|id}}</samp><br /><samp>AcceptBirthdayGift_{{t|tag}}</samp><br /><samp>AcceptBirthdayGift_{{t|taste}}</samp><br /><samp>AcceptBirthdayGift_Negative</samp><br /><samp>AcceptBirthdayGift_Positive</samp><br /><samp>AcceptBirthdayGift</samp>
 +
| Shown when receiving a birthday gift from the player. If omitted, defaults to the generic translations for all NPCs.
 +
 +
The first matching dialogue is used in this order:
 +
# by item ID (like <samp>AcceptBirthdayGift_(O)128</samp>);
 +
# by context tag (like <samp>AcceptBirthdayGift_category_fish</samp>);
 +
# by gift taste (one of <samp>AcceptBirthdayGift_Loved</samp>, <samp>AcceptBirthdayGift_Liked</samp>, <samp>AcceptBirthdayGift_Neutral</samp>, <samp>AcceptBirthdayGift_Disliked</samp>, or <samp>AcceptBirthdayGift_Hated</samp>);
 +
# <samp>AcceptBirthdayGift_Negative</samp> (hated or disliked gift) or <samp>AcceptBirthdayGift_Positive</samp> (neutral, liked, or loved gift);
 +
# for all items (via <samp>AcceptBirthdayGift</samp>).
 +
 +
|-
 +
| <samp>AcceptBouquet</samp>
 +
| Shown when the NPC accepts a [[bouquet]] from the player. Defaults to a generic dialogue.
 +
|-
 +
| <samp>AcceptGift_{{t|id}}</samp><br /><samp>AcceptGift_{{t|tag}}</samp>
 +
| Shown when receiving a non-birthday gift from the player. This can be by item ID (like <samp>AcceptGift_(O)128</samp>) or context tag (like <samp>AcceptGift_category_fish</samp>). If omitted, defaults to the dialogue in <samp>Data/NPCGiftTastes</samp>.
 +
|-
 +
| <samp>DumpsterDiveComment</samp>
 +
| Shown when the NPC catches the player digging through a trash can. Defaults to a generic dialogue based on the NPC's age.
 +
|-
 +
| <samp>HitBySlingshot</samp>
 +
| Shown when the player shoots them with a [[slingshot]]. Defaults to a generic dialogue.
 +
|-
 +
| <samp>RejectBouquet_Divorced</samp><br /><samp>RejectBouquet_NotDatable</samp><br /><samp>RejectBouquet_NpcAlreadyMarried</samp><br /><samp>RejectBouquet_VeryLowHearts</samp><br /><samp>RejectBouquet_LowHearts</samp><br /><samp>RejectBouquet</samp>
 +
| Shown when the NPC rejects a [[bouquet]].
 +
 +
A specific dialogue is shown if possible:
 +
* <samp>RejectBouquet_Divorced</samp>: the NPC won't accept this bouquet because you divorced them.
 +
* <samp>RejectBouquet_NotDatable</samp>: the NPC isn't romanceable.
 +
* <samp>RejectBouquet_NpcAlreadyMarried</samp>: the NPC is already married to another player. You can use <samp>{0}</samp> in the dialogue for the other player's name.
 +
* <samp>RejectBouquet_VeryLowHearts</samp>: you have less than 4 hearts with the NPC.
 +
* <samp>RejectBouquet_LowHearts</samp>: you have less than 8 hearts with the NPC.
 +
 +
If the specific dialogue isn't set, the game will use the <samp>RejectBouquet</samp> dialogue (if set), else it'll default to generic dialogue for each case.
 +
|-
 +
| <samp>RejectGift_Divorced</samp>
 +
| Shown when the NPC rejects a gift because you divorced them.
 +
|-
 +
| <samp>RejectItem_{{t|id}}</samp><br /><samp>RejectItem_{{t|tag}}</samp>
 +
| If set, the NPC will refuse to accept any matching item and show this dialogue instead. This can be by item ID (like <samp>RejectItem_(O)128</samp>) or context tag (like <samp>RejectItem_category_fish</samp>). This can prevent gifting, movie tickets, bouquets, mermaid pendants, etc. However it won't prevent accepting an item for an active quest or special order.
 +
|-
 +
| <samp>RejectMermaidPendant_Divorced</samp><br /><samp>RejectMermaidPendant_NeedHouseUpgrade</samp><br /><samp>RejectMermaidPendant_NotDatable</samp><br /><samp>RejectMermaidPendant_NpcWithSomeoneElse</samp><br /><samp>RejectMermaidPendant_PlayerWithSomeoneElse</samp><br /><samp>RejectMermaidPendant_Under8Hearts</samp><br /><samp>RejectMermaidPendant_Under10Hearts</samp><br /><samp>RejectMermaidPendant_Under10Hearts_AskedAgain</samp><br /><samp>RejectMermaidPendant</samp>
 +
| Shown when the NPC rejects a [[Mermaid's Pendant|mermaid's pendant]].
 +
 +
A specific dialogue is shown if possible. The cases are checked in this order:
 +
# <samp>RejectMermaidPendant_PlayerWithSomeoneElse</samp>: the player is already engaged or married to someone else. You can use <samp>{0}</samp> in the dialogue for the player's spouse name.
 +
# <samp>RejectMermaidPendant_NotDatable</samp>: the NPC isn't romanceable.
 +
# <samp>RejectMermaidPendant_Divorced</samp>: you divorced them, so they won't accept gifts or proposals from you.
 +
# <samp>RejectMermaidPendant_NpcWithSomeoneElse</samp>: the NPC is already engaged or married to someone else. You can use <samp>{0}</samp> in the dialogue for the other player's name.
 +
# <samp>RejectMermaidPendant_Under8Hearts</samp>: you have under 8 hearts with the NPC.
 +
# <samp>RejectMermaidPendant_Under10Hearts</samp>: you have under 10 hearts with the NPC.
 +
# <samp>RejectMermaidPendant_Under10Hearts_AskedAgain</samp>: you have under 10 hearts with the NPC, and asked again after they already said no. (Defaults to the previous dialogue if not set.)
 +
# <samp>RejectMermaidPendant_NeedHouseUpgrade</samp>: you need to upgrade your house before they can accept.
 +
 +
If the specific dialogue isn't set, the game will use the <samp>RejectMermaidPendant</samp> dialogue (if set), else it'll default to generic dialogue for each case.
 +
|-
 +
| <samp>RejectMovieTicket_AlreadyInvitedBySomeoneElse</samp><br /><samp>RejectMovieTicket_AlreadyWatchedThisWeek</samp><br /><samp>RejectMovieTicket_Divorced</samp><br /><samp>RejectMovieTicket_DontWantToSeeThatMovie</samp><br /><samp>RejectMovieTicket</samp>
 +
| Show when the NPC rejects a [[Movie Ticket|movie ticket]].
 +
 +
A specific dialogue is shown if possible:
 +
* <samp>RejectMovieTicket_AlreadyInvitedBySomeoneElse</samp>: someone else already invited the NPC to a movie. You can use <samp>{0}</samp> in the dialogue for the other player's name.
 +
* <samp>RejectMovieTicket_AlreadyWatchedThisWeek</samp>: the NPC already watched a movie this week.
 +
* <samp>RejectMovieTicket_Divorced</samp>: you divorced the NPC, so they won't accept gifts from you.
 +
* <samp>RejectMovieTicket_DontWantToSeeThatMovie</samp>: the movie data marks that NPC as unwilling to watch it (e.g. kids for horror movies).
 +
 +
If the specific dialogue isn't set, the game will use the <samp>RejectMovieTicket</samp> dialogue (if set), else it'll default to generic dialogue for each case.
 +
|-
 +
| <samp>SpouseFarmhouseClutter</samp>
 +
| Shown by an NPC spouse when they couldn't pathfind to their kitchen standing spot in the farmhouse.
 +
|-
 +
| <samp>SpouseGiftJealous</samp>
 +
| Shown by an NPC spouse when you gave a gift to another eligible NPC of the same gender as your spouse (unless it's their birthday). You can use <samp>{0}</samp> in the dialogue for the other NPC's name, and <samp>{1}</samp> for the gifted item name.
 +
|-
 +
| <samp>Spouse_MonstersInHouse</samp>
 +
| Shown by an NPC spouse when they're in the farmhouse and there's a monster close to them.
 +
|-
 +
| <samp>SpouseStardrop</samp>
 +
| Shown when receiving the [[stardrop]] from your spouse.
 +
|-
 +
| <samp>Fair_Judging</samp>
 +
| Shown at the [[Stardew Valley Fair]] while Lewis is judging the grange displays. If omitted, the NPC will keep their normal festival dialogue.
 +
 +
If this is set without <samp>Fair_Judged*</samp>, the NPC will keep this dialogue after judging is done.
 +
 +
''This replaces the previously hardcoded translations in <samp>Strings/StringsFromCSFiles</samp>: <samp>Event.cs.1602</samp> (Marnie), <samp>Event.cs.1604</samp> (Pierre), and <samp>Event.cs.1606</samp> (Willy).''
 +
|-
 +
| <samp>Fair_Judged_PlayerLost_PurpleShorts</samp><br /><samp>Fair_Judged_PlayerLost_Skipped</samp><br /><samp>Fair_Judged_PlayerLost</samp><br /><samp>Fair_Judged_PlayerWon</samp><br /><samp>Fair_Judged</samp>
 +
| Shown at the [[Stardew Valley Fair]] after Lewis finishes judging the grange displays.
 +
 +
The first matching dialogue is used in this order:
 +
# <samp>Fair_Judged_PlayerLost_PurpleShorts</samp>: the player put the [[Secrets#Lucky Purple Shorts|lucky purple shorts]] in their display (which is an automatic loss).  Defaults to <samp>Fair_Judged_PlayerLost</samp> if omitted.
 +
# <samp>Fair_Judged_PlayerLost_Skipped</samp>: the player didn't put anything in their display. Defaults to <samp>Fair_Judged_PlayerLost</samp> if omitted.
 +
# <samp>Fair_Judged_PlayerLost</samp> or <samp>Fair_Judged_PlayerWon</samp>: the player didn't/did win first place. Defaults to <samp>Fair_Judged</samp> if omitted.
 +
# <samp>Fair_Judged</samp>: shown if a more specific dialogue didn't match. If omitted, the NPC will keep their current dialogue.
 +
 +
''These replace the previously hardcoded translations in <samp>Strings/StringsFromCSFiles</samp>: <samp>Event.cs.1591</samp> (Pierre when he won), <samp>Event.cs.1593</samp> (Pierre when the player won), <samp>Event.cs.1595</samp> (Marnie), <samp>Event.cs.1597</samp> (Willy), and <samp>Event.cs.1600</samp> (Marnie for the purple shorts).''
 +
|-
 +
| <samp>FlowerDance_Accept_Roommate</samp><br /><samp>FlowerDance_Accept_Spouse</samp><br /><samp>FlowerDance_Accept</samp>
 +
| Shown at the [[Flower Dance]] when the NPC agrees to dance. The game will prefer the <samp>_Roommate</samp> (if roommates) or <samp>_Spouse</samp> (if married) variant if applicable, else it'll check for the normal key. If omitted, defaults to a generic accept dialogue.
 +
 +
''This replaces the previously hardcoded translations in <samp>Strings/StringsFromCSFiles</samp> (<samp>Event.cs.1613</samp>, <samp>Event.cs.1615</samp>, <samp>Event.cs.1617</samp>, <samp>Event.cs.1619</samp>, <samp>Event.cs.1621</samp>, <samp>Event.cs.1623</samp>, <samp>Event.cs.1625</samp>, <samp>Event.cs.1627</samp>, <samp>Event.cs.1629</samp>, and <samp>Event.cs.1631</samp>).''
 +
|-
 +
| <samp>FlowerDance_Decline</samp>
 +
| Shown at the [[Flower Dance]] when the NPC declines to dance. This replaces the former <samp>danceRejection</samp> key (which still works as a fallback).
 +
|-
 +
| <samp>WinterStar_GiveGift_Before_Roommate</samp><br /><samp>WinterStar_GiveGift_Before_Spouse</samp><br /><samp>WinterStar_GiveGift_Before</samp><br /><samp>WinterStar_GiveGift_After_Roommate</samp><br /><samp>WinterStar_GiveGift_After_Spouse</samp><br /><samp>WinterStar_GiveGift_After</samp>
 +
| Shown at the [[Feast of the Winter Star]] when the NPC gives the player their gift (before and after the player opens it). The game will prefer the <samp>_Roommate</samp> (if roommates) or <samp>_Spouse</samp> (if married) variant if applicable, else it'll check for the normal key. If omitted, the before/after dialogues each separately default to a generic translation for all NPCs.
 +
|-
 +
| <samp>WinterStar_ReceiveGift_{{t|id}}</samp><br /><samp>WinterStar_ReceiveGift_{{t|tag}}</samp><br /><samp>WinterStar_ReceiveGift</samp>
 +
| Shown at the [[Feast of the Winter Star]] when receiving their gift from the player. This can be by item ID (like <samp>WinterStar_ReceiveGift_(O)128</samp>), context tag (like <samp>WinterStar_ReceiveGift_category_fish</samp>), or for any item (like <samp>WinterStar_ReceiveGift</samp>). If omitted, defaults to the generic translation for all NPCs.
 +
|-
 +
| <samp>WipedMemory</samp>
 +
| Shown the first time you talk to the NPC after erasing their memory using the [[Dark Shrine of Memory]].
 +
|}
 +
</li>
 +
<li>Added new [[Modding:Dialogue|dialogue]] commands:
 +
{| class="wikitable"
 +
|-
 +
! command
 +
! description
 +
|- id="gender-switch"
 +
| <samp>${male^female}$</samp><br /><samp>${male^female^non-binary}$</samp>
 +
| Change text depending on the player's gender. This largely supersedes the <samp>^</samp> dialogue token (which still works), and is supported in many more places than that token. This is applied before most other commands or parsing, so it can safely be used in cases where <samp>^</samp> might have a different meaning (e.g. mail text). For example: <code>Ahoy there ${lad^lass}$!</code> or <code>Ahoy there ${lad^lass^matey}$!</code>.
 +
 +
You can optionally use <samp>¦</samp> instead of <samp>^</samp>, in which case any <samp>^</samp> characters are left as-is.
 +
 +
Note that 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.
 +
|-
 +
| <samp>$action {{t|action}}</samp>
 +
| Run a [[Modding:Trigger actions|trigger action string]], like <samp>$action AddMoney 500</samp> to add {{price|500}} to the current player.
 +
|-
 +
| <samp>$query {{t|query}}#{{t|if true}}&#124;{{t|if false}}</samp>
 +
| Show different dialogue text depending on the [[Modding:Game state queries|game state query]] in {{t|query}}. For example:
 +
<syntaxhighlight lang="js">
 +
"Mon": "$query !PLAYER_VISITED_LOCATION Current Mine#Did you know there's an old abandoned mine up in the mountain? Apparently it's crawling with monsters!|I heard you went into the old mines up in the mountain!#Did you find anything tasty?$h"
 +
</syntaxhighlight>
 +
|-
 +
| <samp>$t {{t|topic ID}} {{o|day length}}</samp>
 +
| Add a [[Modding:Dialogue#Conversation topics|conversation topic]] for the next {{o|day length}} days (default 4 days).
 +
|-
 +
| <samp>$v {{t|event id}} {{o|check preconditions}} {{o|skip if seen}}</samp>
 +
| Immediately start an [[Modding:Event data|event]] and end the current dialogue, subject to the conditions:
 +
* {{o|check preconditions}}: whether to ignore the command if the [[Modding:Event data#Event preconditions|event's preconditions]] don't match (one of <samp>true</samp> or <samp>false</samp>). Default true.
 +
* {{o|skip if seen}}: whether to ignore the command if the player has already seen the given event. Default true.
 +
 +
If the event is not played, the dialogue continues to the next line instead.
 +
 +
For example, <code>$v 60367 false false</code> will replay the bus arrival event from the start of the game. <code>$v SomeMod.Test true false#$b#Wow! Good timing!$1</code> will play the event "SomeMod.Test" if the player meets the precondition requirements. If they do not, the dialogue "Wow! Good timing!$1" will play instead. 
 +
 +
Note: The command will only work if it is at the very start of the dialogue. Adding any dialogue or other commands before it will cause it not to trigger the event and display the event commands as dialogue instead.
 +
|}
 +
</li>
 +
<li>Improved dialogue commands:
 +
{| class="wikitable"
 +
|-
 +
! command
 +
! changes
 +
|-
 +
| <samp>$p</samp>
 +
| You can now check multiple answer IDs. For example, this will show the first dialogue if the player chose dialogue answer 17, 18, or 19:
 +
<pre>$p 17|18|19#I guess you think nothing would happen, right?$u|Maybe a wicked ghost would appear!</pre>
 +
|}</li>
 +
<li>[[Modding:Dialogue#Response IDs|Dialogue response IDs]] are now [[Modding:Common data field types#Unique string ID|unique string IDs]].</li>
 +
<li>[[Secrets#Item Spawn Cheat|Item spawn codes]] now use string item IDs. That means you can spawn any item using its [[#Custom items|qualified item ID]] (like <code>[(F)1664]</code> for a [[Mystic Rug]]), but can no longer prepend zeros (e.g. <code>[128]</code> is a pufferfish but <code>[0128]</code> is an error item).</li>
 +
<li>For C# mods, <samp>Dialogue</samp> now tracks the translation key used to build it (when applicable). For example, you can detect when the player is rejected at the [[Flower Dance]] (derived from {{github|spacechase0/StardewValleyMods|Three-Heart Dance Partner}}):
 +
<syntaxhighlight lang="c#">
 +
private void OnMenuChanged(object sender, MenuChangedEventArgs e)
 +
{
 +
    bool isDanceRejection =
 +
        Game1.currentLocation?.currentEvent?.FestivalName == "Flower Dance"
 +
        && e.NewMenu is DialogueBox dialogueBox
 +
        && dialogueBox.characterDialogue is {} dialogue
 +
        && dialogue.TranslationKey == $"Characters\\Dialogue\\{dialogue.speaker?.Name}:danceRejection";
 +
}
 +
</syntaxhighlight>
 +
 +
For C# mods that create <samp>Dialogue</samp> instances directly, there's a few ways to do it now:
 +
<syntaxhighlight lang="c#">
 +
// from a translation key
 +
var dialogue = new Dialogue(npc, "Strings\\StringsFromCSFiles:Utility.cs.5360");
 +
 +
// from custom text (with or without a translation key)
 +
var dialogue = new Dialogue(npc, null, "Some arbitrary text to show as-is");
 +
 +
// from a translation with tokens
 +
var dialogue = Dialogue.FromTranslation(npc, "Data\\ExtraDialogue:PurchasedItem_2_QualityLow_Willy", whatToCallPlayer, particle, i.DisplayName);
 +
</syntaxhighlight>
 +
 +
You can also easily add fallback logic using <samp>Dialogue.TryGetDialogue</samp> or <samp>npc.TryGetDialogue</samp>. For example:
 +
<syntaxhighlight lang="c#">
 +
Dialogue dialogue =
 +
    npc.TryGetDialogue($"rejection_{itemId}_{locationName}_{x}_{y}")
 +
    ?? npc.TryGetDialogue($"rejection_{itemId}_{locationName}")
 +
    ?? npc.TryGetDialogue($"rejection_{itemId}")
 +
    ?? new Dialogue(npc, "Strings\\StringsFromCSFiles:NPC.cs.3971");
 +
</syntaxhighlight>
 +
</li>
 +
<li>For C# mods, added a <samp>dialogue.sideEffects</samp> field to run code when the dialogue is displayed.</li>
 +
<li>The 'reveal taste' dialogue command now uses the format <samp>%revealtaste:{{t|npc name}}:{{t|item ID}}</samp> to support item IDs. (The previous <samp>%revealtaste{{t|npc name}}{{t|item index}}</samp> format still works to support old content packs, but the item index can only be a number.)</li>
 +
<li>NPCs no longer override the portrait for a gift taste dialogue that uses a portrait command explicitly.</li>
 +
<li>Fixed unknown [[Modding:Dialogue|dialogue]] commands starting with <samp>$</samp> being parsed as a portrait number when not numeric.</li>
 +
<li>Fixed NPCs only using a <code>{day name}{hearts}_{year}</code> dialogue if they also have a <code>{day name}{hearts}</code> one.</li>
 +
<li>Fixed NPCs only using the <code>MovieInvitation</code> dialogue key in English.</li>
 +
</ul>
 +
 +
===Schedule changes===
 +
{{/doc status|[[Modding:Schedule data]]|done=false}}
 +
 +
<ul>
 +
<li>Schedule keys are now case-insensitive.</li>
 +
<li>Added a new <samp>{{t|day of week}}_{{t|min hearts}}</samp> schedule key.</li>
 +
<li>Added an <samp>NPC.ScheduleKey</samp> field which always matches their loaded schedule.</li>
 +
<li>Schedule commands now trim surrounding whitespace, so they can be multilined for readability. For example:
 +
<syntaxhighlight lang="js">"Wed": "
 +
    1000 ArchaeologyHouse 11 9 0/
 +
    1800 Town 47 87 0/
 +
    2200 SeedShop 1 9 3 abigail_sleep
 +
"</syntaxHighlight></li>
 +
<li>Removed an unintended schedule fallback to a <samp>{season}_spring_{hearts}</samp> key. It'll skip to the <samp>spring</samp> default instead.</li>
 +
<li>Schedules are now fault-tolerant:
 +
* Fixed crash if a selected schedule can't be parsed. The NPC now logs an error and continues with the next fallback instead.
 +
* Fixed crash if certain hardcoded schedules aren't present (like Penny's <samp>marriageJob</samp> or Pam's <samp>bus</samp>).
 +
* Fixed error if a schedule command is empty.</li>
 +
</ul>
 +
 +
===Other NPC changes===
 +
{{/doc status|[[Modding:NPC data]] as needed|done=false}}
 +
 +
<ul>
 +
<li>Added <samp>Game1.characterData</samp> and <samp>Game1.farmAnimalData</samp> to read NPC/animal info without constantly reloading the <samp>Data/Characters</samp> or <samp>Data/FarmAnimals</samp> asset.</li>
 +
<li>All translated NPC names are now in <samp>Strings/NPCNames</samp>.
 +
<li>Added new fields & methods for C# mods:
 +
 +
{| class="wikitable"
 +
|-
 +
! type
 +
! field/method
 +
! effect
 +
|-
 +
|rowspan="2"| <samp>AdventureGuild</samp>
 +
| <samp>IsComplete(data)</samp>
 +
| Get whether an [[Adventurer's Guild]] monster eradication goal has been completed, regardless of whether the player collected its rewards yet.
 +
|-
 +
| <samp>HasCollectedReward(player, id)</samp>
 +
| Get whether a given player has completed an [[Adventurer's Guild]] monster eradication goal and collected its rewards. For example:
 +
<syntaxhighlight lang="c#">
 +
bool isPhoneUnlocked = AdventureGuild.HasCollectedReward(Game1.player, "Gil_FlameSpirits");
 +
</syntaxhighlight>
 +
|-
 +
| <samp>AnimalHouse</samp>
 +
| <samp>adoptAnimal</samp>
 +
| Add an animal to this location and set the location as the animal's home.
 +
|-
 +
| <samp>AnimatedSprite</samp>
 +
| <samp>Owner</samp>
 +
| The NPC which owns the sprite.
 +
|-
 +
|rowspan="3"| <samp>Character</samp>
 +
| <samp>IsVillager</samp>
 +
| Whether this is an NPC-type villager (i.e. not a monster, horse, pet, player's child, etc). In other words, this checks whether the NPC would use data from <samp>Data/Characters</samp> (regardless of whether they currently have an entry in the asset).
 +
|-
 +
| <samp>StandingPixel</samp>
 +
| The character's cached pixel position within the current location, based on the center pixel of their bounding box.
 +
|-
 +
| <samp>Tile</samp><br /><samp>TilePoint</samp>
 +
| The character's cached tile position within their current location. <samp>Tile</samp> is their exact non-integer position, and <samp>TilePoint</samp> is their integer tile position.
 +
|-
 +
|rowspan="7"| <samp>FarmAnimal</samp>
 +
| <samp>isAdult</samp>
 +
| Get whether the farm animal is fully grown (opposite of <samp>isBaby()</samp>).
 +
|-
 +
| <samp>CanGetProduceWithTool</samp>
 +
| Get whether the farm animal's produce can be collected with a given tool (e.g. milk pail for a cow).
 +
|-
 +
| <samp>CanLiveIn</samp>
 +
| Get whether the animal can be added to a building.
 +
|-
 +
| <samp>GetDisplayName</samp><br /><samp>GetShopDescription</samp>
 +
| Get the translated display name or shop description for this animal.
 +
|-
 +
| <samp>GetHarvestType</samp>
 +
| Get whether the animal's produce is dropped or collected with a tool.
 +
|-
 +
| <samp>growFully</samp>
 +
| Instantly age the animal to adulthood if it's still a baby.
 +
|-
 +
| <samp>ReloadTextureIfNeeded</samp>
 +
| Update the animal sprite based on the current state + data.
 +
|-
 +
| rowspan="2"| <samp>Farmer</samp>
 +
| <samp>GetDisplayPants</samp><br /><samp>GetDisplayShirt</samp>
 +
| Get the texture and sprite index to draw for the player's pants or shirt. This accounts for override clothing, worn clothing, and the default clothing drawn when the farmer isn't wearing anything.
 +
 +
For example:
 +
<syntaxhighlight lang="c#">
 +
Game1.player.GetDisplayShirt(out Texture2D texture, out int spriteIndex);
 +
</syntaxhighlight>
 +
|-
 +
| <samp>CanDyePants</samp><br /><samp>CanDyeShirt</samp>
 +
| Get whether the currently equipped pants or shirt can be [[Dyeing|dyed]].
 +
|-
 +
| <samp>Monster</samp>
 +
| <samp>GetDisplayName(name)</samp>
 +
| Get the translated display name for a monster type.
 +
|-
 +
|rowspan="4"| <samp>NPC</samp>
 +
| <samp>CanReceiveGifts</samp>
 +
| Get whether this NPC can receive gifts from the player (regardless of whether they've already received one today).
 +
|-
 +
| <samp>GetData</samp><br /><samp>NPC.TryGetData</samp>
 +
| Get the underlying data from <samp>Data/Characters</samp> for this NPC, if any.
 +
|-
 +
| <samp>NPC.GetDisplayName(name)</samp>
 +
| Get the translated display name in the current language for an NPC by their internal name.
 +
|-
 +
| <samp>hasDarkSkin</samp>
 +
| Whether this character has dark skin for the purposes of child genetics.
 +
|-
 +
| <samp>Pet</samp>
 +
| <samp>GetPetData</samp><br /><samp>TryGetData</samp>
 +
| Get the underlying data from <samp>Data/Pets</samp> for this pet, if any.
 +
|-
 +
| <samp>ShopMenu</samp>
 +
| <samp>ShopId</samp>
 +
| A key which identifies the current shop. This may be the unique shop ID in <samp>Data/Shops</samp> for a standard shop, <samp>Dresser</samp> or <samp>FishTank</samp> for furniture, etc. This is guaranteed to be set to a relevant shop ID.
 +
 +
This replaces the former <samp>shopContext</samp> field, and will usually have the same value in cases where that was set to a unique shop ID.
 +
|-
 +
| <samp>Utility</samp>
 +
| <samp>getAllVillagers</samp>
 +
| Get all villager NPCs (excluding horses, pets, monsters, player children, etc). This works just like <samp>getAllCharacters</samp> with an added filter.
 +
|}
 +
</li>
 +
<li>NPCs now update on save loaded when their home data changes.</li>
 +
<li><samp>NPC.reloadSprite()</samp> now has an argument to only reload the appearance, without changing other data.</li>
 +
<li><samp>Utility.getAllCharacters()</samp> now returns a plain <samp>List&lt;NPC&gt;</samp> value instead of a custom <samp>DisposableList&lt;NPC&gt;</samp>, so you can use normal LINQ querying on it.</li>
 +
<li><samp>Utility.GetHorseWarpRestrictionsForFarmer(player)</samp> now returns an enum (which is more efficient and easier for mods to patch), and added a new <samp>Utility.GetHorseWarpErrorMessage(restrictions)</samp> method to get the error message to show for it.</li>
 +
<li><samp>Farmer.hasAFriendWithHeartLevel</samp> now has an optional max-hearts argument.</li>
 +
<li>Removed most <samp>FarmAnimal</samp> fields/properties which just mirror the underlying data.</li>
 +
<li>Removed invalid item IDs in <samp>Data/NPCGiftTastes</samp>.</li>
 +
<li>Fixed NPCs sometimes duplicated on save load (particularly if their home location changed).</li>
 +
<li>Fixed child NPCs like [[Jas]] or [[Vincent]] ignoring relative titles like "mom" in <samp>Data/NPCDispositions</samp> (now <samp>Data/Characters</samp>) for reveal-gift-taste dialogues.</li>
 +
<li>Fixed custom NPCs ignoring dialogue when they use a subclass of <samp>NPC</samp>.</li>
 +
<li>Fixed monsters not loading their display name from <samp>Data/Monsters</samp> for English players.</li>
 +
<li>Fixed player children not applying the <samp>IsInvisible</samp> flag.</li>
 +
</ul>
 +
 +
==What's new for everything else==
 +
===Buff overhaul===
 +
{{/doc status|a new doc page|done=false}}
 +
 +
: ''See also: [[#Custom buffs|custom buffs]].''
 +
 +
1.6 rewrites buffs to work more consistently and be more extensible:
 +
 +
* Buff logic is unified into <samp>Game1.player.buffs</samp>, which is the single source of truth for buff data. This replaces the previous <samp>player.added*</samp> and <samp>player.appliedBuffs</samp> fields, <samp>BuffsDisplay</samp> logic, enchantment stat bonuses, and boots/ring attribute changes on (un)equip.
 +
* This also removes limitations on buff types (e.g. buffs can add weapon bonuses and weapons can add attribute buffs) and buffable equipment (e.g. equipped tools can have buffs too).
 +
* Buff effects are now fully recalculated when they change, to fix a range of longstanding bugs like attribute drift and double-debuffs. Just like before, the buffs are managed locally; only the buff IDs and aggregate attribute effects are synced.
 +
 +
'''For C# mods:'''
 +
* Each buff now has a unique string ID. You can apply a new buff with the same ID to replace it (so you no longer need to manually find and remove previous instances of the buff).
 +
* The buff duration can now be set to <samp>Buff.ENDLESS</samp> to remove the duration. It'll last all day until the player sleeps.
 +
* You can add standard buff effects to any equipment by overriding <samp>Item.AddEquipmentEffects</samp>, or add custom behaviour/buffs by overriding <samp>Item.onEquip</samp> and <samp>Item.onUnequip</samp>.
 +
* You can add custom food or drink buffs by overriding <samp>Item.GetFoodOrDrinkBuffs()</samp>.
 +
* The <samp>Buff</samp> constructor now supports a custom icon texture, sprite index, display name, description, and millisecond duration to fully support custom buffs.
 +
* You can change how buff attributes are displayed (or add new attributes) by extending the <samp>BuffsDisplay.displayAttributes</samp> list.
 +
* You can have invisible buffs by setting <samp>buff.visible = false</samp>.
 +
 +
For example, here's how to add a custom buff which adds +3 speed:
 +
 +
<syntaxhighlight lang="c#">
 +
Buff buff = new Buff(
 +
    id: "Example.ModId_ZoomZoom",
 +
    displayName: "Zoom Zoom", // can optionally specify description text too
 +
    iconTexture: this.Helper.ModContent.Load<Texture2D>("assets/zoom.png"),
 +
    iconSheetIndex: 0,
 +
    duration: 30_000, // 30 seconds
 +
    effects: new BuffEffects()
 +
    {
 +
        Speed = { 10 } // shortcut for buff.Speed.Value = 10
 +
    }
 +
);
 +
Game1.player.applyBuff(buff);
 +
</syntaxhighlight>
 +
 +
You can also implement your own custom effects in code by checking if the buff is active, like <code>Game1.player.hasBuff("Example.ModId_ZoomZoom")</code>.
 +
 +
===Custom audio===
 +
{{/doc status|[[Modding:Audio]]|done=true}}
 +
 +
You can now add or edit music tracks or sound effects by editing the new <samp>Data/AudioChanges</samp> asset. New cues are added to the game's soundbank, so they can be used anywhere normal audio can be used (e.g. the <samp>Music</samp> [[Modding:Maps|map property]]). This supports <samp>.ogg</samp> and <samp>.wav</samp> files, and the vanilla audio features (e.g. randomizing audio from one ID).
 +
 +
Audio is also more fault-tolerant in 1.6: the game no longer crashes when playing audio which doesn't exist, it now logs an error and returns a default quiet click sound instead. (If you use <code>try..catch</code> to check if an audio cue exists, you should check <code>Game1.soundbank.Exists(name)</code> instead.)
 +
 +
===Custom buffs===
 +
{{/doc status|a new doc page|done=false}}
 +
 +
: ''See also: [[#Buff overhaul|buff overhaul]].''
 +
 +
You can now define custom buffs by editing the new <samp>Data/Buffs</samp> asset. You can then use the buff from other places like <samp>Data/Object</samp>'s <samp>Buff</samp> field or the C# <samp>Buff</samp> constructor.
 +
 +
This consists of a string → model lookup, where...
 +
* The key is a [[Modding:Common data field types#Unique string ID|unique string ID]] for the buff.
 +
* The value is a model with the fields listed below.
 +
 +
{| class="wikitable"
 +
|-
 +
! field
 +
! purpose
 +
|-
 +
| <samp>DisplayName</samp>
 +
| A [[Modding:Tokenizable strings|tokenizable string]] for the buff name.
 +
|-
 +
| <samp>Description</samp>
 +
| ''(Optional)'' A [[Modding:Tokenizable strings|tokenizable string]] for the buff name. Default none.
 +
|-
 +
| <samp>IsDebuff</samp>
 +
| ''(Optional)'' >Whether this buff counts as a debuff, so its duration should be halved when wearing a [[Sturdy Ring|sturdy ring]]. Default false.
 +
|-
 +
| <samp>GlowColor</samp>
 +
| ''(Optional)'' The glow color to apply to the player. See [[#Color fields|color format]]. Default none.
 +
|-
 +
| <samp>Duration</samp>
 +
| The duration in milliseconds for which the buff should be active. This can be set to value <samp>-2</samp> for a buff that should last for the rest of the day.
 +
|-
 +
| <samp>MaxDuration</samp>
 +
| ''(Optional)'' The maximum buff duration in milliseconds. If specified and larger than <samp>Duration</samp>, a random value between <samp>Duration</samp> and <samp>MaxDuration</samp> will be selected for each buff. Default none.
 +
|-
 +
| <samp>IconTexture</samp>
 +
| The asset name for the texture containing the buff's sprite.
 +
|-
 +
| <samp>IconSpriteIndex</samp>
 +
| ''(Optional)'' The sprite index for the buff icon within the <samp>IconTexture</samp>. Default 0.
 +
|-
 +
| <samp>Effects</samp>
 +
| ''(Optional)'' The buff attributes to apply. Default none.
 +
 +
This consists of a model with any combination of these fields:
 +
{| class="wikitable"
 +
|-
 +
! field
 +
! purpose
 +
|-
 +
| <samp>FarmingLevel</samp><br /><samp>FishingLevel</samp><br /><samp>ForagingLevel</samp><br /><samp>LuckLevel</samp><br /><samp>MiningLevel</samp>
 +
| ''(Optional)'' An amount applied to the matching [[Skills|skill level]] while the buff is active. This can be negative for a debuff. Default 0.
 +
|-
 +
| <samp>Attack</samp><br /><samp>Defense</samp><br /><samp>MagneticRadius</samp><br /><samp>MaxStamina</samp><br /><samp>Speed</samp>
 +
| ''(Optional)'' An amount applied to the player's [[attack]], [[defense]], [[Magnetism|magnetic radius]], maximum [[Energy|stamina]], or [[speed]] while the buff is active. This can be negative for a debuff. Default 0.
 +
|}
 +
|-
 +
| <samp>ActionsOnApply</samp>
 +
| ''(Optional)'' Run any number of [[Modding:Trigger actions|trigger action strings]] when the buff is applied to the current player. For example, this increments a player stat:
 +
<syntaxhighlight lang="js">
 +
"ActionsOnApply": [
 +
    "IncrementStat {{ModId}}_NumberEaten 1"
 +
]
 +
</syntaxhighlight>
 +
|-
 +
| <samp>CustomFields</samp>
 +
| ''(Optional)'' The [[#Custom data fields|custom fields]] for this entry.
 +
|}
 +
 +
===Custom data fields===
 +
{{/doc status|[[Modding:Common data field types#Custom fields]]|done=true}}
 +
 +
Many data assets now have a <samp>CustomFields</samp> field. This is ignored by the game, but lets mods add their own data (e.g. to enable mod framework features).
 +
 +
For example, a content pack can [[#Custom crops|add a crop]] with custom fields:
 +
{{#tag:syntaxhighlight|<nowiki>
 +
{
 +
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
 +
    "Changes": [
 +
        {
 +
            "Action": "EditData",
 +
            "Target": "Data/Crops",
 +
            "Entries": {
 +
                "Example.Id_CucumberSeeds": {
 +
                    "Seasons": [ "summer" ],
 +
                    "DaysInPhase": [ 1, 2, 2, 2 ],
 +
                    "HarvestItemId": "Example.Id_Cucumber",
 +
                    "Texture": "{{InternalAssetKey: assets/crops.png}}",
 +
                    "SpriteIndex": 0,
 +
 +
                    "CustomFields": {
 +
                        "Example.FrameworkMod/WetTexture": "{{InternalAssetKey: assets/crops-wet.png}}"
 +
                    }
 +
                }
 +
            }
 +
        }
 +
    ]
 +
}</nowiki>|lang=javascript}}
 +
 +
And then a C# mod could handle the custom field if it's set:
 +
<syntaxhighlight lang="c#">
 +
if (Game1.currentLocation.IsRainingHere())
 +
{
 +
    CropData data = crop.GetData();
 +
    if (data != null && data.CustomFields.TryGetValue("Example.FrameworkMod/WetTexture", out string textureName))
 +
    {
 +
        // do magic
 +
    }
 +
}
 +
</syntaxhighlight>
 +
 +
See <samp>CustomFields</samp> in the docs for each asset type to see if it's supported. Besides the sections listed on this page, custom fields were also added to <samp>Data/AdditionalFarms</samp>, <samp>Data/AdditionalLanguages</samp>, <samp>Data/FishPondData</samp>, <samp>Data/HomeRenovations</samp>, <samp>Data/Movies</samp>, and <samp>Data/SpecialOrders</samp>.
 +
 +
See [[Modding:Common data field types#Custom fields]] for the main docs.
 +
 +
===Custom giant crops===
 +
{{/doc status|a new doc page|done=false}}
 +
 +
You can now add/edit [[Crops#Giant Crops|giant crops]] by editing the <samp>Data/GiantCrops</samp> data asset.
 +
 +
This consists of a string → model lookup, where...
 +
* The key is a [[Modding:Common data field types#Unique string ID|unique string ID]] for the giant crop.
 +
* The value is a model with the fields listed below.
 +
 +
{| class="wikitable"
 +
|-
 +
! field
 +
! effect
 +
|-
 +
| <samp>FromItemId</samp>
 +
| The [[#Custom items|item ID]] (qualified or unqualified) for the harvest ID of the regular crop which can turn into this giant crop. For example, <samp>(O)254</samp> is [[melon]].
 +
 +
Any number of giant crops can use the same <samp>FromItemId</samp> value. The first giant crop whose other fields match (if any) will spawn.
 +
|-
 +
| <samp>HarvestItems</samp>
 +
| The items which can be dropped when you break the giant crop. If multiple items match, they'll all be dropped.
 +
 +
This consists of a list of models with these fields:
 +
{| class="wikitable"
 +
|-
 +
! field
 +
! effect
 +
|-
 +
| ''common fields''
 +
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields supported for harvest items.
 +
 +
If set to an [[Modding:Item queries|item query]] which returns multiple items, one of them will be selected at random.
 +
|-
 +
| <samp>Chance</samp>
 +
| ''(Optional)'' The probability that this entry is selected, as a value between 0 (never drops) and 1 (always drops). Default 1 (100% chance).
 +
|-
 +
| <samp>ForShavingEnchantment</samp>
 +
| ''(Optional)'' Whether this item is only dropped for [[Enchantments#Tool enchantments|Shaving enchantment]] drops (<samp>true</samp>), only when the giant crop is broken (<samp>false</samp>), or both (<samp>null</samp>). Default both.
 +
|-
 +
| <samp>ScaledMinStackWhenShaving</samp><br /><samp>ScaledMaxStackWhenShaving</samp>
 +
| ''(Optional)'' If set, the min/max stack size when this item is dropped due to the [[Forge#Enchantments|shaving enchantment]], scaled to the tool's power level.
 +
 +
This value is multiplied by the health deducted by the tool hit which triggered the enchantment. For example, an iridium axe which reduced the giant crop's health by 3 points will produce three times this value per hit.
 +
 +
If both fields are set, the stack size is randomized between them. If only one is set, it's applied as a limit after the generic fields. If neither is set, the generic <samp>MinStack</samp>/<samp>MaxStack</samp> fields are applied as usual without scaling.
 +
|}
 +
|-
 +
| <samp>Texture</samp>
 +
| The asset name for the texture containing the giant crop's sprite.
 +
|-
 +
| <samp>TexturePosition</samp>
 +
| ''(Optional)'' The top-left pixel position of the sprite within the <samp>Texture</samp>, specified as a model with <samp>X</samp> and <samp>Y</samp> fields. Defaults to (0, 0).
 +
|-
 +
| <samp>TileSize</samp>
 +
| ''(Optional)'' The area in tiles occupied by the giant crop, specified as a model with <samp>X</samp> and <samp>Y</samp> fields. This affects both its sprite size (which should be 16 pixels per tile) and the grid of crops needed for it to grow. Note that giant crops are drawn with an extra tile's height. Defaults to (3, 3).
 +
|-
 +
| <samp>Health</samp>
 +
| ''(Optional)'' The health points that must be depleted to break the giant crop. The number of points depleted per [[axe]] chop depends on the axe power level. Default 3.
 +
|-
 +
| <samp>Chance</samp>
 +
| ''(Optional)'' The percentage chance that a given grid of crops will grow into the giant crop each night, as a value between 0 (never) and 1 (always). Default 0.01 (1%).
 +
 +
Note that the chance is checked for each giant crop that applies. If three giant crops each have a 1% chance of spawning for the same crop, then there's a 3% chance that one of them will spawn.
 +
|-
 +
| <samp>Condition</samp>
 +
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this giant crop is available to spawn. Defaults to always true.
 +
|-
 +
| <samp>CustomFields</samp>
 +
| The [[#Custom data fields|custom fields]] for this entry.
 +
|}
 +
 +
===Custom jukebox tracks===
 +
{{/doc status|a new doc page|done=false}}
 +
 +
You can now change [[jukebox]] audio tracks by editing the new <samp>Data/JukeboxTracks</samp> data asset.
 +
 +
This consists of a string → model lookup, where...
 +
* The key is the [[#Custom audio|audio cue ID]] to play (case-sensitive).
 +
* The value is a model with the fields listed below.
 +
 +
If the player has heard a music track not listed in <samp>Data/JukeboxTracks</samp>, it's automatically available with the title set to the cue name. To disable a track, add an entry with <samp>"Available": false</samp>.
 +
 +
{| class="wikitable"
 +
|-
 +
! field
 +
! effect
 +
|-
 +
| <samp>Name</samp>
 +
| ''(Optional)'' A [[Modding:Tokenizable strings|tokenizable string]] for the music track's in-game title. Defaults to the ID.
 +
|-
 +
| <samp>Available</samp>
 +
| ''(Optional)'' Whether the track should be shown in the jukebox menu. This can be <samp>true</samp> (always shown), <samp>false</samp> (never shown), or <samp>null</samp> (show if the player has heard it before). Default <samp>null</samp>.
 +
 +
Tracks with <samp>"Available": true</samp> are listed first in the jukebox menu.
 +
|-
 +
| <samp>AlternativeTrackIds</samp>
 +
| ''(Optional)'' A list of other cue names for this audio track (not case-sensitive). If the player has heard any of these track IDs, this entry is available in the menu. Default none.
 +
 +
For example, this can be used when renaming a track to keep it unlocked for existing players:
 +
<syntaxhighlight lang="js">
 +
"{{ModId}}_TrackName": {
 +
    "Name": "{{i18n: track-name}}",
 +
    "AlternativeTrackIds": [ "OldTrackName" ]
 +
}
 +
</syntaxhighlight>
 +
|}
 +
 +
===Custom movies===
 +
{{/doc status|[[Modding:Movie theater data]]|done=false}}
 +
 +
: ''See also: [[#Custom movie concessions|custom movie concessions]].''
 +
 +
[[Modding:Movie theater data#Movie data|Movie data]] was previously very limited and prone to mod conflicts, since (a) we needed incrementing movie IDs like <samp>spring_movie_3</samp>, (b) we were limited to one movie per season, and (c) all sprites for each movie had to be in the vanilla <samp>LooseSprites/Movies</samp> spritesheet.
 +
 +
Stardew Valley 1.6 revamps how movies work to address those limitations.
 +
 +
<dl>
 +
<dt>Movie selection</dt>
 +
<dd><p>Movies were previously selected based on a specific ID pattern: <samp>spring_movie_0</samp> would play in spring the year you built the movie theater, <samp>spring_movie_1</samp> would play in spring the next year, etc. That meant it'd take two in-game years to see the first custom movie, and ID conflicts had to be managed manually.</p>
 +
 +
In 1.6, we can now have multiple movies per month based on the new fields listed below. If multiple movies can play in the same season, each movie will be shown for an equal block of days within the month (e.g. four movies will each play for seven consecutive days). If there are more movies than days, 28 movies will be chosen at random to play that month.</dd>
 +
 +
<dt>New data fields</dd>
 +
<dd>
 +
{| class="wikitable"
 +
|-
 +
! field
 +
! effect
 +
|-
 +
| <samp>Seasons</samp>
 +
| ''(Optional)'' The seasons when the movie should play, or omit for any season. For example:
 +
<syntaxhighlight lang="js">"Seasons": [ "Spring", "Summer" ]</syntaxhighlight>
 +
|-
 +
| <samp>YearModulus</samp><br /><samp>YearRemainder</samp>
 +
| ''(Optional)'' If set, plays the movie on alternating years based on the formula <samp>theater_age % modulus == remainder</samp>, where <samp>theater_age</samp> is the number of years since the movie theater was built. If omitted, the movie plays in any year.
 +
 +
For example:
 +
 +
<syntaxhighlight lang="js">
 +
// play in the first year, and every second year thereafter
 +
"YearModulus": 2,
 +
"YearRemainder": 0
 +
</syntaxhighlight>
 +
<syntaxhighlight lang="js">
 +
// play in the second year, and every second year thereafter
 +
"YearModulus": 2,
 +
"YearRemainder": 1
 +
</syntaxhighlight>
 +
|-
 +
| <samp>Texture</samp>
 +
| ''(Optional)'' The asset name for the movie poster and screen images, or omit to use <samp>LooseSprites\Movies</samp>.
 +
 +
This must be a spritesheet with one 490×128 pixel row per movie. A 13×19 area in the top-left corner of the row should contain the movie poster. With a 16-pixel offset from the left edge, there should be two rows of five 90×61 pixel movie screen images, with a six-pixel gap between each image. (The movie doesn't need to use all of the image slots.)
 +
|-
 +
| <samp>CranePrizes</samp>
 +
| ''(Optional)'' The items to add to the [[Movie Theater#Crane Game|crane game]] prize pool on days when this movie is playing, if any.
 +
 +
This consists of a list of models with these fields:
 +
{| class="wikitable"
 +
|-
 +
! field
 +
! effect
 +
|-
 +
| ''common fields''
 +
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields supported for ammo items.
 +
 +
If set to an [[Modding:Item queries|item query]] which returns multiple items, one of them will be selected at random.
 +
|-
 +
| <samp>Rarity</samp>
 +
| ''(Optional)'' The prize pool to add the item to. The possible values are <samp>1</samp> (common), <samp>2</samp> (rare), and <samp>3</samp> (deluxe). Default <samp>1</samp>.
 +
|}
 +
|-
 +
| <samp>ClearDefaultCranePrizeGroups</samp>
 +
| ''(Optional)'' The prize pools whose default items to discard, so only those specified by <samp>CranePrizes</samp> are available. Default none.
 +
 +
For example:
 +
<syntaxhighlight lang="js">"ClearDefaultCranePrizeGroups": [ 2, 3 ]</syntaxhighlight>
 +
|}
 +
</dd>
 +
 +
<dt>Other changes</dt>
 +
<dd>
 +
* <samp>Data/Movies</samp>, <samp>Data/Concessions</samp>, and <samp>Data/MoviesReactions</samp> no longer have language variants. Instead translations were moved into <samp>Strings/*</samp> assets, and the data assets use [[Modding:Tokenizable strings|tokenizable strings]] to get text.
 +
* <samp>Data/Movies</samp> is now a list instead of a dictionary. The order determines the order movies are shown within a season. Content packs can edit them the same way as before.
 +
* Added a <samp>debug movieSchedule {{o|year}}</samp> command to help troubleshoot movie selection.
 +
* Added methods for C# mods: <samp>MovieTheater.GetMovieToday()</samp>, <samp>GetUpcomingMovie()</samp>, and <samp>GetUpcomingMovie(afterDate)</samp>.
 +
</dd>
 +
</dl>
 +
 +
For example, this content pack adds a new 'Pufferchick II' movie which plays in winter every third year:
 +
{{#tag:syntaxhighlight|<nowiki>
 +
{
 +
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
 +
    "Changes": [
 +
        {
 +
            "Action": "EditData",
 +
            "Target": "Data/Movies",
 +
            "Entries": {
 +
                "{{ModId}}_PufferchickII": {
 +
                    "Id": "{{ModId}}_PufferchickII", // must specify ID again when creating a new entry
 +
 +
                    "Seasons": [ "winter" ],
 +
                    "YearModulus": 3,
 +
                    "YearRemainder": 0,
 +
 +
                    "Title": "Pufferchick II", // display text should usually use {{i18n}} for translations in actual usage
 +
                    "Description": "A sequel to the breakthrough adventure anime Pufferchick. The world is saved; what happens next?",
 +
                    "Tags": [ "family", "adventure" ],
 +
 +
                    "Texture": "{{InternalAssetKey: assets/movie.png}}", // an image in your content pack
 +
                    "SheetIndex": 0,
 +
 +
                    "Scenes": [ ... ]
 +
                }
 +
            }
 +
        }
 +
    ]
 +
}</nowiki>|lang=javascript}}
 +
 +
===Custom wedding event===
 +
{{/doc status|a new doc page|done=false}}
 +
 +
The [[Marriage#The Wedding|wedding]] event can now be changed by editing the <samp>Data\Weddings</samp> data asset, which consists of a data model with two relevant fields (listed below).
 +
 +
{| class="wikitable"
 +
|-
 +
! field
 +
! effect
 +
|-
 +
| <samp>EventScript</samp>
 +
| The [[Modding:Event data|event scripts]] which play the wedding. The game will use the script for the spouse NPC/player if it exists, otherwise it'll use the default script.
 +
 +
This consists of a string → string dictionary, where...
 +
* The key is an NPC internal name (like <samp>Abigail</samp>), unique player ID, or <samp>default</samp> for the default script (which handles marrying either an NPC or player);
 +
* The value is a [[Modding:Tokenizable strings|tokenizable strings]] for the event script to play.
 +
 +
The event scripts also have access to three extra tokens:
 +
{| class="wikitable"
 +
|-
 +
! token
 +
! effect
 +
|-
 +
| <samp>[SetupContextualWeddingAttendees]</samp>
 +
| The concatenated <samp>Setup</samp> values for each of the <samp>Attendees</samp> present in the wedding.
 +
|-
 +
| <samp>[ContextualWeddingCelebrations]</samp>
 +
| The concatenated <samp>Celebration</samp> values for each of the <samp>Attendees</samp> present in the wedding.
 +
|-
 +
| <samp>[SpouseActor]</samp>
 +
| The actor ID for the NPC or other player being married (like <samp>Abigail</samp> for an NPC or <samp>farmer2</samp> for a player). This can be used in event commands like <code>faceDirection [SpouseActor] 1</code>.
 +
 +
(You can also use <samp>spouse</samp> as an actor ID, but that will only work when marrying an NPC.)
 +
|}
 +
|-
 +
| <samp>Attendees</samp>
 +
| The other NPCs which should attend the wedding (unless they're the spouse). This consists of a string → model lookup, where the key is the internal NPC name, and the value is a model with these fields:
 +
{| class="wikitable"
 +
|-
 +
! field
 +
! effect
 +
|-
 +
| <samp>ID</samp>
 +
| The internal NPC name.
 +
|-
 +
| <samp>Setup</samp>
 +
| The NPC's tile position and facing direction when they attend. This is equivalent to field index 2 in the [[Modding:Event data#Basic format|event basic data]].
 +
|-
 +
| <samp>Celebration</samp>
 +
| ''(Optional)'' The [[Modding:Event data|event script]] to run during the celebration, like <samp>faceDirection Pierre 3 true</samp> which makes Pierre turn to face left. This can contain any number of script commands.
 +
|-
 +
| <samp>Condition</samp>
 +
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether the NPC should attend. Defaults to true.
 +
|-
 +
| <samp>IgnoreUnlockConditions</samp>
 +
| ''(Optional)'' Whether to add the NPC even if their entry in <samp>Data/Characters</samp> has an <samp>UnlockConditions</samp> field which doesn't match. Default false.
 +
|}
 +
|}
 +
 +
===Game state queries===
 +
{{/doc status|[[Modding:Game state queries]]|done=true}}
 +
 +
A ''game state query'' is a new vanilla way to specify conditions for some content like [[#Custom shops|shop data]], inspired by [[Modding:Content Patcher|Content Patcher]]'s conditions.
 +
 +
===Gender changes===
 +
{{/doc status|[[Modding:Dialogue]]|done=false}}
 +
 +
* Added an [[#gender-switch|''inline gender-switch token'']] to change text depending on the player's gender. This reduces duplicate text, works in more places than the <samp>^</samp> dialogue token, works in mail and other places where <samp>^</samp> has a different meaning, and supports non-binary gender.
 +
* For C# mod authors, added a unified <samp>Gender</samp> field for players and NPCs with the possible values <samp>Male</samp>, <samp>Female</samp>, and <samp>Unspecified</samp>. This replaces <samp>Farmer.isMale</samp> and the numeric NPC gender constants. Note that vanilla still only sets players to male or female, though mods can override it.
 +
* Gender-specific clothing variants can now be worn by any gender.
 +
* Removed French-only support for using <samp>^</samp> dialogue token in non-dialogue text. This is superseded by the new inline gender-switch command.
 +
 +
===Item queries===
 +
{{/doc status|[[Modding:Item queries]]|done=true}}
 +
 +
''Item queries'' are a new built-in way to choose one or more items dynamically, instead of specifying a single item ID. These are used in various places like [[#Custom machines|machine data]] and [[#Custom shops|shop data]].
 +
 +
For example, a shop can sell a random [[House Plant|house plant]] using the <samp>RANDOM_ITEMS</samp> query:
 +
<syntaxhighlight lang="js">
 +
{
 +
    "ItemId": "RANDOM_ITEMS (F) 1376 1390",
 +
    "MaxItems": 1
 +
}
 +
</syntaxhighlight>
 +
 +
===Item spawn fields===
 +
{{/doc status|[[Modding:Item queries#Item spawn fields]]|done=true}}
 +
 +
Several data assets (like [[#Custom machines|machines]] and [[#Custom shops|shops]]) let you configure items to create using item queries. For consistency, these all share a set of common fields.
 +
 +
===Color fields===
 +
{{/doc status|[[Modding:Common data field types#Color]]|done=true}}
 +
 +
1.6 adds a standardized color format used in various data fields. This can be a color name, hexadecimal color code, or 8-bit RGB color code.
 +
 +
For example, you can set debris color in [[#Custom wild trees|<samp>Data/WildTrees</samp>]]:
 +
<syntaxhighlight lang="js">
 +
"DebrisColor": "White"
 +
</syntaxhighlight>
 +
 +
===<samp>modData</samp> field changes===
 +
The <samp>modData</samp> fields are dictionaries of arbitrary string values which are synchronized in multiplayer and persisted in the save file, so mods can store custom data about the instances. The game already has the field for buildings, characters (including NPCs and players), items, locations, and terrain features.
 +
 +
Stardew Valley 1.6...
 +
* Adds <samp>modData</samp> fields to the <samp>Crop</samp>, <samp>Projectile</samp>, and <samp>Quest</samp> types too.
 +
* Moves <samp>ModDataDictionary</samp> into the <samp>StardewValley.Mods</samp> namespace.
 +
* Fixes <samp>Item.modData</samp> not copied when performing special equipment replacement (e.g. for the [[Pans|copper pan]] work as a hat).
 +
 +
===Quantity modifiers===
 +
{{/doc status|[[Modding:Common data field types]]|done=false}}
 +
 +
''Quantity modifiers'' apply dynamic changes to a numeric field in a data asset like [[#Custom shops|<samp>Data/Shops</samp>]] or [[#Custom machines|<samp>Data/Machines</samp>]]. For example, you can multiply a shop item's price or increase a machine output's quality. You can specify any number of modifiers for the same field.
 +
 +
====Modifier format====
 +
These consist of a list of models with these fields:
 +
{| class="wikitable"
 +
|-
 +
! field
 +
! effect
 +
|-
 +
| <samp>Id</samp>
 +
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this modifier within the current list.
 +
|-
 +
| <samp>Modification</samp>
 +
| The type of change to apply. The possible values are <samp>Add</samp>, <samp>Subtract</samp>, <samp>Multiply</samp>, <samp>Divide</samp>, and <samp>Set</samp>.
 +
|-
 +
| <samp>Amount</samp>
 +
| ''(Optional if <samp>RandomAmount</samp> specified)'' The operand applied to the target value (e.g. the multiplier if used with <samp>Multiply</samp>).
 +
|-
 +
| <samp>RandomAmount</samp>
 +
| ''(Optional)'' A list of possible amounts to randomly choose from. If set, <samp>Amount</samp> is optional and ignored. Each entry in the list has an equal probability of being chosen, and the choice is persisted for the current day. For example:
 +
<syntaxhighlight lang="js">
 +
"RandomAmount": [ 1, 2, 3.5, 4 ]
 +
</syntaxhighlight>
 +
|-
 +
| <samp>Condition</samp>
 +
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this change should be applied. Defaults to always true.
 +
|}
 +
 +
====Modifier mode====
 +
Quality modifier fields are often accompanied by a ''mode'' field (like <samp>PriceModifiers</samp> and <samp>PriceModifierMode</samp>), which indicate what to do when multiple modifiers apply to the same value. Available modes:
 +
 +
{| class="wikitable"
 +
|-
 +
! value
 +
! effect
 +
|-
 +
| <samp>Stack</samp>
 +
| Apply each modifier to the result of the previous one. For example, two modifiers which double a value will quadruple it.
 +
|-
 +
| <samp>Minimum</samp>
 +
| Apply the modifier which results in the lowest value.
 +
|-
 +
| <samp>Maximum</samp>
 +
| Apply the modifier which results in the highest value.
 +
|}
 +
 +
====Examples====
 +
For example, this will double the price of a shop item in <samp>Data/Shops</samp>:
 +
<syntaxhighlight lang="js">
 +
"PriceModifiers": [
 +
    {
 +
        "Modification": "Multiply",
 +
        "Amount": 2.0
 +
    }
 +
]
 +
</syntaxhighlight>
 +
 +
This will set the price to a random value between 100–1000, ''or'' 3–5 times the item's normal sell price, whichever is higher (like the [[Traveling Cart]]):
 +
<syntaxhighlight lang="js">
 +
"PriceModifierMode": "Maximum",
 +
"PriceModifiers": [
 +
    {
 +
        "Modification": "Set",
 +
        "RandomAmount": [ 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000 ]
 +
    },
 +
    {
 +
        "Modification": "Multiply",
 +
        "RandomAmount": [ 3, 4, 5 ]
 +
    }
 +
]
 +
</syntaxhighlight>
 +
 +
===Tokenizable string format===
 +
{{/doc status|[[Modding:Tokenizable strings]]|done=true}}
 +
 +
Stardew Valley 1.6 adds ''tokenizable strings'', which support any combination of literal text and token values. That includes a set of built-in tokens like <samp>FarmName</samp>, <samp>LocalizedText</samp>, etc.
 +
 +
For example, previously you often needed to load text from a [[Modding:Common data field types#Translation key|translation key]]. With this new format, you can use the literal text directly in the asset instead (including [[Modding:Content Patcher|Content Patcher]] tokens):
 +
 +
<syntaxhighlight lang="js">
 +
// before
 +
"Dialogue": "Strings\\StringsFromCSFiles:ShopMenu.cs.11488",
 +
 +
// after: any combination of literal text and tokens
 +
"Dialogue": "Welcome to Pierre's, {{PlayerName}}! How is [FarmName] doing?",
 +
</syntaxhighlight>
 +
 +
Tokenizable strings are only usable in specific fields (as indicated in their wiki or code docs).
 +
 +
See [[Modding:Tokenizable strings]] for usage.
 +
 +
===[[Modding:Event data|Event]] changes===
 +
{{/doc status|[[Modding:Event data]]|done=false}}
 +
 +
====High-level changes====
 +
* Event IDs are now [[Modding:Common data field types#Unique string ID|unique string IDs]], so mods can use a unique key instead of hoping no other mod uses the same number. Unconditional events must have an empty precondition in their key (like <samp>"Example.ModId_EventName/"</samp>) to distinguish them from forks.
 +
* Event/festival commands with a direction argument now allow both case-insensitive names (like <samp>up</samp>) and numeric values.
 +
* Event script errors are now logged (in addition to being shown in the chatbox like before).
 +
* For C# mods:
 +
** You can now add custom event preconditions & commands using new <samp>Event</samp> methods (<samp>RegisterPrecondition</samp>, <samp>RegisterPreconditionAlias</samp>, <samp>RegisterCommand</samp>, and <samp>RegisterCommandAlias</samp>).
 +
** Added <samp>Event.fromAssetName</samp>, which indicates which data asset (if any) the event was loaded from.
 +
** Added <samp>Game1.eventsSeenSinceLastLocationChange</samp> to track the events that played since the player arrived in their current location.
 +
 +
====Precondition changes====
 +
<ul>
 +
<li>Added validation for preconditions. If a format or assumption is invalid, the game now logs a detailed error.</li>
 +
<li>Added case-insensitive readable names for all preconditions. For example, <code>j 4/t 800 1300/a 0 54/H</code> can now optionally be written <code>daysPlayed 4/time 800 1300/tile 0 54/isHost</code>.
 +
{{collapse|list of new names|content=
 +
List of new event precondition names:
 +
<pre>
 +
alias | readable name
 +
----- | ------------------------------
 +
*    | WorldState
 +
*n    | HostOrLocalMail
 +
a    | Tile
 +
b    | ReachedMineBottom
 +
B    | SpouseBed
 +
C    | CommunityCenterOrWarehouseDone
 +
c    | FreeInventorySlots
 +
D    | Dating
 +
e    | SawEvent
 +
f    | Friendship
 +
g    | Gender
 +
H    | IsHost
 +
h    | MissingPet
 +
Hn    | HostMail
 +
i    | HasItem
 +
j    | DaysPlayed
 +
J    | JojaBundlesDone
 +
L    | InUpgradedHouse
 +
m    | EarnedMoney
 +
M    | HasMoney
 +
N    | GoldenWalnuts
 +
n    | LocalMail
 +
O    | Spouse
 +
p    | NpcVisibleHere
 +
q    | ChoseDialogueAnswers
 +
r    | Random
 +
R    | Roommate
 +
S    | SawSecretNote
 +
s    | Shipped
 +
t    | Time
 +
u    | DayOfMonth
 +
v    | NpcVisible
 +
w    | Weather
 +
x    | SendMail
 +
y    | Year
 +
</pre>
 +
And for deprecated preconditions (e.g. <code>NotSeason</code> is superseded by <code>!Season</code>):
 +
<pre>
 +
alias | readable name
 +
----- | ---------------------------------
 +
*l    | NotHostOrLocalMail
 +
A    | NotActiveDialogueEvent
 +
d    | NotDayOfWeek
 +
F    | NotFestivalDay
 +
Hl    | NotHostMail
 +
k    | NotSawEvent
 +
l    | NotLocalMail
 +
o    | NotSpouse
 +
Rf    | NotRoommate
 +
U    | NotUpcomingFestival
 +
X    | NotCommunityCenterOrWarehouseDone
 +
z    | NotSeason
 +
</pre>
 +
}}
 +
</li>
 +
<li>Event & preconditions are now quote-aware, so you can escape spaces and slashes in arguments like <code>/G "SEASON Spring"/</code>.</li>
 +
<li>Added new preconditions:
 +
{| class="wikitable"
 +
|-
 +
! precondition
 +
! description
 +
|-
 +
| <samp>!</samp>
 +
| Prefixing <samp>!</samp> to any other precondition will now invert it. For example, <code>!spouse Abigail</code> will match if the player is ''not'' married to Abigail.
 +
|-
 +
| <samp>ActiveDialogueEvent {{t|id}}</samp>
 +
| The special dialogue event with the given ID (including [[Modding:Dialogue#Conversation_topics|Conversation Topics]]) is in progress.
 +
|-
 +
| <samp>DayOfWeek {{t|day}}+</samp>
 +
| Today is one of the specified days (may specify multiple days). This can be a case-insensitive three-letter abbreviation (like <samp>Mon</samp>) or full name (like <samp>Monday</samp>).
 +
|-
 +
| <samp>FestivalDay</samp>
 +
| Today is a [[Festivals|festival]] day.
 +
|-
 +
| <samp>GameStateQuery {{t|query}}</samp>
 +
| A [[Modding:Game state queries|game state query]] matches, like <code>G !WEATHER Here Sun</code> for 'not sunny in this location'.
 +
|-
 +
| <samp>Season {{t|season}}+</samp>
 +
| The current season is one of the given values (may specify multiple seasons).
 +
|-
 +
| <samp>Skill {{t|skill name}} {{t|min level}}</samp>
 +
| The current farmer has reached at least {{t|min level}} for the given {{t|skill name}} (one of <samp>Combat</samp>, <samp>Farming</samp>, <samp>Fishing</samp>, <samp>Foraging</samp>, <samp>Luck</samp>, or <samp>Mining</samp>).
 +
|-
 +
| <samp>UpcomingFestival {{t|day offset}}</samp>
 +
| A [[Festivals|festival]] day will occur within the given number of days.
 +
|}</li>
 +
<li>Changed specific preconditions:
 +
{| class="wikitable"
 +
|-
 +
! name
 +
! changes
 +
|-
 +
| <samp>ChoseDialogueAnswers</samp> (<samp>q</samp>)
 +
| &#32;
 +
* Fixed precondition ignoring every second answer ID.
 +
|-
 +
| <samp>InUpgradedHouse</samp> (<samp>L</samp>)
 +
| &#32;
 +
* Added optional argument for the min upgrade level.
 +
|-
 +
| <samp>MissingPet</samp> (<samp>h</samp>)
 +
| &#32;
 +
* You can now specify any pet type ID.
 +
* You can now omit the argument to check for a pet of any type.
 +
|-
 +
| <samp>NotDayOfWeek</samp> (<samp>d</samp>)
 +
| &#32;
 +
* You can now specify a full name like <samp>Monday</samp>.
 +
* The day of week is now case-insensitive.
 +
|-
 +
| <samp>NotSeason</samp> (<samp>z</samp>)
 +
| &#32;
 +
* You can now list values (like <code>notSeason spring summer fall</code> instead of <code>notSeason fall/notSeason winter/notSeason fall</code>).
 +
|-
 +
| <samp>ReachedMineBottom</samp> (<samp>b</samp>)
 +
| &#32;
 +
* Argument is now optional (default 1).
 +
|-
 +
| <samp>SendMail</samp> (<samp>x</samp>)
 +
| &#32;
 +
* Deprecated; see [[#Send-mail (x) precondition deprecated|''Send-mail (x) precondition deprecated'']] for more info.
 +
|-
 +
| <samp>Tile</samp> (<samp>a</samp>)
 +
| &#32;
 +
* Now also works when the player isn't currently warping, in which case it checks their current tile instead of their warp arrival tile.
 +
|}</li>
 +
</ul>
 +
 +
====Command changes====
 +
<ul>
 +
<li>Added validation for event commands. If a format or assumption is invalid, the game now logs a detailed error and (if applicable) skips the command, instead of crashing or silently ignoring it. This also means event arguments are stricter (e.g. you can no longer set a true/false field to an invalid value, inner quotes in quoted arguments now need to be escaped, etc).</li>
 +
<li>Event commands are now quote-aware, so you can escape spaces and slashes in arguments like <code>/speak "I'm running A/B tests"/</code>.</li>
 +
<li>Event commands now trim surrounding whitespace, so they can be multilined for readability. Line breaks must be before or after the <samp>/</samp> delimiter. For example:
 +
<syntaxhighlight lang="js">
 +
"SomeEventId/": "
 +
    none/
 +
    -1000 -1000/
 +
    farmer 5 7 0/
 +
    ...
 +
"
 +
</syntaxHighlight>
 +
This can be also combined with the [[Modding:Event data#Comments|comment syntax]] to add notes. For example:
 +
<syntaxhighlight lang="js">
 +
"SomeEventId/": "
 +
    none/            -- music/
 +
    -1000 -1000/    -- initial viewport position/
 +
    farmer 5 7 0/    -- actor positions/
 +
    ...
 +
"
 +
</syntaxHighlight>
 +
</li>
 +
<li>You can now mark NPCs optional in event commands by suffixing their name with <code>?</code>. For example, <code>jump Kent?</code> won't log an error if Kent is missing. When used in the initial event positions, the NPC is only added in they exist in <samp>Data/Characters</samp> and their <samp>UnlockConditions</samp> match.</li>
 +
<li>Added new event commands:
 +
{| class="wikitable"
 +
|-
 +
! command
 +
! description
 +
|-
 +
| <samp>action {{t|action}}</samp>
 +
| Run a [[Modding:Trigger actions|trigger action string]], like <samp>action AddMoney 500</samp> to add {{price|500}} to the current player.
 +
|-
 +
| <samp>addItem {{t|item ID}} {{o|count}} {{o|quality}}</samp>
 +
| Add an item to the player inventory (or open a grab menu if their inventory is full). The {{t|item ID}} is the [[#Custom items|qualified or unqualified item ID]], and {{o|quality}} is a [[Modding:Items#Quality|numeric quality value]].
 +
|-
 +
| <samp>addSpecialOrder {{t|order ID}}</samp><br /><samp>removeSpecialOrder {{t|order ID}}</samp>
 +
| Add or remove a special order to the player team. This affects all players, since special orders are shared.
 +
|-
 +
| <samp>eventSeen {{t|event ID}} {{o|seen}}</samp>
 +
| Add or remove an event ID from the player's list of seen events, based on {{o|seen}} (default <samp>true</samp> to add).
 +
 +
An event can mark ''itself'' unseen using <samp>eventSeen {{t|event ID}} false</samp>. This takes effect immediately (i.e. the event won't be added to the list when it completes), but the game will prevent the event from playing again until the player changes location to avoid event loops. The event will still replay when re-entering the location.
 +
|-
 +
| <samp>mailToday {{t|mail key}}</samp>
 +
| Adds a letter to the mailbox immediately, given the {{t|mail key}} in <samp>Data/Mail</samp>.
 +
|-
 +
| <samp>questionAnswered {{t|answer ID}} {{o|answered}}</samp>
 +
| Add or remove an answer ID from the player's list of chosen dialogue answers, based on {{o|answered}} (default <samp>true</samp> to add).
 +
|-
 +
| <samp>replaceWithClone {{t|NPC name}}</samp>
 +
| Replace an NPC already in the event with a temporary copy. This allows changing the NPC for the event without affecting the real NPC.
 +
 +
For example, this event changes Marnie's name/portrait only within the event:
 +
<syntaxhighlight lang="js">
 +
"Some.ModId_ExampleEvent/": "continue/64 15/farmer 64 15 2 Marnie 64 17 0/replaceWithClone Marnie/changeName Marnie Pufferchick/changePortrait Marnie Pufferchick/[...]/end"
 +
</syntaxhighlight>
 +
|-
 +
| <samp>setSkipActions {{o|actions}}</samp>
 +
| Set [[Modding:Trigger actions|trigger actions]] that should run if the player skips the event. You can list multiple actions delimited with <samp>#</samp>, or omit {{o|actions}} so no actions are run. When the player skips, the last <samp>setSkipActions</samp> before that point is applied.
 +
 +
For example, this adds the [[Garden Pot|garden pot]] recipe and item to the player if the event is skipped, but avoids adding the item if the event already did it:
 +
<pre>
 +
/setSkipActions AddCraftingRecipe Current "Garden Pot"#AddItem (BC)62
 +
/skippable
 +
/...
 +
/addItem (BC)62
 +
/setSkipActions AddCraftingRecipe Current "Garden Pot"
 +
</pre>
 +
 +
Skip actions aren't applied if the event completes normally without being skipped.
 +
|-
 +
| <samp>stopSound {{t|sound ID}} {{o|immediate}}</samp>
 +
| Stop a sound started with the <samp>startSound</samp> command. This has no effect if the sound has already stopped playing on its own (or hasn't been started). If you started multiple sounds with the same ID, this will stop all of them (e.g. <code>startSound fuse/startSound fuse/stopSound fuse</code>).
 +
 +
By default the sound will stop immediately. For looping sounds, you can pass <samp>false</samp> to the {{o|immediate}} argument to stop the sound when it finishes playing the current iteration instead (e.g. <code>stopSound fuse false</code>).
 +
|-
 +
| <samp>temporaryAnimatedSprite ...</samp>
 +
| Add a temporary animated sprite to the event, using these space-delimited fields:
 +
{| class="wikitable"
 +
|-
 +
! index
 +
! field
 +
! effect
 +
|-
 +
| 0
 +
| <samp>texture</samp>
 +
| The asset name for texture to draw.
 +
|-
 +
| 1&ndash;4
 +
| <samp>rectangle</samp>
 +
| The pixel area within the <samp>texture</samp> to draw, in the form <samp>{{t|x}} {{t|y}} {{t|width}} {{t|height}}</samp>.
 +
|-
 +
| 5
 +
| <samp>interval</samp>
 +
| The millisecond duration for each frame in the animation.
 +
|-
 +
| 6
 +
| <samp>frames</samp>
 +
| The number of frames in the animation.
 +
|-
 +
| 7
 +
| <samp>loops</samp>
 +
| The number of times to repeat the animation.
 +
|-
 +
| 8&ndash;9
 +
| <samp>tile</samp>
 +
| The tile position at which to draw the sprite, in the form <samp>{{t|x}} {{t|y}}</samp>.
 +
|-
 +
| 10
 +
| <samp>flicker</samp>
 +
| Causes the sprite to flicker in and out of view repeatedly. (one of <samp>true</samp> or <samp>false</samp>).
 +
|-
 +
| 11
 +
| <samp>flip</samp>
 +
| Whether to flip the sprite horizontally when it's drawn (one of <samp>true</samp> or <samp>false</samp>).
 +
|-
 +
| 12
 +
| <samp>sort tile Y</samp>
 +
| The tile Y position to use in the layer depth calculation, which affects which sprite is drawn on top if two sprites overlap. The larger the number, the higher layer the sprite is on.
 +
|-
 +
| 13
 +
| <samp>alpha fade</samp>
 +
| Fades out the sprite based on alpha set. The larger the number, the faster the fade out. 1 is instant.
 +
|-
 +
| 14
 +
| <samp>scale</samp>
 +
| A multiplier applied to the sprite size (in addition to the normal 4× pixel zoom).
 +
|-
 +
| 15
 +
| <samp>scale change</samp>
 +
| Changes the scale based on the multiplier applied on top of the normal zoom. Continues endlessly.
 +
|-
 +
| 16
 +
| <samp>rotation</samp>
 +
| The rotation to apply to the sprite, measured in [[wikipedia:radians|radians]].
 +
|-
 +
| 17
 +
| <samp>rotation change</samp>
 +
| Continuously rotates the sprite, causing it to spin. The speed is determined by input value.
 +
|-
 +
| 18+
 +
| ''flags''
 +
| Any combination of these space-delimited flags:
 +
* <samp>color {{t|color}}</samp>: apply a [[#Color fields|standard color]] to the sprite.
 +
* <samp>hold_last_frame</samp>: after playing the animation once, freeze the last frame as long as the sprite is shown.
 +
* <samp>ping_pong</samp>: Causes the animation frames to play forwards and backwards alternatingly. Example: An animation with the frames 0, 1, 2 will play "0 1 2 0 1 2" without the ping_pong flag and play "0 1 2 1 0" with the ping_pong flag.
 +
* <samp>motion {{t|x}} {{t|y}}</samp>: Sprite moves based on the values set. Numbers can be decimals or negative.
 +
* <samp>acceleration {{t|x}} {{t|y}}</samp>: '''[TODO: document what this does]'''
 +
* <samp>acceleration_change {{t|x}} {{t|y}}</samp>: '''[TODO: document what this does]'''
 +
|}
 +
|-
 +
| <samp>translateName {{t|actor}} {{t|translation key}}</samp>
 +
| Set the display name for an NPC in the event to match the given translation key.
 +
|-
 +
| <samp>warpFarmers [{{t|x}} {{t|y}} {{t|direction}}]+ {{t|default offset}} {{t|default x}} {{t|default}} {{t|direction}}</samp>
 +
| Warps connected players to the given [[Modding:Modder Guide/Game Fundamentals#Tiles|tile coordinates]] and [[Modding:Event data#Directions|numeric directions]]. The {{t|x}} {{t|y}} {{t|direction}} triplet is repeated for each connected player (e.g. the first triplet is for the main player, second triplet is for the first farmhand, etc). The triplets are followed by an offset direction (one of <samp>up</samp>, <samp>down</samp>, <samp>left</samp>, or <samp>right</samp>), and a final triplet which defines the default values used by any other player.
 +
|}
 +
</li>
 +
<li>Fixed some commands assuming a boolean argument is true if present, regardless of its value. This affects the <samp>changeToTemporaryMap</samp>, <samp>emote</samp>, <samp>extendSourceRect</samp>, <samp>faceDirection</samp>, <samp>globalFade</samp>, <samp>globalFadeToClear</samp>, <samp>positionOffset</samp>, and <samp>warp</samp> commands.</li>
 +
<li>Fixed some commands assuming any value except the exact case-sensitive string <samp>true</samp> is false. This affects the <samp>animate</samp>, <samp>glow</samp>, <samp>hideShadow</samp>, <samp>ignoreMovementAnimation</samp>, <samp>temporaryAnimatedSprite</samp>, <samp>temporarySprite</samp>, and <samp>viewport</samp> commands.</li>
 +
<li>Fixed some commands silently ignoring values they can't parse as the expected type. This affects the <samp>addItem</samp>, <samp>makeInvisible</samp>, and <samp>removeItem</samp> commands.</li>
 +
<li>Fixed crash when some commands are passed <samp>farmer[number]</samp> for a player who's not available, or <samp>farmer[number]</samp> when they expect <samp>farmer</samp>.</li>
 +
<li>Fixed some commands not taking into account custom farmer actors when checking <samp>farmer*</samp> actor IDs.</li>
 +
<li>Fixed warp-out event commands able to use NPC-only or gendered warps. They now use a valid warp for the player if possible.</li>
 +
<li>Changed specific commands:
 +
{| class="wikitable"
 +
|-
 +
! command
 +
! changes
 +
|-
 +
| <samp>addCookingRecipe</samp>
 +
| Fixed error if player already knows the recipe.
 +
|-
 +
| <samp>addMailReceived</samp>
 +
| &#32;
 +
* Renamed to <samp>mailReceived</samp>. (The old name is now an alias, so it'll still work.)
 +
* You can now remove a mail received by setting the optional third argument to false, like <samp>mailReceived {{t|id}} false</samp>.
 +
|-
 +
| <samp>addTemporaryActor</samp>
 +
| &#32;
 +
* Underscores in the asset name are now only replaced with spaces if an exact match wasn't found. You should quote arguments containing spaces instead, like <code>addTemporaryActor "White Chicken" …</code>.
 +
* Underscores in the display name are no longer replaced with spaces. You should quote arguments containing spaces instead.
 +
* Argument 9 ({{o|animal name}}) is now {{o|override name}}, and can be used to set the name for non-animals too.
 +
|-
 +
| <samp>animate</samp>
 +
| Underscores in the NPC name are now only replaced with spaces if an exact match wasn't found. You should quote arguments containing spaces instead, like <code>animate "Mr Qi" …</code>.
 +
|-
 +
| <samp>ambientLight</samp>
 +
| Removed four-argument form (which was unused and had confusing behavior). The other versions of <samp>ambientLight</samp> still work like before.
 +
|-
 +
| <samp>awardFestivalPrize</samp>
 +
| Added support for arbitrary item IDs, like <code>awardFestivalPrize (O)128</code> for a pufferfish.
 +
|-
 +
| <samp>changeLocation</samp>
 +
| It now updates the event position offset if needed.
 +
|-
 +
| <samp>changeName</samp>
 +
| Underscores in the NPC name are no longer replaced with spaces. You should quote arguments containing spaces instead, like <code>changeName Leo "Neo Leo"</code>.
 +
|-
 +
| <samp>changePortrait</samp><br /><samp>changeSprite</samp>
 +
| You can now omit the suffix argument to reset the NPC back to their normal portrait/sprite.
 +
|-
 +
| <samp>faceDirection</samp>
 +
| You can now specify the direction in words, like <samp>faceDirection up</samp>
 +
|-
 +
| <samp>ignoreMovementAnimation</samp>
 +
| &#32;
 +
* Fixed its ''ignore'' argument being ignored.
 +
* Underscores in the NPC name are now only replaced with spaces if an exact match wasn't found. You should quote arguments containing spaces instead, like <code>ignoreMovementAnimation "Mr Qi" …</code>.
 +
|-
 +
| <samp>itemAboveHead</samp>
 +
| Added support for arbitrary item IDs, like <code>itemAboveHead (O)128</code> for a pufferfish.
 +
|-
 +
| <samp>makeInvisible</samp>
 +
| Fixed terrain features not hidden when using the default area size.
 +
|-
 +
| <samp>playSound</samp>
 +
| Sounds started via <samp>playSound</samp> now stop automatically when the event ends.
 +
|-
 +
| <samp>removeItem</samp>
 +
| Added argument for an optional count, like <code>removeItem (O)128 10</code> to remove 10 pufferfish.
 +
|-
 +
| <samp>speak</samp>
 +
| Fixed friendship & socialize quest not updated when calling it with a translation key.
 +
|}</li>
 +
<li>Removed some commands:
 +
{| class="wikitable"
 +
|-
 +
! command
 +
! changes
 +
|-
 +
| <samp>addToTable</samp>
 +
| Removed (it was unused and worked in counterintuitive ways).
 +
|-
 +
| <samp>addTool</samp>
 +
| Removed (it was unused and only supported the [[Return Scepter|return scepter]]). Use <samp>addItem</samp> instead, which supports adding tools.
 +
|-
 +
| <samp>grabObject</samp>
 +
| Removed (it was unused and broken).
 +
|-
 +
| <samp>showRivalFrame</samp><br /><samp>taxVote</samp>
 +
| Removed (they were part of unimplemented features).
 +
|-
 +
| <samp>weddingSprite</samp>
 +
| Removed (it was broken and unused).
 +
|}
 +
</ul>
 +
 +
====Festival changes====
 +
* Festivals can now have a custom festival-started notification message by setting the <samp>startedMessage</samp> field in <samp>Data/Festivals/*</samp> to a [[Modding:Tokenizable strings|tokenizable string]].
 +
* Festivals now set the event ID to a value like <samp>festival_fall16</samp>, instead of <samp>-1</samp>.
 +
* All in-festival data fields now support [[Modding:Festival data#Year variants|year variants]].
 +
* Fixed NPCs getting duplicated in festivals if they're added to the <samp>set-up</samp> fields multiple times. Subsequent entries now move them instead.
 +
* Fixed [[Modding:Festival data#Year variants|year variants]] for festival <samp>set-up</samp> field being appended to the main script instead of replacing it.
 +
 +
====Send-mail (<samp>x</samp>) precondition deprecated====
 +
Using the <samp>x</samp> event precondition as a way to send mail is now deprecated (but still works). You should use [[#Trigger actions|trigger actions]] instead to perform actions like that.
 +
 +
All vanilla events which used it have been replaced by equivalent trigger actions. This event IDs below no longer exist; if you check them (e.g. via <samp>HasSeenEvent</samp>), you'll need to check the new action or the mail flag they set instead.
 +
{| class="wikitable"
 +
|-
 +
! old event ID
 +
! new action ID
 +
! mail flag
 +
|-
 +
| <samp>68</samp>
 +
| <samp>Mail_Mom_5K</samp>
 +
| <samp>mom1</samp>
 +
|-
 +
| <samp>69</samp>
 +
| <samp>Mail_Mom_15K</samp>
 +
| <samp>mom2</samp>
 +
|-
 +
| <samp>70</samp>
 +
| <samp>Mail_Mom_32K</samp>
 +
| <samp>mom3</samp>
 +
|-
 +
| <samp>71</samp>
 +
| <samp>Mail_Mom_120K</samp>
 +
| <samp>mom4</samp>
 +
|-
 +
| <samp>72</samp>
 +
| <samp>Mail_Dad_5K</samp>
 +
| <samp>dad1</samp>
 +
|-
 +
| <samp>73</samp>
 +
| <samp>Mail_Dad_15K</samp>
 +
| <samp>dad2</samp>
 +
|-
 +
| <samp>74</samp>
 +
| <samp>Mail_Dad_32K</samp>
 +
| <samp>dad3</samp>
 +
|-
 +
| <samp>75</samp>
 +
| <samp>Mail_Dad_120K</samp>
 +
| <samp>dad4</samp>
 +
|-
 +
| <samp>76</samp>
 +
| <samp>Mail_Tribune_UpAndComing</samp>
 +
| <samp>newsstory</samp>
 +
|-
 +
| <samp>706</samp>
 +
| <samp>Mail_Pierre_Fertilizers</samp>
 +
| <samp>fertilizers</samp>
 +
|-
 +
| <samp>707</samp>
 +
| <samp>Mail_Pierre_FertilizersHighQuality</samp>
 +
| <samp>fertilizers2</samp>
 +
|-
 +
| <samp>909</samp>
 +
| <samp>Mail_Robin_Woodchipper</samp>
 +
| <samp>WoodChipper</samp>
 +
|-
 +
| <samp>2111194</samp>
 +
| <samp>Mail_Emily_8heart</samp>
 +
| <samp>EmilyClothingTherapy</samp>
 +
|-
 +
| <samp>2111294</samp>
 +
| <samp>Mail_Emily_10heart</samp>
 +
| <samp>EmilyCamping</samp>
 +
|-
 +
| <samp>2346091</samp>
 +
| <samp>Mail_Alex_10heart</samp>
 +
| <samp>joshMessage</samp>
 +
|-
 +
| <samp>2346092</samp>
 +
| <samp>Mail_Sam_10heart</samp>
 +
| <samp>samMessage</samp>
 +
|-
 +
| <samp>2346093</samp>
 +
| <samp>Mail_Harvey_10heart</samp>
 +
| <samp>harveyBalloon</samp>
 +
|-
 +
| <samp>2346094</samp>
 +
| <samp>Mail_Elliott_10heart</samp>
 +
| <samp>elliottBoat</samp>
 +
|-
 +
| <samp>2346095</samp>
 +
| <samp>Mail_Elliott_8heart</samp>
 +
| <samp>elliottReading</samp>
 +
|-
 +
| <samp>2346096</samp>
 +
| <samp>Mail_Penny_10heart</samp>
 +
| <samp>pennySpa</samp>
 +
|-
 +
| <samp>2346097</samp>
 +
| <samp>Mail_Abigail_8heart</samp>
 +
| <samp>abbySpiritBoard</samp>
 +
|-
 +
| <samp>3333094</samp>
 +
| <samp>Mail_Pierre_ExtendedHours</samp>
 +
| <samp>pierreHours</samp>
 +
|-
 +
| <samp>3872126</samp>
 +
| <samp>Mail_Willy_BackRoomUnlocked</samp>
 +
| <samp>willyBackRoomInvitation</samp>
 +
|}
 +
 +
===[[Modding:Mail data|Mail]] changes===
 +
{{/doc status|[[Modding:Mail data]]|done=false}}
 +
 +
<ul>
 +
<li>Mail can now have multiple items attached (using multiple <samp>%item</samp> commands). When the player grabs the top item, the next one will appear in the slot to grab next.</li>
 +
<li>Added mail commands:
 +
{| class="wikitable"
 +
|-
 +
! command
 +
! effect
 +
|-
 +
| <samp>%action {{t|action}}%%</samp>
 +
| Run a [[Modding:Trigger actions|trigger action string]], like <samp>%action AddMoney 500%%</samp> to add {{price|500}} to the current player.
 +
|}</li>
 +
<li>Improved mail commands:
 +
{| class="wikitable"
 +
|-
 +
! command
 +
! changes
 +
|-
 +
| <samp>%item</samp>
 +
| &#32;
 +
* Added <samp>%item id {{t|item id}} {{o|count}}</samp> form which accepts a [[#Custom items|qualified or unqualified item ID]]. If multiple items are listed (''e.g.,'' <samp>%item id (BC)12 3 (O)34 5 %%</samp>) one set will be picked randomly. This deprecates the <samp>bigobject</samp>, <samp>furniture</samp>, <samp>object</samp>, and <samp>tools</samp> options.
 +
* Added <samp>%item specialOrder {{t|order id}} {{o|immediately}}</samp> form to attach a special order to the letter.
 +
* Added optional {{t|key}} argument to <samp>%item cookingRecipe {{t|key}}</samp>, to learn a specific [[Modding:Recipe data|cooking recipe]]. The previous <samp>%item cookingRecipe</samp> form (without a key) works the same way as before.
 +
* The type argument is now case-insensitive.
 +
* Fixed <samp>%item craftingRecipe</samp> not supporting recipe IDs containing underscores. It now checks for an exact match first, then tries replacing underscores with spaces like before, then logs a warning if neither was found instead of adding an invalid recipe.
 +
|}</li>
 +
<li>All wallet items are now tracked via mail flags. That adds these mail flags: <samp>HasClubCard</samp>, <samp>HasDarkTalisman</samp>, <samp>HasDwarvishTranslationGuide</samp>, <samp>HasMagicInk</samp>, <samp>HasMagnifyingGlass</samp>, <samp>HasRustyKey</samp>, <samp>HasSkullKey</samp>, <samp>HasSpecialCharm</samp>, <samp>HasTownKey</samp>, and <samp>HasUnlockedSkullDoor</samp>.</li>
 +
<li>Fixed letter viewer error when opening an invalid letter.</li>
 +
</ul>
 +
 +
===Stat changes for C# mods===
 +
The tracked stats API (e.g. <code>Game1.stats</code> and <code>Game1.player.stats</code>) has been overhauled.
 +
 +
In particular, all stats are now in the underlying stat dictionary. If you use a stat field directly (like <code>stats.dirtHoed</code>), you'll need to use the property (like <code>stats.DirtHoed</code>) or method (like <code>stats.Get(StatsKey.DirtHoed)</code>). This lets the game or mods access all stats in a standard way without reflection. 1.6 also adds <samp>StatsKey</samp> constants for all stats tracked by the game.
 +
 +
The <samp>stats</samp> API has also been redesigned:
 +
{| class="wikitable"
 +
|-
 +
! member
 +
! comments
 +
|-
 +
| <samp>Values</samp>
 +
| The numeric metrics tracked by the game. This replaces <samp>stats_dictionary</samp>.
 +
|-
 +
| <samp>Get(key)</samp>
 +
| Get the value of a tracked stat. This replaces <samp>getStat</samp>.
 +
 +
For example:
 +
<syntaxhighlight lang="c#">
 +
uint daysPlayed = Game1.stats.Get(StatKeys.DaysPlayed);
 +
</syntaxhighlight>
 +
|-
 +
| <samp>Set(key, value)</samp>
 +
| Set the new value of a tracked stat. This method is new.
 +
 +
For example:
 +
<syntaxhighlight lang="c#">
 +
Game1.stats.Set(StatKeys.ChildrenTurnedToDoves, 5);
 +
</syntaxhighlight>
 +
|-
 +
| <samp>Increment(key)</samp><br /><samp>Increment(key, amount)</samp>
 +
| Add the given amount to the stat (default 1), and return the new stat value. This improves on the original <samp>incrementStat</samp>.
 +
 +
For example:
 +
<syntaxhighlight lang="c#">
 +
uint stepsTaken = Game1.stats.Increment(StatKeys.StepsTaken);
 +
</syntaxhighlight>
 +
|}
 +
 +
This can also be used to track custom mod stats, they doesn't need to be stats normally tracked by the game. Custom stats should be prefixed with your mod's unique ID to avoid conflicts:
 +
<syntaxhighlight lang="c#">
 +
Game1.stats.Set("Your.ModId_CustomStat", 5);
 +
</syntaxhighlight>
 +
 +
And finally, setting a stat to 0 now removes it from the stats dictionary (since that's the default for missing stats).
 +
 +
===New C# utility methods===
 +
Stardew Valley 1.6 adds several new methods to simplify common logic.
 +
 +
====Argument handling====
 +
The new <samp>ArgUtility</samp> class handles splitting, reading, and validating <samp>string[]</samp> argument lists. The main methods are:
 +
 +
; Splitting arrays&#58;
 +
: {| class="wikitable"
 +
|-
 +
! <samp>ArgUtility</samp> method
 +
! effect
 +
|-
 +
| <samp>SplitBySpace</samp>
 +
| Split space-separated arguments in a string. This automatically ignores extra spaces, so <samp>" x &nbsp;y "</samp> and <samp>"x y"</samp> are equivalent. For example:
 +
<syntaxhighlight lang="c#">
 +
string[] fields = ArgUtility.SplitBySpace("a b c");
 +
string secondField = fields[1]; // "b"
 +
</syntaxhighlight>
 +
|-
 +
| <samp>SplitBySpaceAndGet</samp>
 +
| Get the value at an index in a space-delimited string (if found), else return the default value. For example:
 +
 +
<syntaxhighlight lang="c#">
 +
string thirdField = ArgUtility.SplitBySpaceAndGet("a b c", 2); // "c"
 +
string invalidFieldA = ArgUtility.SplitBySpaceAndGet("a b c", 5); // null
 +
string invalidFieldB = ArgUtility.SplitBySpaceAndGet("a b c", 5, defaultValue: "boop"); // "boop"
 +
</syntaxhighlight>
 +
 +
This is more efficient than <samp>SplitBySpace</samp> when you only need a single value, but it's slower if you need multiple values.
 +
|-
 +
| <samp>SplitBySpaceQuoteAware</samp>
 +
| Split space-separated arguments in a string, with support for using quotes to protect spaces within an argument. See <samp>SplitQuoteAware</samp> below for info on quote handling.
 +
 +
For example:
 +
<syntaxhighlight lang="c#">
 +
string buildingName = ArgUtility.SplitBySpaceQuoteAware("BUILDINGS_CONSTRUCTED Here \"Junimo Hut\"")[1]; // Junimo Hut
 +
</syntaxhighlight>
 +
|-
 +
| <samp>SplitQuoteAware</samp>
 +
| Split delimited arguments in a string, with support for using quotes to protect delimiters within an argument.
 +
 +
A quote in the text causes any delimiter to be ignored until the next quote, unless it's escaped like <code>\"</code>. Unescaped quotes are removed from the string. (Remember that backslashes need to be escaped in C# or JSON strings, like <code>"\\"</code> for a single backslash.)
 +
 +
For example:
 +
<syntaxhighlight lang="c#">
 +
ArgUtility.SplitQuoteAware("A,B,C", ',');        // [ "A", "B", "C" ]
 +
ArgUtility.SplitQuoteAware("A,\"B,C\",D", ','); // [ "A", "B,C", "D" ]
 +
ArgUtility.SplitQuoteAware("A,\\\"B,C", ',');    // [ "A", "\"B", "C" ]
 +
</syntaxhighlight>
 +
 +
You can also set the optional arguments for more advanced cases. For example, [[Modding:Game state queries|game state queries]] use this to split twice:
 +
<syntaxhighlight lang="c#">
 +
string gameStateQuery = "BUILDINGS_CONSTRUCTED Here \"Junimo Hut\", SEASON Spring";
 +
 +
string[] queries = ArgUtility.SplitQuoteAware(gameStateQuery, ',', StringSplitOptions.RemoveEmptyEntries, keepQuotesAndEscapes: true); // [ "BUILDINGS_CONSTRUCTED Here \"Junimo Hut\"", "SEASON Spring" ]
 +
string buildingName = ArgUtility.SplitBySpaceQuoteAware(queries[0]); // Junimo Hut
 +
</syntaxhighlight>
 +
|-
 +
| <samp>EscapeQuotes</samp>
 +
| Escape quotes in a string so they're ignored by methods like <samp>SplitQuoteAware</samp>.
 +
 +
This isn't idempotent (e.g. calling it twice will result in double-escaped quotes).
 +
|-
 +
| <samp>UnsplitQuoteAware</samp>
 +
| Combine an array of arguments into a single string with a custom delimiter, using quotes where needed to escape delimiters within an argument. Calling <samp>SplitQuoteAware</samp> on the resulting string with the same delimiter will produce the original values.
 +
 +
For example:
 +
<syntaxhighlight lang="c#">
 +
string args = ArgUtility.UnsplitQuoteAware(new[] { "A", "B C", "D" }, ' '); // A "B C" D
 +
</syntaxhighlight>
 +
 +
This isn't idempotent (e.g. calling it twice will result in double-escaped quotes).
 +
|}
 +
 +
; Reading arrays&#58;
 +
: {| class="wikitable"
 +
|-
 +
! <samp>ArgUtility</samp> method
 +
! effect
 +
|-
 +
| <samp>HasIndex</samp>
 +
| Get whether an index is within the bounds of the array. For example:
 +
<syntaxhighlight lang="c#">
 +
string[] fields = ArgUtility.SplitByString("10 5");
 +
bool inRange = ArgUtility.HasIndex(fields, 1); // true (index 1 has the value '5')
 +
</syntaxhighlight>
 +
|-
 +
| <samp>Get</samp><br /><samp>GetBool</samp><br /><samp>GetDirection</samp><br /><samp>GetEnum</samp><br /><samp>GetFloat</samp><br /><samp>GetInt</samp>
 +
| Get the value at a position in an array, parsed as the relevant type (e.g. a string, boolean, [[Modding:Event data#Directions|direction]], enum, etc). If the index isn't in the array or the value can't be parsed as the expected type, returns a default value.
 +
 +
For example, code like this:
 +
<syntaxhighlight lang="c#">
 +
int value = fields.Length > 4 && int.TryParse(fields[4], out int parsed)
 +
    ? parsed
 +
    : -1;
 +
</syntaxhighlight>
 +
 +
Can now be rewritten like this:
 +
<syntaxhighlight lang="c#">
 +
int value = ArgUtility.GetInt(fields, 4, -1);
 +
</syntaxhighlight>
 +
|-
 +
| <samp>TryGet</samp><br /><samp>TryGetBool</samp><br /><samp>TryGetDirection</samp><br /><samp>TryGetEnum</samp><br /><samp>TryGetFloat</samp><br /><samp>TryGetInt</samp><br /><samp>TryGetPoint</samp><br /><samp>TryGetRectangle</samp><br /><samp>TryGetVector2</samp>
 +
| Try to get a parsed value from an array by its index. If it's not found or can't be converted to the expected value, it sets the <samp>out string error</samp> argument so you can log an error if needed.
 +
 +
For example, this parses a numeric value from a space-delimited string:
 +
<syntaxhighlight lang="c#">
 +
string[] fields = ArgUtility.SplitByString("10 35");
 +
if (ArgUtility.TryGetInt(fields, 1, out int value, out string error))
 +
    this.Helper.Monitor.Log($"Parsed value: {value}"); // "Parsed value: 35"
 +
else
 +
    this.Helper.Monitor.Log($"Failed parsing value: {error}", LogLevel.Warn);
 +
</syntaxhighlight>
 +
|-
 +
| <samp>TryGetOptional</samp><br /><samp>TryGetOptionalBool</samp><br /><samp>TryGetOptionalDirection</samp><br /><samp>TryGetOptionalEnum</samp><br /><samp>TryGetOptionalFloat</samp><br /><samp>TryGetOptionalInt</samp><br /><samp>TryGetOptionalRemainder</samp>
 +
| Equivalent to <samp>TryGet*</samp>, except that it'll return a default value if the argument is missing. For example:
 +
<syntaxhighlight lang="c#">
 +
string[] fields = ArgUtility.SplitByString("10");
 +
if (ArgUtility.TryGetOptionalInt(fields, 1, out int value, out error, defaultValue: 99))
 +
    this.Helper.Monitor.Log($"Parsed value: {value}"); // "Parsed value: 99"
 +
else
 +
    this.Helper.Monitor.Log($"Failed parsing value: {error}", LogLevel.Warn);
 +
</syntaxhighlight>
 +
|-
 +
| <samp>GetRemainder</samp><br /><samp>TryGetRemainder</samp><br /><samp>TryGetOptionalRemainder</samp>
 +
| Similar to the previous methods, but gets arguments starting from an index as a concatenated string. For example:
 +
<syntaxhighlight lang="c#">
 +
string[] fields = ArgUtility.SplitByString("A B C D E F");
 +
if (ArgUtility.TryGetRemainder(fields, 2, out string remainder, out string error))
 +
    this.Helper.Monitor.Log($"Remainder: {remainder}"); // "Remainder: C D E F"
 +
else
 +
    this.Helper.Monitor.Log($"Failed getting remainder: {error}", LogLevel.Warn);
 +
</syntaxhighlight>
 +
|-
 +
| <samp>GetSubsetOf</samp>
 +
| Get a slice of the input array. For example:
 +
<syntaxhighlight lang="c#">
 +
string[] subset1 = ArgUtility.GetSubsetOf(new[] { "A", "B", "C", "D" }, startAt: 1); // B, C, D
 +
string[] subset2 = ArgUtility.GetSubsetOf(new[] { "A", "B", "C", "D" }, startAt: 1, length: 2); // B, C
 +
</syntaxhighlight>
 +
 +
This is fault-tolerant as long as <samp>startAt</samp> isn't negative. For example:
 +
<syntaxhighlight lang="c#">
 +
string[] subset2 = ArgUtility.GetSubsetOf(new[] { "A", "B", "C", "D" }, startAt: 100); // <empty array>
 +
string[] subset1 = ArgUtility.GetSubsetOf(new[] { "A", "B", "C", "D" }, startAt: 1, length: 100); // B, C, D
 +
</syntaxhighlight>
 +
|}
 +
 +
====Content assets====
 +
{| class="wikitable"
 +
|-
 +
! method
 +
! effect
 +
|-
 +
| <samp>LocalizedContentManager.DoesAssetExist</samp>
 +
| Get whether an asset exists in the game's <samp>Content</samp> folder or is provided through [[Modding:Modder Guide/APIs/Content|SMAPI's content API]]. For example:
 +
<syntaxhighlight lang="c#">
 +
bool exists = Game1.content.DoesAssetExist<Map>("Maps/Town");
 +
</syntaxhighlight>
 +
|-
 +
| <samp>LocalizedContentManager.IsValidTranslationKey</samp>
 +
| Get whether a string is a translation key in the form <samp>{{t|asset name}}:{{t|key}}</samp>, and the asset and key both exist. For example:
 +
<syntaxhighlight lang="c#">
 +
bool exists = Game1.content.IsValidTranslationKey("Strings\\NPCNames:Abigail");
 +
</syntaxhighlight>
 +
|}
 +
 +
====Filtering====
 +
The game now has an optimized <samp>RemoveWhere</samp> method for O(n) filtering on <samp>NetCollection</samp>, <samp>NetDictionary</samp>, <samp>NetList</samp>, and (via extension) <samp>IDictionary</samp>. This also deprecates <samp>Filter</samp> methods where they existed.
 +
 +
For example:
 +
<syntaxhighlight lang="c#">
 +
int dirtTilesRemoved = Game1.currentLocation.terrainFeatures.RemoveWhere(pair => pair.Value is HoeDirt);
 +
</syntaxhighlight>
 +
 +
====Game paths====
 +
The game folder paths were previously hardcoded throughout the code. These are now centralized with a few methods:
 +
 +
{| class="wikitable"
 +
|-
 +
! method
 +
! effect
 +
|-
 +
| <samp>Program.GetLocalAppDataFolder</samp><br /><samp>Program.GetAppDataFolder</samp>
 +
| Get the absolute path to the game's app data folder (which contains the [[saves|<Samp>Saves</samp> folder]]) or local app data folder (which contains <samp>ErrorLogs</samp> and <samp>Screenshots</samp>). These methods are equivalent on Windows, but different on Linux/macOS.
 +
|-
 +
| <samp>Program.GetSavesFolder</samp>
 +
| Get the absolute path to the game's [[saves|<samp>Saves</samp> folder]].
 +
|-
 +
| <samp>Game1.GetScreenshotFolder</samp>
 +
| Get the absolute path to the game's <samp>Screenshots</samp> folder.
 +
|-
 +
| <samp>options.GetFilePathForDefaultOptions</samp>
 +
| Get the absolute path to the game's <samp>default_options</samp> file.
 +
|}
 +
 +
====Hash sets====
 +
Since the [[#Hash set fields|game now uses hash sets]], it has a few extensions for working with them:
 +
 +
{| class="wikitable"
 +
|-
 +
! method
 +
! effect
 +
|-
 +
| <samp>AddRange</samp>
 +
| Add all the values from a list or enumerable to the set.
 +
|-
 +
| <samp>RemoveWhere</samp>
 +
| Remove all values matching a condition.
 +
|-
 +
| <samp>Toggle</samp>
 +
| Add or remove a value in the set based on a boolean. For example:
 +
<syntaxhighlight lang="c#">
 +
public bool hasClubCard
 +
{
 +
    get { return mailReceived.Contains("HasClubCard"); }
 +
    set { mailReceived.Toggle("HasClubCard", value); }
 +
}
 +
</syntaxhighlight>
 +
|}
 +
 +
====Iteration====
 +
The new <samp>Utility.ForEach*</samp> methods let you check every thing of a type in the game world quickly and efficiently (with minimal allocations, boxing, etc). These are significantly faster than equivalent code using LINQ or <samp>yield</samp> methods.
 +
 +
{| class="wikitable"
 +
|-
 +
! method
 +
! effect
 +
|-
 +
| <samp>Utility.ForEachBuilding</samp>
 +
| Perform an action for each building in the game world.
 +
|-
 +
| <samp>Utility.ForEachCharacter</samp><br /><samp>Utility.ForEachVillager</samp>
 +
| Perform an action for each NPC in the game world. <samp>ForEachCharacter</samp> matches all NPC types (villagers, horses, pets, monsters, player children, etc), while <samp>ForEachVillager</samp> only matches villager NPCs like [[Abigail]].
 +
|-
 +
| <samp>Utility.ForEachCrop</samp>
 +
| Perform an action for each crop in the game world planted in the ground or in a [[Garden Pot|garden pot]].
 +
|-
 +
| <samp>Utility.ForEachItem</samp>
 +
| Perform an action for each item in the game world, including items within items (e.g. in a chest or on a table), hats placed on children, items in player inventories, etc.
 +
|-
 +
| <samp>Utility.ForEachItemIn</samp>
 +
| Perform an action for each item within a given location, including items within items (e.g. in a chest or on a table).
 +
|-
 +
| <samp>Utility.ForEachLocation</samp>
 +
| Perform an action for each location in the game world, optionally including building interiors and generated [[The Mines|mine]] or [[Volcano Dungeon|volcano]] levels.
 +
|}
 +
 +
For example, this code counts how many parsnips are planted everywhere in the world:
 +
<syntaxhighlight lang="c#">
 +
int parsnips = 0;
 +
Utility.ForEachCrop(crop =>
 +
{
 +
    if (crop.IndexOfHarvest == "24")
 +
        parsnips++;
 +
    return true; // whether to keep iterating after this crop
 +
});
 +
</syntaxhighlight>
 +
 +
Or you could replace all instances of an obsolete item with a new one:
 +
<syntaxhighlight lang="c#">
 +
Utility.ForEachItem((item, remove, replaceWith) =>
 +
{
 +
    if (item.QualifiedItemId == "(O)OldId")
 +
    {
 +
        Item newItem = ItemRegistry.Create("(O)NewId", item.Stack, item.Quality);
 +
        replaceWith(newItem);
 +
    }
 +
 +
    return true;
 +
});
 +
</syntaxhighlight>
 +
C# mods which add custom item types can override <samp>Item.ForEachItem</samp> to add support for nested items.
 +
 +
====Randomization====
 +
{| class="wikitable"
 +
|-
 +
! method
 +
! effect
 +
|-
 +
| <samp>Utility.CreateDaySaveRandom</samp>
 +
| Creates a <samp>Random</samp> instance using the most common seed (based on the save ID and total days played).
 +
|-
 +
| <samp>Utility.CreateRandom</samp><br /><samp>Utility.CreateRandomSeed</samp>
 +
| Creates a <samp>Random</samp> (or seed for a <samp>Random</samp>) by combining the given seed values, which can be any numeric type.
 +
|-
 +
| <samp>Utility.TryCreateIntervalRandom</samp>
 +
| Get an RNG which produces identical results for all RNGs created with the same sync key during the given interval (one of <samp>tick</samp>, <samp>day</samp>, <samp>season</samp>, or <samp>year</samp>), including between players in multiplayer mode.
 +
 +
For example, this will return the same number each time it's called until the in-game day changes:
 +
<syntaxhighlight lang="c#">
 +
public int GetDailyRandomNumber()
 +
{
 +
    Utility.TryCreateIntervalRandom("day", "example sync key", out Random random, out _);
 +
    return random.Next();
 +
}
 +
</syntaxhighlight>
 +
|-
 +
| <samp>Utility.TryGetRandom</samp>
 +
| Get a random entry from a dictionary.
 +
|-
 +
| <samp>random.Choose</samp>
 +
| Choose a random option from the values provided:
 +
<syntaxhighlight lang="c#">
 +
string npcName = Game1.random.Choose("Abigail", "Penny", "Sam");
 +
</syntaxhighlight>
 +
|-
 +
| <samp>random.ChooseFrom</samp>
 +
| Choose a random option from a list or array:
 +
<syntaxhighlight lang="c#">
 +
string[] names = new[] { "Abigail", "Penny", "Sam" };
 +
string npcName = Game1.random.ChooseFrom(names);
 +
</syntaxhighlight>
 +
|-
 +
| <samp>random.NextBool</samp>
 +
| Randomly choose <samp>true</samp> or <samp>false</samp>. For example:
 +
<syntaxhighlight lang="c#">
 +
bool flipSprite = Game1.random.NextBool();
 +
</syntaxhighlight>
 +
 +
You can optionally set the probability of <samp>true</samp>:
 +
<syntaxhighlight lang="c#">
 +
bool flipSprite = Game1.random.NextBool(0.8);
 +
</syntaxhighlight>
 +
|}
 +
 +
====Other====
 +
Here are some of the other new methods:
 +
 +
{| class="wikitable"
 +
|-
 +
! method
 +
! effect
 +
|-
 +
| <samp>Game1.getOfflineFarmhands()</samp>
 +
| Get all farmhands who aren't connected to the game.
 +
|-
 +
| <samp>Game1.PerformActionWhenPlayerFree</samp>
 +
| Calls the provided callback next time the player is free (e.g. no menu or event is up, not using a tool, etc). If the player is already free, it's run immediately.
 +
 +
For example, if you receive your first geode from a fishing chest, this is used to show the geode-received animation & animation when it closes.
 +
|-
 +
| <samp>Game1.createRadialDebris_MoreNatural</samp>
 +
| Scatter item debris around a position with a more randomized distribution than <samp>createRadialDebris</samp>.
 +
|-
 +
| <samp>Object.GetCategoryColor</samp><br /><samp>Object.GetCategoryDisplayName</samp>
 +
| Get the color and display name for the given category number when it's shown in a tooltip.
 +
|-
 +
| <samp>Utility.distanceFromScreen</samp>
 +
| Get the pixel distance between a position in the world and the player's screen viewport, where 0 is within the viewport.
 +
|-
 +
| <samp>Utility.DrawErrorTexture</samp>
 +
| Draw the game's missing-texture image (🚫) to the screen, stretched to fit a given pixel area.
 +
|-
 +
| <samp>Utility.DrawSquare</samp>
 +
| Draw a square to the screen with a background color and/or borders.
 +
|-
 +
| <samp>Utility.GetEnumOrDefault</samp>
 +
| Get an enum value if it's valid, else get a default value. This is mainly used to validate input from data files.
 +
 +
For example:
 +
<syntaxhighlight lang="c#">
 +
NpcGender gender = (NPCGender)999999;
 +
gender = Utility.GetEnumOrDefault(gender, Gender.Male); // returns Gender.Male since there's no enum constant with value 999999
 +
</syntaxhighlight>
 +
|-
 +
| <samp>Utility.getRandomNpcFromHomeRegion</samp>
 +
| Get a random social NPC based on their <samp>HomeRegion</samp> value in [[#Custom NPCs|<samp>Data/Characters</samp>]]. For example, this gets a random NPC for the <samp>Town</samp> home region:
 +
<syntaxhighlight lang="c#">
 +
NPC npc = Utility.getRandomNpcFromHomeRegion(NPC.region_town);
 +
</syntaxhighlight>
 +
|-
 +
| <samp>Utility.isFestivalDay</samp>
 +
| This method existed before 1.6, but you can now omit arguments to check today instead of a specific date:
 +
<syntaxhighlight lang="c#">
 +
bool festivalToday = Utility.isFestivalToday();
 +
</syntaxhighlight>
 +
 +
Or check for a festival in specific location context:
 +
<syntaxhighlight lang="c#">
 +
bool desertFestivalToday = Utility.isFestivalToday(LocationContexts.DesertId);
 +
</syntaxhighlight>
 +
|-
 +
| <samp>Utility.IsPassiveFestivalDay</samp>
 +
| This method existed before 1.6, but now can now omit arguments to check today instead of a specific date:
 +
<syntaxhighlight lang="c#">
 +
bool passiveFestivalToday = Utility.IsPassiveFestivalDay();
 +
</syntaxhighlight>
 +
 +
Or check for a specific passive festival:
 +
<syntaxhighlight lang="c#">
 +
bool nightMarketToday = Utility.IsPassiveFestivalDay("NightMarket");
 +
</syntaxhighlight>
 +
|-
 +
| <samp>Utility.TryGetPassiveFestivalData</samp><br /><samp>Utility.TryGetPassiveFestivalDataForDay</samp>
 +
| Get the [[#Custom passive festivals|passive festival data]] for the given ID or date.
 +
|-
 +
| <samp>Utility.TryParseDirection</samp>
 +
| Parse a string into a direction value (like <samp>Game1.down</samp>), if it's valid. This supports case-insensitive direction names (one of <samp>down</samp>, <samp>left</samp>, <samp>right</samp>, or <samp>up</samp>) or [[Modding:Event data#Directions|numeric values]].
 +
|-
 +
| <samp>Utility.TryParseEnum</samp>
 +
| Parse a string into an enum value if possible, case-insensitively. Unlike [https://learn.microsoft.com/en-us/dotnet/api/system.enum.tryparse <samp>Enum.TryParse</samp>], an invalid numeric value won't be cast:
 +
<syntaxhighlight lang="c#">
 +
Enum.TryParse("999999", out DayOfWeek day);        // true, even though there's no matching DayOfWeek value
 +
Utility.TryParseEnum("999999", out DayOfWeek day); // false
 +
</syntaxhighlight>
 +
|-
 +
| <samp>Utility.fuzzyCompare</samp>
 +
| Get whether a term is a fuzzy match for a search query. Returns the numeric match priority (where lower values are a better match), or null if the term doesn't match the query.
 +
|-
 +
| <samp>rectangle.GetPoints</samp><br /><samp>rectangle.GetVectors</samp>
 +
| Get all the integer coordinates within a given <samp>Rectangle</samp>. For example:
 +
<syntaxhighlight lang="c#">
 +
var tileArea = new Rectangle(0, 0, 2, 2);
 +
Point[] tiles = tileArea.GetPoints(); // (0, 0), (1, 0), (0, 1), (1, 1)
 +
</syntaxhighlight>
 +
|-
 +
| <samp>Utility.GetDeterministicHashCode</samp>
 +
| ''(Specialized)'' Get a [https://en.wikipedia.org/wiki/Hash_function hash code] for a string key or numeric values. Unlike [https://learn.microsoft.com/en-us/dotnet/api/system.object.gethashcode <samp>string.GetHashCode</samp>] or [https://learn.microsoft.com/en-us/dotnet/api/system.hashcode.combine <samp>HashCode.Combine</samp>], this produces a consistent hash for the same inputs between sessions and connected players.
 +
|-
 +
| <samp>Utility.WrapIndex</samp>
 +
| Constrain an index to a range by wrapping out-of-bounds values to the other side (e.g. last index + 1 is the first index, and first index - 1 is the last one).
 +
 +
For example:
 +
<syntaxhighlight lang="c#">
 +
string[] values = new[] { "0", "1", "2" };
 +
int index = Utility.WrapIndex(-1, values.Length); // 2
 +
</syntaxhighlight>
 +
|}
 +
 +
===Static delegate builder===
 +
For C# mods, <samp>StaticDelegateBuilder</samp> is a specialized class which converts a method name into an optimized delegate which can be called by code. This is used by vanilla code to optimize methods referenced in assets like [[#Custom machines|<samp>Data/Machines</samp>]].
 +
 +
For example, given a static method like this:
 +
<syntaxhighlight lang="c#">
 +
public static bool OutputDeconstructor(Object machine, Item inputItem, bool probe, MachineItemOutput outputData, out int? overrideMinutesUntilReady) { ... }
 +
</syntaxhighlight>
 +
 +
And a delegate which matches it:
 +
<syntaxhighlight lang="c#">
 +
public delegate bool MachineOutputDelegate(Object machine, Item inputItem, bool probe, MachineItemOutput outputData, out int? overrideMinutesUntilReady);
 +
</syntaxhighlight>
 +
 +
You can create an optimized delegate and call it like this:
 +
<syntaxhighlight lang="c#">
 +
if (StaticDelegateBuilder.TryCreateDelegate("StardewValley.Object.OutputDeconstructor", out MachineOutputDelegate method, out string error))
 +
    return method(this, inputItem, probe, outputData, out minutesUntilMorning);
 +
else
 +
    Game1.log.Warn($"Machine {ItemId} has invalid output method: {error}");
 +
</syntaxhighlight>
 +
 +
The <samp>TryCreateDelegate</samp> method will cache created delegates, so calling it again will just return the same delegate instance.
 +
 +
===Game logging changes===
 +
The game now writes debug output through an internal <samp>Game1.log</samp> wrapper, instead of using <samp>Console.WriteLine</samp> directly. For example:
 +
<syntaxhighlight lang="c#">
 +
// old code
 +
Console.WriteLine("Error playing sound: " + ex);
 +
 +
// new code
 +
Game1.log.Error("Error playing sound.", ex);
 +
</syntaxhighlight>
 +
 +
This has a few benefits:
 +
* For vanilla players, the game no longer uses time & resources writing to a console that's not visible anyway.
 +
* For modded players, SMAPI can now...
 +
** distinguish between the game's debug/warn/error messages (so many warnings/errors that would previously appear as hidden <samp>TRACE</samp> messages will now be shown with the correct level);
 +
** apply its formatting rules to exceptions logged by the game too;
 +
** redirect game output much more efficiently without console interception.
 +
 +
===Other changes===
 +
====Audio====
 +
<ul>
 +
<li>Added <samp>Game1.sounds</samp>, which unifies the high-level sound effect logic (e.g. distance fading and multiplayer sync).</li>
 +
<li>Added <samp>silence</samp> [[Modding:Audio|audio cue]] for music. This is different from <samp>none</samp> in that it suppresses both town music and ambient sounds.</li>
 +
<li>Added <samp>Game1.soundBank.Exists(cueName)</samp> method to check if an audio cue exists.</li>
 +
<li>Added <samp>Game1.playSound</samp> overloads to get the audio cue being played.</li>
 +
<li>Added <samp>character.playNearbySoundAll</samp> and <samp>playNearbySoundAllLocal</samp> methods to play a sound for players near the player/character.</li>
 +
<li>Added position argument to <samp>DelayedAction.playSoundAfterDelay</samp>.</li>
 +
<li>Removed <samp>NetAudioCueManager</samp> and <samp>Game1.locationCues</samp> (unused).</li>
 +
<li>Unified the methods for playing normal/pitched/positional sounds (which also adds support for pitched non-synced & pitched positional sounds):
 +
{| class="wikitable"
 +
|-
 +
! old methods
 +
! new method
 +
|-
 +
| <samp>Game1.playSound</samp><br /><samp>Game1.playSoundAt</samp><br /><samp>Game1.playSoundPitched</samp>
 +
| <samp>Game1.playSound</samp>
 +
|-
 +
| <samp>GameLocation.playSound</samp><br /><samp>GameLocation.playSoundAt</samp><br /><samp>GameLocation.playSoundPitched</samp>
 +
| <samp>GameLocation.playSound</samp>
 +
|-
 +
| <samp>GameLocation.localSound</samp><br /><samp>GameLocation.localSoundAt</samp>
 +
| <samp>GameLocation.localSound</samp>
 +
|-
 +
| <samp>NetAudio.Play</samp><br /><samp>NetAudio.PlayAt</samp><br /><samp>NetAudio.PlayPitched</samp>
 +
| <samp>NetAudio.Play</samp>
 +
|-
 +
| <samp>NetAudio.PlayLocal</samp><br /><samp>NetAudio.PlayLocalAt</samp>
 +
| <samp>NetAudio.PlayLocal</samp>
 +
|}</li>
 +
</ul>
 +
 +
====Debug commands====
 +
{{/doc status|[[Modding:Console commands]]|done=false}}
 +
 +
<ul>
 +
<li>All debug commands are now quote-aware, so you can pass spaces in arguments like <code>debug build "Junimo Hut"</code>.</li>
 +
<li>Added new [[Modding:Console commands|debug commands]]:
 +
{| class="wikitable"
 +
|-
 +
! command
 +
! description
 +
|-
 +
| <samp>action {{t|action}}</samp>
 +
| Run a [[Modding:Trigger actions|trigger action string]], like <samp>action AddMoney 500</samp> to add {{price|500}} to the current player.
 +
|-
 +
| <samp>artifactSpots</samp>
 +
| Spawn an [[Artifact Spot|artifact spot]] in each empty tile around the player.
 +
|-
 +
| <samp>endEvent</samp> / <samp>ee</samp>
 +
| Immediately end the current event or festival, applying the event's skip logic (if any). The event is marked seen, but you can rewatch it using the <samp>eventById</samp> command if needed.
 +
 +
This replaces the pre-1.6 commands (<samp>ee</samp>, <samp>endEvent</samp>/<samp>leaveEvent</samp>, and <samp>eventOver</samp>) which worked in different ways and had side-effects like restarting the event or clearing the player's mail.
 +
|-
 +
| <samp>exportShops</samp>
 +
| Export a summary of what's in every shop in the game, taking into account their current conditions. This is saved to a file on disk, and the file path shown in the console.
 +
|-
 +
| <samp>filterLoadMenu</samp> / <samp>flm</samp>
 +
| ''Syntax: <samp>filterLoadMenu {{t|search text}}''
 +
 +
Filter the current list of saves to those whose player name or farm name contains the given text.
 +
|-
 +
| <samp>forcebuild</samp>
 +
| Equivalent to <samp>build</samp>, but disables all safety checks so you can build in a location that wouldn't normally allow buildings, build on top of farm animals or placed objects, etc.
 +
|-
 +
| <samp>gamequery</samp> / <samp>gq</samp>
 +
| ''Syntax:'' <samp>gq {{t|query}}</samp>
 +
 +
Check whether the given [[Modding:Game state queries|game state query]] matches in the current context. For example:
 +
<pre>
 +
gq !SEASON Spring, WEATHER Here Sun
 +
> Result: true.
 +
</pre>
 +
|-
 +
| <samp>itemquery</samp> / <samp>iq</samp>
 +
| ''Syntax:'' <samp>iq {{t|query}}</samp>
 +
 +
Open a shop menu with all the items matching an [[Modding:Item queries|item query]] (all items free). For example:
 +
* <samp>debug iq ALL_ITEMS</samp> shows all items;
 +
* <samp>debug iq ALL_ITEMS (W)</samp> shows all weapons;
 +
* <samp>debug iq (O)128</samp> shows a pufferfish (object 128);
 +
* <samp>debug iq FLAVORED_ITEM Wine (O)128</samp> shows Pufferfish Wine.
 +
|-
 +
| <samp>logFile</samp>
 +
| Begin writing debug messages to a log file at <samp>%appdata%/StardewValley/ErrorLogs/game-latest.txt</samp> to simplify troubleshooting. You can also enter <samp>/logtext</samp> into the in-game chatbox to enable it.
 +
 +
This does nothing if SMAPI is installed, since the debug messages are already saved to SMAPI's log.
 +
|-
 +
| <samp>logSounds</samp>
 +
| Log info about each sound effect played to the SMAPI console window.
 +
|-
 +
| <samp>movieSchedule {{o|year}}</samp>
 +
| Lists the movies that will play in a given {{o|year}} (default this year), with the dates they'll play.
 +
|-
 +
| <samp>qualifiedid</samp>
 +
| Print the held item's display name and [[#Custom items|qualified item ID]].
 +
|-
 +
| <samp>search</samp>
 +
| ''Syntax:'' <samp>search {{o|term}}</samp>
 +
 +
List all debug commands that match the given search term (or all debug commands if the search term is omitted). For example:
 +
<pre>debug search backpack
 +
> Found 2 debug commands matching search term 'backpack':
 +
    - Backpack
 +
    - FillBackpack (fbp, fill, fillbp)</pre>
 +
|-
 +
| <samp>setFarmEvent</samp> / <samp>sfe</samp>
 +
| ''Syntax:'' <samp>setFarmEvent {{t|event id}}</samp>
 +
 +
Queue an [[Random Events#Farm events|overnight farm event]] if one doesn't plan naturally instead. The {{t|event id}} can be one of...
 +
* <samp>dogs</samp>;
 +
* [[Random Events#Earthquake|<samp>earthquake</samp>]];
 +
* [[Random Events#The Crop Fairy|<samp>fairy</samp>]];
 +
* [[Random Events#Meteorite|<samp>meteorite</samp>]];
 +
* [[Random Events#Stone Owl|<samp>owl</samp>]];
 +
* [[Random Events#Strange Capsule|<samp>ufo</samp>]];
 +
* [[Random Events#The Witch|<samp>witch</samp>]].
 +
 +
Note that even if the farm event runs, it may exit without doing anything (e.g. rare events like <samp>ufo</samp> have extra condition checks when the start).
 +
|-
 +
| <samp>shop</samp>
 +
| ''Syntax:'' <samp>shop {{t|shop ID}} {{o|owner name}}</samp>
 +
 +
Open a [[#Custom shops|shop defined in <samp>Data/Shops</samp>]], regardless of whether one of the owners is nearby. Specifying {{o|owner name}} will use that NPC, otherwise the command will find the closest valid NPC if possible (else open with no NPC).
 +
|-
 +
| <samp>skinBuilding</samp> / <samp>bsm</samp>
 +
| If the player is standing right under a building, open a menu to change the building appearance.
 +
|-
 +
| <samp>testwedding</samp>
 +
| Immediately play the [[Marriage#The Wedding|wedding]] event. This requires the player to be married first - to test specific NPCs, <samp>debug marry</samp> the NPC followed by this command.
 +
|-
 +
| <samp>thishouseupgrade</samp> / <samp>thishouse</samp> / <samp>thu</samp>
 +
| Equivalent to <samp>houseupgrade</samp>, but can be used to upgrade another player's house by running it from inside or just south of its exterior.
 +
|-
 +
| <samp>toggleCheats</samp>
 +
| Enable or disable entering debug commands into the in-game chat (prefixed with <samp>/</samp>).
 +
|-
 +
| <samp>tokens</samp>
 +
| ''Syntax:'' <samp>tokens {{t|tokenized string}}</samp>
 +
 +
Parses a [[Modding:Tokenizable strings|tokenizable string]] and prints its output. For example:
 +
<pre>
 +
tokens [LocalizedText Strings\StringsFromCSFiles:MapPage.cs.11064 [EscapedText [FarmName]]]
 +
> Result: "Lon Lon Farm"
 +
</pre>
 +
|-
 +
| <samp>worldMapLines</samp>
 +
| Toggles the [[Modding:World map#Debug view|world map's debug view]].
 +
|}</li>
 +
<li>Improved existing debug commands:
 +
{| class="wikitable"
 +
|-
 +
! command
 +
! changes
 +
|-
 +
| <samp>build</samp>
 +
| Removed custom space handling; quote arguments with spaces instead of replacing them with 9 (e.g. <code>Junimo9Hut</code> → <code>"Junimo Hut"</code>).
 +
|-
 +
| <samp>clearFurniture</samp>
 +
| Now works outside the farmhouse too.
 +
|-
 +
| <samp>dialogue</samp>
 +
| Removed custom space handling; quote NPC names containing spaces instead, with all text after the first argument treated as part of the dialogue (e.g. <code>debug dialogue "Some NPC" Some dialogue text$h</code>).
 +
|-
 +
| <samp>ebi</samp>
 +
| Fixed event not played correctly if called from the same location as the event.
 +
|-
 +
| <samp>fish</samp>
 +
| Fixed error if you're not holding a fishing rod. It now opens the fishing minigame with no tackle instead.
 +
|-
 +
| <samp>frameOffset</samp>
 +
| &#32;
 +
* Simplified usage. You can now pass negative offsets directly (like <samp>debug frameOffset -5 -10</samp>) instead of using the <samp>s</samp> number prefix.
 +
* Fixed command only taking the last digit in each number.
 +
|-
 +
| <samp>getStat</samp><br /><samp>setStat</samp>
 +
| Added argument validation.
 +
|-
 +
| <samp>grass</samp>
 +
| Now applies to the current location, instead of the farm.
 +
|-
 +
| <samp>growAnimals</samp><br /><samp>growAnimalsFarm</samp>
 +
| Merged into one <samp>growAnimals</samp> command that supports any location and doesn't reset the age of animals which are already adults.
 +
|-
 +
| <samp>growCrops</samp>
 +
| Fixed error growing mixed seeds or giant crops.
 +
|-
 +
| <samp>itemNamed</samp>
 +
| Removed custom space handling; quote arguments with spaces instead of removing them (e.g. <code>EelRoe</code> → <code>"Eel Roe"</code>).
 +
|-
 +
| <samp>junimoGoodbye</samp><br /><samp><samp>junimoStar</samp>
 +
| Added validation to check that you're inside the community center.
 +
|-
 +
| <samp>killAll</samp><br /><samp>killAllHorses</samp><br /><samp>killNpc</samp>
 +
| These now remove matching NPCs inside constructed buildings too.
 +
|-
 +
| <samp>killMonsterStat</samp>
 +
| Removed custom space handling; quote arguments with spaces instead of replacing them with 0 (e.g. <code>Dust0Spirit</code> → <code>"Dust Spirit"</code>).
 +
|-
 +
| <samp>mailForTomorrow</samp>
 +
| Fixed zeros in the mail ID getting replaced with underscores.
 +
|-
 +
| <samp>monster</samp>
 +
| Added validation for the monster name.
 +
|-
 +
| <samp>moveBuilding</samp>
 +
| Now applies to the current location, instead of the farm.
 +
|-
 +
| <samp>movie</samp>
 +
| Rewritten; it's now simpler, applies the normal game logic, defaults to today's movie, and avoids depending on NPC indexes in <samp>Data/NPCDispositions</samp> since those can change with custom NPCs.
 +
 +
New usage:
 +
: ''<samp>debug movie {{o|movie ID}} {{o|invite NPC name}}''
 +
: ''<samp>debug movie current {{o|invite NPC name}}''
 +
 +
The movie ID defaults to today's movie, and the NPC name can be omitted to watch the movie without an invitee. Specifying <samp>current</samp> as the movie uses the default value.
 +
|-
 +
| <samp>panMode</samp>
 +
| The command no longer overrides debug command handling while it's active. Instead you can now turn it back off by running <samp>debug panMode</samp> again, clear with <samp>debug panMode clear</samp>, or set a time with <samp>debug panMode {time}</samp>.
 +
|-
 +
| <samp>paintBuilding</samp>
 +
| &#32;
 +
* Now applies to the current location, instead of the farm.
 +
* Added validation for the target building.
 +
|-
 +
| <samp>playSound</samp>
 +
| Added an optional pitch argument, like <samp>debug playSound barrelBreak 1200</samp>. The pitch is a value from 1 (low pitch) to 2400 (high pitch) inclusively.
 +
|-
 +
| <samp>question</samp>
 +
| You can now forget a selected answer (instead of adding it) by setting the second argument to false, like <samp>question {{t|id}} false</samp>.
 +
|-
 +
| <samp>runTestEvent</samp>
 +
| Fixed support for Unix line endings.
 +
|-
 +
| <samp>seenEvent</samp>
 +
| You can now forget an event (instead of adding it) by setting the second argument to false, like <samp>seenEvent {{t|id}} false</samp>.
 +
|-
 +
| <samp>seenMail</samp>
 +
| You can now remove a mail received (instead of adding it) by setting the second argument to false, like <samp>seenMail {{t|id}} false</samp>.
 +
|-
 +
| <samp>skinBuilding</samp>
 +
| &#32;
 +
* Now applies to the current location, instead of the farm.
 +
* Added validation for the target building.
 +
|-
 +
| <samp>skullGear</samp>
 +
| &#32;
 +
* Fixed command setting 32 slots instead of 36.
 +
* Fixed command not adding empty inventory slots as expected by some game code.
 +
|-
 +
| <Samp>setupFishPondFarm</samp>
 +
| Fixed error if the farm already has non-fish-pond buildings constructed.
 +
|-
 +
| <samp>speech</samp>
 +
| Removed custom space handling; quote NPC names containing spaces instead, with all text after the first argument treated as part of the dialogue (e.g. <code>debug speech "Some NPC" Some dialogue text$h</code>).
 +
|-
 +
| <samp>spreadDirt</samp>
 +
| Now applies to the current location, instead of the farm.
 +
|-
 +
| <samp>spreadSeeds</samp>
 +
| Now applies to the current location, instead of the farm.
 +
|-
 +
| <samp>thisHouseUpgrade</samp>
 +
| Now applies to the current location, instead of the farm.
 +
|-
 +
| <samp>warpToPlayer</samp>
 +
| Removed custom space handling; quote arguments with spaces instead of removing them (e.g. <code>JohnSmith</code> → <code>"John Smith"</code>).
 +
|-
 +
| <samp>whereIs</samp>
 +
| &#32;
 +
* Now lists all matching NPCs instead of the first one.
 +
* Now searches the current event or festival, if any.
 +
|}</li>
 +
 +
<li>Removed some debug commands:
 +
{| class="wikitable"
 +
|-
 +
! command
 +
! notes
 +
|-
 +
| <samp>ax</samp><br /><samp>bigItem</samp>/<samp>b</samp>/<samp>bi</samp>/<samp>big</samp><br /><samp>boots</samp><br /><samp>clothes</samp><br /><samp>hoe</samp><br /><samp>milkPail</samp>/<samp>mp</samp><br /><samp>pan</samp><br /><samp>pickaxe</samp>/<samp>pick</samp>/<samp>pickax</samp><br /><samp>ring</samp>/<samp>addRing</samp><br /><samp>shears</samp>/<samp>scissors</samp><br /><samp>slingshot</samp><br /><samp>tool</samp><br /><samp>wateringCan</samp>/<samp>can</samp><br /><samp>wand</samp><br /><samp>weapon</samp>
 +
| These are replaced by more general commands like <code>item (O)128</code> (spawn item by ID), <code>fuzzyItemNamed pufferfish</code> (spawn by item name), or <code>itemQuery FLAVORED_ITEM Wine (O)128</code> (spawn by [[Modding:Item queries|item query]]).
 +
|-
 +
| <samp>addQuartz</samp><br /><samp>blueBook</samp><br /><samp>blueprint</samp><br /><samp>end</samp>
 +
| These were part of unused features removed in 1.6.
 +
|-
 +
| <samp>changeStat</samp>
 +
| Removed; use <samp>setStat</samp> instead.
 +
|-
 +
| <samp>ee</samp><br /><samp>endEvent</samp>/<samp>leaveEvent</samp><br /><samp>eventOver</samp>
 +
| Replaced by the new <samp>endEvent</samp> command.
 +
|-
 +
| <samp>everythingshop</samp>
 +
| Removed. You can get all items like <code>debug iq ALL_ITEMS</code>, or all items of a given type like <code>debug iq ALL_ITEMS (O)</code>.
 +
|-
 +
| <samp>oldMineGame</samp>
 +
| Removed along with the pre-1.4 [[Junimo Kart]] code.
 +
|-
 +
| <samp>pathSpouseToMe</samp>/<samp>pstm</samp>
 +
| Removed along with the unimplemented farm activities code.
 +
|}</li>
 +
 +
<li>Added alternative names for some debug commands (new names in parentheses): <samp>bpm</samp> + <samp>bsm</samp> (<samp>paintBuilding</samp> + <samp>skinBuilding</samp>), <samp>craftingRecipe</samp> (</samp>addCraftingRecipe</samp>), <samp>db</samp> (</samp>speakTo</samp>), <samp>dialogue</samp> (</samp>addDialogue</samp>), <samp>pdb</samp> (</samp>printGemBirds</samp>), <samp>r</samp> (</samp>resetForPlayerEntry</samp>), <samp>removeLargeTf</samp> (</samp>removeLargeTerrainFeature</samp>), <samp>sb</samp> (</samp>showTextAboveHead</samp>), <samp>sl</samp> + <samp>sr</samp> (<samp>shiftToolbarLeft</samp> + </samp>shiftToolbarRight</samp>), <samp>sn</samp> (</samp>secretNote</samp>), and <samp>tls</samp> (</samp>toggleLightingScale</samp>).</li>
 +
<li>Reworked how debug commands log output. This fixes an issue where they don't always log to the right place (e.g. a command run through the chatbox might log to the console or vice-versa), and lets mods pass a custom logger to capture or redirect output.</li>
 +
</ul>
 +
 +
====Location logic====
 +
* The [[desert]] no longer assumes the player arrived by bus unless their previous location was the [[Bus Stop|bus stop]].
 +
* The ticket price for the bus and Willy's boat can now be edited by C# mods via <samp>BusStop.TicketPrice</samp> and <samp>BoatTunnel.TicketPrice</samp> respectively.
 +
 +
====Menus & UI====
 +
* Rewrote calendar menu (<samp>Billboard</samp>) to simplify custom events & event types. C# mods can now edit <samp>billboard.calendarDayData</samp> or patch <samp>billboard.GetEventsForDay</samp> to add new events.
 +
* Added <samp>Game1.textShadowDarkerColor</samp> field for the colors previously hardcoded in <samp>Utility.drawTextWithShadow</samp>.
 +
* Added <samp>MoneyDial.ShouldShakeMainMoneyBox</samp> field to simplify custom dials.
 +
* Partly de-hardcoded <samp>ShopMenu</samp> filter tabs. You can now change filter tabs by setting the <samp>shopMenu.tabButtons</samp> field with arbitrary <samp>Func&lt;ISalable, bool&gt; Filter</samp> values, or by using a predefined set of tabs like <samp>shopMenu.UseDresserTabs()</samp>.
 +
* The <samp>SpriteText</samp> methods now accept arbitrary <samp>Color</samp> tints instead of a few predefined color IDs.
 +
* The <samp>DiscreteColorPicker.getColorFromSelection</samp> methods are now static for reuse.
 +
* Fixed <samp>DiscreteColorPicker</samp> constructor ignoring the initial color argument, and added a constructor which takes a <samp>Color</samp> value.
 +
* Fixed an edge case where a custom language's fonts wouldn't be loaded when switching language.
 +
 +
====[[Modding:Modder Guide/Game Fundamentals#Net fields|Net fields]]====
 +
* Removed implicit conversion operators for most types due to their sometimes counter-intuitive behavior. The only ones left are <samp>NetBool</samp>, <samp>NetInt</samp>, and <samp>NetString</samp>; those are now marked obsolete and will raise build warnings on use.
 +
* <samp>NetLocationRef</samp> now has a public <samp>LocationName</samp> and <samp>IsStructure</samp>, and its <samp>Update</samp> method allows forcing an update.
 +
 +
====Quests====
 +
{{/doc status|[[Modding:Quest data]]|done=false}}
 +
 +
* Quests now have string IDs, to simplify custom quest frameworks.
 +
* Added validation for quest data parsing.
 +
* In [[Modding:Special orders|<samp>Data/SpecialOrders</samp>]], the <samp>Duration</samp> and <samp>Repeatable</samp> fields are now strongly-typed and case-insensitive.
 +
* For C# mods, fixed <samp>DescriptionElement</samp> not allowing more than four translation token substitutions.
 +
 +
====Dates & seasons====
 +
* Added a <samp>Season</samp> enum for strongly-typed, case-insensitive season checks (like <code>Game1.season == Season.Spring</code> instead of <code>Game1.currentSeason == "spring"</code>).
 +
* Added <samp>Game1.season</samp>, <samp>Game1.GetSeasonForLocation</samp>, <samp>Game1.WorldDate.Season</samp>, and <samp>location.GetSeason()</samp> to get the season enum.
 +
* Added <samp>Utility.getSeasonKey</samp> to get the key form from a season enum.
 +
* Improved <samp>WorldDate</samp>:
 +
** added <samp>Now()</samp> to get a new instance matching the current date;
 +
** added <samp>WorldDate.Equals</samp> and <samp>GetHashCode</samp> implementations;
 +
** added code docs;
 +
** <samp>TotalDays</samp> is no longer written to the save file.
 +
* Renamed some members for clarity (<samp>Game1.GetSeasonForLocation</samp> → <samp>GetSeasonKeyForLocation</samp>, <samp>location.GetSeasonForLocation</samp> → <samp>GetSeasonKey</samp>, <samp>WorldDate.Season</samp> → <samp>SeasonKey</samp>).
 +
* Fixed <samp>location.GetSeasonKey()</samp> not applying the greenhouse logic.
 +
 +
====Time====
 +
* For C# mods, the <samp>Game1.realMilliSecondsPerGame</samp> and <samp>Game1.realMilliSecondsPerGameTenMinutes</samp> fields are no longer marked <samp>const</samp>, and the <samp>GameLocation.getExtraMillisecondsPerInGameMinuteForThisLocation()</samp> method has been replaced with a settable <samp>ExtraMillisecondsPerInGameMinute</samp> property. That lets you change the time rate used by the vanilla game code, but you should be careful doing this since it may cause unintended effects.
 +
 +
====Other====
 +
* Error stack traces on Linux/macOS now have line numbers.
 +
* All space-delimited fields now ignore extra spaces instead of crashing. This affects map/tile properties, data assets, event commands, game state queries, etc.
 +
* All players and NPCs now have <samp>Tile</samp> & <samp>TilePoint</samp> properties (their cached tile position) and a <samp>StandingPixel</samp> property (the cached pixel coordinate at the center of their bounding box). These [[#Other breaking API changes|replace various deleted methods]].
 +
* All terrain features now have <samp>Tile</samp> and <samp>Location</samp> properties, and their methods no longer have location/tile parameters in most cases.
 +
* All [[Modding:Modder Guide/Game Fundamentals#Net fields|net fields]] now have <samp>Name</samp> and <samp>Owner</samp> fields, which are used to show informative error messages when there's a sync issue and validate common mistakes (e.g. a net field not added to the <samp>NetFields</samp> collection).
 +
* The game now tracks the locations a player has visited. Mods can check the list in C# (via <samp>Game1.player.locationsVisited</samp>) or [[Modding:Game state queries|game state queries]] (via <samp>PLAYER_VISITED_LOCATION</samp>). For pre-existing saves, the list is retroactively populated based on accessible locations, events seen, mail flags set, etc.
 +
* Added menu queuing (via <samp>Game1.nextClickableMenu</samp> in C#). For example, this applies if you try to take an item from a mail letter when your inventory is full.
 +
* Added C# code docs in many places.
 +
* Added <samp>Id</samp> fields to simplify content pack edits in fish pond, movie concession, random bundle, and tailoring recipe data.
 +
* Added <samp>Game1.Multiplayer</samp> to get the game's low-level handler. (Most code should still use [[Modding:Modder Guide/APIs/Multiplayer|SMAPI's multiplayer API]] though.)
 +
* Added <samp>Game1.versionBuildNumber</samp> with the build number (like <samp>26039</samp>).
 +
* Added field-changed events to <samp>NetPosition</samp>.
 +
* Added <samp>LocalizedContentManager.CurrentLanguageString</samp>, which caches the language code like <samp>pt-BR</samp>).
 +
* The game now uses <samp>[XmlInclude]</samp> on its types more consistently. That means the default save serializer can handle more types (e.g. all monsters), and it's easier to create custom serializers.
 +
* Refactored many parts of the code to make it more moddable for C# mods. This includes marking all classes public, changing <samp>private</samp> members to <samp>protected</samp> or <samp>public</samp>, marking members <samp>virtual</samp>, rewriting or splitting code so it's easier to extend, etc.
 +
* The <samp>startup_preferences</samp> file is now formatted to simplify troubleshooting.
 +
* Fixed many cases where the game used <samp>Game1.player</samp> instead of the provided player.
 +
 +
==Breaking changes for C# mods==
 +
'''This section only describes how this update may break existing mods. See the ''what's new'' sections above for more info, including new functionality mods can use.'''
 +
 +
See also [[#Breaking changes for content packs|''Breaking changes for content packs'']], which affect C# mods too.
 +
 +
===.NET 6===
 +
: ''See also: [[#.NET 6|.NET 6]] under what's new.''
 +
 +
Stardew Valley 1.6 updates from .NET 5 to .NET 6. SMAPI can still load .NET 5 mods fine, but you'll get a build error when compiling them. To update a C# mod:
 +
<ol>
 +
<li>Make sure you have [https://visualstudio.microsoft.com/vs Visual Studio Community 2022] or later. (Compiling .NET 6 with earlier versions of Visual Studio isn't officially supported.)</li>
 +
<li>In Visual Studio, click ''Help > Check For Updates'' and install the latest version.</li>
 +
<li>Fully exit Visual Studio.</li>
 +
<li>Open each mod's <samp>.csproj</samp> file in a text editor, then find this line:
 +
<syntaxhighlight lang="xml">
 +
<TargetFramework>net5.0</TargetFramework>
 +
</syntaxhighlight>
 +
 +
And change it to this:
 +
<syntaxhighlight lang="xml">
 +
<TargetFramework>net6.0</TargetFramework>
 +
</syntaxhighlight>
 +
</li>
 +
<li>Delete your solution's hidden <samp>.vs</samp> folder, and every project's <samp>bin</samp> and <samp>obj</samp> folders.</li>
 +
<li>Reopen the solution in Visual Studio, click ''Build > Rebuild Solution'', and make sure it still loads into the game fine.</li>
 +
</ol>
 +
 +
===Item ID changes===
 +
: ''See also: [[#Custom items|custom items in what's new]].''
 +
 +
The [[#Custom items|main <samp>Item</samp> properties have changed]]. To migrate existing code:
 +
<ul>
 +
<li>Don't use <samp>ParentSheetIndex</samp> to compare items. For example, <samp>item.ParentSheetIndex == 0</samp> will match both [[weeds]] and any custom item whose sprite is the first one in its custom spritesheet. You should compare items using [[#Custom items|their new <samp>ItemId</samp> and <samp>QualifiedItemId</samp> properties]] instead. For example, here's how to migrate various common forms:
 +
 +
{| class="wikitable"
 +
|-
 +
! old code
 +
! new code
 +
|-
 +
|-
 +
| <samp>item.ParentSheetIndex == 848</samp>
 +
| <samp>item.QualifiedItemId == "(O)848"</samp>
 +
|-
 +
| <samp>IsNormalObjectAtParentSheetIndex(item, 74)</samp>
 +
| <samp>item.QualifiedItemId == "(O)74"</samp>
 +
|-
 +
| <samp>!item.bigCraftable && item.ParentSheetIndex == 128</samp>
 +
| <samp>item.QualifiedItemId == "(O)128"</samp>
 +
|-
 +
| <samp>item is Boots && item.ParentSheetIndex == 505</samp>
 +
| <samp>item.QualifiedItemId == "(B)505"</samp>
 +
|}</li>
 +
<li>Don't assume item sprites are in the vanilla spritesheets. For example, instead of rendering <samp>Game1.objectSpriteSheet</samp> for an object, call <code>ItemRegistry.GetMetadata(item.QualifiedItemId).GetTexture()</code> to get its texture.</li>
 +
<li>Creating items works just like before, except that you now specify the item's <samp>ItemId</samp> (''not'' <samp>QualifiedItemId</samp>) instead of its <samp>ParentSheetIndex</samp>. This is the same value for vanilla items. For example:
 +
 +
<syntaxhighlight lang="c#">
 +
new Object("634", 1);                      // vanilla item
 +
new Object("Example.ModId_Watermelon", 1); // custom item
 +
</syntaxhighlight>
 +
 +
You can also use the new <samp>ItemRegistry</samp> API to construct items from their <samp>QualifiedItemId</samp>:
 +
 +
<syntaxhighlight lang="c#">
 +
Item item = ItemRegistry.Create("(B)505"); // Rubber Boots
 +
</syntaxhighlight></li>
 +
</ul>
 +
 +
===Other ID changes===
 +
Many other things in the game now have unique string IDs too (including [[#Buff overhaul|buffs]], [[#String event IDs|events]], and fruit trees). To migrate existing code:
 +
 +
* When referencing numeric IDs, you usually just need to convert them into a string (like <code>Game1.player.hasBuff("1590166")</code> or <code>Game1.player.eventsSeen.Contains("1590166")</code>).
 +
* When creating buffs, see [[#Buff overhaul|buff overhaul]] for how to create buffs now.
 +
* For pre-existing content pack data, see migration steps in the ''[[#Unique string IDs|unique string IDs]]'' section.
 +
 +
===Building and animal changes===
 +
: ''See also: [[#Build anywhere|build anywhere in what's new]].''
 +
 +
* Since all locations now allow buildings and animals, mod code which handles <samp>BuildableGameLocation</samp> and <samp>IAnimalLocation</samp> won't detect all buildable locations. You can replace them with <samp>location.IsBuildableLocation()</samp> (or just access <samp>location.buildings</samp> directly) and <samp>location.animals.Any()</samp> instead. Mods should no longer have any reference at all to <samp>BuildableGameLocation</samp> and <samp>IAnimalLocation</samp>.
 +
* Since buildings can be built anywhere, you can no longer assume a building is on the farm. You can check the new <samp>building.buildingLocation</samp> field instead.
 +
* You should review direct references to the farm (like <code>Game1.getFarm()</code> or <code>Game1.getLocationFromName("Farm")</code>) to see if it needs to be rewritten to allow other locations.
 +
* <code>Utility.numSilos()</code> should no longer be used to calculate available hay, since it doesn't account for custom buildings with hay storage. Use <code>Game1.getFarm().GetHayCapacity()</code> instead.
 +
* The <samp>Cat</samp> and <samp>Dog</samp> classes are now unused; all pets are now <samp>Pet</samp> directly.
 +
 +
===Player changes===
 +
: ''See also: [[#Buff overhaul|buff overhaul in what's new]].''
 +
 +
<ul>
 +
<li>Several <samp>Game1.player</samp> / <samp>Farmer</samp> fields changed as part of the [[#Buff overhaul|buff overhaul]]:
 +
{| class="wikitable"
 +
|-
 +
! old field
 +
! how to migrate
 +
|-
 +
| <samp>appliedBuffs</samp><br /><samp>appliedSpecialBuffs</samp>
 +
| Use <code>Game1.player.hasBuff(id)</code> instead.
 +
|-
 +
| <samp>attack</samp><br /><samp>immunity</samp>
 +
| Use <samp>Attack</samp> and <samp>Immunity</samp> instead.
 +
|-
 +
| <samp>addedCombatLevel</samp><br /><samp>addedFarmingLevel</samp><br /><samp>addedFishingLevel</samp><br /><samp>addedForagingLevel</samp><br /><samp>addedLuckLevel</samp><br /><samp>addedMiningLevel</samp><br /><samp>attackIncreaseModifier</samp><br /><samp>critChanceModifier</samp><br /><samp>critPowerModifier</samp><br /><samp>knockbackModifier</samp><br /><samp>weaponPrecisionModifier</samp><br /><samp>weaponSpeedModifier</samp>
 +
| Use equivalent properties under <samp>Game1.player.buffs</samp> instead (e.g. <samp>Game1.player.buffs.CombatLevel</code>).
 +
|-
 +
| <samp>resilience</samp>
 +
| Use <samp>buffs.Defense</samp> instead.
 +
|-
 +
| <samp>addedSpeed</samp><br /><samp>CombatLevel</samp><br /><samp>CraftingTime</samp><br /><samp>FarmingLevel</samp><br /><samp>FishingLevel</samp><br /><samp>ForagingLevel</samp><br /><samp>LuckLevel</samp><br /><samp>MagneticRadius</samp><br /><samp>MaxStamina</samp><br /><samp>MiningLevel</samp><br /><samp>Stamina</samp>
 +
| These are now readonly and can't be set directly. You can change them by [[#Buff overhaul|adding a buff]] (which can be invisible), equipment bonus, etc instead.
 +
|}</li>
 +
<li>Buffs are now recalculated automatically, and you can reset a buff by just reapplying it. See [[#Buff overhaul|buff overhaul]] for more info.</li>
 +
<li>Buff logic has been centralized into <samp>Game1.player.buffs</samp>. This replaces a number of former fields/methods like <samp>Game1.buffsDisplay</samp>.</li>
 +
</ul>
 +
 +
===Collision changes===
 +
The game's tile collision logic has been overhauled and merged into a simpler set of methods on <samp>GameLocation</samp> instances:
 +
 +
{| class="wikitable"
 +
|-
 +
! method
 +
! effect
 +
|-
 +
| <samp>CanSpawnCharacterHere</samp>
 +
| Get whether NPCs can be placed on the given tile (e.g. it's within the map bounds and tile is walkable), there's no placed object there, and the <samp>NoFurniture</samp> [[Modding:Maps|tile property]] isn't set.
 +
|-
 +
| <samp>CanItemBePlacedHere</samp>
 +
| Get whether items can be placed on the given tile in non-floating form (e.g. it's within the map bounds and not blocked by a non-walkable item), and the <samp>NoFurniture</samp> [[Modding:Maps|tile property]] isn't set.
 +
|-
 +
| <samp>isBuildable</samp>
 +
| Get whether buildings can be placed on the given tile.
 +
|-
 +
| <samp>IsTilePassable</samp>
 +
| Get whether the tile can be walked on (ignoring collisions with in-game objects, NPCs, etc).
 +
|-
 +
| <samp>IsTileOccupiedBy</samp>
 +
| Get whether the tile contains a player, object, NPC/monster/pet/etc, terrain feature, building, etc. You can choose which entities to check, and which ones to ignore if they don't block movement.
 +
|-
 +
| <samp>IsTileBlockedBy</samp>
 +
| Equivalent to calling both <samp>IsTilePassable</samp> and <samp>IsTileOccupiedBy</samp>.
 +
|-
 +
| <samp>IsLocationSpecificOccupantOnTile</samp><br /><samp>IsLocationSpecificPlacementRestriction</samp>
 +
| Generally shouldn't be used directly. Checks for location-specific collisions (e.g. ladders in [[The Mines|the mines]] or parrot platforms on [[Ginger Island]]).
 +
|}
 +
 +
===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 unused code====
 +
1.6 removes a lot of unused code. That includes these classes:
 +
{| class="wikitable"
 +
|-
 +
! namespace
 +
! class name
 +
|-
 +
| <samp>StardewValley</samp>
 +
| &#32;
 +
* <samp>BuildingUpgrade</samp>
 +
* <samp>DisposableList</samp>
 +
* <samp>FurniturePlacer</samp>
 +
* <samp>ListPool</samp>
 +
* <samp>OneTimeRandom</samp>
 +
|-
 +
| <samp>StardewValley.Characters</samp>
 +
| &#32;
 +
* <samp>BotchedNetBool</samp>
 +
* <samp>BotchedNetField</samp>
 +
* <samp>BotchedNetInt</samp>
 +
* <samp>BotchedNetLong</samp>
 +
|-
 +
| <samp>StardewValley.Menus</samp>
 +
| &#32;
 +
* <samp>FarmInfoPage</samp>
 +
* <samp>MiniatureTerrainFeature</samp><!-- not a typo, it really was in StardewValley.Menus -->
 +
|-
 +
| <samp>StardewValley.Monsters</samp>
 +
| &#32;
 +
* <samp>LavaCrab</samp>
 +
|-
 +
| <samp>StardewValley.Objects</samp>
 +
| &#32;
 +
* <samp>ObjectFactory</samp> (replaced by [[#Custom items|<samp>ItemRegistry</samp>]])
 +
|-
 +
| <samp>StardewValley.TerrainFeatures</samp>
 +
| &#32;
 +
* <samp>Quartz</samp>
 +
|-
 +
| <samp>StardewValley.Tools</samp>
 +
| &#32;
 +
* <samp>Blueprints</samp>
 +
* <samp>ToolFactory</samp> (replaced by [[#Custom items|<samp>ItemRegistry</samp>]])
 +
|}
 +
 +
And these class members:
 +
{| class="wikitable"
 +
|-
 +
! type
 +
! members
 +
|-
 +
| <samp>Axe</samp>
 +
| &#32;
 +
* <samp>StumpStrength</samp>
 +
|-
 +
| <samp>Bush</samp>
 +
| &#32;
 +
* <samp>alpha</samp>
 +
* <samp>lastPlayerToHit</samp>
 +
|-
 +
| <samp>Chest</samp>
 +
| &#32;
 +
* <samp>chestType</samp>
 +
* <samp>coins</samp>
 +
|-
 +
| <samp>CosmeticPlant</samp>
 +
| &#32;
 +
* <samp>scale</samp>
 +
|-
 +
| <samp>CraftingRecipe</samp>
 +
| &#32;
 +
* <samp>itemType</samp>
 +
|-
 +
| <samp>Critter</samp>
 +
| &#32;
 +
* <samp>InitShared()</samp>
 +
|-
 +
| <samp>Crop</samp>
 +
| &#32;
 +
* <samp>daysOfUnclutteredGrowth</samp>
 +
|-
 +
| <samp>Dialogue</samp>
 +
| &#32;
 +
* <samp>dialogueToBeKilled</samp>
 +
|-
 +
| <samp>Farm</samp>
 +
| &#32;
 +
* <samp>GetSpouseOutdoorAreaSpritesheetIndex()</samp>
 +
|-
 +
| <samp>FarmAnimal</samp>
 +
| &#32;
 +
* <samp>homeLocation</samp>
 +
|-
 +
| <samp>Farmer</samp>
 +
| &#32;
 +
* <samp>barnUpgradeLevel</samp> and <samp>BarnUpgradeLevel</samp>
 +
* <samp>blueprints</samp>
 +
* <samp>coalPieces</samp> and <samp>CoalPieces</samp>
 +
* <samp>coopUpgradeLevel</samp> and <samp>CoopUpgradeLevel</samp>
 +
* <samp>copperPieces</samp> and <samp>CopperPieces</samp>
 +
* <samp>eyeColor</samp>
 +
* <samp>feed</samp> and <samp>Feed</samp>
 +
* <samp>furnitureOwned</samp>
 +
* <samp>goldPieces</samp> and <samp>GoldPieces</samp>
 +
* <samp>hasBusTicket</samp>
 +
* <samp>hasGreenhouse</samp>
 +
* <samp>iridiumPieces</samp> and <samp>IridiumPieces</samp>
 +
* <samp>ironPieces</samp> and <samp>IronPieces</samp>
 +
* <samp>newSkillPointsToSpend</samp>
 +
* <samp>overallsColor</samp>
 +
* <samp>ownsFurniture</samp>
 +
* <samp>quartzPieces</samp> and <samp>QuartzPieces</samp>
 +
* <samp>shirtColor</samp>
 +
* <samp>skinColor</samp>
 +
* <samp>stonePieces</samp> and <samp>StonePieces</samp>
 +
* <samp>theaterBuildDate</samp>
 +
* <samp>woodPieces</samp> and <samp>WoodPieces</samp>
 +
|-
 +
| <samp>Game1</samp>
 +
| &#32;
 +
* <samp>boardingBus</samp>
 +
* <samp>chanceToRainTomorrow</samp>
 +
* <samp>checkForNewLevelPerks</samp>
 +
* <samp>cloud</samp>
 +
* <samp>coopDwellerBorn<samp>
 +
* <samp>cropsOfTheWeek</samp>
 +
* <samp>currentBarnTexture</samp>
 +
* <samp>currentBillboard</samp>
 +
* <samp>currentCoopTexture</samp>
 +
* <samp>currentFloor</samp>
 +
* <samp>currentHouseTexture</samp>
 +
* <samp>currentWallpaper</samp>
 +
* <samp>dealerCalicoJackTotal</samp>
 +
* <samp>FarmerFloor</samp>
 +
* <samp>farmerWallpaper</samp>
 +
* <samp>fertilizer</samp>
 +
* <samp>floorPrice</samp>
 +
* <samp>greenhouseTexture</samp>
 +
* <samp>inMine<samp>
 +
* <samp>jukeboxPlaying</samp>
 +
* <samp>keyHelpString</samp>
 +
* <samp>listeningForKeyControlDefinitions<samp>
 +
* <samp>littleEffect</samp>
 +
* <samp>logoScreenTexture</samp>
 +
* <samp>mailboxTexture</samp>
 +
* <samp>menuChoice</samp>
 +
* <samp>menuUp<samp>
 +
* <samp>nameSelectUp<samp>
 +
* <samp>nameSelectType</samp>
 +
* <samp>numberOfSelectedItems</samp>
 +
* <samp>particleRaining<samp>
 +
* <samp>pickingTool</samp>
 +
* <samp>pickToolDelay</samp>
 +
* <samp>pickToolInterval</samp>
 +
* <samp>priceOfSelectedItem</samp>
 +
* <samp>progressBar</samp>
 +
* <samp>removeSquareDebrisFromTile(…)</samp>
 +
* <samp>selectedItemsType</samp>
 +
* <samp>shiny</samp>
 +
* <samp>shippingTax</samp>
 +
* <samp>showKeyHelp<samp>
 +
* <samp>slotResult</samp>
 +
* <samp>startedJukeboxMusic</samp>
 +
* <samp>tinyFontBorder</samp>
 +
* <samp>toolHeld</samp>
 +
* <samp>toolIconBox</samp>
 +
* <samp>tvStation</samp>
 +
* <samp>tvStationTexture</samp>
 +
* <samp>wallpaperPrice</samp>
 +
|-
 +
| <samp>GameLocation</samp>
 +
| &#32;
 +
* <samp>boardBus(…)</samp>
 +
* <samp>checkForMapChanges()</samp>
 +
* <samp>getWallDecorItem(…)</samp>
 +
* <samp>removeBatch(…)</samp>
 +
* <samp>removeDirt(…)</samp>
 +
* <samp>removeStumpOrBoulder(…)</samp>
 +
* <samp>tryToBuyNewBackpack()</samp>
 +
|-
 +
| <samp>GiantCrop</samp>
 +
| &#32;
 +
* <samp>forSale</samp>
 +
|-
 +
| <samp>IClickableMenu</samp>
 +
| &#32;
 +
* <samp>currentRegion</samp>
 +
|-
 +
| <samp>MeleeWeapon</samp>
 +
| &#32;
 +
* <samp>attackSwordCooldownTime</samp>
 +
* <samp>doStabbingSwordFunction(…)</samp>
 +
|-
 +
| <samp>Monster</samp>
 +
| &#32;
 +
* <samp>doHorizontalMovement(…)</samp>
 +
* <samp>durationOfRandomMovements</samp>
 +
* <samp>coinsToDrop</samp>
 +
|-
 +
| <samp>NPC</samp>
 +
| &#32;
 +
* <samp>idForClones</samp>
 +
|-
 +
| <samp>Object</samp>
 +
| &#32;
 +
* <samp>attachToSprinklerAttachment(…)</samp>
 +
* <samp>canBePlacedInWater()</samp>
 +
* <samp>consumeRecipe(…)</samp>
 +
* <samp>copperBar</samp>
 +
* <samp>goldBar</samp>
 +
* <samp>iridiumBar</samp>
 +
* <samp>ironBar</samp>
 +
* <samp>isHoeDirt</samp> and <samp>IsHoeDirt</samp>
 +
|-
 +
| <samp>PathFindController</samp>
 +
| &#32;
 +
* <samp>CheckClearance(…)</samp>
 +
* <samp>limit</samp>
 +
|-
 +
| <samp>SaveGame</samp>
 +
| &#32;
 +
* <samp>cropsOfTheWeek</samp>
 +
* <samp>currentFloor</samp>
 +
* <samp>currentWallpaper</samp>
 +
* <samp>FarmerFloor</samp>
 +
* <samp>farmerWallpaper</samp>
 +
* <samp>shippingTax</samp>
 +
|-
 +
| <samp>Spiker</samp>
 +
| &#32;
 +
* <samp>GetSpawnPosition</samp>
 +
|-
 +
| <samp>Stats</samp>
 +
| &#32;
 +
* <samp>barsSmelted</samp> and <samp>BarsSmelted</samp>
 +
* <samp>coalFound</samp> and <samp>CoalFound</samp>
 +
* <samp>coinsFound</samp> and <samp>coinsFound</samp>
 +
* <samp>starLevelCropsShipped</samp> and <samp>starLevelCropsShipped</samp>
 +
|-
 +
| <samp>Tool</samp>
 +
| &#32;
 +
* <samp>batteredSwordSpriteIndex</samp>
 +
* <samp>copperColor</samp>
 +
* <samp>GetSecondaryEnchantmentCount()</samp>
 +
* <samp>goldColor</samp>
 +
* <samp>iridiumColor</samp>
 +
* <samp>nonUpgradeable</samp>
 +
* <samp>parsnipSpriteIndex</samp>
 +
* <samp>Stackable</samp>
 +
* <samp>startOfNegativeWeaponIndex</samp>
 +
* <samp>steelColor</samp>
 +
|-
 +
| <samp>Utility</samp>
 +
| &#32;
 +
* <samp>buyFloor()</samp>
 +
* <samp>buyWallpaper()</samp>
 +
* <samp>cropsOfTheWeek()</samp>
 +
* <samp>facePlayerEndBehavior(…)</samp>
 +
* <samp>getRandomSlotCharacter()</samp>
 +
* <samp>plantCrops(…)</samp>
 +
* <samp>showLanternBar()</samp>
 +
|}
 +
 +
====Renamed classes====
 +
These classes were renamed in 1.6:
 +
{| class="wikitable"
 +
|-
 +
! old name
 +
! new name
 +
|-
 +
| <samp>Game1.MusicContext</samp>
 +
| <samp>MusicContext</samp> (in <samp>StardewValley.GameData</samp>)
 +
|-
 +
| <samp>LocationContext</samp>
 +
| <samp>LocationContexts</samp>
 +
|-
 +
| <samp>SpecialOrder.QuestStatus</samp>
 +
| <samp>SpecialOrderStatus</samp> (in <samp>StardewValley.SpecialOrders</samp>)
 +
|}
 +
 +
And these were moved to a different namespace:
 +
{| class="wikitable"
 +
|-
 +
! type
 +
! old namespace
 +
! new namespace
 +
|-
 +
| <samp>AmethystEnchantment</samp><br /><samp>AquamarineEnchantment</samp><br /><samp>ArchaeologistEnchantment</samp><br /><samp>ArtfulEnchantment</samp><br /><samp>AutoHookEnchantment</samp><br /><samp>AxeEnchantment</samp><br /><samp>BaseEnchantment</samp><br /><samp>BaseWeaponEnchantment</samp><br /><samp>BottomlessEnchantment</samp><br /><samp>BugKillerEnchantment</samp><br /><samp>CrusaderEnchantment</samp><br /><samp>DiamondEnchantment</samp><br /><samp>EfficientToolEnchantment</samp><br /><samp>EmeraldEnchantment</samp><br /><samp>FishingRodEnchantment</samp><br /><samp>GalaxySoulEnchantment</samp><br /><samp>GenerousEnchantment</samp><br /><samp>HaymakerEnchantment</samp><br /><samp>HoeEnchantment</samp><br /><samp>JadeEnchantment</samp><br /><samp>MagicEnchantment</samp><br /><samp>MasterEnchantment</samp><br /><samp>MilkPailEnchantment</samp><br /><samp>PanEnchantment</samp><br /><samp>PickaxeEnchantment</samp><br /><samp>PowerfulEnchantment</samp><br /><samp>PreservingEnchantment</samp><br /><samp>ReachingToolEnchantment</samp><br /><samp>RubyEnchantment</samp><br /><samp>ShavingEnchantment</samp><br /><samp>ShearsEnchantment</samp><br /><samp>SwiftToolEnchantment</samp><br /><samp>TopazEnchantment</samp><br /><samp>VampiricEnchantment</samp><br /><samp>WateringCanEnchantment</samp>
 +
| <samp>StardewValley</samp>
 +
| <samp>StardewValley.Enchantments</samp>
 +
|-
 +
| <samp>Extensions</samp>
 +
| <samp>StardewValley</samp>
 +
| <samp>StardewValley.Extensions</samp>
 +
|-
 +
| <samp>ModDataDictionary</samp><br /><samp>ModHooks</samp>
 +
| <samp>StardewValley</samp>
 +
| <samp>StardewValley.Mods</samp>
 +
|-
 +
| <samp>PathFindController</samp><br /><samp>PathNode</samp><br /><samp>PriorityQueue</samp><br /><samp>SchedulePathDescription</samp>
 +
| <samp>StardewValley</samp>
 +
| <samp>StardewValley.Pathfinding</samp>
 +
|-
 +
| <samp>SpecialOrder</samp>
 +
| <samp>StardewValley</samp>
 +
| <samp>StardewValley.SpecialOrders</samp>
 +
|-
 +
| <samp>CollectObjective</samp><br /><samp>DeliverObjective</samp><br /><samp>DonateObjective</samp><br /><samp>FishObjective</samp><br /><samp>GiftObjective</samp><br /><samp>JKScoreObjective</samp><br /><samp>OrderObjective</samp><br /><samp>ReachMineFloorObjective</samp><br /><samp>ShipObjective</samp><br /><samp>SlayObjective</samp>
 +
| <samp>StardewValley</samp>
 +
| <samp>StardewValley.SpecialOrders.Objectives</samp>
 +
|-
 +
| <samp>FriendshipReward</samp><br /><samp>GemsReward</samp><br /><samp>MailReward</samp><br /><samp>MoneyReward</samp><br /><samp>OrderReward</samp><br /><samp>ResetEventReward</samp>
 +
| <samp>StardewValley</samp>
 +
| <samp>StardewValley.SpecialOrders.Rewards</samp>
 +
|}
 +
 +
====Other API changes====
 +
These class members changed in 1.6:
 +
 +
{| class="wikitable"
 +
|-
 +
! type
 +
! member
 +
! migration
 +
|-
 +
| <samp>BigSlime</samp>
 +
| <samp>heldObject</samp>
 +
| Replaced by <samp>heldItem</samp>, which allows non-object items too.
 +
|-
 +
|rowspan="3"| <samp>Bush</samp>
 +
| <samp>overrideSeason</samp>
 +
| Removed; use <code>bush.Location.GetSeason()</code> instead.
 +
|-
 +
| <samp>greenhouseBush</samp>
 +
| Removed; use <code>bush.IsSheltered()</code> or <code>bush.currentLocation.IsGreenhouse</code> instead.
 +
|-
 +
| <samp>inBloom</samp>
 +
| Remove the arguments, like <code>bush.inBloom(Game1.currentSeason, Game1.dayOfMonth)</code> → <code>bush.inBloom()</code>.
 +
|-
 +
|rowspan="3"| <samp>Character</samp>
 +
| <samp>getStandingX</samp><br /><samp>getStandingY</samp><br /><samp>getStandingXY</samp>
 +
| Removed; use <samp>character.StandingPixel</samp> instead.
 +
|-
 +
| <samp>getTileLocation</samp><br /><samp>getTileX</samp><br /><samp>getTileY</samp><br />
 +
| Removed; use <samp>character.Tile</samp> instead.
 +
|-
 +
| <samp>getTileLocationPoint</samp>
 +
| Removed; use <samp>character.TilePoint</samp> instead.
 +
|-
 +
| <samp>Chest</samp>
 +
| <samp>MoveToSafePosition</samp>
 +
| Replaced by the simpler <samp>TryMoveToSafePosition</samp>
 +
|-
 +
|rowspan="2"| <samp>Dialogue</samp>
 +
| <samp>dialogues</samp>
 +
| Changed from <code>List&lt;string&gt;</code> to <code>List&lt;DialogueLine&gt;</code>. The <samp>Text</samp> field on each dialogue line is equivalent to the old value.
 +
|-
 +
| <samp>isOnFinalDialogue()</samp>
 +
| This now indicates whether it's showing the last dialogue ''with message text''; there may still be entries in <samp>dialogues</samp> which apply side-effects without message text.
 +
|-
 +
|rowspan="3"| <samp>Farmer</samp>
 +
| <samp>changePants(…)</samp>
 +
| Renamed to <samp>changePantsColor(…)</samp> for consistency with <samp>change[Eye&#124;Hair&#124;Shoe]Color</samp>.
 +
|-
 +
| <samp>isMarried()</samp>
 +
| Renamed to <samp>isMarriedOrRoommates()</samp> for clarity.
 +
|-
 +
| <samp>visibleQuestCount</samp>
 +
| Replaced by <samp>hasVisibleQuests</samp>.
 +
|-
 +
| <samp>Flooring</samp>
 +
| <samp>GetFloorPathLookup</samp>
 +
| Use <samp>Game1.floorPathData</samp> instead.
 +
|-
 +
| <samp>Forest</samp>
 +
| <samp>log</samp>
 +
| Moved into <samp>Forest.resourceClumps</samp>.
 +
|-
 +
| <samp>FruitTree</samp>
 +
| <samp>GreenHouseTree</samp>
 +
| Replaced by <samp>IgnoresSeasonsHere()</samp>.
 +
|-
 +
|rowspan="3"| <samp>Game1</samp>
 +
| <samp>bigCraftableInformation</samp>
 +
| Overhauled into [[#Custom big craftables|<samp>Game1.bigCraftableData</samp>]].
 +
|-
 +
| <samp>clothingInformation</samp>
 +
| Overhauled into [[#Custom shirts|<samp>Game1.shirtData</samp>]] and [[#Custom pants|<samp>Game1.pantsData</samp>]].
 +
|-
 +
| <samp>objectInformation</samp>
 +
| Overhauled into [[#Custom objects|<samp>Game1.objectData</samp>]].
 +
|-
 +
|rowspan="3"| <samp>GameLocation</samp>
 +
| <samp>getCharacters</samp>
 +
| Removed; use the <samp>characters</samp> field instead.
 +
|-
 +
| <samp>GetMapPropertyPosition</samp>
 +
| Replaced by <samp>TryGetMapPropertyAs</samp>, which supports multiple data types (not just <samp>Point</samp>).
 +
|-
 +
| <samp>isTileOccupied</samp><br /><samp>isTileOccupiedForPlacement</samp><br /><samp>isTileOccupiedIgnoreFloors</samp><br /><samp>isTileLocationOpenIgnoreFrontLayers</samp><br /><samp>isTileLocationTotallyClearAndPlaceable</samp><br /><samp>isTileLocationTotallyClearAndPlaceableIgnoreFloors</samp>
 +
| Removed. The collision logic has been significantly rewritten and uses a new set of methods (mainly <samp>isTilePassable</samp>, <samp>IsTileOccupiedBy</samp>, and <samp>CanItemBePlacedHere</samp>). Mods should ideally be updated to use the new methods.
 +
 +
Here's a drop-in set of extension methods which re-add the older methods. This lets you temporarily fix code until you can update it properly, but depending on these isn't recommended since they won't be maintained in future versions.
 +
{{collapse|expand for non-recommended code|content=<syntaxhighlight lang="c#">
 +
public static class GameLocationExtensions
 +
{
 +
    public static bool isTileOccupiedForPlacement(this GameLocation location, Vector2 tileLocation, Object toPlace = null)
 +
    {
 +
        return location.CanItemBePlacedHere(tileLocation, toPlace != null && toPlace.isPassable());
 +
    }
 +
 +
    public static bool isTileOccupied(this GameLocation location, Vector2 tileLocation, string characterToIgnore = "", bool ignoreAllCharacters = false)
 +
    {
 +
        CollisionMask mask = ignoreAllCharacters ? CollisionMask.All & ~CollisionMask.Characters & ~CollisionMask.Farmers : CollisionMask.All;
 +
        return location.IsTileOccupiedBy(tileLocation, mask);
 +
    }
 +
 +
    public static bool isTileOccupiedIgnoreFloors(this GameLocation location, Vector2 tileLocation, string characterToIgnore = "")
 +
    {
 +
        return location.IsTileOccupiedBy(tileLocation, CollisionMask.Buildings | CollisionMask.Furniture | CollisionMask.Objects | CollisionMask.Characters | CollisionMask.TerrainFeatures, ignorePassables: CollisionMask.Flooring);
 +
    }
 +
 +
    public static bool isTileLocationOpenIgnoreFrontLayers(this GameLocation location, Location tile)
 +
    {
 +
        return location.map.RequireLayer("Buildings").Tiles[tile.X, tile.Y] == null && !location.isWaterTile(tile.X, tile.Y);
 +
    }
 +
 +
    public static bool isTileLocationTotallyClearAndPlaceable(this GameLocation location, int x, int y)
 +
    {
 +
        return location.isTileLocationTotallyClearAndPlaceable(new Vector2(x, y));
 +
    }
 +
 +
    public static bool isTileLocationTotallyClearAndPlaceableIgnoreFloors(this GameLocation location, Vector2 v)
 +
    {
 +
        return location.isTileOnMap(v) && !location.isTileOccupiedIgnoreFloors(v) && location.isTilePassable(new Location((int)v.X, (int)v.Y), Game1.viewport) && location.isTilePlaceable(v);
 +
    }
 +
 +
    public static bool isTileLocationTotallyClearAndPlaceable(this GameLocation location, Vector2 v)
 +
    {
 +
        Vector2 pixel = new Vector2((v.X * Game1.tileSize) + Game1.tileSize / 2, (v.Y * Game1.tileSize) + Game1.tileSize / 2);
 +
        foreach (Furniture f in location.furniture)
 +
        {
 +
            if (f.furniture_type != Furniture.rug && !f.isPassable() && f.GetBoundingBox().Contains((int)pixel.X, (int)pixel.Y) && !f.AllowPlacementOnThisTile((int)v.X, (int)v.Y))
 +
                return false;
 +
        }
 +
 +
        return location.isTileOnMap(v) && !location.isTileOccupied(v) && location.isTilePassable(new Location((int)v.X, (int)v.Y), Game1.viewport) && location.isTilePlaceable(v);
 +
    }
 +
}
 +
</syntaxhighlight>
 +
}}
 +
|-
 +
| <samp>GiantCrop</samp>
 +
| <samp>which</samp>
 +
| Replaced by <samp>itemId</samp>.
 +
|-
 +
| <samp>Item</samp>
 +
| <samp>SanitizeContextTag</samp>
 +
| Replaced by <samp>ItemContextTagManager.SanitizeContextTag</samp>.
 +
|-
 +
| <samp>LocalizedContentManager</samp>
 +
| <samp>LanguageCodeString</samp>
 +
| Now static.
 +
|-
 +
| <samp>LocationContextData</samp>
 +
| <samp>Name</samp>
 +
| Removed; use its dictionary key in <samp>Game1.locationContextData</samp> instead.
 +
|-
 +
| <samp>NetFields</samp>
 +
| <samp>AddFields</samp>
 +
| Removed; use <samp>AddField</samp> instead. For example:
 +
<syntaxhighlight lang="c#">
 +
// old code
 +
NetFields.AddFields(textureName, spriteWidth, spriteHeight);
 +
 +
// new code
 +
NetFields
 +
    .AddField(textureName)
 +
    .AddField(spriteWidth)
 +
    .AddField(spriteHeight);
 +
</syntaxhighlight>
 +
Note that the second argument (<samp>name</samp>) should usually be omitted, since it'll be auto-populated from the value passed to the first argument.
 +
|-
 +
|rowspan="7"| <samp>NPC</samp>
 +
| <samp>canReceiveThisItemAsGift(…)</samp>
 +
| Removed. The closest equivalent is <code>item.canBeGivenAsGift()</code>, or you can check if the NPC will accept the player's held object (as a gift or otherwise) using <code>npc.tryReceiveActiveObject(Game1.player, probe: true)</code>.
 +
|-
 +
| <samp>Gender</samp><br /><samp>female</samp><br /><samp>male</samp><br /><samp>undefined</samp>
 +
| The <samp>Gender</samp> field now uses a <samp>Gender</samp> enum instead of numeric constants. For example, <code>npc.Gender == NPC.female</code> becomes <code>npc.Gender == Gender.Female</code> in 1.6.
 +
|-
 +
| <samp>homeRegion</samp>
 +
| Removed; use <samp>npc.GetData()?.HomeRegion</samp> instead. Change <samp>0</samp> to <samp>"Other"</samp> or <samp>NPC.region_other</samp>, <samp>1</samp> to <samp>"Desert"</samp> or <samp>NPC.region_desert</samp>, and <samp>2</samp> to <samp>"Town"</samp> or <samp>NPC.region_town</samp>.
 +
|-
 +
| <samp>isBirthday</samp>
 +
| Remove the arguments, like <code>npc.isBirthday(Game1.currentSeason, Game1.dayOfMonth)</code> → <code>npc.isBirthday()</code>.
 +
|-
 +
| <samp>isVillager()</samp>
 +
| Deprecated; use the <samp>character.IsVillager</samp> property instead.
 +
|-
 +
| <samp>populateRoutesFromLocationToLocationList</samp>
 +
| Replaced by <samp>WarpPathfindingCache.PopulateCache</samp>.
 +
|-
 +
| <samp>Schedule</samp>
 +
| No longer assignable, use one of the <samp>TryLoadSchedule</samp> overloads instead.
 +
|-
 +
|rowspan="3"| <samp>Object</samp>
 +
| <samp>GetContextTagList()</samp>
 +
| Replaced by <samp>GetContextTags()</samp>, which returns a hash set instead of a list.
 +
|-
 +
| <samp>HasBeenPickedUpByPlayer</samp>
 +
| Removed; use <samp>HasBeenInInventory</samp> instead.
 +
|-
 +
| <samp>isPotentialBasicShippedCategory</samp>
 +
| The second argument should now be an integer (like <samp>-75</samp> or <samp>Object.VegetableCategory</samp>) instead of a string (like <samp>"-75"</samp>).
 +
|-
 +
|rowspan="9"| <samp>Utility</samp>
 +
| <samp>doesItemWithThisIndexExistAnywhere</samp>
 +
| Replace with <samp>Utility.doesItemExistAnywhere</samp>, which takes a string item ID. For example:
 +
* <code>Utility.doesItemWithThisIndexExistAnywhere(128)</code> &rarr; <code>Utility.doesItemExistAnywhere("(O)128")</code>;
 +
* <code>Utility.doesItemWithThisIndexExistAnywhere(128, true)</code> &rarr; <code>Utility.doesItemExistAnywhere("(BC)128")</code>.
 +
|-
 +
| <samp>ForAllLocations</samp><br /><samp>iterateAllCrops</samp><br /><samp>iterateAllItems</samp>
 +
| Removed; use the equivalent <samp>Utility.ForEach*</samp> methods instead.
 +
|-
 +
| <samp>GetHorseWarpRestrictionsForFarmer</samp>
 +
| This now returns a flag enum instead of a list of integer values. The equivalent values are 1 → <samp>NoOwnedHorse</samp>, 2 → <samp>Indoors</samp>, 3 → <samp>NoRoom</samp>, and 4 → <samp>InUse</samp>.
 +
 +
For example:
 +
<syntaxhighlight lang="c#">
 +
// old code
 +
bool inUse = Utility.GetHorseWarpRestrictionsForFarmer(player).Any(p => p == 4);
 +
 +
// new code
 +
bool inUse = Utility.GetHorseWarpRestrictionsForFarmer(player).HasFlag(Utility.HorseWarpRestrictions.InUse);
 +
</syntaxhighlight>
 +
 +
Or to check if no restrictions apply:
 +
<syntaxhighlight lang="c#">
 +
bool canSummon = Utility.GetHorseWarpRestrictionsForFarmer(player) == Utility.HorseWarpRestrictions.None;
 +
</syntaxhighlight>
 +
 +
C# mods can patch <samp>Utility.GetHorseWarpErrorMessage</samp> if they need to add an error message for a custom restriction value.
 +
|-
 +
| <samp>getRandomTownNPC(…)</samp>
 +
| Replaced by either <code>Utility.GetRandomWinterStartParticipant(…)</code> or <code>Utility.getRandomNpcFromHomeRegion(NPC.region_town)</code>.
 +
|-
 +
| <samp>getTodaysBirthdayNPC</samp>
 +
| Remove the arguments, like <code>Utility.getTodaysBirthdayNPC(Game1.currentSeason, Game1.dayOfMonth)</code> → <code>Utility.getTodaysBirthdayNPC()</code>.
 +
|-
 +
| <samp>getPooledList</samp><br /><samp>returnPooledList</samp>
 +
| The game no longer uses a list pool. In most cases you should use the [[#Iteration|<samp>Utility.ForEach*</samp> methods]] instead, which don't need it.
 +
|-
 +
| <samp>numObelisksOnFarm</samp>
 +
| Renamed to <samp>GetObeliskTypesBuilt</samp>, which searches all locations.
 +
|-
 +
| <samp>numSilos</samp>
 +
| Removed.
 +
 +
If you're using this to calculate hay capacity, it's a bit more complicated in 1.6 since hay storage can be enabled for custom buildings and building construction can be enabled for any location. To get capacity for the current location, use <samp>Game1.currentLocation.GetHayCapacity()</samp> instead. To get total hay capacity in the world, use <samp>Utility.ForEachLocation</samp> to call it on every location.
 +
 +
If you actually need the number of silos, use <samp>location.getNumberBuildingsConstructed("Silo")</samp> (one location) or <samp>Game1.GetNumberBuildingsConstructed("Silo")</samp> (all locations).
 +
|-
 +
| <samp>removeThisCharacterFromAllLocations</samp>
 +
| Removed; use <samp>Game1.removeCharacterFromItsLocation</samp> instead.
 +
|-
 +
| <samp>ShopMenu</samp>
 +
| <samp>storeContext</samp>
 +
| Replaced by <samp>ShopId</samp>.
 +
|-
 +
|rowspan="3"| <samp>Stats</samp>
 +
| <samp>averageBedtime</samp><br /><samp>beveragesMade</samp><br /><samp>bouldersCracked</samp><br /><samp>caveCarrotsFound</samp><br /><samp>cheeseMade</samp><br /><samp>chickenEggsLayed</samp><br /><samp>copperFound</samp><br /><samp>cowMilkProduced</samp><br /><samp>cropsShipped</samp><br /><samp>daysPlayed</samp><br /><samp>diamondsFound</samp><br /><samp>dirtHoed</samp><br /><samp>duckEggsLayed</samp><br /><samp>fishCaught</samp><br /><samp>geodesCracked</samp><br /><samp>giftsGiven</samp><br /><samp>goatCheeseMade</samp><br /><samp>goatMilkProduced</samp><br /><samp>goldFound</samp><br /><samp>goodFriends</samp><br /><samp>individualMoneyEarned</samp><br /><samp>iridiumFound</samp><br /><samp>ironFound</samp><br /><samp>itemsCooked</samp><br /><samp>itemsCrafted</samp><br /><samp>itemsForaged</samp><br /><samp>itemsShipped</samp><br /><samp>monstersKilled</samp><br /><samp>mysticStonesCrushed</samp><br /><samp>notesFound</samp><br /><samp>otherPreciousGemsFound</samp><br /><samp>piecesOfTrashRecycled</samp><br /><samp>preservesMade</samp><br /><samp>prismaticShardsFound</samp><br /><samp>questsCompleted</samp><br /><samp>rabbitWoolProduced</samp><br /><samp>rocksCrushed</samp><br /><samp>seedsSown</samp><br /><samp>sheepWoolProduced</samp><br /><samp>slimesKilled</samp><br /><samp>stepsTaken</samp><br /><samp>stoneGathered</samp><br /><samp>stumpsChopped</samp><br /><samp>timesFished</samp><br /><samp>timesUnconscious</samp><br /><samp>totalMoneyGifted</samp><br /><samp>trufflesFound</samp><br /><samp>weedsEliminated</samp>
 +
| Removed; use the equivalent property or methods. For example, <code>Game1.stats.daysPlayed</code> can be replaced with <code>Game1.stats.DaysPlayed</code> or methods like <code>Game1.stats.Get(StatKeys.DaysPlayed)</code>. See [[#Stat changes for C# mods|stat changes for C# mods]].
 +
|-
 +
| <samp>getStat(…)</samp><br /><samp>incrementStat(…)</samp>
 +
| Replaced by <samp>Get(…)</samp> and <samp>Increment(…)</samp>. See [[#Stat changes for C# mods|stat changes for C# mods]].
 +
|-
 +
| <samp>stat_dictionary</samp>
 +
| Renamed to <samp>Values</samp>. See [[#Stat changes for C# mods|stat changes for C# mods]].
 +
|-
 +
| <samp>Woods</samp>
 +
| <samp>stumps</samp>
 +
| Moved into <samp>resourceClumps</samp>.
 +
|}
 +
 +
===Check for obsolete code===
 +
Perform a full rebuild of your mod (in Visual Studio, click ''Build > Rebuild Solution''), then check the Error List pane for any warnings like "'''X' is obsolete''". Anything from the vanilla game code which is marked obsolete won't work anymore and is only kept for save migrations. Usually the warning will include an explanation of what you should use instead.
 +
 +
==Breaking changes for content packs==
 +
'''This section only describes how this update may break existing mods. See the ''what's new'' sections above for more info, including new functionality mods can use.'''
 +
 +
===Standardized ID fields===
 +
Stardew Valley 1.6 adds an <samp>Id</samp> field to these assets. For Content Patcher content packs, these replace the previous synthetic ID:
 +
 +
{| class="wikitable"
 +
|-
 +
! asset
 +
! old key
 +
! new key
 +
! migration steps
 +
|-
 +
| <samp>Data/ConcessionTastes</samp><br /><samp>Data/MovieReactions</samp><br /><samp>Data/RandomBundles</samp> (area)<br /><samp>Data/RandomBundles</samp> (bundle)
 +
| <samp>Name</samp><br /><samp>NPCName</samp><br /><samp>AreaName</samp><br />''none''
 +
|<samp>Id</samp>
 +
| None. The <samp>Id</samp> field is set automatically to the same value (or <samp>Name</samp> for bundles), so there's no change for content packs. Omit the new field when creating a new entry.
 +
|-
 +
| <samp>Data/FishPondData</samp><br /><samp>Data/RandomBundles</samp> (bundle set)
 +
| <samp>RequiredTags</samp><br />''none''
 +
| <samp>Id</samp>
 +
| Use the new <samp>Id</samp> field to target an entry, and add it when creating a new entry. Required.
 +
|-
 +
| <samp>Data/TailoringRecipes</samp>
 +
| <samp>FirstItemTags</samp> and <samp>SecondItemTags</samp>
 +
| <samp>Id</samp>
 +
| Use the new <samp>Id</samp> field to target an entry, and add it when creating a new entry. Defaults to the <samp>CraftedItemIds</samp> (comma-delimited) or <samp>CraftedItemId</samp> value if omitted, but there's a high chance of conflicts so mods should always specify a unique ID.
 +
|}
 +
 +
For example, let's say you have a patch like this using Content Patcher:
 +
{{#tag:syntaxhighlight|<nowiki>
 +
{
 +
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
 +
    "Changes": [
 +
        {
 +
            "Action": "EditData",
 +
            "Target": "Data/TailorRecipes",
 +
            "Entries": {
 +
                "item_cloth|item_pufferchick": {
 +
                    "FirstItemTags": [ "item_cloth" ],
 +
                    "SecondItemTags": [ "item_pufferchick" ],
 +
                    "CraftedItemId": "(S)1260"
 +
                }
 +
            }
 +
        }
 +
    ]
 +
}</nowiki>|lang=javascript}}
 +
 +
When updating to Stardew Valley 1.6, replace the synthetic ID (<samp>item_cloth|item_pufferchick</samp>) with a real one:
 +
* To edit an existing entry, unpack the asset and get its new <samp>Id</samp> value.
 +
* To add a custom entry, use a [[Modding:Common data field types#Unique string ID|unique string ID]].
 +
 +
For example:
 +
{{#tag:syntaxhighlight|<nowiki>
 +
{
 +
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
 +
    "Changes": [
 +
        {
 +
            "Action": "EditData",
 +
            "Target": "Data/TailorRecipes",
 +
            "Entries": {
 +
                "ExampleAuthor.ModId_RainCoatFromPufferchick": {
 +
                    "Id": "ExampleAuthor.ModId_RainCoatFromPufferchick", // need to specify ID again when creating it
 +
                    "FirstItemTags": [ "item_cloth" ],
 +
                    "SecondItemTags": [ "item_pufferchick" ],
 +
                    "CraftedItemId": "(S)1260"
 +
                }
 +
            }
 +
        }
 +
    ]
 +
}</nowiki>|lang=javascript}}
 +
 +
===Event ID changes===
 +
{{/doc status|[[Modding:Event data]]|done=false}}
 +
 +
: ''See also: [[#String event IDs|string event IDs in what's new]].''
 +
 +
Events now have unique string IDs.
 +
 +
When creating an event:
 +
<ul>
 +
<li>New events should use a globally unique ID in the form <samp>Your.ModId_EventName</samp>. Existing events should be fine as-is, but it may be worth migrating them to avoid future conflicts.</li>
 +
<li>Every non-fork event '''must''' have a precondition in its key (even if it's empty). For example, change <code>"Your.ModId_EventName": "..."</code> to <code>"Your.ModId_EventName/": "..."</code>. This is needed for the game to distinguish between events and fork scripts.
 +
 +
<syntaxhighlight lang="js">
 +
"Example.ModId_EventName/": "...", // event: loaded automatically by the game
 +
"SomeFork": "..."                  // event fork: ignored unless it's loaded through an event script
 +
</syntaxhighlight></li>
 +
</ul>
 +
 +
===Monster eradication goal flag changes===
 +
{{/doc status|a new doc page|done=false}}
 +
 +
: ''See also: [[#Custom monster eradication goals|Custom monster eradication goals]].''
 +
 +
The game now tracks [[Adventurer's Guild]] monster eradication goal completion by the goal ID, instead of the produced item. You'll need to replace these mail flags if you check them:
 +
 +
{| class="wikitable"
 +
|-
 +
! old flag
 +
! new flag
 +
|-
 +
| <samp>Gil_Slime Charmer Ring</samp>
 +
| <samp>Gil_Slimes</samp>
 +
|-
 +
| <samp>Gil_Savage Ring</samp>
 +
| <samp>Gil_Shadows</samp>
 +
|-
 +
| <samp>Gil_Vampire Ring</samp>
 +
| <samp>Gil_Bats</samp>
 +
|-
 +
| <samp>Gil_Skeleton Mask</samp>
 +
| <samp>Gil_Skeletons</samp>
 +
|-
 +
| <samp>Gil_Insect Head</samp>
 +
| <samp>Gil_Insects</samp>
 +
|-
 +
| <samp>Gil_Hard Hat</samp>
 +
| <samp>Gil_Duggy</samp>
 +
|-
 +
| <samp>Gil_Burglar's Ring</samp>
 +
| <samp>Gil_DustSpirits</samp>
 +
|-
 +
| <samp>Gil_Crabshell Ring</samp>
 +
| <samp>Gil_Crabs</samp>
 +
|-
 +
| <samp>Gil_Arcane Hat</samp>
 +
| <samp>Gil_Mummies</samp>
 +
|-
 +
| <samp>Gil_Knight's Helmet</samp>
 +
| <samp>Gil_Dinos</samp>
 +
|-
 +
| <samp>Gil_Napalm Ring</samp>
 +
| <samp>Gil_Serpents</samp>
 +
|-
 +
| <samp>Gil_Telephone</samp>
 +
| <samp>Gil_FlameSpirits</samp>
 +
|}
 +
 +
===XNB impact===
 +
====Overview====
 +
This section provides a summary of the XNB files which changed in Stardew Valley 1.6. 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.6 (e.g. typo fixes).
 +
* "✓ mostly unaffected": mods will only be affected if they replace the entire asset, or edit specific entries or fields.
 +
* Blank: no expected impact for the vast majority of mods.
 +
 +
{| class="wikitable"
 +
|-
 +
!rowspan="2"| content asset
 +
!rowspan="2"| changes in 1.6
 +
!colspan="2"| compatibility for pre-1.6 mods
 +
|-
 +
! XNB mods
 +
! Content Patcher packs
 +
|-
 +
| <samp>Buildings/houses</samp>
 +
| &#32;
 +
* fixed missing pixels
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Characters/Dialogue/Abigail</samp><br /><samp>Characters/Dialogue/Alex</samp>
 +
| &#32;
 +
* added [[#Dialogue changes|flower dance dialogue]]
 +
* fixed typos
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Characters/Dialogue/Caroline</samp><br /><samp>Characters/Dialogue/Demetrius</samp>
 +
| &#32;
 +
* fixed typos
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Characters/Dialogue/Elliott</samp>
 +
| &#32;
 +
* added [[#Dialogue changes|flower dance dialogue]]
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Characters/Dialogue/Emily</samp>
 +
| &#32;
 +
* added [[#Dialogue changes|flower dance dialogue]]
 +
* fixed typos
 +
* updated <samp>%revealtaste</samp> format (backwards-compatible)
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Characters/Dialogue/George</samp>
 +
| &#32;
 +
* added [[#Dialogue changes|Winter Star gift exchange dialogue]]
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Characters/Dialogue/Gus</samp>
 +
| &#32;
 +
* fixed typos
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Characters/Dialogue/Haley</samp>
 +
| &#32;
 +
* added [[#Dialogue changes|flower dance dialogue]]
 +
* fixed typos
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Characters/Dialogue/Harvey</samp>
 +
| &#32;
 +
* added [[#Dialogue changes|flower dance dialogue]]
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Characters/Dialogue/Jas</samp><br /><samp>Characters/Dialogue/Jodi</samp>
 +
| &#32;
 +
* fixed typos
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Characters/Dialogue/Krobus</samp>
 +
| &#32;
 +
* added [[#Dialogue changes|roommate stardrop dialogue]]
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Characters/Dialogue/Leah</samp>
 +
| &#32;
 +
* added [[#Dialogue changes|flower dance dialogue]]
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Characters/Dialogue/Lewis</samp>
 +
| &#32;
 +
* updated <samp>%revealtaste</samp> format (backwards-compatible)
 +
|
 +
|
 +
|-
 +
| <samp>Characters/Dialogue/Linus</samp>
 +
| &#32;
 +
* added [[#Dialogue changes|dumpster dive dialogue]]
 +
* fixed typos
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Characters/Dialogue/Marnie</samp>
 +
| &#32;
 +
* added [[#Dialogue changes|Stardew Valley Fair dialogue]]
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Characters/Dialogue/MarriageDialogue</samp><br /><samp>Characters/Dialogue/MarriageDialogueAbigail</samp><br /><samp>Characters/Dialogue/MarriageDialogueElliott</samp>
 +
| &#32;
 +
* fixed typos
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Characters/Dialogue/MarriageDialogueEmily</samp>
 +
| &#32;
 +
* changed <samp>spring_Maru</samp> key to <samp>spring_Emily</samp>
 +
* fixed typos
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Characters/Dialogue/MarriageDialogueKrobus</samp><br /><samp>Characters/Dialogue/MarriageDialogueLeah</samp><br /><samp>Characters/Dialogue/MarriageDialogueMaru</samp><br /><samp>Characters/Dialogue/MarriageDialoguePenny</samp><br /><samp>Characters/Dialogue/MarriageDialogueSam</samp>
 +
| &#32;
 +
* fixed typos
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Characters/Dialogue/Maru</samp>
 +
| &#32;
 +
* added [[#Dialogue changes|flower dance dialogue]]
 +
* fixed typos
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Characters/Dialogue/Penny</samp>
 +
| &#32;
 +
* added [[#Dialogue changes|flower dance dialogue]]
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Characters/Dialogue/Pierre</samp>
 +
| &#32;
 +
* added [[#Dialogue changes|Stardew Valley Fair dialogue]]
 +
* fixed typos
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Characters/Dialogue/Robin</samp>
 +
| &#32;
 +
* fixed typos
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Characters/Dialogue/Sam</samp>
 +
| &#32;
 +
* added [[#Dialogue changes|flower dance dialogue]]
 +
* fixed typos
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Characters/Dialogue/Sandy</samp>
 +
| &#32;
 +
* fixed typos
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Characters/Dialogue/Sebastian</samp>
 +
| &#32;
 +
* added [[#Dialogue changes|flower dance dialogue]]
 +
* fixed typos
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Characters/Dialogue/Willy</samp>
 +
| &#32;
 +
* added [[#Dialogue changes|Stardew Valley Fair dialogue]]
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Characters/Dialogue/Shane</samp>
 +
| &#32;
 +
* added [[#Dialogue changes|flower dance dialogue]]
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Characters/Farmer/hats</samp>
 +
| &#32;
 +
* removed stray pixel on chicken mask
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Characters/schedules/Elliott</samp>
 +
| &#32;
 +
* fixed order of <samp>Fri_6</samp> and <samp>Fri</samp> entries
 +
| '''✘ broken'''
 +
|
 +
|-
 +
| <samp>Characters/schedules/Lewis</samp>
 +
| &#32;
 +
* fixed <samp>winter_Sun</samp> schedule
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Characters/schedules/Maru</samp>
 +
| &#32;
 +
* fixed <samp>summer_Mon</samp> and <samp>summer_Sun</samp> schedules
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Characters/schedules/Penny</samp>
 +
| &#32;
 +
* fixed <samp>summer_Sun</samp> schedule
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Characters/Schedules/Shane</samp>
 +
| &#32;
 +
* fixed dialogue key
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Data/animationDescriptions</samp>
 +
| &#32;
 +
* fixed frame in Lewis' Saloon drinking animation
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Data/AquariumFish</samp>
 +
| &#32;
 +
* [[#Custom items|changed key type]]
 +
* added hat position for [[Sea Urchin]]
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Data/BigCraftablesInformation</samp>
 +
| &#32;
 +
* asset replaced by [[#Custom big craftables|<samp>Data/BigCraftables</samp>]]:
 +
** migrated to data model format
 +
** added new features
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected<br /><small>(covered by runtime migration)</small>
 +
|-
 +
| <samp>Data/Blueprints</samp>
 +
| &#32;
 +
* asset replaced by [[#Custom buildings|<samp>Data/Buildings</samp>]]:
 +
** migrated to data model format
 +
** added new features
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected<br /><small>(covered by runtime migration)</small>
 +
|-
 +
| <samp>Data/Boots</samp>
 +
| &#32;
 +
* [[#Custom items|changed key type]]
 +
* added display name
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected<br /><small>(covered by runtime migration)</small>
 +
|-
 +
| <samp>Data/Bundles</samp>
 +
| &#32;
 +
* can no longer omit empty fields before display name
 +
* added display name field in English
 +
* removed meat items in animal bundle
 +
| '''✘ broken'''
 +
| '''✘ likely broken'''
 +
|-
 +
| <samp>Data/ClothingInformation</samp>
 +
| &#32;
 +
* asset replaced by [[#Custom pants|<samp>Data/Pants</samp>]] and [[#Custom shirts|<samp>Data/Shirts</samp>]]:
 +
** migrated to data model format
 +
** added new features
 +
| '''✘ broken'''
 +
| '''✘ likely broken'''
 +
|-
 +
| <samp>Data/Concessions</samp>
 +
| &#32;
 +
* [[#Custom movie concessions|added new required fields (<samp>Texture</samp> and <samp>SpriteIndex</samp>)]]
 +
* replaced translations with [[Modding:Tokenizable strings|tokenizable strings]]
 +
* changed IDs to strings
 +
| '''✘ broken'''
 +
| '''✘ likely broken'''
 +
|-
 +
| <samp>Data/ConcessionTastes</samp>
 +
| &#32;
 +
* added automatic <samp>ID</samp> field
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Data/CookingRecipes</samp>
 +
| &#32;
 +
* replaced translations with [[Modding:Tokenizable strings|tokenizable strings]]
 +
* display names can now be omitted to use item name
 +
| ✘ will remove changes
 +
| ✓ may remove unaffected
 +
|-
 +
| <samp>Data/CraftingRecipes</samp>
 +
| &#32;
 +
* replaced translations with [[Modding:Tokenizable strings|tokenizable strings]]
 +
* display names can now be omitted to use item name
 +
* added <samp>default</samp> unlock condition
 +
* fixed typo in Cookout Kit entry
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Data/Crops</samp>
 +
| &#32;
 +
* [[#Custom crops|completely overhauled]]
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected<br /><small>(covered by runtime migration)</small>
 +
|-
 +
| <samp>Data/Events/AnimalShop</samp>
 +
| &#32;
 +
* updated command syntax (backwards-compatible)
 +
|
 +
|
 +
|-
 +
| <samp>Data/Events/Farm</samp>
 +
| &#32;
 +
* replaced send-mail events with [[Modding:Trigger actions|trigger actions]]
 +
* updated pet event to support custom pet types
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected<br /><small>(✘ may cause duplicate mail if they edit<br />send-mail events)</small>
 +
|-
 +
| <samp>Data/Events/FishShop</samp>
 +
| &#32;
 +
* fixed typos
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Data/Events/Forest</samp>
 +
| &#32;
 +
* fixed typos
 +
* updated Jas <samp>faceDirection</samp> command for sewer event
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Data/Events/IslandHut</samp>
 +
| &#32;
 +
* updated how Leo's name is translated
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Data/Events/IslandNorth</samp>
 +
| &#32;
 +
* updated quote format
 +
* fixed blank music field (backwards-compatible)
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected<br /><small>(✘ likely broken if they edit the <samp>6497421</samp> event)</small>
 +
|-
 +
| <samp>Data/Events/IslandSouth</samp>
 +
| &#32;
 +
* fixed blank music field (backwards-compatible)
 +
* fixed typos
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Data/Events/JoshHouse</samp>
 +
| &#32;
 +
* fixed typos
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Data/Events/LeahHouse</samp>
 +
| &#32;
 +
* fixed <samp>move</samp> command format in Leah's 2-heart event
 +
* fixed typos
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Data/Events/Mountain</samp>
 +
| &#32;
 +
* fixed skipped dialogue in Maru's 14-heart event
 +
* fixed typos
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Data/Events/Saloon</samp><br /><samp>Data/Events/ScienceHouse</samp><br /><samp>Data/Events/SebastianRoom</samp>
 +
| &#32;
 +
* fixed typos
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Data/Events/Town</samp>
 +
| &#32;
 +
* fixed <samp>warp</samp> command format in community center completed event
 +
* fixed typos
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Data/Events/WizardHouse</samp>
 +
| &#32;
 +
* fixed typos
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Data/ExtraDialogue</samp>
 +
| &#32;
 +
* split <samp>SummitEvent_Dialogue1_Spouse</samp> entry
 +
* fixed event command formats in some summit dialogue
 +
* moved [[#Dialogue changes|dumpster dive dialogue into NPC files]]
 +
* removed unused entries
 +
* fixed typos
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Data/FarmAnimals</samp>
 +
| &#32;
 +
* [[#Custom farm animals|completely overhauled]]
 +
| '''✘ broken'''
 +
| '''✘ broken'''
 +
|-
 +
| <samp>Data/Festivals/fall16</samp>
 +
| &#32;
 +
* updated command syntax (backwards-compatible)
 +
* fixed typos
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Data/Festivals/fall27</samp>
 +
| &#32;
 +
* removed <samp>shop</samp> field (moved into [[#Custom shops|<samp>Data/Shops</samp>]])
 +
| ✓ mostly unaffected
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Data/Festivals/spring13</samp>
 +
| &#32;
 +
* migrated to new <samp>warpFarmers</samp> command
 +
* removed <samp>shop</samp> field (moved into [[#Custom shops|<samp>Data/Shops</samp>]])
 +
* updated <samp>faceDirection</samp> syntax
 +
* fixed typos
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected<br /><small>(✘ broken if they edit <samp>mainEvent</samp> or<br /><samp>afterEggHunt</samp> fields)</small>
 +
|-
 +
| <samp>Data/Festivals/spring24</samp><br /><samp>Data/Festivals/summer11</samp><br /><samp>Data/Festivals/summer28</samp>
 +
| &#32;
 +
* migrated to new <samp>warpFarmers</samp> command
 +
* removed <samp>shop</samp> field (moved into [[#Custom shops|<samp>Data/Shops</samp>]])
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected<br /><small>(✘ broken if they edit <samp>mainEvent</samp> field)</small>
 +
|-
 +
| <br /><samp>Data/Festivals/winter8</samp>
 +
| &#32;
 +
* migrated to new <samp>warpFarmers</samp> command
 +
* removed <samp>shop</samp> field (moved into [[#Custom shops|<samp>Data/Shops</samp>]])
 +
* removed broken <samp>loadActors MainEvent</samp> command
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected<br /><small>(✘ broken if they edit <samp>mainEvent</samp> or<br /><samp>afterIceFishing</samp> field)</small>
 +
|-
 +
| <samp>Data/Festivals/winter25</samp>
 +
| &#32;
 +
* removed <samp>shop</samp> field (moved into [[#Custom shops|<samp>Data/Shops</samp>]])
 +
| ✓ mostly unaffected
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Data/Fish</samp>
 +
| &#32;
 +
* no longer has per-language versions
 +
* [[#Custom items|changed key type]]
 +
* field 13 now refers to whether fish can be tutorial catch
 +
| '''✘ broken'''
 +
| ✘ likely broken
 +
|-
 +
| <samp>Data/FishPondData</samp>
 +
| &#32;
 +
* added required <samp>Id</samp> & optional <samp>Precedence</samp> fields
 +
* standardized <samp>ID</samp>→<samp>Id</samp> naming
 +
* changed to qualified item IDs
 +
* moved fallback entries to bottom
 +
| '''✘ broken'''
 +
| ✘ likely broken
 +
|-
 +
| <samp>Data/fruitTrees</samp>
 +
| &#32;
 +
* [[#Custom fruit trees|completely overhauled]]
 +
| '''✘ broken'''
 +
| '''✘ broken'''
 +
|-
 +
| <samp>Data/Furniture</samp>
 +
| &#32;
 +
* [[#Custom items|changed key type]]
 +
* replaced translations with [[Modding:Tokenizable strings|tokenizable strings]]
 +
* [[#Custom items|changed key type]]
 +
* can no longer omit empty fields before display name
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected<br /><small>(covered by runtime migration)</small>
 +
|-
 +
| <samp>Data/hats</samp>
 +
| &#32;
 +
* [[#Custom items|changed key type]]
 +
* can no longer omit empty fields before display name
 +
* added display name field in English
 +
| '''✘ broken'''
 +
| '''✘ likely broken'''
 +
|-
 +
| <samp>Data/Locations</samp>
 +
| &#32;
 +
* [[#Custom locations|completely overhauled]]
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected<br /><small>(covered by runtime migration)</small>
 +
|-
 +
| <samp>Data/mail</samp>
 +
| &#32;
 +
* migrated to <samp>%item id</samp> (backwards-compatible)
 +
* removed unused entries
 +
* fixed typos
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Data/Monsters</samp>
 +
| &#32;
 +
* changed ''Dust Spirit'' display name to ''Dust Sprite''
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Data/Movies</samp>
 +
| &#32;
 +
* [[#Custom movies|significantly overhauled]]
 +
| '''✘ broken'''
 +
| '''✘ broken'''
 +
|-
 +
| <samp>Data/MoviesReactions</samp>
 +
| &#32;
 +
* replaced translations with [[Modding:Tokenizable strings|tokenizable strings]]
 +
* standardized <samp>ID</samp>→<samp>Id</samp> naming
 +
* fixed typo
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Data/NPCDispositions</samp>
 +
| &#32;
 +
* asset replaced by [[#Custom NPCs|<samp>Data/Characters</samp>]]
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected<br /><small>(covered by runtime migration)</small>
 +
|-
 +
| <samp>Data/NPCGiftTastes</samp>
 +
| &#32;
 +
* removed invalid item IDs
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Data/ObjectContextTags</samp>
 +
| &#32;
 +
* asset removed (replaced by <samp>ContextTags</samp> field in [[#Custom big craftables|<samp>Data/BigCraftables</samp>]] and [[#Custom objects|<samp>Data/Objects</samp>]])
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected<br /><small>(covered by runtime migration,<br />except context tags defined<br />before their objects and context<br />tags for bigcraftables.)
 +
</small>
 +
|-
 +
| <samp>Data/ObjectInformation</samp>
 +
| &#32;
 +
* asset replaced by [[#Custom objects|<samp>Data/Objects</samp>]]:
 +
** migrated to data model format
 +
** added new features
 +
** added new entries
 +
** adjusted [[#Other item changes|litter items]]
 +
** fixed typos
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected<br /><small>(covered by runtime migration)</small>
 +
|-
 +
| <samp>Data/PaintData</samp>
 +
| &#32;
 +
* fixed trailing slash in <samp>Deluxe Barn</samp> entry
 +
|
 +
|
 +
|-
 +
| <samp>Data/Quests</samp>
 +
| &#32;
 +
* changed key type to string
 +
* migrated to use item IDs (backwards-compatible)
 +
* fixed typo
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Data/RandomBundles</samp>
 +
| &#32;
 +
* add optional <samp>Id</samp> field
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Data/SecretNotes</samp>
 +
| &#32;
 +
* updated <samp>%revealtaste</samp> format (backwards-compatible)
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Data/SpecialOrders</samp>
 +
| &#32;
 +
* changed type of <samp>Repeatable</samp> and <samp>Duration</samp> fields
 +
* added optional <samp>CustomFields</samp> and <samp>Conditions</samp> fields
 +
| '''✘ broken'''
 +
|
 +
|-
 +
| <samp>Data/SpousePatios</samp><br /><samp>Data/SpouseRooms</samp>
 +
| &#32;
 +
* removed asset (merged into [[#Custom NPCs|<samp>Data/Characters</samp>]])
 +
| '''✘ broken'''
 +
| '''✘ broken'''
 +
|-
 +
| <samp>Data/TailoringRecipes</samp>
 +
| &#32;
 +
* changed to [[#Custom items|string item IDs]] (backwards-compatible)
 +
* added optional <samp>Id</samp> and <samp>CraftedItemIdFeminine</samp> fields
 +
* removed <samp>CraftedItemColor</samp> field
 +
* adjusted recipes for gender-variant shirts
 +
* standardized <samp>ID</samp>→<samp>Id</samp> naming
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected<br /><small>(<samp>MoveEntries</samp> may break, but fallback entries<br />are now checked last automatically)</small>
 +
|-
 +
| <samp>Data/TV/CookingChannel</samp><br /><samp>Data/TV/TipChannel</samp>
 +
| &#32;
 +
* fixed typos
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Data/weapons</samp>
 +
| &#32;
 +
* [[#Custom melee weapons|completely overhauled]]
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected<br /><small>(covered by runtime migration)</small>
 +
|-
 +
| <samp>LooseSprites/Cursors</samp>
 +
| &#32;
 +
* new sprites in empty area
 +
* moved mailbox to <samp>Buildings/Mailbox</samp>
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>LooseSprites/Cursors2</samp>
 +
| &#32;
 +
* new sprite in empty area
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>LooseSprites/map</samp>
 +
| &#32;
 +
* redrawn to better match in-game locations
 +
* added more detail
 +
| '''✘ broken'''
 +
| ✘ likely broken
 +
|-
 +
| <samp>Maps/AbandonedJojaMart</samp><br /><samp>Maps/AdventureGuild</samp>
 +
| &#32;
 +
* moved <samp>Music</samp> property into <samp>Data/Locations</samp>
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Maps/AnimalShop</samp>
 +
| &#32;
 +
* removed unused pathfinding tiles
 +
|
 +
|
 +
|-
 +
| <samp>Maps/ArchaeologyHouse</samp>
 +
| &#32;
 +
* removed unused pathfinding tiles
 +
* moved <samp>Music</samp> property into <samp>Data/Locations</samp>
 +
|
 +
|
 +
|-
 +
| <samp>Maps/Backwoods</samp><br /><samp>Maps/Backwoods_GraveSite</samp><br /><samp>Maps/Backwoods_Staircase</samp>
 +
| &#32;
 +
* removed unused tile properties
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
|
 +
|
 +
|-
 +
| <samp>Maps/Barn</samp><br /><samp>Maps/Barn2</samp>
 +
| &#32;
 +
* removed unused map properties
 +
|
 +
|
 +
|-
 +
| <samp>Maps/Barn3</samp>
 +
| &#32;
 +
* added <samp>AutoFeed</samp> map property
 +
* removed unused map properties
 +
| '''✘ broken'''
 +
|
 +
|-
 +
| <samp>Maps/BathHouse_Entry</samp><br /><samp>Maps/BathHouse_MensLocker</samp>
 +
| &#32;
 +
* moved <samp>Music</samp> property into <samp>Data/Locations</samp>
 +
* removed unused pathfinding tiles
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Maps/BathHouse_Pool</samp>
 +
| &#32;
 +
* removed unused pathfinding tiles
 +
* removed unused map & tile properties
 +
|
 +
|
 +
|-
 +
| <samp>Maps/BathHouse_WomensLocker</samp>
 +
| &#32;
 +
* moved <samp>Music</samp> property into <samp>Data/Locations</samp>
 +
* removed unused pathfinding tiles
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Maps/Beach</samp>
 +
| &#32;
 +
* removed unused map properties
 +
* removed unused pathfinding tiles
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
|
 +
|
 +
|-
 +
| <samp>Maps/Beach-Jellies</samp><br /><samp>Maps/Beach-Luau</samp><br /><samp>Maps/Beach-NightMarket</samp>
 +
| &#32;
 +
* updated for festival shops now in <samp>Data/Shops</samp>
 +
* removed unused map/tile properties
 +
* removed unused pathfinding tiles
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Maps/Blacksmith</samp>
 +
| &#32;
 +
* removed unused pathfinding tiles
 +
|
 +
|
 +
|-
 +
| <samp>Maps/BoatTunnel</samp>
 +
| &#32;
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
|
 +
|
 +
|-
 +
| <samp>Maps/BugLand</samp>
 +
| &#32;
 +
* moved <samp>Music</samp> property into <samp>Data/Locations</samp>
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Maps/BusStop</samp>
 +
| &#32;
 +
* removed unused map/tile properties
 +
* removed unused pathfinding tiles
 +
* changed <samp>Action BusTicket</samp> to <samp>Action None</samp>
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
|
 +
|
 +
|-
 +
| <samp>Maps/Caldera</samp>
 +
| &#32;
 +
* removed unused map property
 +
|
 +
|
 +
|-
 +
| <samp>Maps/Cellar</samp>
 +
| &#32;
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
|
 +
|
 +
|-
 +
| <samp>Maps/Club</samp>
 +
| &#32;
 +
* added <samp>LocationContext</samp> map property
 +
* moved <samp>Music</samp> property into <samp>Data/Locations</samp>
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Maps/Coop</samp><br /><samp>Maps/Coop2</samp>
 +
| &#32;
 +
* removed unused map properties
 +
|
 +
|
 +
|-
 +
| <samp>Maps/Coop3</samp>
 +
| &#32;
 +
* added <samp>AutoFeed</samp> map property
 +
* removed unused map properties
 +
| '''✘ broken'''
 +
|
 +
|-
 +
| <samp>Maps/Desert</samp>
 +
| &#32;
 +
* added <samp>LocationContext</samp> map property
 +
* removed unused map/tile properties
 +
* removed unused pathfinding tiles
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
| '''✘ broken'''
 +
|
 +
|-
 +
| <samp>Maps/ElliottHouse</samp>
 +
| &#32;
 +
* removed unused pathfinding tiles
 +
|
 +
|
 +
|-
 +
| <samp>Maps/Farm</samp><br /><samp>Maps/Farm_Combat</samp><br /><samp>Maps/Farm_Fishing</samp><br /><samp>Maps/Farm_Foraging</samp><br /><samp>Maps/Farm_FourCorners</samp><br /><samp>Maps/Farm_Island</samp><br /><samp>Maps/Farm_Mining</samp>
 +
| &#32;
 +
* added new tilesheet
 +
* added cabin positions for players 5–8
 +
* added <samp>PetBowlLocation</samp> map property (for <samp>Maps/Four_Corners</samp> and <samp>Farm/Island</samp> only)
 +
* added <samp>SpouseAreaLocation</samp> map property (for <samp>Maps/Farm_Island</samp> only)
 +
* significant tile & tile property changes
 +
* removed farmhouse + pet bowl areas (now moveable)
 +
* removed unused map/tile properties
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
| '''✘ broken'''
 +
| ✘ may remove changes
 +
|-
 +
| <samp>Maps/Farm_Greenhouse_Dirt</samp><br /><samp>Maps/Farm_Greenhouse_Dirt_FourCorners</samp>
 +
| &#32;
 +
* removed unused map properties
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
|
 +
|
 +
|-
 +
| <samp>Maps/FarmHouse</samp><br /><samp>Maps/FarmHouse_Bedroom_Normal</samp><br /><samp>Maps/FarmHouse_Bedroom_Open</samp><br /><samp>Maps/FarmHouse_Cellar</samp><br /><samp>Maps/FarmHouse_ChildBed_0</samp><br /><samp>Maps/FarmHouse_ChildBed_1</samp><br /><samp>Maps/FarmHouse_CornerRoom_Add</samp><br /><samp>Maps/FarmHouse_CornerRoom_Remove</samp><br /><samp>Maps/FarmHouse_SouthernRoom_Add</samp><br /><samp>Maps/FarmHouse_SouthernRoom_Remove</samp><br /><samp>Maps/FarmHouse1</samp><br /><samp>Maps/FarmHouse1_marriage</samp><br /><samp>Maps/FarmHouse2</samp><br /><samp>Maps/FarmHouse2_marriage</samp>
 +
| &#32;
 +
* removed unused map properties
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
|
 +
|
 +
|-
 +
| <samp>Maps/FishingGame</samp>
 +
| &#32;
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
|
 +
|
 +
|-
 +
| <samp>Maps/FishShop</samp>
 +
| &#32;
 +
* fixed broken <samp>DayTiles</samp> and <samp>NightTiles</samp> values
 +
* removed unused pathfinding tiles
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Maps/Forest</samp>
 +
| &#32;
 +
* removed unused map/tile properties
 +
* removed unused pathfinding tiles
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
|
 +
|
 +
|-
 +
| <samp>Maps/Forest-FlowerFestival</samp>
 +
| &#32;
 +
* updated for festival shops now in <samp>Data/Shops</samp>
 +
* removed unused map/tile properties
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Maps/Forest-IceFestival</samp>
 +
| &#32;
 +
* updated for festival shops now in <samp>Data/Shops</samp>
 +
* fixed warp positions
 +
* removed unused map/tile properties
 +
* removed unused pathfinding tiles
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Maps/Forest-SewerClean</samp>
 +
| &#32;
 +
* removed unused map/tile properties
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
|
 +
|
 +
|-
 +
| <samp>Maps/HaleyHouse</samp><br /><samp>Maps/HarveyRoom</samp>
 +
| &#32;
 +
* removed unused pathfinding tiles
 +
|
 +
|
 +
|-
 +
| <samp>Maps/Hospital</samp>
 +
| &#32;
 +
* removed deprecated <samp>UniquePortrait</samp> & <samp>UniqueSprite</samp> map properties
 +
* removed unused pathfinding tiles
 +
| ✘ will remove changes<br /><small>(This may cause mod conflicts)</samp>
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Maps/Island_Bridge_Broken</samp><br /><samp>Maps/Island_Bridge_Repaired</samp><br /><samp>Maps/Island_House_Cave</samp>
 +
| &#32;
 +
* removed unused map properties
 +
|
 +
|
 +
|-
 +
| <samp>Maps/Island_N</samp>
 +
| &#32;
 +
* update walnut bush tile so it still works in 1.6
 +
* removed unused tile property
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Maps/IslandNorthCave1</samp><br /><samp>Maps/IslandSouthEastCave</samp><br /><samp>Maps/IslandSouthEastCave_pirates</samp><br /><samp>Maps/IslandWestCave1</samp>
 +
| &#32;
 +
* moved <samp>Music</samp> property into <samp>Data/Locations</samp>
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Maps/Island_Bridge_Broken</samp><br /><samp>Maps/Island_Bridge_Repaired</samp>
 +
| &#32;
 +
* removed unused map property
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
|
 +
|
 +
|-
 +
| <samp>Maps/Island_E</samp><br /><samp>Maps/IslandFarmCave</samp>
 +
| &#32;
 +
* moved <samp>Music</samp> property into <samp>Data/Locations</samp>
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Maps/Island_House_Cave</samp>
 +
| &#32;
 +
* removed unused map property
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
|
 +
|
 +
|-
 +
| <samp>Maps/Island_Hut</samp>
 +
| &#32;
 +
* moved <samp>Music</samp> property into <samp>Data/Locations</samp>
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Maps/Island_N</samp>
 +
| &#32;
 +
* added a <samp>NowSpawn False</samp> tile property to fix tree that hides a golden walnut
 +
* removed unused tile property
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Maps/Island_N_Trader</samp><br /><samp>Maps/Island_Secret</samp>
 +
| &#32;
 +
* removed unused tile property
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
|
 +
|
 +
|-
 +
| <samp>Maps/Island_Shrine</samp>
 +
| &#32;
 +
* moved <samp>Music</samp> property into <samp>Data/Locations</samp>
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Maps/Island_W</samp>
 +
| &#32;
 +
* removed unused tile property
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
|
 +
|
 +
|-
 +
| <samp>Maps/IslandFarmHouse</samp>
 +
| &#32;
 +
* removed unused tile properties
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
|
 +
|
 +
|-
 +
| <samp>Maps/JojaMart</samp><br /><samp>Maps/JoshHouse</samp><br /><samp>Maps/LeahHouse</samp><br /><samp>Maps/ManorHouse</samp>
 +
| &#32;
 +
* removed unused pathfinding tiles
 +
|
 +
|
 +
|-
 +
| <samp>Maps/MarnieBarn</samp>
 +
| &#32;
 +
* removed unused map properties
 +
|
 +
|
 +
|-
 +
| <samp>Maps/Mine</samp>
 +
| &#32;
 +
* updated for [[#Custom minecarts|minecart changes]]
 +
* removed unused map properties
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Maps/Mountain</samp>
 +
| &#32;
 +
* removed unused map/tile properties
 +
* removed unused pathfinding tiles
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
|
 +
|
 +
|-
 +
| <samp>Maps/Mountain-BridgeFixed</samp><br /><samp>Maps/Mountain_Shortcuts</samp>
 +
| &#32;
 +
* removed unused map/tile properties
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
|
 +
|
 +
|-
 +
| <samp>Maps/MovieTheater</samp>
 +
| &#32;
 +
* moved <samp>Music</samp> property into <samp>Data/Locations</samp>
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Maps/MovieTheaterScreen</samp>
 +
| &#32;
 +
* updated for tilesheet changes
 +
| ✘ broken visuals (e.g. missing chairs)
 +
| ✓ mostly unaffected<br /><small>(✘ broken visuals if they edit the affected tiles)</small>
 +
|-
 +
| <samp>Maps/MovieTheaterScreen_TileSheet</samp>
 +
| &#32;
 +
* improved light cone
 +
* moved chair sprite to make room for new light cone
 +
| ✘ broken visuals (e.g. missing chairs)
 +
| ✓ mostly unaffected<br /><small>(✘ broken visuals if they edit the affected sprites)</small>
 +
|-
 +
| <samp>Maps/paths</samp>
 +
| &#32;
 +
* added icon for [[#Custom wild trees|custom wild tree spawn]]
 +
* removed unused pathfinding tiles
 +
|
 +
|
 +
|-
 +
| <samp>Maps/QiNutRoom</samp>
 +
| &#32;
 +
* moved <samp>Music</samp> property into <samp>Data/Locations</samp>
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Maps/Railroad</samp>
 +
| &#32;
 +
* removed unused map property
 +
* removed unused pathfinding tiles
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
|
 +
|
 +
|-
 +
| <samp>Maps/Saloon</samp><br /><samp>Maps/SamHouse</samp>
 +
| &#32;
 +
* removed unused pathfinding tiles
 +
|
 +
|
 +
|-
 +
| <samp>Maps/SandyHouse</samp>
 +
| &#32;
 +
* added <samp>LocationContext</samp> map property
 +
| '''✘ broken'''
 +
|
 +
|-
 +
| <samp>Maps/ScienceHouse</samp><br /><samp>Maps/SebastianRoom</samp>
 +
| &#32;
 +
* removed unused pathfinding tiles
 +
|
 +
|
 +
|-
 +
| <samp>Maps/SeedShop</samp>
 +
| &#32;
 +
* removed unused tile properties
 +
* removed unused pathfinding tiles
 +
|
 +
|
 +
|-
 +
| <samp>Maps/Sewer</samp>
 +
| &#32;
 +
* moved <samp>Music</samp> property into <samp>Data/Locations</samp>
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Maps/Shed</samp><br /><samp>Maps/Shed2</samp>
 +
| &#32;
 +
* added <samp>FloorIDs</samp> and <samp>WallIDs</samp> map properties
 +
| '''✘ broken'''
 +
|
 +
|-
 +
| <samp>Maps/SkullCave</samp>
 +
| &#32;
 +
* added <samp>LocationContext</samp> map property
 +
* moved <samp>Music</samp> property into <samp>Data/Locations</samp>
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Maps/SlimeHutch</samp>
 +
| &#32;
 +
* removed unused tile property
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
|
 +
|
 +
|-
 +
| <samp>Maps/spousePatios</samp>
 +
| &#32;
 +
* removed unused map/tile properties
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
|
 +
|
 +
|-
 +
| <samp>Maps/spring_outdoorsTileSheet</samp><br /><samp>Maps/summer_outdoorsTileSheet</samp><br /><samp>Maps/fall_outdoorsTileSheet</samp><br /><samp>Maps/winter_outdoorsTileSheet</samp>
 +
| &#32;
 +
* pet bowl moved to <samp>Buildings/Pet Bowl</samp>
 +
| ✓ mostly unaffected
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Maps/Submarine</samp>
 +
| &#32;
 +
* removed unused tile property
 +
|
 +
|
 +
|-
 +
| <samp>Maps/Sunroom</samp>
 +
| &#32;
 +
* added <samp>IsGreenhouse</samp map property
 +
| '''✘ broken'''
 +
|
 +
|-
 +
| <samp>Maps/Tent</samp>
 +
| &#32;
 +
* removed unused pathfinding tiles
 +
|
 +
|
 +
|-
 +
| <samp>Maps/Town</samp>
 +
| &#32;
 +
* updated [[#Custom garbage cans|garbage can IDs]] (backwards-compatible)
 +
* removed unused map/tile properties
 +
* removed unused pathfinding tiles
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
|
 +
|
 +
|-
 +
| <samp>Maps/Town-Christmas</samp>
 +
| &#32;
 +
* updated for festival shops now in <samp>Data/Shops</samp>
 +
* removed unused map/tile properties
 +
* removed unused pathfinding tiles
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Maps/Town-DogHouse</samp>
 +
| &#32;
 +
* removed unused map/tile properties
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
|
 +
|
 +
|-
 +
| <samp>Maps/Town-EggFestival</samp>
 +
| &#32;
 +
* updated for festival shops now in <samp>Data/Shops</samp>
 +
* fixed Elliott appearing twice during egg hunt
 +
* removed unused map/tile properties
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Maps/Town-Fair</samp>
 +
| &#32;
 +
* removed unused map/tile properties
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
|
 +
|
 +
|-
 +
| <samp>Maps/Town-Halloween</samp>
 +
| &#32;
 +
* updated for festival shops now in <samp>Data/Shops</samp>
 +
* removed unused map/tile properties
 +
* removed unused pathfinding tiles
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Maps/Town-Theater</samp><br /><samp>Maps/Town-TheaterCC</samp><br /><samp>Maps/Town-TrashGone</samp>
 +
| &#32;
 +
* removed unused tile properties
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
|
 +
|
 +
|-
 +
| <samp>Maps/Trailer</samp>
 +
| &#32;
 +
* removed unused tile property
 +
* removed unused pathfinding tiles
 +
|
 +
|
 +
|-
 +
| <samp>Maps/Trailer_big</samp>
 +
| &#32;
 +
* removed unused pathfinding tiles
 +
|
 +
|
 +
|-
 +
| <samp>Maps/Tunnel</samp>
 +
| &#32;
 +
* moved <samp>Music</samp> property into <samp>Data/Locations</samp>
 +
* removed unused map property
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Maps/WitchHut</samp>
 +
| &#32;
 +
* moved <samp>Music</samp> property into <samp>Data/Locations</samp>
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Maps/WitchSwamp</samp>
 +
| &#32;
 +
* moved <samp>Music</samp> property into <samp>Data/Locations</samp>
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Maps/WitchWarpCave</samp>
 +
| &#32;
 +
* moved <samp>Music</samp> property into <samp>Data/Locations</samp>
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Maps/WizardHouse</samp>
 +
| &#32;
 +
* moved <samp>Music</samp> property into <samp>Data/Locations</samp>
 +
* removed unused pathfinding tiles
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Maps/WizardHouseBasement</samp>
 +
| &#32;
 +
* moved <samp>Music</samp> property into <samp>Data/Locations</samp>
 +
* removed unused map property
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Maps/Woods</samp>
 +
| &#32;
 +
* removed unused tile property
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
|
 +
|
 +
|-
 +
| <samp>Minigames/boatJourneyMap</samp>
 +
| &#32;
 +
* asset replaced by redrawn seasonal variants like <samp>fall_boatJourneyMap</samp>
 +
| '''✘ broken'''
 +
| '''✘ broken'''
 +
|-
 +
| <samp>Strings/Characters</samp>
 +
| &#32;
 +
* added new entries
 +
| '''✘ broken'''
 +
|
 +
|-
 +
| <samp>Strings/BundleNames</samp>
 +
| &#32;
 +
* removed unused entries
 +
|
 +
|
 +
|-
 +
| <samp>Strings/Characters</samp>
 +
| &#32;
 +
* added new entries
 +
* removed unused entry
 +
| '''✘ broken'''
 +
|
 +
|-
 +
| <samp>Strings/credits</samp>
 +
| &#32;
 +
* updated for 1.6
 +
* various changes
 +
| ✘ will remove changes
 +
| ✘ will remove changes
 +
|-
 +
| <samp>Strings/Events</samp>
 +
| &#32;
 +
* moved [[#Dialogue changes|flower dance dialogue]] for Emily and Shane to their NPC dialogue files
 +
| ✓ mostly unaffected
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Strings/FarmAnimals</samp>
 +
| &#32;
 +
* added new entries
 +
| '''✘ broken'''
 +
|
 +
|-
 +
| <samp>Strings/Lexicon</samp>
 +
| &#32;
 +
* removed unused entries
 +
|
 +
|
 +
|-
 +
| <samp>Strings/Locations</samp>
 +
| &#32;
 +
* added new entries
 +
* added placeholder to <samp>BusStop_BuyTicketToDesert</samp>
 +
* renamed <samp>BoatTunnel_BuyTicket</samp> to <samp>BuyTicket</samp>
 +
* updated how Professor Snail's name is translated, removed unused entries
 +
* fixed typos
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Strings/NPCNames</samp>
 +
| &#32;
 +
* added new entries
 +
* removed unused entry
 +
| '''✘ broken'''
 +
|
 +
|-
 +
| <samp>Strings/Notes</samp>
 +
| &#32;
 +
* trimmed trailing whitespace
 +
|
 +
|
 +
|-
 +
| <samp>Strings/Objects</samp>
 +
| &#32;
 +
* added new entries
 +
* removed unused entries
 +
| '''✘ broken'''
 +
|
 +
|-
 +
| <samp>Strings/schedules/Caroline</samp>
 +
| &#32;
 +
* fixed typo
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Strings/SpecialOrderStrings</samp>
 +
| &#32;
 +
* renamed ''Dust Spirits'' to ''Dust Sprites''
 +
* fixed typos
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Strings/StringsFromCSFiles</samp>
 +
| &#32;
 +
* added new entries
 +
* removed unused entries
 +
* reworked <samp>FarmComputer_*</samp> translations
 +
* merged some gendered translations
 +
* merged <samp>ItemDeliveryQuest.cs.13533</samp> into <samp>ItemDeliveryQuest.cs.13534</samp>–<samp>13536</samp>
 +
* changed some player names from <samp>{0}</samp> to <samp>@</samp>
 +
* fixed typo
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Strings/StringsFromMaps</samp>
 +
| &#32;
 +
* fixed typos
 +
* removed unused entries
 +
| ✘ will remove changes
 +
|
 +
|-
 +
| <samp>Strings/UI</samp>
 +
| &#32;
 +
* added new entries
 +
* added placeholder for cabin count in <samp>Character_CoopHelpString</samp>
 +
* fixed typos
 +
* removed unused entries
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|}
 +
 +
====Removed unused assets====
 +
Stardew Valley 1.6 deletes assets which weren't used by the game. Mods usually aren't affected by this.
 +
 +
Removed assets:
 +
* <samp>Characters/Dana</samp>
 +
* <samp>Characters/Dick</samp>
 +
* <samp>Characters/femaleRival</samp>
 +
* <samp>Characters/maleRival</samp>
 +
* <samp>Characters/shirts</samp>
 +
* <samp>Characters/WeddingOutfits</samp>
 +
* <samp>Data/TV/InterviewShow</samp>
 +
* <samp>Effects/BrightWhite</samp>
 +
* <samp>Fonts/tinyFontBorder</samp>
 +
* <samp>Maps/Cabin</samp>
 +
* <samp>Maps/Cabin1</samp>
 +
* <samp>Maps/Cabin1_marriage</samp>
 +
* <samp>Maps/Cabin2</samp>
 +
* <samp>Maps/Cabin2_marriage</samp>
 +
* <samp>Maps/Island_Boulder_Removed</samp>
 +
* <samp>Maps/qiNutRoom_tilesheet_0</samp>
 +
* <samp>Maps/spring_outrdoorsTileSheet_lightergrass</samp>
 +
* <samp>Portraits/Dobson</samp>
 +
* <samp>TerrainFeatures/DiggableWall_basic</samp>
 +
* <samp>TerrainFeatures/DiggableWall_basic_dark</samp>
 +
* <samp>TerrainFeatures/DiggableWall_frost</samp>
 +
* <samp>TerrainFeatures/DiggableWall_frost_dark</samp>
 +
* <samp>TerrainFeatures/DiggableWall_lava</samp>
 +
* <samp>TerrainFeatures/DiggableWall_lava_dark</samp>
 +
* <samp>TerrainFeatures/Quartz</samp>
 +
 +
==Vanilla release notes==
 +
''Moved to [[Version History#1.6]].''
  
 
==See also==
 
==See also==
* [[User:Pathoschild/Modding wishlist/Completed#Done in Stardew Valley 1.6|Modding wishlist items done in Stardew Valley 1.6]]
+
* [[User:Pathoschild/Modding wishlist/Completed#Done in Stardew Valley 1.6|Modding wishlist items done in Stardew Valley 1.6]] lists a few specialized changes not mentioned on this page.
  
 
[[Category:Modding]]
 
[[Category:Modding]]

Latest revision as of 21:07, 21 April 2024

Index

This page is for mod authors. Players: see Modding:Mod compatibility instead.


This page explains how to update your mods for compatibility with Stardew Valley 1.6, and documents some of the changes and new functionality. See also Migrate to SMAPI 4.0.

FAQs

What's changing?

Stardew Valley 1.6 makes fundamental changes to the game code to make it more extensible for mods.

Is this the modapocalypse?

Maybe. The update includes major changes to fundamental parts of the game, and SMAPI and Content Patcher can't feasibly rewrite every older mod for compatibility with some of the changes. This will break many existing mods until they're updated for the changes. However, per discussion between the game developers and modding community, we've agreed that this short-term pain is more than offset by the huge long-term improvements to modding.

How to update your mod

The rest of this page may seem overwhelming, but fortunately most of it probably doesn't apply to your specific mods. Here's a suggested 'quick start' guide to update a mod for Stardew Valley 1.6.

For C# mods:
  1. Update the mod build config NuGet package to the latest version.
  2. In each .csproj project file, change <TargetFramework>net5.0</TargetFramework> to <TargetFramework>net6.0</TargetFramework>.
    (Tip: if the second line looks like <Project ToolsVersion=... instead of <Project Sdk="Microsoft.NET.Sdk">, you'll need to migrate it to Stardew Valley 1.5.5 first.)
  3. Rebuild the solution.
  4. Fix any build errors. You can search this page for relevant info as needed.
  5. Review all build warnings (particularly obsolete-code warnings), which may indicate code that broke in 1.6.
  6. 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.)
  7. Test to make sure the mod works.
  8. Skim through breaking changes for C# mods and the table of contents, and check any section that might be relevant to the mod.
For Content Patcher packs:
  1. Follow the Content Patcher migration guide until your content pack has "Format": "2.0.0".
    Do not skip this step! Content Patcher will assume your content pack is pre-1.6 if you don't, which can cause confusing errors if you already updated it.
  2. Review breaking changes for content packs and update the content pack as needed.
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.

What's new architecturally?

.NET 6

See also: .NET 6 under breaking changes.

For C# mod authors, Stardew Valley 1.6 updates from .NET 5 to .NET 6. See What's new in .NET 6 and What's new in C# 10 for more info, but some highlights include...

Trigger actions

See the updated docs at Modding:Trigger actions. This section below focuses on what's new in 1.6.

Trigger actions are a new feature which lets content packs perform an action when something happens, with support for a wide range of actions (like sending mail, changing friendship, starting a quest, etc).

For example, it lets you have logic like "When the player arrives in the Farm location, if Leo has moved to the valley, then send a letter and start a conversation topic":

{
    "Trigger": "LocationChanged",
    "Location": "Farm",
    "Condition": "PLAYER_HAS_FLAG Host leoMoved",
    "Actions": [
        "AddMail Current Abigail_LeoMoved Today",
        "AddConversationTopic LeoMoved 5"
    ]
}

Hash set fields

For C# mod authors, the game now uses hash sets for many list fields which expect unique values. That allows much more efficient O(1) read/write, prevents duplicate values, and simplifies common logic.

This affects:

type fields
Farmer achievements
dialogueQuestionsAnswered
eventsSeen
mailForTomorrow
mailReceived
professions
secretNotesSeen
songsHeard
FarmerTeam acceptedSpecialOrderTypes
broadcastedMail
completedSpecialOrders
collectedNutTracker
Game1 worldStateIDs
NetWorldState ActivePassiveFestivals
CheckedGarbage
FoundBuriedNuts
IslandVisitors
LocationsWithBuildings

Usage is very similar, and many list methods like Contains work the same way with hash sets. Here are the main differences:

  • Hash sets aren't ordered. For example, there's no guarantee that the first value when you enumerate it was the earliest one added.
  • Hash sets can't be indexed. For example, you can no longer use list[0] to get the first value. You can still enumerate them or use LINQ methods like set.First(), but in most cases you should use the set methods like Add or Contains instead.

    To remove multiple matching values from the set, you can use RemoveWhere instead:

    // old code
    for (int i = Game1.player.mailReceived.Count - 1; i >= 0; i--)
    {
        if (Game1.player.mailReceived[i].StartsWith("Example.ModId_"))
            Game1.player.mailReceived.RemoveAt(i);
    }
    
    // new code
    Game1.player.mailReceived.RemoveWhere(id => id.StartsWith("Example.ModId_"));
    
  • You no longer need to check before adding a value, since the hash set will ignore duplicates.
  • The Add/Remove/RemoveWhere methods return whether a value was added/removed, which lets you check at the same time. For example:
    if (Game1.player.mailReceived.Add("BackpackTip")) // returns true if it wasn't in the set yet
        Game1.addMailForTomorrow("pierreBackpack");
    

DataLoader

DataLoader is a new C# utility which provides strongly-typed methods to load the game's data assets.

This solves an issue where we often needed fragile code like Game1.content.Load<Dictionary<string, PassiveFestivalData>>("Data\\PassiveFestivals"). With that code, it's easy to accidentally misspell the asset name, use different capitalization (which would break on Linux/macOS), or use the wrong return type. If you did, you likely wouldn't notice until the code actually executed at runtime and threw an exception.

In Stardew Valley 1.6, you can now rewrite that code like DataLoader.PassiveFestivals(Game1.content). That's simpler, you can't use the wrong asset name or type, and it's more future-proof in case the game changes them.

Unique string IDs

See the updated docs at Modding:Common data field types#Unique string ID. This section below focuses on what's new in 1.6.

Stardew Valley now uses unique string IDs throughout the code to identify data (like events, locations, items, NPCs, etc). For example, Town is the unique ID for the Pelican Town location; no other location can use that ID. The IDs are used for a wide range of purposes, from internal game logic to content pack edits.

For mods, it's strongly recommended to...

  • Use namespaced IDs prefixed with your mod's unique ID for all new content. For example, if your mod ID is Example.PufferchickMod and you're adding a pufferchick plushy, your item ID would look like Example.PufferchickMod_PufferchickPlushy. In a Content Patcher pack, you can use {{ModId}}_PufferchickPlushy to insert your mod ID automatically. This eliminates ID conflicts between mods, and makes it easy (for both troubleshooters and mod code) to identify which mod added a particular content. See the new format docs for the recommended format.
  • Only use alphanumeric (a–z, A–Z, 0–9), underscore (_), and dot (.) characters in string IDs. This is important because they're often used in places where some characters have special meaning (like file names or game state queries).

You can optionally migrate pre-1.6 content to use unique string IDs too, without breaking existing players' saves. This is recommended to reduce mod conflicts and simplify troubleshooting going forward. Here's how to migrate for each data type:

migration steps for pre-1.6 content 
content type how to change IDs
event IDs
item IDs
mail IDs
recipe IDs
song IDs for jukebox
Content Patcher adds a custom trigger action which can migrate IDs everywhere in the save data.

For example, this migrates two crafting recipe IDs:

{
    "Action": "EditData",
    "Target": "Data/TriggerActions",
    "Entries": {
        "{{ModId}}_MigrateToUniqueIds": {
            "Id": "{{ModId}}_MigrateToUniqueIds",
            "Trigger": "DayStarted",
            "Actions": [
                // Note: use double-quotes around an argument if it contains spaces. This example has single-quotes for
                // the action itself, so we don't need to escape the double-quotes inside it.
                'Pathoschild.ContentPatcher_MigrateIds CraftingRecipes "Puffer Plush" {{ModId}}_PufferPlush "Puffer Sofa" {{ModId}}_PufferSofa'
            ],
            "HostOnly": true
        }
    }
}

See the Content Patcher docs for more info about using the trigger action, including restrictions and valid ID types.

location IDs Add the old name to the location's FormerLocationNames field in Data/Locations.
NPC internal names Add the old name to the NPC's FormerCharacterNames field in Data/Characters.
quest and special order IDs Currently there's no safe way to migrate quest and special order IDs, since removing and readding them will reset any progress the player has made on them.

What's new for items

Custom items

These docs should be merged into Modding:Items. When copying content, make sure you attribute the original authors.

Overview

Stardew Valley 1.6 makes three major changes to how items work in the game:

  1. Each item now has a string ID (ItemId) and a globally unique string ID (QualifiedItemId). The QualifiedItemId is auto-generated by prefixing the ItemId with the item type identifier.

    For legacy reasons, the ItemId for vanilla items may not be globally unique. For example, Pufferfish (object 128) and Mushroom Box (bigcraftable 128) both have ItemId: 128. They can be distinguished by their QualifiedItemId, which are (O)128 and (BC)128 respectively.

  2. Each item type now has an item data definition in the game code which tells the game how to handle it. C# mods can add or edit definitions. Each definition has a unique prefix which is used in the qualified item IDs. The vanilla types are bigcraftables ((BC)), boots ((B)), farmhouse flooring ((FL)), furniture ((F)), hats ((H)), objects ((O)), pants ((P)), shirts ((S)), tools ((T)), wallpaper ((WP)), and weapons ((W)).
  3. Custom items can now provide their own item texture, specified in a new field in the item data assets (see below). The item's ParentSheetIndex field is the index within that texture.

In other words, the four important fields for items are:

name type description
ItemId string A unique string ID for this item which should be globally unique (but may not be for existing vanilla items for backwards compatibility). For example, 128 (vanilla item) or Example.ModId_Watermelon (custom item).
QualifiedItemId string A globally unique item key, like (O)128 for a vanilla item or (O)Example.ModId_Watermelon for a custom one. This is auto-generated from the TypeDefinitionId and ItemId fields.
ParentSheetIndex int The item's sprite index within its spritesheet.
TypeDefinitionId string The ID for the data definition which defines the item, like (O) for an object. You can use ItemRegistry.type_* constants with this field:
if (item.TypeDefinitionId == ItemRegistry.type_object)
   ...

Item references

Item references throughout the game code now use the ItemId instead of the ParentSheetIndex. Since the ItemId is identical to the index for existing vanilla items, most data assets are unaffected by this change. For example, here's from Data/NPCGiftTastes with one custom item:

"Universal_Like": "-2 -7 -26 -75 -80 72 395 613 634 635 636 637 638 724 459 Example.ModID_watermelon"

Unless otherwise noted, unqualified item IDs will produce objects. Some assets let you override that by specifying a QualifiedItemId value instead. For example, you can add (O)128 to the gift taste list to explicitly add for an object. Here's a partial list of data assets and their supported item ID formats:

data asset item ID format
Data/CraftingRecipes
Data/CookingRecipes
  • Ingredients: both supported.
  • Output: set field 2 to the unqualified item ID, and field 3 to one of true (bigcraftable) or false (object).
Data/fruitTrees
  • Fruit: both supported.
  • Sapling: unqualified only.
Data/NPCGiftTastes Both supported, but only (O) items can be gifted.

Item types

These are the item types for which custom items can added/edited:

item type type identifier data asset
big craftables (BC) Data/BigCraftables
Each item can set a custom texture name in the Texture field, and sprite index in the SpriteIndex field. The default texture is TileSheets/Craftables.
boots (B) Data/Boots
Each item can set a custom texture name in fields 9 (item) and 7 (shoe color), and sprite index in fields 8 (item) and 5 (shoe color). The default textures are Maps/springobjects (item) and Characters/Farmer/shoeColors (shoe color).
crops not technically an item type Data/Crops
Each crop can set a custom texture name and sprite index. The default texture is TileSheets/crops.
fish (in fish tanks) not technically an item type Data/AquariumFish
Each fish can set a custom aquarium texture name in field 6, and sprite index in field 0. The default texture is LooseSprites/AquariumFish.
furniture (F) Data/Furniture
Each item can set a custom texture name in field 9, and sprite index in field 8. The default texture is TileSheets/furniture.
fruit trees not technically an item type Data/FruitTrees
Each fruit tree can set a custom texture name and sprite index. The default texture is TileSheets/fruitTrees.
hats (H) Data/Hats
Each item can set a custom texture name in field 7, and sprite index in field 6. The default texture is Characters/Farmer/hats.
objects (O) Data/Objects
Each item can set a custom texture name in the Texture field, and sprite index in the SpriteIndex field. The default texture is Maps/springobjects.
pants (P) Data/pantsData
Each item can set a custom texture name in the Texture field, and sprite index in the SpriteIndex field. The default texture is Characters/Farmer/pants.
shirts (S) Data/shirtData
Each item can set a custom texture name in the Texture field, and sprite index in the SpriteIndex field. The default texture is Characters/Farmer/shirts.

Shirt textures must be exactly 256 pixels wide, divided into two halves: the left half for the shirt sprites, and the right half for any dye masks. The remaining space can be left blank if needed.

      sprites       dye masks
   /-----------\  /-----------\
┌────────────────────────────────┐
│ ┌───┐┌───┐┌───┐┌───┐┌───┐┌───┐ │
│ │ 0 ││ 1 ││ 2 ││ a ││ b ││ c │ │
│ └───┘└───┘└───┘└───┘└───┘└───┘ │
│ ┌───┐┌───┐┌───┐┌───┐┌───┐┌───┐ │
│ │ 3 ││ 4 ││ 5 ││ d ││ e ││ f │ │
│ └───┘└───┘└───┘└───┘└───┘└───┘ │
└────────────────────────────────┘
tools (T) Data/Tools
Each item can set a custom texture name in the Texture field, and sprite index in the SpriteIndex field. The vanilla tools use the TileSheets/Tools texture.
Wallpaper & floorpaper (WP) and (FL) Data/AdditionalWallpaperFlooring
See format docs.
weapons (W) Data/Weapons
Completely overhauled into a data model.

When resolving an unqualified item ID like 128, the game will get the first item type for which it exists in this order: object, big craftable, furniture, weapon, boots, hat, pants, shirt, tool, wallpaper, and floorpaper.

Define a custom item

You can define custom items for most vanilla item types using only Content Patcher or SMAPI's content API.

For example, this content pack adds a new Pufferchick item with a custom image, custom gift tastes, and a custom crop that produces it. Note that item references in other data assets like Data/Crops and Data/NPCGiftTastes use the item ID.

{
    "Format": "2.0.0",
    "Changes": [
        // add item
        {
            "Action": "EditData",
            "Target": "Data/Objects",
            "Entries": {
                "{{ModId}}_Pufferchick": {
                    "Name": "{{ModId}}_Pufferchick", // best practice to match the ID, since it's sometimes used as an alternate ID (e.g. in Data/CraftingRecipes)
                    "Displayname": "Pufferchick",
                    "Description": "An example object.",
                    "Type": "Seeds",
                    "Category": -74,
                    "Price": 1200,

                    "Texture": "Mods/{{ModId}}/Objects",
                    "SpriteIndex": 0
                }
            }
        },

        // add gift tastes
        {
            "Action": "EditData",
            "Target": "Data/NPCGiftTastes",
            "TextOperations": [
                {
                    "Operation": "Append",
                    "Target": ["Entries", "Universal_Love"],
                    "Value": "{{ModId}}_Pufferchick",
                    "Delimiter": " " // if there are already values, add a space between them and the new one
                }
            ]
        },

        // add crop (Pufferchick is both seed and produce, like coffee beans)
        {
            "Action": "EditData",
            "Target": "Data/Crops",
            "Entries": {
                "{{ModId}}_Pufferchick": {
                    "Seasons": [ "spring", "summer", "fall" ],
                    "DaysInPhase": [ 1, 1, 1, 1, 1 ],
                    "HarvestItemId": "{{ModId}}_Pufferchick",

                    "Texture": "Mods/{{ModId}}/Crops",
                    "SpriteIndex": 0
                }
            }
        },

        // add item + crop images
        {
            "Action": "Load",
            "Target": "Mods/{{ModId}}/Crops, Mods/{{ModId}}/Objects",
            "FromFile": "assets/{{TargetWithoutPath}}.png" // assets/Crops.png, assets/Objects.png
        }
    ]
}

Most item data assets work just like Data/Objects. See also specific info for custom fruit trees, custom tools, and melee weapons.

Error items

In-game items with no underlying data (e.g. because you removed the mod which adds them) would previously cause issues like invisible items, errors, and crashes. This was partly mitigated by the bundled Error Handler mod.

Stardew Valley 1.6 adds comprehensive handling for such items. They'll be shown with a 🛇 sprite in inventory UIs and in-game, the name Error Item, and a description which indicates the missing item ID for troubleshooting.

For C# mods

Compare items
Since Item.QualifiedItemId is globally unique, it can be used to simplify comparing items. For example:
old code new code
item.ParentSheetIndex == 128 item.QualifiedItemId == "(O)128"
IsNormalObjectAtParentSheetIndex(item, 128) item.QualifiedItemId == "(O)128"
!item.bigCraftable && item.ParentSheetIndex == 128 item.QualifiedItemId == "(O)128"
item is Boots && item.ParentSheetIndex == 505 item.QualifiedItemId == "(B)505"

You can also use ItemRegistry.QualifyItemId to convert any item ID into a qualified one (if it's valid), and ItemRegistry.HasItemId to check if an item has a qualified or unqualified item ID.

Note that flavored item don't have their own ID. For example, Blueberry Wine and Wine are both (O)348. This affects flavored jellies, juices, pickles, and wines. In those cases you should still compare their separate fields like preservedParentSheetIndex (which actually contains the preserved item's ItemId, not its ParentSheetIndex).

Construct items
Creating items works just like before, except that you now specify the item's ItemId (not QualifiedItemId) instead of its ParentSheetIndex. For example:
new Object("128", 1);                      // vanilla item
new Object("Example.ModId_Watermelon", 1); // custom item

You can use a new utility method to construct items from their QualifiedItemId:

Item item = ItemRegistry.Create("(B)505"); // Rubber Boots
Define custom item types
You can implement IItemDataDefinition for your own item type, and call ItemRegistry.AddTypeDefinition to register it. This provides all the logic needed by the game to handle the item type: where to get item data, how to draw them, etc. This is extremely specialized, and multiplayer compatibility is unknown. Most mods should add custom items within the existing types instead.
New Is* methods
1.6 adds some StardewValley.Object methods to handle custom items in a generic way (and to let mods patch the logic):
method effect
object.IsBar() Whether the item is a copper bar, iron bar, gold bar, iridium bar, or radioactive bar.
object.IsBreakableStone() Whether the item is a stone debris item which can be broken by a pickaxe.
object.IsFence() Whether the item is a fence.
object.IsFruitTreeSapling() Whether the item is a fruit tree sapling. This checks the Data\fruitTrees keys, so it works with custom fruit trees too.
object.IsHeldOverHead() Whether the player is shown holding up the item when it's selected in their toolbar. Default true (except for furniture).
object.IsIncubator() Whether the item can incubate farm animal eggs when placed in a building.
object.IsTapper() Whether the item is a tapper or heavy tapper.
object.IsTeaSapling() Whether the item is a tea sapling.
object.IsTwig() Whethere the item is a twig debris item.
object.IsWeeds() Whether the item is a weed debris item.
Work with item metadata
1.6 adds an ItemRegistry API for working with the new item system. Some of the provided methods are:
method effect
ItemRegistry.Create Create an item from its item ID (qualified or unqualified). If the ID doesn't match a real item, the optional allowNull parameter indicates whether to return null or an Error Item. For example:
Item item = ItemRegistry.Create("(B)505"); // Rubber Boots

You can also get a specific value type instead of Item if needed. This will throw a descriptive exception if the type isn't compatible (e.g. you try to convert furniture to boots).

Boots item = ItemRegistry.Create<Boots>("(B)505"); // Rubber Boots
ItemRegistry.Exists Get whether a qualified or unqualified item ID matches an existing item. For example:
bool pufferfishExist = ItemRegistry.Exists("(O)128");
ItemRegistry.IsQualifiedId Get whether the given item ID is qualified with the type prefix (like (O)128 instead of 128).
ItemRegistry.QualifyItemId Get the unique qualified item ID given an unqualified or qualified one. For example:
string qualifiedId = ItemRegistry.QualifyItemId("128"); // returns (O)128
ItemRegistry.GetMetadata This lets you get high-level info about an item:
// get info about Rubber Boots
ItemMetadata info = ItemRegistry.GetMetadata("(B)505");

// get item ID info
$"The item has unqualified ID {info.LocalId}, qualified ID {info.QualifiedId}, and is defined by the {info.TypeIdentifier} item data definition.";

// does the item exist in the data files?
bool exists = info.Exists();

And get common parsed item data:

// get parsed info
ParsedItemData data = info.GetParsedData();
$"The internal name is {data.InternalName}, translated name {data.DisplayName}, description {data.Description}, etc.";

// draw an item sprite
Texture2D texture = data.GetTexture();
Rectangle sourceRect = data.GetSourceRect();
spriteBatch.Draw(texture, Vector2.Zero, sourceRect, Color.White);

And create an item:

Item item = metadata.CreateItem();

And get the type definition (note that this is very specialized, and you should usually use ItemRegistry instead to benefit from its caching and optimizations):

IItemDataDefinition typeDefinition = info.GetTypeDefinition();
ItemRegistry.ResolveMetadata Equivalent to ItemRegistry.GetMetadata, except that it'll return null if the item doesn't exist.
ItemRegistry.GetData Get the parsed data about an item, or null if the item doesn't exist. This is a shortcut for ItemRegistry.ResolveMetadata(id)?.GetParsedData(); see the previous method for info on the parsed data.
ItemRegistry.GetDataOrErrorItem Equivalent to ItemRegistry.GetData, except that it'll return info for an Error Item if the item doesn't exist (e.g. for drawing in inventory).
ItemRegistry.GetErrorItemName Get a translated Error Item label.

Custom big craftables:

These docs should be merged into Modding:Items#Big craftables. When copying content, make sure you attribute the original authors.

You can now create/edit big craftables by editing the new Data/BigCraftables asset, which replaces the previous slash-delimited Data/BigCraftablesInformation.

Besides the format change, this adds...

  • context tags (moved from the former Data/ObjectContextTags asset);
  • custom fields to let framework mods support additional features.

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

  • The key is the unqualified item ID.
  • The value is a model with the fields listed below.

Basic info

field purpose
Name The internal item name.
DisplayName
Description
A tokenizable string for the item's in-game display name and description.
Price (Optional) The price when sold by the player. This is not the price when bought from a shop. Default 0.

Behavior

field purpose
Fragility (Optional) How the item can be picked up. The possible values are 0 (pick up with any tool), 1 (destroyed if hit with an axe/hoe/pickaxe, or picked up with any other tool), or 2 (can't be removed once placed). Default 0.
CanBePlacedIndoors
CanBePlacedOutdoors
(Optional) Whether the item can be placed indoors or outdoors. Default true.
IsLamp (Optional) Whether this is a lamp and should produce light when dark. Default false.

Appearance

field purpose
Texture (Optional) The asset name for the texture containing the item's sprite. Defaults to TileSheets/Craftables.
SpriteIndex (Optional) The sprite's index within the Texture, where 0 is the top-left sprite.

Context tags

field purpose
ContextTags (Optional) The custom context tags to add for this item (in addition to the tags added automatically based on the other object data). This is formatted as a list; for example:
"ContextTags": [ "light_source", "torch_item" ]

Advanced

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

Custom crops

Crops are still stored in Data/Crops, but that asset has been overhauled in Stardew Valley 1.6. The slash-delimited entries are now models to simplify edits and enable new features.

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

  • The key is the unqualified item ID for the seed item.
  • The value is model with the fields listed below.
field effect
Growth
Seasons The seasons in which this crop can grow (any combination of spring, summer, fall, and winter).
DaysInPhase The number of days in each visual step of growth before the crop is harvestable. Each step corresponds to a sprite in the crop's row (see SpriteIndex).

For example, a crop with "DaysInPhase": [ 1, 1, 1, 1 ] will grow from seed to harvestable in 4 days, moving to the next sprite in the row each day.

RegrowDays (Optional) The number of days before the crop regrows after harvesting, or -1 if it can't regrow. The crop will keep the full-grown sprite (i.e. the last phase in DaysInPhase) during this time. Default -1.
IsRaised (Optional) Whether this is a raised crop on a trellis that can't be walked through. Default false.
IsPaddyCrop (Optional) Whether this crop can be planted near water for a unique paddy dirt texture, faster growth time, and auto-watering. For example, rice and taro are paddy crops. Default false.
NeedsWatering (Optional) Whether this crop needs to be watered to grow (e.g. fiber seeds don't). Default true.
Harvest
HarvestItemId The item ID produced when this crop is harvested.
HarvestMethod (Optional) How the crop can be harvested. This can be Grab (crop is harvested by hand) or Scythe (harvested with a scythe). Default Grab.
HarvestMinStack
HarvestMaxStack
(Optional) The minimum and maximum number of HarvestItemId to produce (before HarvestMaxIncreasePerFarmingLevel and ExtraHarvestChance are applied). A value within this range (inclusive) will be randomly chosen each time the crop is harvested. The minimum defaults to 1, and the maximum defaults to the minimum.
HarvestMinQuality
HarvestMaxQuality
(Optional) If set, the minimum and maximum quality of the harvest crop. These fields set a constraint that's applied after the quality is calculated normally, they don't affect the initial quality logic.
HarvestMaxIncreasePerFarmingLevel (Optional) The number of extra harvests to produce per farming level. This is rounded down to the nearest integer and added to HarvestMaxStack. Defaults to 0.

For example, a value of 0.2 is equivalent to +1 max at level 5 and +2 at level 10.

ExtraHarvestChance (Optional) The probability that harvesting the crop will produce extra harvest items, as a value between 0 (never) and 0.9 (nearly always). This is repeatedly rolled until it fails, then the number of successful rolls is added to the produced count. For example, tomatoes use 0.05. Default 0. This is a geometric series with expected value of 1/(1-ExtraHarvestChance) - 1, so it will grow faster than you expect it should. For example, with a value of 0.9, this field has an expected value of nine additional crops.
Appearance
Texture The asset name for the texture (under the game's Content folder) containing the crop sprite. For example, the vanilla crops use TileSheets\crops.
SpriteIndex (Optional) The index of this crop in the Texture, one crop per row, where 0 is the top row. Default 0.
TintColors (Optional) The colors with which to tint the sprite when drawn (e.g. for colored flowers). A random color from the list will be chosen for each crop. See color format. Default none.
Achievements
CountForMonoculture (Optional) Whether the player can ship 300 of this crop's harvest item to unlock the monoculture achievement. Default false.
CountForPolyculture (Optional) Whether the player must ship 15 of this crop's harvest item (along with any other required crops) to unlock the polyculture achievement. Default false.
Advanced
PlantableLocationRules (Optional) The rules to decide which locations you can plant the seed in, if applicable. The first matching rule is used. This can override location checks (e.g. crops being limited to the farm), but not built-in requirements like crops needing dirt.

This consists of a list of models with these fields:

field effect
Id The unique string ID for this entry within the list.
Result Indicates whether the seed can be planted in a location if this entry is selected. The possible values are:
  • Default: the seed can be planted if the location normally allows it. This can be used to stop processing further rules, and/or set a custom DeniedMessage.
  • Allow: the seed can be planted here, regardless of whether the location normally allows it.
  • Deny: the seed can't be planted here, regardless of whether the location normally allows it.
Condition (Optional) A game state query which indicates whether this entry applies. Default true.
PlantedIn (Optional) The planting context to apply this rule for. The possible values are Ground (planted directly in dirt), GardenPot (planted in a garden pot), or Any. Default Any.
DeniedMessage (Optional) If this rule prevents planting the seed, the tokenizable string to show to the player (or null to default to the normal behavior for the context). This also applies when the Result is Default, if that causes the planting to be denied.
CustomFields The custom fields for this entry.

For example, this adds a custom cucumber crop (assuming you've already added custom items for cucumber seeds and cucumber):

{
    "Format": "2.0.0",
    "Changes": [
        {
            "Action": "EditData",
            "Target": "Data/Crops",
            "Entries": {
                "Example.Id_CucumberSeeds": {
                    "Seasons": [ "summer" ],
                    "DaysInPhase": [ 1, 2, 2, 2 ], // grows in 7 days with four growing sprites
                    "HarvestItemId": "Example.Id_Cucumber",
                    "Texture": "{{InternalAssetKey: assets/crops.png}}",
                    "SpriteIndex": 0
                }
            }
        }
    ]
}

Custom fences

These docs should be merged into a new doc page. When copying content, make sure you attribute the original authors.

You can now add or customize fences by editing the Data/Fences asset.

This consists of a string → model lookup, where the key is the unqualified item ID of the fence object, and the value is a model with these fields:

field effect
Health The health points for a fence when it's first placed, which affects how quickly it degrades. A fence loses 1/1440 points per in-game minute (roughly 0.04 points per hour or 0.5 points for a 12-hour day).

Repairing a fence sets its max health to 2 × (base_health + repair_health_adjustment), where base_health is this field's value and repair_health_adjustment is a random value between RepairHealthAdjustmentMinimum and RepairHealthAdjustmentMaximum.

Texture The asset name for the texture (under the game's Content folder) when the fence is placed. Use \ (or \\ in JSON) to separate name segments if needed. For example, the vanilla fences use individual tilesheets like LooseSprites\Fence1 (wood fence).
RemovalToolIds
RemovalToolTypes
A list of tool IDs (matching the keys in Data\ToolData) or C# full type names which can be used to break the fence.

For example, this will let the player break the fence with an iridium axe and any pickaxe:

"RemovalToolIds": ["IridiumAxe"],
"RemovalToolTypes": ["StardewValley.Tools.Pickaxe"]

A tool must match RemovalToolIds or RemovalToolTypes to be a valid removal tool. If both lists are null or empty, all tools can remove the fence.

PlacementSound The audio cue ID played when the fence is placed or repaired (e.g. axe used by Wood Fence).
RemovalSound (Optional) The audio cue ID played when the fence is broken or picked up by the player. Defaults to the same sound as PlacementSound.
RemovalDebrisType (Optional) The type of cosmetic debris particles to 'splash' from the tile when the fence is broken with a tool. The defined values are 0 (copper), 2 (iron), 4 (coal), 6 (gold), 8 (coins), 10 (iridium), 12 (wood), 14 (stone), 32 (big stone), and 34 (big wood). Default 14 (stone).
RepairHealthAdjustmentMinimum
RepairHealthAdjustmentMaximum
(Optional) A random amount added to the Health when a fence is repaired by a player. See the Health field description. Both default to 0.
HeldObjectDrawOffset (Optional) When an item like a torch is placed on the fence, the pixel offset to apply to its draw position. Specified as a string in the form "<x>, <y>". Defaults to "0, -20" if omitted.
LeftEndHeldObjectDrawX
RightEndHeldObjectDrawX
(Optional) The X pixel offset to apply when the fence is oriented horizontally, with only one connected fence on the right (for LeftEndHeldObjectDrawX) or left (for RightEndHeldObjectDrawX). This fully replaces the X value specified by HeldObjectDrawOffset when it's applied. Default 0.

Custom floors (craftable) & paths

These docs should be merged into a new doc page. When copying content, make sure you attribute the original authors.

You can now add or customize craftable floors & paths by editing the Data/FloorsAndPaths asset.

This consists of a string → model lookup, where the key matches the ID field and the value is a model with these fields:

field effect
ID The unique string ID for this floor/path.
ItemId The unqualified item ID for the corresponding object-type item.
Texture The asset name for the texture (under the game's Content folder) when the flooring is applied or the path is placed. Use \ (or \\ in JSON) to separate name segments if needed. For example, the vanilla tilesheet is TerrainFeatures\Flooring.
Corner The top-left pixel position for the sprite within the Texture spritesheet, specified as a model with X and Y fields.
PlacementSound The audio cue ID played when the item is applied/placed (e.g. axchop used by Wood Floor).
FootstepSound The audio cue ID played when the player steps on the tile (e.g. woodyStep used by Wood Floor).
WinterTexture
Corner
(Optional) Equivalent to Texture and Corner, but applied if the current location is in winter.
RemovalSound (Optional) The audio cue ID played when the item is unapplied or picked up. Defaults to the same sound as PlacementSound.
RemovalDebrisType (Optional) The type of cosmetic debris particles to 'splash' from the tile when the item is unapplied or picked up. The defined values are 0 (copper), 2 (iron), 4 (coal), 6 (gold), 8 (coins), 10 (iridium), 12 (wood), 14 (stone), 32 (big stone), and 34 (big wood). Default 14 (stone).
ShadowType (Optional) The type of shadow to draw under the tile sprite. Default None.

The possible values are:

value effect
None Don't draw a shadow.
Square Draw a shadow under the entire tile.
Contoured raw a shadow that follows the lines of the path sprite.
ConnectType (Optional) When drawing the flooring across multiple tiles, how the flooring sprite for each tile is selected. Defaults to Default.

The possible values are:

value usage
Default For normal floors, intended to cover large square areas. This uses some logic to draw inner corners.
Path For floors intended to be drawn as narrow paths. These are drawn without any consideration for inner corners.
CornerDecorated For floors that have a decorative corner. Use CornerSize to change the size of this corner.
Random For floors that don't connect. When placed, one of the tiles is randomly selected.
CornerSize (Optional) The pixel size of the decorative border when the ConnectType field is set to CornerDecorated or Default.
FarmSpeedBuff (Optional) The speed boost applied to the player, on the farm only, when they're walking on paths of this type. Negative values are ignored. Default 0.1.

Custom machines

See the updated docs at Modding:Machines. This section below focuses on what's new in 1.6.

You can now add/edit machine logic by editing the Data/Machines asset. This supports the full range of vanilla functionality, including calling custom code define in C# mods.

For C# mods, 1.6 also adds a new MachineDataUtility class and various Object to simplify working with machines in code. These are used by the game code itself to implement the base machine logic.

Custom melee weapons

These docs should be merged into Modding:Items#Weapons. When copying content, make sure you attribute the original authors.

Melee weapons are still stored in Data/Weapons, but that asset has been overhauled in Stardew Valley 1.6. The slash-delimited entries are now models to simplify edits and enable new features (like the new Projectiles feature).

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

  • The key is the unqualified item ID for the weapon.
  • The value is model with the fields listed below.

Basic weapon info

field effect
Name The internal weapon name.
DisplayName
Description
A tokenizable string for the translated display name & description.
Type The weapon type. One of 0 (stabbing sword), 1 (dagger), 2 (club or hammer), or 3 (slashing sword).

Appearance

field effect
Texture The asset name for the spritesheet containing the weapon's sprite.
SpriteIndex The index within the Texture for the weapon sprite, where 0 is the top-left sprite.

Stats

field effect
MinDamage
MaxDamage
The minimum and maximum based damage caused when hitting a monster with this weapon.
Knockback (Optional) How far the target is pushed when hit, as a multiplier relative to a base weapon like the Rusty Sword (e.g. 1.5 for 150% of Rusty Sword's weight). Default 1.
Speed (Optional) How fast the player can swing the weapon. Each point of speed is worth 40ms of swing time relative to 0. This stacks with the player's weapon speed. Default 0.
Precision (Optional) Reduces the chance that a strike will miss. Default 0.
Defense (Optional) Reduces damage received by the player. Default 0.
AreaOfEffect (Optional) Slightly increases the area of effect. Default 0.
CritChance (Optional) The chance of a critical hit, as a decimal value between 0 (never) and 1 (always). Default 0.02.
CritMultiplier (Optional) A multiplier applied to the base damage for a critical hit. This can be a decimal value. Default 3.

Game logic

field effect
CanBeLostOnDeath Whether the player can lose this tool when they die. Default true.
MineBaseLevel
MineMinLevel
(Optional) The base and minimum mine level, which affect mine container drops. Both default to -1, which disables automatic mine drops.

Advanced

field effect
Projectiles (Optional) The projectiles fired when the weapon is used, which continue along their path until they hit a monster and cause damage. A separate projectile is fired for each entry in this list.

This consists of a list of models with these fields (one projectile will fire for each entry in the list):

field effect
Id The unique string ID for the projectile within the current weapon's data.
Damage (Optional) The amount of damage caused when the projectile hits a monster. Default 10.
Explodes (Optional) Whether the projectile explodes when it collides with something. Default false.
Bounces (Optional) The number of times the projectile can bounce off walls before being destroyed. Default 0.
MaxDistance (Optional) The maximum tile distance the projectile can travel. Default 4.
Velocity (Optional) The speed at which the projectile moves. Default 10.
RotationVelocity (Optional) The rotation velocity. Default 32.
TailLength (Optional) The length of the tail which trails behind the main projectile. Default 1.
FireSound
BounceSound
CollisionSound
(Optional) The sound played when the projectile is fired, bounces off a wall, or collides with something. All three default to none.
MinAngleOffset
MaxAngleOffset
(Optional) A random offset applied to the direction of the project each time it's fired. Both fields default to 0, in which case it's always shot at the 90° angle matching the player's facing direction.
SpriteIndex (Optional) The sprite index in the TileSheets/Projectiles asset to draw for this projectile. Defaults to 11 (a glowing-yellow-ball sprite).
Item (Optional) The item to shoot. If set, this overrides SpriteIndex.

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 ammo items.

If set to an item query which returns multiple items, one of them will be selected at random.

Note that these are magic projectiles fired when the weapon is used, they're not aimed directly like slingshot projectiles.

CustomFields The custom fields for this entry.

Custom movie concessions

These docs should be merged into Modding:Movie theater data. When copying content, make sure you attribute the original authors.
See also: custom movies.

You could already add/edit concessions sold in the movie theater, but conflicts were likely since each concession had an incrementing numeric ID which matched its position in the vanilla tilesheet.

Stardew Valley 1.6 addresses that with two changes:

  • The Id field is now a unique string ID.
  • You can now use a different texture with two new required fields:
    field effect
    Texture The asset name for the texture containing the concession's sprite.
    SpriteIndex The index within the Texture for the concession sprite, where 0 is the top-left sprite.

For example, this content pack adds a new 'Pufferchick Pop' concession with a custom image:

{
    "Format": "2.0.0",
    "Changes": [
        {
            "Action": "EditData",
            "Target": "Data/Concessions",
            "Entries": {
                "{{ModId}}_PufferchickPop": {
                    "Id": "{{ModId}}_PufferchickPop",   // must specify ID again when creating a new entry
                    "Name": "{{ModId}}_PufferchickPop", // best practice to match the ID, since it's sometimes used as an alternate ID
                    "DisplayName": "Pufferchick Pop",
                    "Description": "A cute cake pop shaped like a pufferchick.",
                    "Price": 25,
                    "Texture": "{{InternalAssetKey: assets/pufferchick-pop.png}}" // an image in your content pack
                    "SpriteIndex": 0
                }
            }
        }
    ]
}

Custom museum donations & rewards

These docs should be merged into a new doc page. When copying content, make sure you attribute the original authors.

You can now add/edit the items which the museum gives back in rewards through the new Data/MuseumRewards data asset.

Format

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

  • The key is a unique string ID for the reward group.
  • The value is a model with the fields listed below.
field effect
TargetContextTags The items that must be donated to complete this reward group. The player must fulfill every entry in the list to unlock the reward. This consists of a list of models with these fields:
field effect
Tag The context tag for the items to require.
Count The minimum number of items matching the context tags that must be donated.

For example, an entry with the tag forage_item and count 2 will require donating any two forage items.

Special case: an entry with the exact values Tag: "", Count: -1 passes if the museum is complete (i.e. the player has donated the max number of items).

FlagOnCompletion (Optional if RewardItemIsSpecial is true) Whether to add the ID value to the player's received mail. This is used to track whether the player has collected the reward, and should almost always be true. If this is omitted and RewardItemIsSpecial is false, the player will be able collect the reward infinite times. Default false.

After the reward is collected, you can check this value using the HasFlag condition in Content Patcher.

RewardActions Run one or more trigger action strings. For example, this adds data-sort-value="500"> 500g to the current player:
"RewardActions": [
    "AddMoney 500"
]
RewardItemId (Optional) The qualified item ID for the item given to the player when they donate all required items for this group. There's no reward item if omitted.
RewardItemCount (Optional) The stack size for the RewardItemId (if the item supports stacking). Default 1.
RewardItemIsSpecial (Optional) Whether to mark the RewardItemId as a special permanent item, which can't be destroyed/dropped and can only be collected once. Default false.
RewardItemIsRecipe (Optional) Whether to give the player a cooking/crafting recipe which produces the RewardItemId, instead of the item itself. Ignored if the item type can't be cooked/crafted (i.e. non-object-type items). Default false.
CustomFields The custom fields for this entry.

For example, this content pack adds two rewards (one mail and one item):

{
    "Format": "2.0.0",
    "Changes": [
        {
            "Action": "EditData",
            "Target": "Data/MuseumRewards",
            "Entries": {
                // send a letter when a specific item is donated
                "{{ModId}}_ShinyArtifact": {
                    "TargetContextTags": [
                        {
                            "Tag": "id_{{ModId}}_ShinyArtifact", // unique context tag identifying the item by ID
                            "Count": 1
                        },
                    ],
                    "FlagOnCompletion": true,
                    "RewardActions": [ "AddMail Current {{ModId}}_ShinyArtifact" ]
                },

                // give item when 18 minerals are donated
                "{{ModId}}_18MineralItems": {
                    "TargetContextTags": [
                        {
                            "Tag": "item_type_minerals",
                            "Count": 18
                        },
                    ],
                    "RewardItemId": "(BC){{ModId}}_SuperMachine",
                    "RewardItemCount": 1,
                    "FlagOnCompletion": true
                }
            }
        }
    ]
}

See also mail data, custom items, and custom machines to add the custom mail and items.

Achievements

The A Complete Collection achievement is automatically adjusted to require any custom donations added too. This is based on the number of donated items though, so removing custom donations later may incorrectly mark the museum complete (since you may have donated enough items to meet the total required).

Custom fruit trees

These docs should be merged into Modding:Fruit trees. When copying content, make sure you attribute the original authors.

Data format

You can now add custom fruit trees by editing the revamped Data/fruitTrees asset. This consists of a string → model lookup, where...

  • The key is the unqualified item ID for the sapling item in Data/Objects.
  • The value is a model with the fields listed below.
field effect
DisplayName A tokenizable string for the tree's display name. This should return a display name without 'tree' (like Cherry for a cherry tree). This is used in UI messages like "Your <display name> tree wasn't able to grow last night".
Seasons The seasons in which the fruit tree bears fruit. This consists of an array of season names (any combination of spring, summer, fall, or winter).

Note: the previous 'island' season value is no longer valid. Using summer is equivalent to how it worked before (since we now have per-location seasons).

Fruit The fruit items to add to the tree each day while the tree is in-season. The first matching fruit (if any) is selected each day.

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 fruit items.

Notes:

  • If set to an item query which returns multiple items, one of them will be selected at random.
  • Season conditions are ignored in non-seasonal locations like the greenhouse and Ginger Island.
Season (Optional) If set, the group only applies if the tree's location is in this season. This is ignored in non-seasonal locations like the greenhouse and Ginger Island.
Chance (Optional) The probability that this entry is selected, as a value between 0 (never drops) and 1 (always drops). Default 1 (100% chance).
Texture The asset name for the texture under the game's Content folder. Use \ (or \\ in JSON) to separate name segments if needed. For example, vanilla fruit trees use TileSheets\fruitTrees.
TextureSpriteRow The tree's row index in the Texture spritesheet (e.g. 0 for the first tree, 1 for the second tree, etc).
PlantableLocationRules (Optional) The rules to decide which locations you can plant the sapling in, if applicable. The first matching rule is used. This can override location checks (e.g. crops being limited to the farm), but not built-in requirements like crops needing dirt.

This consists of a list of models with these fields:

field effect
Id The unique string ID for this entry within the list.
Result Indicates whether the sapling can be planted in a location if this entry is selected. The possible values are:
  • Default: the sapling can be planted if the location normally allows it. This can be used to stop processing further rules, and/or set a custom DeniedMessage.
  • Allow: the sapling can be planted here, regardless of whether the location normally allows it.
  • Deny: the sapling can't be planted here, regardless of whether the location normally allows it.
Condition (Optional) A game state query which indicates whether this entry applies. Default true.
PlantedIn (Optional) The planting context to apply this rule for. The possible values are Ground (planted directly in the ground), GardenPot (planted in a garden pot), or Any. Default Any.

Note that saplings can't be planted in garden pots.

DeniedMessage (Optional) If this rule prevents planting the sapling, the tokenizable string to show to the player (or null to default to the normal behavior for the context). This also applies when the Result is Default, if that causes the planting to be denied.
CustomFields The custom fields for this entry.

For example, this content pack adds a custom fruit tree, including custom items for the sapling and fruit:

{
    "Format": "2.0.0",
    "Changes": [
        // add fruit + sapling items
        // note: sapling must have an edibility under 0 (usually -300) to be plantable
        {
            "Action": "EditData",
            "Target": "Data/Objects",
            "Entries": {
                "{{ModId}}_Pufferfruit": {
                    "Name": "{{ModId}}_Pufferfruit", // best practice to match the ID, since it's sometimes used as an alternate ID
                    "DisplayName": "Pufferfruit",
                    "Description": "An example fruit item.",
                    "Type": "Basic",
                    "Category": -6,
                    "Price": 1200,

                    "Texture": "Mods/{{ModId}}/Objects",
                    "SpriteIndex": 0
                },
                "{{ModId}}_Puffersapling": {
                    "Name": "{{ModId}}_Puffersapling",
                    "DisplayName": "Puffersapling",
                    "Description": "An example tree sapling.",
                    "Type": "Basic",
                    "Category": -74,
                    "Price": 1200,

                    "Texture": "Mods/{{ModId}}/Objects",
                    "SpriteIndex": 1
                }
            }
        },

        // add fruit tree
        {
            "Action": "EditData",
            "Target": "Data/FruitTrees",
            "Entries": {
                "{{ModId}}_Puffersapling": {
                    "DisplayName": "Pufferfruit",
                    "Seasons": [ "spring" ],
                    "Fruit": [
                        {
                            "Id": "E{{ModId}}_Pufferfruit",
                            "ItemId": "{{ModId}}_Pufferfruit"
                        }
                    ],
                    "Texture": "Mods/{{ModId}}/FruitTrees",
                    "TextureSpriteRow": 0
                }
            }
        },

        // add images
        {
            "Action": "Load",
            "Target": "Mods/{{ModId}}/FruitTrees, Mods/{{ModId}}/Objects",
            "FromFile": "assets/{{TargetWithoutPath}}.png" // assets/FruitTrees.png, assets/Objects.png
        },
    ]
}

The fruit trees can then be added to the game by giving the player a sapling item in the usual ways (e.g. from a shop).

Fruit items

For C# mods, the fruitsOnTree field (number of fruit on the tree) has been replaced by fruit (list of fruit items).

Spawning fruit trees

Custom trees can be added to the game in two ways:

  • Spawn them on map tiles when the location is created, using the new SpawnTree: fruit <tree ID> [growth stage on location created] [growth stage on day-update regrowth] tile property. This must be added on the Paths layer, which must also have tile index 34 from the paths tilesheet.
  • Or give the player a seed item in the usual ways (e.g. from a shop, mail letter, etc).

Custom objects

These docs should be merged into Modding:Items#Objects. When copying content, make sure you attribute the original authors.

You can now create/edit objects (the main item type) by editing the new Data/Objects asset, which replaces the previous slash-delimited Data/objectInformation.

Besides the format change, this adds...

  • support for custom textures;
  • revamped geode drops with support for conditions, probabilities, and item queries;
  • expanded food/drink buffs (e.g. set a custom buff ID, add a custom buff icon, etc);
  • context tags (moved from the former Data/ObjectContextTags asset);
  • custom fields to let framework mods support additional features.

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

  • The key is the unqualified item ID.
  • The value is a model with the fields listed below.

Basic info

field purpose
Name The internal item name.
DisplayName
Description
A tokenizable string for the item's in-game display name and description.
Type The item's general type, like Arch (artifact) or Minerals. See details at Modding:Items#Objects.
Category The item category.
Price (Optional) The price when sold by the player. This is not the price when bought from a shop. Default 0.

Appearance

field purpose
Texture The asset name for the texture containing the item's sprite. Defaults to Maps/springobjects.
SpriteIndex The sprite's index within the Texture, where 0 is the top-left sprite.

Edibility

field purpose
Edibility (Optional) A numeric value that determines how much energy (edibility × 2.5) and health (edibility × 1.125) is restored when this item is eaten. An item with an edibility of -300 can't be eaten, values from -299 to -1 reduce health and energy, and zero can be eaten but doesn't change health/energy. Default -300.
IsDrink (Optional) Whether to drink the item instead of eating it. Default false.
Buffs (Optional) The buffs to apply to the player when this item is eaten, if any. Default none.

This consists of a list of models with these fields:

field purpose
Id The unique string ID for this entry within the list.
Duration (Optional if BuffId is set) The buff duration measured in in-game minutes. This can be set to -2 for a buff that should last for the rest of the day.
BuffId (Optional) The unique ID of a buff from Data/Buffs to apply, or null to ignore Data/Buffs and set the ID to food or drink depending on the item's IsDrink field.

If a buff from Data/Buffs is applied and you also specify other fields, here's how the buff data is combined:

field result
Duration
IconTexture
SpriteIndex
GlowColor
If specified, the value in Data/Objects is used instead of the one in Data/Buffs. If omitted, defaults to the value from Data/Buffs.
CustomAttributes The values from both entries are combined (e.g. +1 speed in Data/Objects and +1 speed in Data/Buffs results in +2 speed).
IsDebuff The value in Data/Objects is used.
IsDebuff (Optional) Whether this buff counts as a debuff, so its duration should be halved when wearing a Sturdy Ring. Default false.
IconTexture (Optional) The asset name for the icon texture to load. This must contain one or more 16x16 icons in a grid of any size. If omitted, the game will draw a default icon based on the BuffId and CustomAttributes fields.
SpriteIndex (Optional) The buff's icon index within the IconTexture, where 0 is the top-left icon. Default 0.
GlowColor (Optional) The glow color to apply to the player. See color format. Default none.
CustomAttributes The custom buff attributes to apply, if any.

This consists of a model with any combination of these fields:

field purpose
FarmingLevel
FishingLevel
ForagingLevel
LuckLevel
MiningLevel
(Optional) An amount applied to the matching skill level while the buff is active. This can be negative for a debuff. Default 0.
Attack
Defense
MagneticRadius
MaxStamina
Speed
(Optional) An amount applied to the player's attack, defense, magnetic radius, maximum stamina, or speed while the buff is active. This can be negative for a debuff. Default 0.
CustomFields (Optional) The custom fields for this entry.

Geodes & artifact spots

field purpose
GeodeDrops
GeodeDropsDefaultItems
(Optional) The items that can be dropped when breaking open this item as a geode. Specifying either or both fields automatically enables geode behavior for this item.

You can specify one or both fields:

  • GeodeDrops can be set to the specific items to drop. Default none. This consists of a list of models with these fields:
    field purpose
    common fields See item spawn fields for the generic item fields supported by geode drops.

    If set to an item query which returns multiple items, one of them will be selected at random.

    Chance (Optional) The probability that the item will be dropped if the other fields match, as a decimal value between 0 (never) and 1 (always). Default 1.
    SetFlagOnPickup (Optional) The mail flag to set for the current player when this drop is picked up.
    Precedence (Optional) The order in which this entry should be checked, where lower values are checked first. This can be a negative value. Geode drops with the same precedence are checked in the order listed. Default 0.

    For consistency, vanilla drops mostly use these values:

    • -1000: special overrides like the Golden Helmet;
    • 0: normal items.
  • GeodeDropsDefaultItems chooses a predefined list of possible geode drops like clay, coal, copper, iridium, etc. Default false.

If both fields are specified, each geode will choose between them with an equal 50% chance. If GeodeDrops is specified but no entries match, the geode will use the GeodeDropsDefaultItems regardless of whether it's true.

ArtifactSpotChances (Optional) If this is an artifact (i.e. the Type field is Arch), the chance that it can be found by digging artifact spots in each location.

This consists of a string → model lookup, where:

  • the key is the internal location name;
  • the value is the probability the item will spawn if checked, as a decimal value between 0 (never) and 1 (always).

Context tags & exclusions

field purpose
ContextTags (Optional) The custom context tags to add for this item (in addition to the tags added automatically based on the other object data). This is formatted as a list; for example:
"ContextTags": [ "color_yellow", "fish_ocean", "fish_upright", "season_summer" ]
ExcludeFromRandomSale (Optional) Whether to exclude this item from shops when selecting random items to sell. Default false.
ExcludeFromFishingCollection
ExcludeFromShippingCollection
(Optional) Whether to exclude this item from the fishing/shipping collection and their respective effect on the perfection score. Default false, in which case the normal requirements apply (e.g. artifacts are always excluded from the shipping collection).

Advanced

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

Custom pants

These docs should be merged into Modding:Items. When copying content, make sure you attribute the original authors.

You can now create/edit pants by editing the new Data/Pants asset, which replaces Data/clothingInformation. This consists of a string → model lookup, where...

  • The key is the unqualified item ID.
  • The value is a model with the fields listed below.

Basic pants data

field purpose
Name (Optional) The internal name for the item. Default Pants.
DisplayName
Description
(Optional) A tokenizable string for the item's in-game display name and description. Defaults to the generic pants text (Pants and A wearable pair of pants).
Price (Optional) The default price when the item is sold to the player in a shop. Default 50.

Appearance

field purpose
Texture The asset name for the texture containing the pants' sprite. Defaults to Characters/Farmer/pants.
SpriteIndex The pants' sprite index within the Texture, where 0 is the top-left set.
DefaultColor (Optional) The dye color to apply to the sprite when the player hasn't dyed it yet, if any. See color format. Default 255 235 203 (which matches the color of the cloth item).
CanBeDyed (Optional) Whether the player can dye these pants. Default false.
IsPrismatic (Optional) Whether the pants continuously shift colors. This overrides DefaultColor and CanBeDyed if set. Default false.

Other

field purpose
CanChooseDuringCharacterCustomization (Optional) Whether these pants can be selected on the character customization screen (e.g. when creating a character). Default false.
CustomFields The custom fields for this entry.

Custom shirts

These docs should be merged into Modding:Items. When copying content, make sure you attribute the original authors.

You can now create/edit shirts by editing the new Data/Shirts asset, which replaces Data/clothingInformation. This consists of a string → model lookup, where...

  • The key is the unqualified item ID.
  • The value is a model with the fields listed below.

Basic shirt data

field purpose
Name (Optional) The internal name for the item. Default Shirt.
DisplayName
Description
(Optional) A tokenizable string for the item's in-game display name and description. Defaults to the generic shirt text (Shirt and A wearable shirt).
Price (Optional) The default price when the item is sold to the player in a shop. Default 50.

Appearance

field purpose
Texture The asset name for the texture containing the shirt's sprite. Defaults to Characters/Farmer/shirts.
SpriteIndex The shirt's sprite index within the Texture, where 0 is the top-left set.
DefaultColor (Optional) The dye color to apply to the sprite when the player hasn't dyed it yet, if any. See color format. Default none.
CanBeDyed (Optional) Whether the player can dye this shirt. Default false.
IsPrismatic (Optional) Whether the shirt continuously shifts colors. This overrides DefaultColor and CanBeDyed if set. Default false.
HasSleeves (Optional) Whether to draw shirt sleeves. Default true.

Other

field purpose
CanChooseDuringCharacterCustomization (Optional) Whether this shirt can be selected on the character customization screen (e.g. when creating a character). Default false.
CustomFields The custom fields for this entry.

Custom tools

These docs should be merged into Modding:Items. When copying content, make sure you attribute the original authors.

You can now create/edit tools by editing the new Data/Tools asset. This consists of a string → model lookup, where...

  • The key is the unqualified item ID.
  • The value is a model with the fields listed below.

Basic tool data

field purpose
ClassName The name of the C# class to construct within the StardewValley.Tools namespace. The class must be a subclass of StardewValley.Tool, and have a constructor with no arguments. For example, given a value of Axe, the game will create StardewValley.Tools.Axe instances.

The main values are:

  • main tools (Axe, FishingRod, Hoe, MeleeWeapon, MilkPail, Pan, Pickaxe, Shears, Wand, and WateringCan);
  • a special GenericTool type which applies the Data/Tools data and only has generic logic, so C# mods can patch in their own logic;
  • and two tools cut from the game which may not work correctly (Lantern and Raft).
Name The internal name to set for the tool item.
DisplayName
Description
A tokenizable string for the tool's in-game display name and description.
AttachmentSlots (Optional) The number of attachment slots to enable on the tool. Note that only FishingRod tools have the code to render and use attachment slots. Default -1, which keeps the default value set by the tool class.
SalePrice (Optional) The default price when the item is sold to the player in a shop. Defaults to -1, in which case you should set the price manually in shops.
CustomFields The custom fields for this entry.

Appearance

Note that drawing the tool correctly in the world (ie, while the player is trying to use it) probably still needs custom code.

field purpose
Texture The asset name for the texture containing the tool's sprite.
SpriteIndex The tool's sprite index within the Texture, where 0 is the top row.
MenuSpriteIndex (Optional) The sprite index within the Texture for the item icon. Defaults to SpriteIndex.

Upgrades

field purpose
UpgradeLevel (Optional) The tool upgrade level. Default -1, which keeps the default value set by the tool class.
ApplyUpgradeLevelToDisplayName (Optional) Whether to adjust the DisplayName for the usual upgrade levels. For example, the display name for a level one Axe changes to 'Copper Axe'. Default false.

The display name format in English is:

upgrade level display name format
1 Copper <display name>
2 Steel <display name>
3 Gold <display name>
4 Iridium <display name>
ConventionalUpgradeFrom (Optional) If set, prepends an upgrade for the given tool ID to the UpgradeFrom field. This applies these rules (based on the UpgradeLevel field, not the upgrade level of the specified tool ID):
upgrade level price items needed
1 data-sort-value="2000"> 2,000g   Copper Bar (5)
2 data-sort-value="5000"> 5,000g   Iron Bar (5)
3 data-sort-value="10000"> 10,000g   Gold Bar (5)
4 data-sort-value="25000"> 25,000g   Iridium Bar (5)

For example, Iridium Axe specifies this value:

"ConventionalUpgradeFrom": "(T)GoldAxe"
UpgradeFrom (Optional) The requirements to buy this tool from Clint's blacksmith tool upgrade shop. If you specify multiple entries, the first one which matches will be applied.

This consists of a list of models with these fields:

field purpose
Price (Optional) The gold price to buy the upgrade. Defaults to 0.
RequireToolId (Optional) If set, the qualified or unqualified item ID for the tool that must be in the player's inventory for the upgrade to appear. The tool will be destroyed when the upgrade is purchased.
TradeItemId (Optional) If set, the qualified or unqualified item ID for an extra item that must be traded to upgrade the tool. (For example, many vanilla tools need metal bars.)
TradeItemAmount (Optional) The number of TradeItemId required. Defaults to 1.
Condition (Optional) A game state query which indicates whether this upgrade is available. Defaults to always true.

For example, these are equivalent to the Steel Axe's upgrade settings:

"UpgradeFrom": [
    {
        "RequireToolId": "(T)CopperAxe",
        "Price": 5000,
        "TradeItemId": "(O)335", // Iron Bar
        "TradeItemAmount": 5
    }
]

If you want the tool to always be available, you can just omit the conditions. For example:

"UpgradeFrom": [
    {
        "Price": 5000
    }
]

Note that Clint needs a few days to smith the new tool. If you want to sell the tool directly, add it to a regular shop instead.

Game logic

field purpose
CanBeLostOnDeath Whether the player can lose this tool when they die. Default false.

Extensibility

field purpose
ModData (Optional) The mod data values to set when the tool is created, accessible in C# code via the tool.modData dictionary. For example:
"ModData": {
    "PowerLevel": 9000
}
SetProperties (Optional) Set the value of arbitrary properties on the tool class. For example, this would disable the tool animation and require no stamina:
"SetProperties": {
    "InstantUse": true,
    "IsEfficient": true
}

Custom wild trees

These docs should be merged into a new doc page. When copying content, make sure you attribute the original authors.

Data format

You can now create/edit wild trees by editing the Data/WildTrees asset.

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

  • The asset key is a unique string ID for the tree type. The vanilla tree IDs are 1 (oak), 2 (maple), 3 (pine), 6 (palm), 7 (mushroom), and 8 (mahogany).
  • The asset value is a model with thee fields listed below.
field effect
Textures The texture to use as the tree's spritesheet in-game. If multiple textures are listed, the first matching one is used.

This consists of a list of models with these fields:

field effect
Texture The asset name for the tree's spritesheet.
Season (Optional) If set, the specific season when this texture should apply. For more complex conditions, see Condition.
Condition (Optional) A game state query which indicates whether this texture should be applied for a tree. Defaults to always enabled.

This is checked when the tree is created, a new day starts, or its texture is reloaded by a mod. More frequent conditions (like time of day) won't work as expected unless a mod manually triggers a tree update.

SeedItemId (Optional) The qualified item ID for the seed item. If omitted, the tree can't be planted and SeedOnShakeChance will be ignored.
SeedPlantable (Optional) Whether the seed can be planted by the player. If this is false, it can only be spawned automatically via map properties. Default true.
GrowthChance (Optional) The probability each day that the tree will grow to the next stage without tree fertilizer, as a value from 0 (will never grow) to 1 (will grow every day). Defaults to 0.2 (20% chance).
FertilizedGrowthChance (Optional) Equivalent to GrowthChance, but with tree fertilizer. Defaults to 1 (100% chance).
SeedSpreadChance (Optional) The probability each day that the tree will plant a seed on a nearby tile, as a value from 0 (never) to 1 (always). This only applied in locations where trees plant seeds (e.g. farms in vanilla). Default 0.15 (15% chance).
SeedOnShakeChance (Optional) The probability each day that the tree will produce a seed that will drop when the tree is shaken, as a value from 0 (never) to 1 (always). Default 0.05 (5% chance).
SeedOnChopChance (Optional) The probability that a seed will drop when the player chops down the tree, as a value from 0 (never) to 1 (always). Default 0.75 (75% chance).
DropWoodOnChop (Optional) Whether to drop wood when the player chops down the tree. Default true.
DropHardwoodOnLumberChop (Optional) Whether to drop hardwood when the player chops down the tree, if they have the Lumberjack profession. Default true.
IsLeafy (Optional) Whether shaking or chopping the tree causes cosmetic leaves to drop from tree and produces a leaf rustle sound. When a leaf drops, the game will use one of the four leaf sprites in the tree's spritesheet in the slot left of the stump sprite. Default true.
IsLeafyInWinter (Optional) Whether IsLeafy also applies in winter. Default false.
GrowsInWinter (Optional) Whether the tree can grow in winter (subject to GrowthChance or FertilizedGrowthChance). Default false.
IsStumpDuringWinter (Optional) Whether the tree is reduced to a stump in winter and regrows in spring, like the vanilla mushroom tree. Default false.
AllowWoodpeckers (Optional) Whether woodpeckers can spawn on the tree. Default true.
UseAlternateSpriteWhenNotShaken
UseAlternateSpriteWhenSeedReady
(Optional) Whether to render a different tree sprite when the player hasn't shaken it on that day (UseAlternateSpriteWhenNotShaken) or it has a seed ready (UseAlternateSpriteWhenSeedReady). If either field is true, the tree spritesheet must be double-width with the alternate textures on the right. If both are true, the same alternate sprites are used for both. Default false.
DebrisColor (Optional) The color of the cosmetic wood chips when chopping the tree. This can be...
  • a standard color format;
  • or one of 12 (brown/woody), 100001 (white), 100001 (light green), 100002 (light blue), 100003 (red), 100004 (yellow), 100005 (black), 100006 (gray), or 100007 (charcoal / dim gray).

Defaults to 12 (brown/woody).

SeedDropItems (Optional) When a seed is dropped subject to SeedOnShakeChance, the item to drop instead of the item specified by SeedItemId. If this is empty or none match, the SeedItemId will be dropped instead.

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 chop drops.

If set to an item query which returns multiple items, one of them will be selected at random.

Season (Optional) If set, the item only applies if the tree's location is in this season.
Chance (Optional) The probability that the item will drop, as a value between 0 (never drops) and 1 (always drops). Default 1 (100% chance).
ContinueOnDrop (Optional) If this item is dropped, whether to continue as if it hadn't been dropped for the remaining drop candidates. Default false.
ChopItems (Optional) The additional items to drop when the tree is chopped down. All matching items are dropped.

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 chop drops.

If set to an item query which returns multiple items, one of them will be selected at random.

Season (Optional) If set, the item only applies if the tree's location is in this season.
Chance (Optional) The probability that the item will drop, as a value between 0 (never drops) and 1 (always drops). Default 1 (100% chance).
MinSize
MaxSize
(Optional) The minimum and/or maximum growth stage for the tree at which this item is produced. The possible values are Seed, Sprout, Sapling, Bush, and Tree. Both default to no limit.
ForStump (Optional) Whether the item is only produced if the tree is a stump (true), not a stump (false), or both (null). Defaults to false (non-stumps only).
ShakeItems The items produced by shaking the tree when it's fully grown. This only applies the first time the tree is shaken each day. All matching items are dropped.

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 shake items.

If set to an item query which returns multiple items, one of them will be selected at random.

Season (Optional) If set, the item only applies if the tree's location is in this season.
Chance (Optional) The probability that this entry is selected, as a value between 0 (never drops) and 1 (always drops). Default 1 (100% chance).
TapItems The items produced by tapping the tree. If multiple items can be produced, the first available one is selected.

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 tapper items.

If set to an item query which returns multiple items, one of them will be selected at random.

Season (Optional) If set, the item only applies if the tree's location is in this season.
Chance (Optional) The probability that this entry is selected, as a value between 0 (never drops) and 1 (always drops). Default 1 (100% chance).
DaysUntilReady The number of days before the tapper is ready to empty.
PreviousItemId (Optional) If set, the item only applies if the previous item produced by the tapper matches one of the given qualified item IDs. If an entry is null or an empty string, it matches when there's no previous item.

For example: "PreviousItemId": [ null ] only applies when a tapper is first added to the tree, and "PreviousItemsId": [ "(O)420" ] applies if the player just collected a red mushroom (object #420) from it.

DaysUntilReadyModifiers (Optional) Quantity modifiers applied to the DaysUntilReady value. Default none.
DaysUntilReadyModifiersMode (Optional) Quantity modifier modes which indicate what to do if multiple modifiers in the DaysUntilReadyModifiersMode field apply at the same time. Default Stack.
PlantableLocationRules (Optional) The rules to decide which locations you can plant the seed in, if applicable. The first matching rule is used. This can override location checks (e.g. crops being limited to the farm), but not built-in requirements like crops needing dirt.

This consists of a list of models with these fields:

field effect
Id The unique string ID for this entry within the list.
Result Indicates whether the seed can be planted in a location if this entry is selected. The possible values are:
  • Default: the seed can be planted if the location normally allows it. This can be used to stop processing further rules, and/or set a custom DeniedMessage.
  • Allow: the seed can be planted here, regardless of whether the location normally allows it.
  • Deny: the seed can't be planted here, regardless of whether the location normally allows it.
Condition (Optional) A game state query which indicates whether this entry applies. Default true.
PlantedIn (Optional) The planting context to apply this rule for. The possible values are Ground (planted directly in the ground), GardenPot (planted in a garden pot), or Any. Default Any.

Note that trees can't be planted in garden pots.

DeniedMessage (Optional) If this rule prevents planting the seed, the tokenizable string to show to the player (or null to default to the normal behavior for the context). This also applies when the Result is Default, if that causes the planting to be denied.
CustomFields The custom fields for this entry.

Spawning wild trees

Custom trees can be added to the game in two ways:

  • Spawn them on map tiles when the location is created, using the new SpawnTree: wild <tree ID> [growth stage on location created] [growth stage on day-update regrowth] tile property. This must be added on the Paths layer, which must also have tile index 34 from the paths tilesheet.
  • Or give the player a seed item in the usual ways (e.g. from a shop, mail letter, etc).

Default recipes

These docs should be merged into Modding:Recipe data. When copying content, make sure you attribute the original authors.

You can now have crafting and cooking recipes that are learned automatically by setting the condition field to default. Any missing default recipes will be learned on day start.

For example, here's the chest entry from Data/CraftingRecipes:

"Chest": "388 50/Home/130/true/default/"

Global inventories

C# mods can now set a chest.GlobalInventoryId field to make it share a global inventory with every other chest having the same ID. This replaces the equivalent hardcoded logic for Junimo chests, which now just default to a "JunimoChests" global inventory ID. For example, this can be used to have multiple Junimo chest networks or make other containers share inventory.

C# mods can also use this to store items for other mod purposes, by using Game1.player.team.globalInventories or Game1.player.team.GetOrCreateGlobalInventory(id) directly.

Hats on aquarium fish

These docs should be merged into Modding:Fish data. When copying content, make sure you attribute the original authors.

Custom fish in aquariums can now wear hats, just like vanilla sea urchins. This can be enabled by specifying a new field in Data/AquariumFish:

index field purpose
7 hat position The pixel position of the hat on the sprite, specified as an object with X and Y values.

Context tag changes

These docs should be merged into Modding:Items#Context tags. When copying content, make sure you attribute the original authors.

New context tags

1.6 adds several new item context tags:

context tag effect
campfire_item Marks the item as a campfire. If the item also has the torch_item context tag, when it's placed in the world and turned on...
  • campfire flames are drawn over it;
  • if the item is big craftable, light is emitted from its center instead of the top.
fish_pond_ignore Prevents players from adding this fish to fish ponds, even if it would otherwise match an entry in Data/FishPondData.
geode_crusher_ignored Prevents breaking this item open in a geode crusher, even if the item has geode fields in Data/Objects.
item_type_<type> For an object-type item, the type value from the 'type and category' field. (Non-object items always have the exact tag item_type_ with nothing after the last underscore.) This is automatic and shouldn't be set manually. The tag is checked in a few places (e.g. the museum to check if an item is an artifact or mineral), but most of the game won't be affected.
museum_donatable
not_museum_donatable
Set whether the item can be donated to the museum, overriding the vanilla logic.
not_giftable Prevents players from gifting this item to NPCs, who'll ignore the item entirely (e.g. as if you were holding a tool).

This only affects gift-giving, it doesn't affect non-gift logic like quest goals or special order objectives. If the NPC also has a reject_* dialogue for the item, the dialogue takes priority.

not_placeable
placeable
Sets whether the item can be placed on the ground.
prevent_loss_on_death Indicates the item can't be lost when the player dies.
sign_item Marks the item as a sign, which lets player display items on it or place it on a fish pond to show the fish count.
torch_item Marks the item as a torch, which lets the player turn it on/off to emit light.

See also campfire_item.

Context tags which affect machine processing:

context tag effect
crystalarium_banned When applied to a gem or mineral item, prevents players from placing it in a crystalarium.
keg_juice
keg_wine
Allows processing the item in a keg to produce a juice or wine variant.
preserves_jelly
preserves_pickle
Allows processing the item in a preserves jar to produce a jelly or pickled variant.
seedmaker_banned When applied to a seed item, prevents players from placing it in a seed maker.
tapper_item Marks the item as a tapper or heavy tapper.
tapper_multiplier_<multiplier> The multiplier applied to the tapper production speed. For example, 2 will make items take half their base time (i.e. each item will finish in base time/speed multiplier). Defaults to 1 if omitted.

And informational tags which have no effect on the game logic:

context tag effect
fish_legendary
fish_legendary_family
Marks the fish as a legendary fish or legendary fish family. These are purely informational; the legendary fish behavior is determined by data fields like CatchLimit or IsBossFish in Data/Locations.
geode (Added automatically) Marks the item as a geode item, which can be broken open at Clint's blacksmith shop or using a geode crusher. This is added automatically if the geode fields are present in Data/Objects.
id_<item id> (Added automatically) The qualified item ID, like id_(o)128. This can be used to match or exclude an item by ID using context tags. Any spaces in the ID are replaced with underscores, and single quotes are removed.
is_machine (Added automatically) Indicates the item has machine logic. This is added automatically based on Data/Machines.
machine_input (Added automatically) Whether the item is a machine which accepts items from the player. This is added automatically based on the machine's fields in Data/Machines:
  • if HasInput is true;
  • or if any output rules have an ItemPlacedInMachine trigger.
machine_output (Added automatically) Whether the item is a machine which produces items for the player to collect. This is added automatically based on the machine's fields in Data/Machines:
  • if HasOutput is true;
  • or if it has any output rules.

ItemContextTagManager class

For C# mods, 1.6 adds a new ItemContextTagManager class which simplifies working with item context tags and reduces repeated code.

This provides a few utility methods:

method effect
GetBaseContextTags(id) Get the base context tags for an item based on its raw data in Data/Objects or Data/BigCraftables. This doesn't include dynamic tags added that are based on instance info (like quality), which you can get using item.GetContextTags().
DoesTagQueryMatch(query, tags) Get whether a context tag query matches the given tags. For example, ItemContextTagManager.DoesTagQueryMatch("bone_item, !fossil_item", item.GetContextTags()) returns true if the item is a bone item but not a fossil (like the Bone Flute).
DoAllTagsMatch(requiredTags, actualTags)
DoAnyTagsMatch(requiredTags, actualTags)
Get whether every (DoAllTagsMatch) or at least one (DoAnyTagsMatch</samp) required tag matches the actual item tags. This supports negated required tags like "!fossil_item" too.
DoesTagMatch(requiredTag, actualTags) Get whether a single tag matches the actual item tags. This supports negated required tags like "!fossil_item" too.
SanitizeContextTag(tag) (Specialized) Replace characters that may appear in item names so they're valid in context tags. For example, SanitizeContextTag("Sam's Boombox") returns sams_boombox.

Other context tag changes

  • Context tags are now case-insensitive.

Inventory class

For C# mods, 1.6 adds a new Inventory class to manage a list of items. This is used for the Farmer.items and Chest.items fields. It implements IList<Item>, so most existing code should still work fine.

This has three main benefits:

  • It has methods to simplify many common operations. For example:
    method effect
    HasAny() Get whether the inventory contains any items (ignoring empty slots).
    CountItemStacks() Get the number of item stacks in the inventory (ignoring empty slots).
    ContainsId(id) Get whether the inventory contains any item with the given qualified or unqualified item ID.
    ContainsId(id, minCount) Get whether the inventory contains items with the given qualified or unqualified item ID, and their combined stack size is at least minCount.
    CountId(id) Get the combined stack size of all items with the given qualified or unqualified item ID.
    GetById(id) Get a list of items in the inventory with the given qualified or unqualified item ID.
    ReduceId(id, count) Remove the given number of items matching the given qualified or unqualified item ID. This reduces the stack size for matching items until a total of count have been removed, and clears any slots which reach a stack size of zero.
  • Many common operations have been unified, so previously player-only methods can now be used with chests too.
  • It has an internal index by item ID, so operations like items.ContainsId("(O)128") are much more efficient since they no longer iterate the list.

This replaces some previous methods:

game class old code migration
Farmer getItemCount(id)
GetTallyOfObject(id)
GetTallyOfObject(id, isBigCraftable)
hasItemInInventory(id, count)
hasItemInList(list, id, count)
  • To check an item ID, use items.CountId(id) or Items.ContainsId(id, count).
  • To check Golden Walnuts or Qi Gems, use the Game1.netWorldState.Value.GoldenWalnuts and Farmer.QiGems fields.
  • To check category matches or -777 (seasonal wild seeds), the getItemCount and getItemCountInList still exist.
hasItemInInventoryNamed(name)
hasItemWithNameThatContains(name)
In most cases, you should match items by ID instead (see the previous row).

If you really need to match items by name, you can replace it like this:

// exact name
bool hasMatch = Game1.player.Items.Any(item => item?.Name == name);

// name contains
bool hasMatch = Game1.player.Items.Any(item => item?.Name?.Contains(name) is true);
areAllItemsNull() Use !items.HasAny().
numberOfItemsInInventory() Use items.CountItemStacks() to count all items, or Items.Count(p => p is Object) to match this method's actual behavior.
consumeObject(id, count) Use items.ReduceId(id, count).
removeItemsFromInventory(id, count)
  • To remove an item by ID, use items.ReduceId(id, count).
  • To deduct Golden Walnuts or Qi Gems, change the Game1.netWorldState.Value.GoldenWalnuts and Farmer.QiGems fields.
Object ConsumeInventoryItem(player, id, count) This was somewhat specialized and shouldn't be called by mod code, but the equivalent would be (Object.autoLoadChest ?? player.items).ReduceId(id, count). See also notes for Farmer.removeItemsFromInventory.
GetTallyOfObject(player, id) This was somewhat specialized and shouldn't be called by mod code, but the equivalent would be (Object.autoLoadChest ?? player.items).CountId(id). See also notes for Farmer.getTallyOfObject.

It implements a new IInventory interface, which lets mods pass their own implementations to code which works on inventories.

Furniture changes

These docs should be merged into Modding:Items#Furniture. When copying content, make sure you attribute the original authors.
  • Data/furniture no longer has language variants. Translations were moved into Strings/Furniture.
  • There are a few changes in Data/furniture:
    • Field index 6 is now placement restrictions and field index 7 is now display name. The display name field is no longer omitted in English.
    • Field index 7 (display name) now allows tokenizable strings.
    • Added new fields:
      index field effect
      8 sprite index The sprite index within the spritesheet texture to draw.
      9 texture (Optional) The asset name of the texture to draw. Defaults to TileSheets/furniture.
      10 off limits for random sale (Optional) Whether to prevent this furniture from appearing in randomly generated shop stocks and the furniture catalogue. Default false.
      11 context tags (Optional) A space-delimited list of context tags which apply to this furniture. Default none.

Other item changes for C# mods

  • Placed object changes:
    • Every placed object now has a Location property set to the location which contains it. This removes location parameters from many object methods.
    • Setting an object's tile position through obj.TileLocation now recalculcates its collision box automatically. (Setting it through the tileLocation net field directly won't though.)
    • The obj.IsScarecrow() and GetScarecrowRadius() methods now work for non-bigcraftable objects too.
  • Clothing changes:
    • Clothes.clothesType is now an enum field.
    • Clothing is no longer gender-specific. This renames indexInTileSheetMale to indexInTileSheet, obsoletes indexInTileSheetFemale, and converts gender-variant clothing into regular items.
    • Removed unused ClothesType.ACCESSORY value.
    • Farmer.pants and Farmer.shirt now store the item ID instead of the sprite index.
    • In Data/TailoringRecipes, added a CraftingIdFeminine field which overrides CraftingId for female characters.
  • Crop changes:
    • Added Game1.cropData to read crop info without constantly reloading the Data/Crops asset.
    • Removed most crop fields which only mirror the data (like harvestMethod or seasonsToGrowIn). Mods can get the info through crop.GetData() instead.
    • Partly de-hardcoded fertilizer logic. Almost all fertilizer logic is now centralized into a new patchable set of HoeDirt methods (see list below). The only fertilizer logic that's still embedded elsewhere is the interaction errors in Utility.tryToPlaceItem.
    • HoeDirt.fertilizer.Value is now set to null when there is no fertilizer. Both qualified and unqualified IDs should be expected.
    • Removed crop.InferSeedIndex(). This was used to support old crops, which are now fixed by a save migration instead.
  • Tool changes:
    • Fixed various logic not handling custom tool upgrade levels.
  • Other item logic:
    • Simplified the constructors for many item types, particularly Object.
    • Honey items now have their preserve field set to a new Honey type (instead of null).
    • The Object.performObjectDropInAction method now applies the probe argument much more consistently. This only affects method calls with probe: true.
    • The Item.salePrice() method now has option to get the price without profit margins.
    • Added new fields & methods:
      type field/method effect
      Chest GetItemsForPlayer() Shortcut for chest.GetItemsForPlayer(Game1.player.UniqueMultiplayerID).
      Crop GetHarvestMethod() Get the method used to harvest the crop (one of HarvestMethod.Grab or HarvestMethod.Scythe).
      IsInSeason(location) Whether the crop can grow in the location's current season (or true if crops ignore seasons in the location, like the greenhouse).
      HoeDirt HasFertilizer() Get whether the dirt has any fertilizer applied.
      CanApplyFertilizer(itemId) Get whether a player can apply the given fertilizer to this dirt.
      CheckApplyFertilizerRules(itemId) Get whether a player can apply the given fertilizer to this dirt, and the reason they can't if applicable.
      GetFertilizerSpeedBoost() Get the crop growth speed boost from fertilizers applied to this dirt.
      GetFertilizerWaterRetentionChance() Get the water retention chance from fertilizers applied to this dirt, as a value between 0 (no change) and 1 (100% chance of staying watered).
      GetFertilizerQualityBoostLevel() Get the quality boost level from fertilizers applied to this dirt, which influences the chance of producing a higher-quality crop.
      GetFertilizerSourceRect() Get the pixel area within the dirt spritesheet to draw for any fertilizer applied to this dirt.

      (This method existed before, but no longer requires the fertilizer ID argument.)

      isWatered() Get whether the dirt is currently watered.
      Item IsRecipe
      Quality
      Stack
      sellToStorePrice(…)
      Equivalent to the previous Object fields/methods, to simplify common code and avoid needing to special-case Object items.
      appliesProfitMargins() Get whether this item should apply profit margins to shop prices.
      CanBeLostOnDeath() Get whether this item can be lost when the player dies, so it can be recovered from the item recovery service.
      HasTypeId(id)
      HasTypeObject()
      HasTypeBigCraftable()
      Get whether the item has the given type definition ID. These are null-safe and double as a null check:
      if (item.HasTypeId(ItemRegistry.type_object))
      {
          // item is non-null and has type (O)
      }
      

      HasTypeObject() and HasTypeBigCraftable() are shortcuts for passing ItemRegistry.type_object and ItemRegistry.type_bigCraftable respectively.

      TryGetTempData
      SetTempData
      Get or set temporary item info that's not synchronized in multiplayer or written to the save file.

      For example, the game uses this to pass spawn options to the fishing minigame:

      if (spawn.IsBossFish)
          fish.SetTempData(nameof(spawn.IsBossFish), true);
      
      ...
      
      fish.TryGetTempData(nameof(SpawnFishData.IsBossFish), out bool bossFish);
      
      FishingRod CanUseBait()
      CanUseTackle()
      GetBait()
      GetTackle()
      HasMagicBait()
      HasCuriosityLure()
      Simplifies working with the fishing rod's bait and tackle.
      Furniture SetPlacement
      SetHeldObject
      Set the furniture's position and rotation (SetPlacement) or held object (SetHeldObject). The latter will initialize the held object's tile position to match the furniture instance.

      These are used by the game to initialize furniture in one go. For example:

      // oak table holding decorative bowl
      Furniture table = ItemRegistry
          .Create<Furniture>("(F)1120")
          .SetPlacement(5, 4, 0)
          .SetHeldObject(ItemRegistry.Create<Furniture>("(F)1364"));
      
      IsTable() Get whether this furniture is a table.
      FruitTree GetQuality() Get the quality of fruit currently being produced by the fruit tree.
      TryAddFruit() Add a fruit item to the tree based on its data.
      IndoorPot Water() Simplifies watering dirt in the garden pot.
      Object GetBoundingBox()
      GetBoundingBoxAt(x, y)
      Get the pixel collision area for the item placed in the world. These replace the former getBoundingBox(position) method.
      Tool isScythe() Equivalent to the previous MeleeWeapon method, to simplify common code and avoid needing to special-case MeleeWeapon items.
      Tree CheckForNewTexture() Reset the tree's texture if it would change based on its data.
      GetMaxSizeHere Get the maximum size the tree can grow in its current position (e.g. accounting for nearby trees blocking growth).
      IsGrowthBlockedByNearbyTree Get whether growth is blocked because it's too close to another fully-grown tree.
    • Modularized Object.CheckForAction to simplify mod patches.
    • Reworked Item.getOne() implementation to avoid common pitfalls. (This only affects mods with custom item classes, or which patch Item.getOne or Item._GetOneFrom.)
    • Fixed fruit trees forgetting the growth stage set in their constructor when they're updated overnight.

    Other item changes

    • Added per-object display names (e.g. for custom flavored items). See the ObjectDisplayName item spawn field, or object.displayNameFormat in C#.
    • Item pedestals are now normal item, so you can spawn them using a mod like CJB Item Spawner to display items.
    • Added optional Condition game state query field to Data/SpecialOrders.
    • Item data changes:
      • The display name field now exists in English too for Data/Boots, Data/Bundles, Data/CookingRecipes, Data/CraftingRecipes, Data/Furniture, Data/Hats, and Data/Weapons.
      • The randomly spawned stones, twigs, and weeds have been formalized into litter. They all now have object type Litter, category -999 (StardewValley.Object.litterCategory), a relevant display name/description (like Gold Stone & Break apart to obtain gold ore instead of Stone & ...), a price of 0 (not sellable), and edibility of -300 (inedible). This also adds all mine ore nodes to Data/Objects, so the game no longer creates invalid items to show their sprite. (Doing so in 1.6 will now show an Error Item sprite instead.)
      • Honey items now have the honey_item context tag.
      • Shirts no longer have a dynamic numeric ID range; every valid shirt is now listed in Data/Shirts.
      • You can now apply a custom buff ID when the item is eaten, via Data/Objects's Buff field.
      • The type field in Data/Objects is no longer checked using substring matching (e.g. the game now uses data.Type == "Fish" instead of typeAndCategory.Contains("Fish")), which may impact mods which depended on that undocumented behavior.
    • Crop changes:
      • Paddy crops now recheck for nearby water each day, so they'll update if you add/remove a building with water or change the map layout.
      • In Data/Crops, each harvest option is now self-contained. For example, you can set HarvestMinStack without ExtraHarvestChance.
    • Fish changes:
      • Data/Fish is no longer translated, so there's only one Data/Fish.xnb field. Fish display names are now taken from Data/Objects.
      • Added a new field (index 13) in Data/Fish, which sets whether the fish can be selected for the first-catch tutorial.
    • Recipe changes in Data/CookingRecipes and Data/CraftingRecipes:
      • These assets no longer have language variants.
      • The display name now supports tokenizable strings.
      • The display name can now be left blank to get it from the first item in the output list.
    • Other item logic:
      • Missing recipes that should already be unlocked are now added to the player automatically on save load.
      • Data/Bundles is now loaded later, so content packs can edit it reliably.
      • Chests with fridge: true are now treated as mini-fridges for the cooking menu.
      • Gift boxes can now contain multiple items.
      • Fixed furniture drawn over sitting players if it has no front texture.
      • Fixed tool being upgraded by Clint not affected by recursive item search logic.
      • Fixed tool.getOne() not copying the tool name.
      • Fixed cooking menu constantly creating hovered item if the item/recipe names don't match.

    What's new for locations & weather

    Custom locations

    See the updated docs at Modding:Location data. This section below focuses on what's new in 1.6.

    You can now add/edit locations by editing the revamped Data/Locations asset. This makes nearly everything in the location configurable — display name, default warp arrival tile, how the location is created, artifact spots / fish / forage / weeds, music, etc.

    See Modding:Location data for docs on the new data format.

    Custom location contexts

    These docs should be merged into Modding:Location data or a new doc page. When copying content, make sure you attribute the original authors.

    Vanilla contexts

    • The game previously had two hardcoded location context enums: Default (for the valley) and Island (for Ginger Island). These have been replaced with data models which define the location context settings, loaded from the Data/LocationContexts asset.
    • The desert is now part of a new Desert context (instead of Default). Some of the previously hardcoded desert logic (like always sunny weather) is now just part of the context data in Data/LocationContexts.

    Format

    Custom contexts can be created by editing the new Data/LocationContexts asset, and setting the context name in the location's LocationContext map property.

    The data asset consists of a string → model lookup, where the key matches the Name field and the value is a model with these fields:

    Required fields:
    field effect
    Name The unique string ID for the location context.
    Player actions:
    field effect
    AllowRainTotem (Optional) Whether a rain totem can be used to force rain in this context tomorrow. If false, using a rain totem here will show a "this item can't be used here" message instead.
    RainTotemAffectsContext (Optional) If set, using a rain totem here will change the weather in the given context ID. For example, rain totems in the desert change weather in the valley.
    MaxPassOutCost (Optional) When the player passes out (due to exhaustion or at 2am) in this context, the maximum amount of gold lost. If omitted or set to -1, uses the same value as the Default context (data-sort-value="1000"> 1,000g by default).
    PassOutMail (Optional) When the player passes out (due to exhaustion or at 2am) in this context, the possible letter IDs to add to their mailbox (if they haven't received it before). If multiple letters are valid, one will be chosen randomly (unless one specifies SkipRandomSelection).

    This consists of a list of models with these fields:

    field effect
    Id The unique string ID for this entry in the list.
    Mail The letter ID to add.

    The game will look for an existing letter ID in Data/mail in this order (where <billed> is Billed if they lost gold or NotBilled otherwise, and <gender> is Female or Male):

    • <letter id>_<billed>_<gender>
    • <letter id>_<billed>
    • <letter id>

    If no match is found in Data/mail, the game will send passedOut2 instead.

    If the mail ID starts with passedOut, {0} in the letter text will be replaced with the gold amount lost, and it won't appear in the collections page.

    MaxPassOutCost (Optional) The maximum amount of gold lost. This is applied after the context's MaxPassOutCost (i.e. the context's value is used to calculate the random amount, then this field caps the result). Defaults to unlimited.
    Condition (Optional) A game state query which indicates whether this entry is active. Defaults to always true.
    SkipRandomSelection (Optional) If true, send this mail if the Condition matches instead of choosing a random valid mail. Default false.
    PassOutLocations (Optional) When the player passes out (due to exhaustion or at 2am) in this context and they started the day in a different location context, the locations where they'll wake up. (If the player started the day in the same context, they'll wake up in the last bed they slept in instead.)

    If the selected location doesn't contain a bed and doesn't have the AllowWakeUpWithoutBed map property, the player will wake up in the farmhouse instead.

    This consists of a list of models with these fields:

    field effect
    Id The unique string ID for this entry in the list.
    Location The internal location name.
    Position The default tile position within the location, specified as an object with X and Y fields. If the location has any bed furniture, they'll be placed in the first bed found instead.
    Condition (Optional) A game state query which indicates whether this entry is active. Defaults to always applied.

    If no locations are specified or none match, the player will wake up in their bed at home.

    ReviveLocations (Optional) If the player just got knocked out in combat, the location names where they'll wake up.

    This consists of a list of models with these fields:

    field effect
    Id The unique string ID for this entry in the list.
    Location The internal location name.
    Position The tile position within the location, specified as an object with X and Y fields.
    Condition (Optional) A game state query which indicates whether this entry is active. Defaults to always applied.

    If the selected location has a standard event with the exact key PlayerKilled (with no / or preconditions in the key), that event will play when the player wakes up and the game will apply the lost items or gold logic. The game won't track this event, so it'll repeat each time the player is revived. If there's no such event, the player will wake up without an event, and no items or gold will be lost.

    If no locations are specified or none match, the player will wake up at Harvey's clinic.

    Season:
    field effect
    SeasonOverride (Optional) The season which is always active for locations within this context (one of spring, summer, fall, or winter). For example, setting summer will make it always summer there regardless of the calendar season. If not set, the calendar season applies.
    Weather:
    field effect
    WeatherConditions (Optional) The weather logic to apply for locations in this context (ignored if CopyWeatherFromLocation is set). Defaults to always sunny. If multiple are specified, the first matching weather is applied.

    This consists of a list of models with these fields:

    field effect
    Id The unique string ID for this entry in the list.
    Weather The weather ID to set.
    Condition (Optional) A game state query which indicates whether to apply the weather. Defaults to always applied.
    CopyWeatherFromLocation (Optional) The Name (i.e. unique ID) of the location context from which to inherit weather.

    If a passive festival is active in any location within this context, the weather is sunny for the entire context regardless of these fields.

    Music:
    field effect
    DefaultMusic (Optional) The cue ID for the music to play when the player is in the location, unless overridden by a Music map property. Despite the name, this has a higher priority than the seasonal music fields below. Ignored if omitted.
    DefaultMusicCondition (Optional) A game state query which returns whether the DefaultMusic field should be applied (if more specific music isn't playing). Defaults to always true.
    DefaultMusicDelayOneScreen (Optional) When the player warps and the music changes, whether to silence the music and play the ambience (if any) until the next warp (similar to the default valley locations). Default false.
    Music (Optional) A list of cue IDs to play before noon in this location unless it's raining, there's a Music map property, or the context has a DefaultMusic value. If multiple values are specified, the game will play one per day in sequence.

    This consists of a list of models with these fields:

    field effect
    Id (Optional) A unique string ID which identifies this entry within the list. Defaults to the Track value.
    Track The audio track ID to play.
    Condition (Optional) A game state query which indicates whether this entry applies. Default true.
    DayAmbience
    NightAmbience
    (Optional) The cue ID for the background ambience to play when there's no music active, depending on the time of day. Both default to none.
    PlayRandomAmbientSounds (Optional) Whether to play random outdoor ambience sounds depending on factors like the season and time of day (e.g. birds, crickets, and mysterious groan sounds in the rain). This is unrelated to the DayAmbience and NightAmbience fields. Default true.
    Advanced:
    field effect
    CustomFields The custom fields for this entry.

    Custom garbage cans

    These docs should be merged into a new doc page. When copying content, make sure you attribute the original authors.

    Format

    You can now add or edit garbage cans on any map by editing the new Data/GarbageCans asset (see examples below).

    The asset consists of a data model with these fields:

    field effect
    DefaultBaseChance The probability that an item will be found when searching garbage cans, as a value between 0 (never) and 1 (always). If the probability check fails, only items that set IgnoreBaseChance can spawn. This can be overridden by the per-garbage-can BaseChance field. Default 0.2.
    BeforeAll
    AfterAll
    The items to prepend (BeforeAll) or append (AfterAll) to the GarbageCansItems field for all garbage cans. These work exactly like the items in that field (e.g. subject to the garbage can's base chance).
    GarbageCans The data for individual garbage cans. This consists of a string → model lookup with these fields:
    field effect
    entry key The unique string ID for this garbage can.
    BaseChance (Optional) If set, overrides the root DefaultBaseChance field for this garbage can. Defaults to DefaultBaseChance.
    Items (Optional) The items to try spawning when the player searches the garbage can. The first matching item in BeforeAll + Items + AfterAll will be spawned, and any further items will be ignored. Defaults to none.

    This consists of a list of models with these fields:

    field effect
    common fields See item spawn fields for the generic item fields supported by garbage cans.

    If set to an item query which returns multiple items, one of them will be selected at random.

    IgnoreBaseChance (Optional) Whether this item can spawn even if the BaseChance probability check didn't pass. Default false.
    IsMegaSuccess (Optional) Whether to treat this item as a 'mega success' if it's selected, which plays a special crit sound and bigger animation. Default false.
    IsDoubleMegaSuccess (Optional) Whether to treat this item as an 'double mega success' if it's selected, which plays an explosion sound and dramatic animation. Default false.
    AddToInventoryDirectly (Optional) Whether to add the item to the player's inventory directly, opening an item grab menu if they don't have room in their inventory. If false, the item will be dropped on the ground next to the garbage can instead. Default false.
    CreateMultipleDebris (Optional) Whether to split the spawned item into multiple stacks which each have a stack size of one. This has no effect if AddToInventoryDirectly is enabled. Default false.

    If the garbage can being searched doesn't have its own entry under GarbageCans, the game will just use the BeforeAll and AfterAll fields.

    CustomFields The custom fields for this entry.

    Example new garbage can

    You can add garbage cans using only Content Patcher or SMAPI's content API. For example, this content pack adds a new garbage can entry with the ID Example.ModId_Carpenter:

    {
        "Format": "2.0.0",
        "Changes": [
            {
                "Action": "EditData",
                "Target": "Data/GarbageCans",
                "TargetField": [ "GarbageCans" ],
                "Entries": {
                    "{{ModId}}_Carpenter": {
                        "Items": [
                            // 25% chance of pufferfish
                            {
                                "ID": "{{ModId}}_Pufferfish",
                                "Condition": "RANDOM 0.25",
                                "ItemId": "(O)128"
                            },
    
                            // else guaranteed random House Plant item
                            {
                                "ID": "{{ModId}}_RandomHousePlant",
                                "ItemID": "RANDOM_ITEMS (F) 1376 1390"
                            }
                        ]
                    }
                }
            }
        ]
    }
    

    Then you'd place an Action: Garbage Example.ModId_Carpenter map tile property to mark a tile as a garbage can using this data.

    Example change for existing garbage can

    You can edit an existing garbage cans using only Content Patcher or SMAPI's content API. For example, this content pack adds pufferfish to the Saloon garbage can, and moves it above the dish of the day.

    Note that this uses TargetField to 'move into' the item list for the saloon, and then treat those items as the entry list being edited. Specifying an ID which isn't in the list will add a new entry, just like when editing a regular list asset.

    {
        "Format": "2.0.0",
        "Changes": [
            {
                "Action": "EditData",
                "Target": "Data/GarbageCans",
                "TargetField": [ "GarbageCans", "Saloon", "Items" ],
                "Entries": {
                    // 25% chance of pufferfish
                    
                    "{{ModId}}_Pufferfish":{
                        "ID": "{{ModId}}_Pufferfish",
                        "Condition": "RANDOM 0.25",
                        "ItemId": "(O)128"
                    }
                },
                "MoveEntries": [
                    { "ID": "{{ModId}}_Pufferfish", "BeforeId": "Base_DishOfTheDay" }
                ]
            }
        ]
    }
    

    Changes for C# mods

    Previously garbage cans were tracked by Town.garbageChecked, an array of boolean fields. That approach doesn't work in Stardew Valley 1.6, since we're no longer limited to a specific set of garbage cans in the town map. This has been replaced by Game1.netWorldState.Value.CheckedGarbage, which is a hash set of garbage can IDs.

    To migrate code:

    action code in 1.5.6 code in 1.6
    check if a garbage can was searched
    Town town = (Town)Game1.getLocationFromName("Town");
    if (town.garbageChecked[5])
       ...
    
    if (Game1.netWorldState.Value.CheckedGarbage.Contains("Saloon"))
       ...
    
    mark a garbage can searched
    Town town = (Town)Game1.getLocationFromName("Town");
    town.garbageChecked[5] = true;
    
    Game1.netWorldState.Value.CheckedGarbage.Add("Saloon");
    

    To migrate former vanilla trash can IDs:

    position ID in 1.5.6 ID in 1.6
    Near Jodi and Kent's house 0 JodiAndKent
    Near Emily and Haley's house 1 EmilyAndHaley
    Near Lewis' house 2 Mayor
    Near Museum 3 Museum
    Near Clint's blacksmith 4 Blacksmith
    Near the Saloon 5 Saloon
    Near Evelyn and George's house 6 Evelyn
    Near JojaMart 7 JojaMart

    Custom map actions

    These docs should be merged into Modding:Maps. When copying content, make sure you attribute the original authors.

    C# mods can now handle custom Action & TouchAction map properties by calling GameLocation.RegisterTileAction & RegisterTouchAction, and passing a callback which receives the location, map property arguments, player who activated it, and tile position.

    For example, let's say you want a locked gate which needs a custom key item. You can add a regular TouchAction Example.ModId_UnlockGate map property (e.g. by adding it directly in the map file, or using Content Patcher's EditMap, or using the content API). Then you can just handle the logic from your C# mod:

    internal class ModEntry : Mod
    {
        /// <inheritdoc />
        public override void Entry(IModHelper helper)
        {
            GameLocation.RegisterTouchAction("Example.ModId_UnlockGate", this.HandleUnlockGate);
        }
    
        private void HandleUnlockGate(GameLocation location, string[] args, Farmer player, Vector2 tile)
        {
            const string mailFlag = "Example.ModId_GateUnlocked";
            const string keyId = "Example.ModId_GateKey";
    
            // unlock gate if locked
            if (!player.mailReceived.Contains(mailFlag))
            {
                if (!Game1.player.Items.ContainsId(id, count))
                {
                    Game1.activeClickableMenu = new DialogueBox("This gate is locked. I wonder where the key is?");
                    return;
                }
    
                player.removeFirstOfThisItemFromInventory(keyId);
                player.mailReceived.Add(mailFlag);
            }
    
            // apply open-gate map edit
            // NOTE: this is a quick example which changes the location's current map. If another mod reloads the map
            // (e.g. a content pack editing it), the change will be lost. For persistent changes, you should use the
            // AssetRequested event to apply the change when the map is reloaded.
            IAssetDataForMap mapHelper = this.Helper.GameContent.GetPatchHelper(location.map).AsMap();
            mapHelper.PatchMap(
                this.Helper.Content.Load<Map>("assets/unlocked-gate.tmx"),
                targetArea: new Rectangle((int)tile.X - 1, (int)tile.Y - 1, 2, 2)
            );
        }
    }
    

    As another example, let's say you want the gate to unlock when the player presses the action key. You can add a regular Action Example.ModId_UnlockGate map property (e.g. by adding it directly in the map file, or using Content Patcher's EditMap, or using the content API). Then you can just handle the logic from your C# mod:

    internal class ModEntry : Mod
    {
        /// <inheritdoc />
        public override void Entry(IModHelper helper)
        {
            GameLocation.RegisterTileAction("Example.ModId_UnlockGate", this.HandleUnlockGate);
        }
    
        private bool HandleUnlockGate(GameLocation location, string[] args, Farmer player, Microsoft.Xna.Framework.Point point)
        {
            const string mailFlag = "Example.ModId_GateUnlocked";
            const string keyId = "Example.ModId_GateKey";
    
            // unlock gate if locked
            if (!player.mailReceived.Contains(mailFlag))
            {
                if (!Game1.player.Items.ContainsId(id, count))
                {
                    Game1.activeClickableMenu = new DialogueBox("This gate is locked. I wonder where the key is?");
                    return false;
                }
    
                player.removeFirstOfThisItemFromInventory(keyId);
                player.mailReceived.Add(mailFlag);
            }
    
            // apply open-gate map edit
            // NOTE: this is a quick example which changes the location's current map. If another mod reloads the map
            // (e.g. a content pack editing it), the change will be lost. For persistent changes, you should use the
            // AssetRequested event to apply the change when the map is reloaded.
            IAssetDataForMap mapHelper = this.Helper.GameContent.GetPatchHelper(location.map).AsMap();
            mapHelper.PatchMap(
                this.Helper.Content.Load<Map>("assets/unlocked-gate.tmx"),
                targetArea: new Rectangle((int)point.X - 1, (int)point.Y - 1, 2, 2)
            );
    
            return true;
        }
    }
    

    Custom map layers

    These docs should be merged into Modding:Maps. When copying content, make sure you attribute the original authors.

    You can now add any number of map layers by suffixing a vanilla layer name (i.e. Back, Buildings, Front, or AlwaysFront) with an offset. For example, Back-1 will be drawn before/under Back, and Back2 will be drawn after/over it. You can increment the number to add more layers.

    This only affects layer rendering. Tile properties must still be set on the original layers.

    Custom minecarts

    These docs should be merged into a new doc page. When copying content, make sure you attribute the original authors.

    You can now extend minecarts by editing the Data\Minecarts data asset.

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

    • The key is a unique string ID for the minecart network. When you interact with a minecart, the destinations listed for its network are shown.
    • The value is a model with the fields listed below.
    field effect
    Destinations The destinations which the player can travel to from minecarts in this network. This consists of a list of model with these fields:
    field effect
    Id A unique string ID for this destination within the network.
    DisplayName A tokenizable string for the destination name shown in the minecart menu. You can use the location's display name with the LocationName token (like [LocationName Desert] for the desert).
    TargetLocation The location ID for the destination.
    TargetTile The destination tile position within the location, specified as a model with X and Y fields.
    TargetDirection The direction the player should face after arrival (one of down, left, right, or up).
    Condition (Optional) A game state query which indicates whether this minecart destination is available. Defaults to always available.
    Price (Optional) The gold price that must be paid each time to use this destination. Default none.
    BuyTicketMessage (Optional) If the destination costs money to use, a tokenizable string for the purchase confirmation message shown. If present, {0} is replaced with the purchase price. Defaults to the network's BuyTicketMessage field.
    CustomFields (Optional) The custom fields for this entry.
    UnlockCondition (Optional) A game state query which indicates whether this minecart network is unlocked. Default always enabled.
    LockedMessage (Optional) A tokenizable string for the message shown when interacting with a minecart when the UnlockCondition false. Defaults to an "Out of order" translation.
    ChooseDestinationMessage (Optional) A tokenizable string for the message shown when listing destinations to choose from. Defaults to a "Choose destination:" translation.
    BuyTicketMessage (Optional) When a destination costs money to use, a tokenizable string for the purchase confirmation message shown. If present, {0} is replaced with the purchase price. Defaults to a "Buy a ticket for {0}g?" translation.

    Open a minecart menu

    You can use an Action: MinecartTransport [network ID] [exclude destination ID] map property to open the minecart menu. When the player interacts with the tile, it'll open the menu for the [network ID] network (default Default). if [exclude destination ID] is specified, the matching destination will be hidden from the list (usually because you're at that minecart). For example, the bus stop minecart uses Action: MinecartTransport Default Bus.

    From a C# mod, you can call Game1.currentLocation.ShowMineCartMenu(networkId, excludeDestinationId) which works the same way (except that networkId is required).

    Example

    This Content Patcher content pack adds the Railroad as a minecart destination, complete with a map edit adding a decorative minecart. It is available after the Earthquake has occurred and minecarts have been unlocked.

    {
        "Format": "2.0.0",
        "Changes": [
            // add minecart destination
            {
                "Action": "EditData",
                "Target": "Data/Minecarts",
                "TargetField": [ "Default", "Destinations" ], // for the "Default" network, edit the "Destinations" field
                "Entries": {
                    "Railroad": {
                        "Id": "Railroad",
                        "DisplayName": "[LocationName Railroad]",
                        "Condition": "LOCATION_ACCESSIBLE Railroad",
    
                        "TargetLocation": "Railroad",
                        "TargetTile": { "X": 16, "Y": 39 },
                        "TargetDirection": "down",
                    }
                }
            },
    
            // add decorative minecart
            {
                "Action": "EditMap",
                "Target": "Maps/Railroad",
                "FromFile": "assets/Custom_Railroad_Minecart.tmx",
                "ToArea": { "X": 15, "Y": 35, "Width": 4, "Height": 5 }
            }
        ]
    }
    

    Custom passive festivals

    These docs should be merged into Modding:Festival data or a new doc page. When copying content, make sure you attribute the original authors.

    You can now add or modify passive festivals by editing the Data/PassiveFestivals asset.

    (A passive festival is a festival like the Night Market. They replace a location for a period of time, the player can enter/leave them anytime, and time continues passing while at the festival.)

    Data format

    The Data/PassiveFestivals asset consists of a string → model lookup, where...

    • The key is a unique string ID for the festival.
    • The value is a model with the fields listed below.
    field effect
    DisplayName A tokenizable string for the display name shown on the calendar.
    Season The season when the festival becomes active.
    StartDay
    EndDay
    The days of month when the festival becomes active.
    StartTime The time of day when the festival opens each day.
    StartMessage A tokenizable string for the in-game toast notification shown when the festival begins each day.
    MapReplacements The locations to swap for the duration of the festival. Despite the field name, this swaps locations (e.g. as added by CustomLocations using Content Patcher), and not the location's map asset.

    This is specified as a string → string lookup, where the key is the original location to replace and the value is the new location. Both use the internal location name, as shown by the Debug Mode mod. For example, this swaps the Beach location with BeachNightMarket during the Night Market:

    "MapReplacements": {
        "Beach": "BeachNightMarket"
    }
    
    Condition (Optional) A game state query which indicates whether the festival is enabled (subject to the other fields like StartDay and EndDay). Defaults to always enabled.
    ShowOnCalendar (Optional) Whether the festival appears on the calendar, using the same iridium-star icon as the Night Market. Default true.
    DailySetupMethod
    CleanupMethod
    (Optional) A C# method which applies custom logic when the day starts (DailySetupMethod) and/or overnight after the last day of the festival (CleanupMethod).

    These must be specified in the form <full type name>: <method name> (like ExampleMod.Namespace.Type, ExampleMod: MethodName). The methods must be static, take zero arguments, and return void.

    CustomFields The custom fields for this entry.

    NPC schedules

    When a passive festival is active, NPCs will check for a schedule entry in this order:

    syntax summary
    <festival ID>_<festival day> Applies on the given date. The <festival day> is relative, so 1 matches the festival StartDay.
    Example: NightMarket_3 or marriage_NightMarket_3
    <festival ID> Applies if there's no date-specific entry.
    Example: NightMarket or marriage_NightMarket

    If the NPC is married to a player, they'll add a marriage_ prefix to the keys (like marriage_<festival ID>_<festival day>) and ignore any entry without the prefix.

    Custom weather

    These docs should be merged into Modding:Weather data. When copying content, make sure you attribute the original authors.

    You can now change the weather algorithm by editing location context data, and (with a C# mod) implement custom weathers.

    Fields like Game1.weather and Game1.weatherForTomorrow are now strings to support custom mod weather IDs. The change for vanilla weather has no effect on Content Patcher packs, since the new weather IDs match the ones Content Patcher was using before (i.e. Sun, Rain, Snow, Storm, and Wind). C# mods may also see a Festival weather, while Content Patcher packs will see Sun for it. The constants like Game1.weather_sunny have the new string values (with new constants like Game1.legacy_weather_sunny for the legacy values).

    The base game will treat an invalid weather as sunny. C# mods can implement custom weather effects using normal SMAPI events like UpdateTicked, or by patching methods like Game1.ApplyWeatherForNewDay and Game1.populateDebrisWeatherArray.

    Custom world maps

    See the updated docs at Modding:World map. This section below focuses on what's new in 1.6.
     
    The default world map, with the farm map area highlighted.

    You can now change the world map shown in the game menu by editing the Data/WorldMap asset. This lets you...

    • add custom maps for certain locations;
    • apply texture overlays;
    • add/edit tooltips;
    • set real-time player marker positioning;
    • etc.

    The game's default map is fully defined in Data/WorldMap, including all the display text and conditional changes.

    New map properties

    These docs should be merged into Modding:Maps. When copying content, make sure you attribute the original authors.

    1.6 adds several new map properties.

    Building construction

    property explanation
    CanBuildHere T
    (valid in any outdoor location)
    Whether to allow constructing buildings in this location. The game will adjust automatically to account for it (e.g. Robin will let you choose where to build). See build anywhere in what's new.
    BuildConditions <query>
    (valid in any outdoor location)
    If CanBuildHere is set, an optional game state query which indicates whether building is allowed currently.
    LooserBuildRestrictions T
    (valid in any outdoor location)
    If set, tiles don't need to be marked Buildable T or Diggable T in their properties. Tiles can be blocked with Buildable F instead. The other restrictions still apply.
    ValidBuildRect <x> <y> <width> <height>
    (valid in any outdoor location)
    The tile area within the map where buildings may be placed. If omitted, buildings may be placed in any open space in the map.

    Crops

    property explanation
    AllowGiantCrops T If set with any non-blank value, giant crops can grow in this location (if crops are also allowed per the crop data or PlantableLocations context field).
    DirtDecayChance <chance> The probability that each dirt tile will disappear overnight if it doesn't contain a crop, as a value between 0 (never) and 1 (always). Defaults to 0 (greenhouses), 0.1 (farms), and 1 (anywhere else).

    Farmhouse interior

    property explanation
    FarmHouseStarterGift [<id> [count]]+ The items that should appear in the initial gift box placed in the farmhouse when the save is created. This consists of one or more pairs of item ID (which can be qualified or unqualified) and count. The count is optional on the last entry.

    For example, this will add 10 pufferfish (object 128) and a blobfish mask (hat 56):

    FarmHouseStarterGift (O)128 10 (H)56 1

    If omitted, the default items (usually a 15 parsnip seeds) are added instead.

    Warps & map positions

    property explanation
    AllowWakeUpWithoutBed <allow> Whether the player can wake up in this location without a bed, similar to the island farmhouse. This is typically used with PassOutLocations in Data/LocationContexts.
    DefaultWarpLocation <x> <y>
    (valid in any location)
    The default arrival tile, used when a player or NPC is added to the location without a target tile (e.g. using debug commands like debug warp or debug eventbyid).
    PetBowlLocation <x> <y>
    (valid in the farm)
    The default position of the pet bowl
    SpouseRoomPosition <x> <y>
    (valid in farmhouse)
    The top-left position at which to place the spouse room.
    TravelingCartPosition <x> <y>
    (valid in the forest)
    The top-left position at which to place the Traveling Cart. This is the top-left corner of the collision box, so the roof will extend two tiles above this tile.

    Other map property changes

    These docs should be merged into Modding:Maps. When copying content, make sure you attribute the original authors.
    map property changes
    Arch
    asdf
    Debris
    Fish
    Removed (these were unused).
    FarmHouseFlooring
    FarmHouseFurniture
    FarmHouseStarterSeedsPosition
    FarmHouseWallpaper
    These now work independently. For example, you can now use FarmHouseFlooring without needing to set FarmHouseFurniture too.
    Music Deprecated; use the music fields in Data/Locations instead. This property is only applied if the location has no music in Data/Locations. This was removed from all vanilla maps.
    NPCWarp
    Warp
    Now fault-tolerant. They'll automatically ignore extra spaces, log an informative warning if parsing still fails, and continue with the next warp if possible.
    Stumps Now works in all locations.
    UniquePortrait
    UniqueSprite
    Deprecated; use custom NPC appearances instead. These properties will override NPC appearances. This was removed from all vanilla maps.

    Tile property changes

    These docs should be merged into Modding:Maps. When copying content, make sure you attribute the original authors.
    • You can now override a tile index property by setting it as a tile property.
    • Added new tile properties:
      layer property explanation
      Paths SpawnTree <category> <ID> <Growth stage> <Regrowth stage> Spawns a tree when the map is created. <category> may be either wild or fruit. wild will spawn a wild tree, while fruit will spawn a fruit tree.
    • Added new Action tile properties:
      layer property explanation
      Buildings Action BuildingSilo If a building covers this tile, enables silo interactions on this tile subject to the building's HayCapacity field in Data/Buildings.
      Buildings Action BuildingToggleAnimalDoor If a building covers this tile, opens or closes its animal door.
      Buildings Action Dialogue
      • The message can now be a tokenizable string.
      • Fixed the cursor not changing to the inspection icon when hovering on an Action Dialogue tile.
      Buildings Action Forge Opens the Forge menu.
      Buildings Action None Does nothing. This is used to mark the tile interactive if the click will be handled separately.
      Buildings Action ObeliskWarp <location name> <x> <y> [whether to dismount] Warps the player to the specified location name and position with the Obelisk animation/sound effects.
      Buildings Action OpenShop <shop id> [from direction] [open time] [close time] [owner tile area] Open the shop with the given <shop id>. All arguments besides the ID are optional:
      • [from direction]: if specified, the player must be standing in this direction relative to the shop (one of down, up, left, right, or none). Setting this to none disables the requirement. The default for most vanilla shops is down.
      • [open time] and [close time]: the start & end times in 26-hour format when the shop is available. Interacting with the tile outside those times does nothing.
      • [owner tile area]: if specified, the tile area which must contain one of the shop owners for the shop to be available. For a custom shop, these are defined by its Owners field. This can be specified in two forms: <x> <y> for a single tile, or <x> <y> <width> <height> for a multi-tile area.
      Buildings Action PlayEvent <event id> [check preconditions] [skip if seen] [fallback action] Immediately start an event, subject to the conditions:
      • [check preconditions]: whether to ignore the action if the event's preconditions don't match (one of true or false). Default true.
      • [skip if seen]: whether to ignore the action if the player has already seen the given event. Default true.

      If the event doesn't start for any reason (including the preceding conditions):

      • If [fallback action] is specified, it'll be run as an action. This can be any Action tile property (without the "Action " prefix), like Action PlayEvent 60367 true true PlayEvent 520702 false false to play a different event.
      • Otherwise the action is silently ignored.

      For example, Action PlayEvent 60367 false false will replay the bus arrival event from the start of the game.

    • Added new TouchAction tile properties:
      layer property explanation
      Back TouchAction PlayEvent <event id> [check preconditions] [skip if seen] [fallback action] Equivalent to Action PlayEvent, but activated on touch. Note that [fallback action] is an Action tile property, not a TouchAction tile property.
    • Changed existing tile properties:
      layer property reason
      Back NoSpawn Added NoSpawn false form, which disables any previous NoSpawn property on the tile. For example, this can be used to enable spawning on a tile which has a NoSpawn tile index property.
      TouchAction Bus Removed. This wasn't used by the game or mods.
      TouchAction Emote Fixed error if the specified NPC isn't found.
      Treasure Added Treasure Item <item ID> form which accepts a qualified or unqualified item ID.
      Buildings Action ItemChest
      Action Minecart
      Action RemoveChest
      Removed. These weren't used by the game or mods.
      Action Kitchen Now works in any location (including those without a fridge).

    Other location/map changes

    These docs should be merged into Modding:Maps and other pages as needed. When copying content, make sure you attribute the original authors.
    • Farm data:
      • Added SpawnMonstersByDefault field to Data/AdditionalFarms to set the default value of the 'spawn monsters at night' advanced save option.
      • Fixed crash on new-save screen if the farm type's tooltip has no description.
    • General location data:
      • All locations can now have animals. The IAnimalLocation is now obsolete and implemented by GameLocation.
      • Added new fishing areas to simplify compatibility between fish & map mods (specifically for hilltop farm, wilderness farm, town, and desert).
      • Added a descriptive error when a required location or layer isn't found. Mods can use map.RequireLayer and Game1.RequireLocation to get a location with similar error-checking.
      • Added WarpPathfindingCache for C# mods, which modularizes the NPC warp route logic. You can edit its IgnoreLocationNames, OverrideTargetNames, and GenderRestrictions fields if needed for custom locations.
      • Game logic which checks tile indexes is now more fault-tolerant, so it won't crash if an expected tile was edited.
      • Finished migrating DecoratableLocation flooring/wallpaper areas to string IDs (started in Stardew Valley 1.5.5).
    • General map changes:
    • Location context data:
      • Building interiors now inherit their parent's location context by default.
      • Added Game1.locationContextData to cache the data from Data/LocationContexts.
      • Added constants for the vanilla context IDs like LocationContexts.IslandId.
      • Added validation for required location context IDs (and LocationContexts.Require(id) for mod logic).
      • Removed the Name field in Data/LocationContexts, which duplicated the ID.
    • Added methods to simplify common operations:
      type method effect
      Building GetParentLocation Get the location which contains this building.
      IsInCurrentLocation Get whether the building is in the same location as the current player.
      HasIndoors Get whether the building has an interior location.
      GetIndoors Get the location within this building, if applicable.
      HasIndoorsName Get whether the building has an interior location and its unique name matches the given value (like building.HasIndoorsName("FarmHouse")).
      GetIndoorsName Get the unique name of the location within this building, if applicable.
      ... see also other building changes for non-location methods.
      Cabin
      FarmHouse
      GetCellar Get the cellar location linked to this cabin, if any.
      CanAssignFarmhand
      AssignFarmhand
      (Cabin only) Check whether the cabin is available to assign to a farmhand, or perform the assignment.
      HasOwner Get whether the home has an assigned player, regardless of whether they've finished creating their character.
      OwnerId Get the unique ID of the player who owns this home, if any.
      IsOwnedByCurrentPlayer Get whether the cabin belongs to the current player.
      IsOwnerActivated Get whether the home has an assigned player and they've finished creating their character.
      HasNpcSpouse Get whether the player who owns this home is married to any NPC (when used like HasNpcSpouse()) or a specific NPC (like HasNpcSpouse(name)). This also replaces shouldShowSpouseRoom().
      Farm GetStarterFarmhouseLocation Get the default tile position for the farmhouse. (See also farm.GetMainFarmHouseEntry().)
      GetStarterPetBowlLocation Get the default tile position for the pet bowl.
      GameLocation AddDefaultBuildings Can be overridden to add custom buildings when the location is created and/or loaded. These can either be re-added whenever they're missing (like the vanilla farmhouse), or only built once on save creation (like the vanilla pre-built cabins).

      This replaces the former farm.AddModularShippingBin() method.

      GetFridge
      GetFridgePosition
      Get the fridge's chest or tile position, if the location has one.
      GetSeason
      GetSeasonIndex
      GetSeasonKey
      Get the local season that applies within the location as an enum, number (like 0 for spring), or string (like spring) respectively. For example, it's always summer on Ginger Island.
      GetWeather
      IsDebrisWeatherHere
      IsLightningHere
      IsRainingHere
      IsSnowingHere
      Get the current weather in this location's context, regardless of whether the player is indoors and sheltered from it.
      InDesertContext
      InIslandContext
      InValleyContext
      Get whether this location is within the Island or Default location context respectively.
      IsActiveLocation Get whether this location is actively synced to the current player (see farmhand shadow world).
      IsTemporary Get whether this is a temporary location for a festival or minigame. This is cached based on the location name (e.g. locations starting with Temp or some other specific names).
      GetLocationContextId Get the ID of the location context in Data/LocationContexts which contains this building.
      GetContainingBuilding Get the building instance which contains this location (like the cabin for a cabin interior), if applicable.
      GetParentLocation Get the parent location which contains this one (like the farm for a cabin interior), or null if it has no parent.
      GetRootLocation Get the parent location which contains this one (like the farm for a cabin interior), or the location itself if it has no parent.
      GetInstancedBuildingInteriors Get all building interiors within this location which are instanced to the building (i.e. not in Game1.locations separately).
      GetMapPropertySplitBySpaces
      GetTilePropertySplitBySpaces
      Get the value of a map/tile property and split it into individual words. If the map/tile property isn't defined, returns an empty array.

      For example:

      string[] fields = Game1.currentLocation.GetMapPropertySplitBySpaces("ScreenshotRegion");
      
      HasMapPropertyWithValue Get whether a map property is defined and has a non-empty value.

      For example:

      bool canUseCasks = Game1.currentLocation.HasMapPropertyWithValue("CanCaskHere");
      
      StoreHayInAnySilo Add hay to any silo with free space (preferring silos in the current location, then the farm, then anywhere).
      TryGetMapProperty Get a map property value as a string, if it's defined.

      For example:

      if (this.TryGetMapProperty("Warps", out string warps))
      {
          // ...
      }
      
      TryGetMapPropertyAs Get a map property and parse it into into a bool, double, Point, Rectangle, or Vector2 value.

      For example:

      if (!this.TryGetMapPropertyAs("MailboxLocation", out Point position))
      {
          position = new Point(68, 16); // default value
      }
      
      removeObjectsAndSpawned Remove all objects, bushes, resource clumps, and terrain features within a tile area.
      OnBuildingConstructed
      OnBuildingMoved
      OnBuildingDemolished
      These methods are called for all players when any player constructs, moves, or demolishes a building.
      LibraryMuseum HasDonatedArtifacts() Get whether any items have been donated to the museum.
      HasDonatedArtifactAt(tile) Get whether any donated item is currently placed at the given tile position within the museum.
      HasDonatedArtifact(itemId) Get whether an artifact with the given qualified or unqualified item ID has been donated to the museum.
      MineShaft GetLevelName Get the location name for a generated mine or Skull Cavern level.

      For example:

      string locationName = MineShaft.GetLevelName(10); // returns "UndergroundMine10"
      Game1.warpFarmer(locationName, 0, 0, false);
      
      IsGeneratedLevel Get whether a location or location name is a generated mine or Skull Cavern level.

      For example:

      string locationName = "UndergroundMine10";
      bool isMine = MineShaft.IsGeneratedLevel(locationName, out int level); // returns true, 10
      
      VolcanoDungeon GetLevelName
      IsGeneratedLevel
      Equivalent to the matching MineShaft methods, but for the Volcano Dungeon.
    • Added map/tile property TryAdd/TryGetValue extensions in StardewValley.Extensions for string property values. For example, this lets you do map.Properties.TryGetValue(key, out string value).
    • MineShaft.tryToAddMonster now returns whether a monster was added.
    • Game1.GetNumberBuildingsConstructed and location.getNumberBuildingsConstructed now have overloads to count all building types and/or specify whether to count under-construction buildings.
    • Fixed location.refurbishMapPortion copying Back source properties to the Building target layer.
    • Fixed door warps in custom indoor locations not consistently detected by the game.

    What's new for buildings

    Custom buildings

    These docs should be merged into Modding:Blueprint data. When copying content, make sure you attribute the original authors.

    You can now add custom buildings by editing the Data/Buildings asset. This consists of a string → model lookup, where...

    • The key is a unique string ID for the building type.
    • The value is a model with the fields listed below.

    Required fields

    field effect
    Name
    Description
    A tokenizable string for the display name and description (e.g. shown in the construction menu).
    Texture The asset name for the texture under the game's Content folder.

    Construction

    field effect
    Builder (Optional) The NPC from whom you can request construction. The vanilla values are Robin and Wizard, but you can specify a different name if a C# mod opens a construction menu for them. Defaults to Robin. If omitted, it won't appear in any menu.
    BuildCost (Optional) The gold cost to construct the building. Defaults to data-sort-value="0"> 0g.
    BuildMaterials (Optional) The materials you must provide to start construction, as a list of models with these fields:
    field effect
    Id (Optional) The unique string ID for this entry within the current list. Defaults to the ItemId if not specified.
    ItemId The required item ID (qualified or unqualified).
    Amount The number of the item required.
    BuildDays (Optional) The number of days needed to complete construction (e.g. 1 for a building completed the next day). If set to 0, construction finishes instantly. Defaults to 0.
    BuildCondition (Optional) A game state query which indicates whether the building should be available in the construction menu. Defaults to always available.
    BuildMenuDrawOffset (Optional) A pixel offset to apply to the building sprite when drawn in the construction menu. Default none.
    AdditionalPlacementTiles (Optional) The extra tiles to treat as part of the building when placing it through the construction menu. For example, the farmhouse uses this to make sure the stairs are clear. This consists of a list of models with these fields:
    field effect
    TileArea The tile area relative to the top-left corner of the building, specified as an object with X, Y, Width, and Height fields.
    OnlyNeedsToBePassable (Optional) Whether this area allows tiles that would normally not be buildable, so long as they are passable. For example, this is used to ensure that an entrance is accessible. Default false.
    IndoorItems (Optional) The items to place in the building interior when it's constructed or upgraded. This consists of a list of models with these fields:
    field effect
    Id The unique string ID for this entry within the current list.
    ItemId The qualified item ID for the item to place.
    Tile The tile position at which to place the item, specified as an object with X and Y fields.
    Indestructible (Optional) Whether to prevent the player from destroying, picking up, or moving the item. Default false.
    MagicalConstruction (Optional) Whether the building is magical. This changes the carpenter menu to a mystic theme while this building's blueprint is selected, and completes the construction instantly when placed.
    AddMailOnBuild (Optional) A list of letter IDs to send to all players when the building is constructed for the first time.

    Upgrades

    field effect
    BuildingToUpgrade (Optional) The ID of the building for which this is an upgrade, or omit to allow constructing it as a new building. For example, the Big Coop sets this to "Coop". Any numbers of buildings can be an upgrade for the same building, in which case the player can choose one upgrade path.
    IndoorItemMoves (Optional) When applied as an upgrade to an existing building, the placed items in its interior to move when transitioning to the new map. This is a list of models with these fields:
    field effect
    Id The unique string ID for this entry within the current list.
    Source The tile position on which any item will be moved.
    Destination The tile position to which to move the item.
    Size (Optional) The tile size of the area to move, specified as a model with X and Y fields. Defaults to a 1×1 area. If this is multiple tiles, the Source and Destination specify the top-left coordinate of the area.
    UpgradeSignTile (Optional) The tile position relative to the top-left corner of the building where the upgrade sign will be placed when Robin is building an upgrade, in the form "<x>, <y>". Defaults to approximately "5, 1" if the building interior type is Shed, else "0, 0".
    UpgradeSignHeight (Optional) The pixel height of the upgrade sign when Robin is building an upgrade. Defaults to 0.

    Exterior behavior

    field effect
    Size (Optional) The building's width and height when constructed, measured in tiles. Defaults to a 1 x 1 area.
    CollisionMap (Optional) An ASCII text block which indicates which of the building's tiles the players can walk onto, where each character can be X (blocked) or O (passable). Defaults to all tiles blocked.

    For example, a stable covers a 2x4 tile area with the front two tiles passable:

    XXXX
    XOOX

    When the collision map is parsed, leading/trailing whitespace is trimmed (both for the entire map and for each line). In JSON, you can specify it in two forms:

    // single line with \n line breaks
    "CollisionMap": "XXXX\nXOOX"
    
    // multi-line with optional indentation
    "CollisionMap": "
        XXXX
        XOOX
    "
    
    HumanDoor (Optional) The position of the door that can be clicked to warp into the building interior. This is measured in tiles relative to the top-left corner tile. Defaults to disabled.
    AnimalDoor (Optional) The position and size of the door that animals use to enter/exit the building, if the building interior is an animal location, specified as an object with X, Y, Width, and Height fields. This is measured in tiles relative to the top-left corner tile. Defaults to disabled.
    AnimalDoorOpenDuration
    AnimalDoorCloseDuration
    (Optional) The duration of the open/close animation for the animal door, measured in milliseconds. If omitted, the door switches to the open/closed state instantly.
    AnimalDoorOpenSound
    AnimalDoorCloseSound
    (Optional) The sound which is played once each time the animal door is opened/closed. Disabled by default.

    Exterior appearance

    field effect
    SourceRect (Optional) The building's pixel area within the Texture, specified as an object with X, Y, Width, and Height fields. Defaults to the entire texture.
    Skins (Optional) The appearances which can be selected from Robin's menu (like stone/plank/log cabins), in addition to the default appearance based on Texture. This consists of a list of models with these fields:
    field effect
    Id The unique string ID for the skin.
    Name
    Description
    Tokenizable strings for the skin's display name and description.
    Texture The asset name for the texture under the game's Content folder.
    Condition (Optional) A game state query which indicates whether this skin should be available to apply. This doesn't change buildings which already have it applied. Defaults to always true.
    BuildDays
    BuildCost
    BuildMaterials
    (Optional) If set, overrides the equivalent field in the building data.
    ShowAsSeparateConstructionEntry (Optional) Whether this skin should be shown as a separate building option in the construction menu (like cabins). Default false.
    Metadata (Optional) Equivalent to the Metadata field on the building. Properties defined in this field are added to the building's metadata when this skin is active, overwriting the previous property with the same name if applicable. Default none.
    FadeWhenBehind (Optional) Whether the building should become semi-transparent when the player is behind it. Default true.
    DrawOffset (Optional) A pixel offset applied to the building sprite's placement in the world. Default 0.
    SeasonOffset (Optional) A pixel offset to apply each season. This is applied to the SourceRect position by multiplying the offset by 0 (spring), 1 (summer), 2 (fall), or 3 (winter). Default 0, so all seasons use the same source rect.
    SortTileOffset (Optional) A Y tile offset applied when figuring out render layering. For example, a value of 2.5 will treat the building as if it was 2.5 tiles further up the screen for the purposes of layering. Default 0.
    DrawLayers (Optional) A list of textures to draw over or behind the building, with support for conditions and animations. This consists of a list of models with these fields:
    field effect
    Id The unique string ID for this entry within the current list.
    SourceRect The pixel area within the texture to draw, formatted like "<x> <y> <width> <height>". If the overlay is animated via FrameCount, this is the area of the first frame.
    DrawPosition The tile position at which to draw the top-left corner of the texture, relative to the building's top-left corner tile.
    Texture (Optional) The asset name of the texture to draw. Defaults to the building's default Texture field.
    DrawInBackground (Optional) Whether to draw the texture behind the building sprite (i.e. underlay) instead of over it.
    SortTileOffset (Optional) A Y tile offset applied when figuring out render layering. For example, a value of 2.5 will treat the texture as if it was 2.5 tiles further up the screen for the purposes of layering. Default 0.
    OnlyDrawIfChestHasContents (Optional) The ID of a chest defined in the Chests field which must contain items. If it's empty, this overlay won't be rendered. Default none.
    FrameCount
    FramesPerRow
    FrameDuration
    (Optional) If FrameCount is more than one, the building overlay will be animated automatically. For each frame, the SourceRect will be offset by its Width to the right up to FramesPerRow - 1 times, and then down by its Height. Each frame will be rendered on-screen for FrameDuration milliseconds before switching to the next frame.

    For example, if you set FrameCount to 6 and FramesPerRow to 3, the building will expect the frames to be laid out like this in the spritesheet (where frame 1 matches SourceRect):

    ┌───┬───┬───┐
    │ 1 │ 2 │ 3 │
    ├───┼───┼───┤
    │ 4 │ 5 │ 6 │
    └───┴───┴───┘
    
    AnimalDoorOffset (Optional) A pixel offset applied to the draw layer when the animal door is open. While the door is opening, the percentage open is applied to the offset (e.g. 50% open = 50% offset).
    DrawShadow (Optional) Whether to draw an automatic shadow along the bottom edge of the building's sprite. Default true.

    Interior

    field effect
    IndoorMap (Optional) The name of the map asset under Maps to load for the building interior. For example, "Shed" will load the shed's Maps/Shed map.
    IndoorMapType (Optional) The full name of the C# location class which will manage the building's interior location. This must be one of the vanilla types to avoid a crash when saving. There are too many to list here, but the most useful types are likely...
    • StardewValley.AnimalHouse;
    • StardewValley.Locations.Cabin;
    • StardewValley.Locations.Cellar;
    • StardewValley.Locations.DecoratableLocation;
    • StardewValley.Locations.FarmCave;
    • StardewValley.Locations.FarmHouse;
    • StardewValley.Shed;
    • and StardewValley.SlimeHutch.

    Defaults to the generic StardewValley.GameLocation class.

    NonInstancedIndoorLocation (Optional) The name of the existing global location to treat as the building's interior, like FarmHouse and Greenhouse for their buildings.

    Each location can only be used by one building. If the location is already in use (e.g. because the player has two of this building), each subsequent building will use the IndoorMap and IndoorMapType instead. For example, the first greenhouse will use the global Greenhouse location, and any subsequent greenhouse will use a separate instanced location.

    MaxOccupants (Optional) The maximum number of animals who can live in this building.
    AllowAnimalPregnancy (Optional) Whether animals can get pregnant and produce offspring in this building. Default false.
    ValidOccupantTypes (Optional) A list of building IDs whose animals to allow in this building too. For example, [ "Barn", "Coop" ] will allow barn and coop animals in this building. Default none.

    Item processing

    field effect
    HayCapacity (Optional) The amount of hay that can be stored in this building. If built on the farm, this works just like silos and contributes to the farm's available hay.
    ItemConversions (Optional) The item processing rules which take input items and convert them into output items using the inventories defined by Chests. This consists of a list of models with these fields:
    field effect
    Id The unique string ID for this rule within the current list.
    RequiredTags A list of context tags to match against an input item. An item must have all of these tags to be accepted.
    SourceChest The ID of the inventory defined in Chests from which to take input items.
    DestinationChest The ID of the inventory defined in Chests in which to store output items.
    ProducedItems The output items produced when an input item is converted. This consists of a list of models with these fields:
    field effect
    common fields See item spawn fields for the generic item fields supported by machine output.

    If set to an item query which returns multiple items, one of them will be selected at random.

    Chance (Optional) The probability that the item will be produced, as a value between 0 (never drops) and 1 (always drops). Default 1 (100% chance).
    RequiredCount (Optional) The number of the input item to consume. Default 1.
    MaxDailyConversions (Optional) The maximum number of the input item which can be processed each day. Each conversion rule has its own separate maximum (e.g. if you have two rules each with a max of 1, then you can convert one of each daily). Set to -1 to allow unlimited conversions. Default 1.
    Chests (Optional) The input/output inventories that can be accessed from a tile on the building exterior. The allowed items are defined by the separate ItemConversions field. This is a list of models with these fields:
    field effect
    Id The unique string ID for this chest within the current list.

    This is referenced from the ItemConversions field.

    Type The inventory type. This must be one of:
    • Chest: show a normal chest UI on click.
    • Collect: provides items for the player to collect. Clicking the tile will do nothing (if empty), grab the item directly (if it only contains one item), else show a grab-only inventory UI.
    • Load: lets the player add items for the building to process.
    Sound (Optional) The sound to play once when the player clicks the chest.
    InvalidItemMessage
    InvalidCountMessage
    ChestFullMessage
    (Optional) A tokenizable string to show when the player tries to add an item to the chest when...
    • it isn't a supported item;
    • it's supported but they don't have enough in their inventory;
    • the chest has no more room to accept it.

    If omitted, the player interaction is ignored with no message shown.

    InvalidItemMessageCondition (Optional) A game state query which indicates whether InvalidItemMessage should be shown. This can use item-related queries like ITEM_TYPE. Defaults to always true.
    DisplayTile (Optional) The chest's position on the building exterior, measured in tiles from the top-left corner of the building, specified in the form "<x>, <y>". This affects the position of the 'item ready to collect' bubble. If omitted, the bubble is disabled.
    DisplayHeight (Optional) If DisplayTile is set, the chest's tile height like 1.5.

    Tile interactions

    field effect
    ActionTiles (Optional) A list of tiles which the player can click to trigger an Action map tile property. This consists of a list of models with these fields:
    field effect
    Id The unique string ID for this entry within the current list.
    Tile The tile position, relative to the building's top-left corner tile.
    Action The tokenizable string for the action to perform, excluding the Action prefix. For example, "Dialogue Hi there @!" to show a messagebox like "Hi there <player name>!". The tokenizable string is expected before the action is raised. See the list of tile properties for useful Action values.
    DefaultAction (Optional) The default tile action if the clicked tile isn't in ActionTiles. Default none.
    TileProperties (Optional) The map tile properties to set. This consists of a list of models with these fields:
    field effect
    Id The unique string ID for this entry within the current list.
    Name The tile property name to set.
    Value (Optional) The tile property value to set, or omit to set a null value.
    Layer The name of the map layer whose tiles to change.
    TileArea The tiles to which to add the property, relative to the top-left corner of the building's collision box. This is specified as an object with X, Y, Width, and Height fields.
    AdditionalTilePropertyRadius (Optional) When checking whether the player clicked on a TileProperties tile, an added distance around the building at which tile locations may be placed. Default 0, so only tile properties within the normal building bounds will work.

    Advanced

    field effect
    Metadata (Optional) A list of custom properties applied to the building, which can optionally be overridden per-skin in the Skins field. Default none.

    The base game recognizes these properties:

    property description
    ChimneyPosition: <x> <y> (Optional) The pixel position at which to place a chimney on the building exterior, relative to the top-left corner of the sprite. This will apply the same logic as the farmhouse chimney (e.g. producing smoke if there's a lit fireplace inside the building).
    ChimneyPosition[upgrade level]: <x> <y> (Optional, for farmhouses/cabins only) Override ChimneyPosition for the given upgrade level, starting from 0 for the initial farmhouse/cabin. If there's no override for the current upgrade level, the highest override for a lower upgrade level is used (if any). For example, ChimneyPosition3 would be used for the third house upgrade (and the fourth if there's no ChimneyPosition4).

    This can also contain arbitrary custom properties, which C# mods can read using building.GetMetadata(key).

    BuildingType (Optional) The full name of the C# type to instantiate for the building instance. Defaults to a generic Building instance.

    ⚠ Caution: this is meant to support vanilla building types like StardewValley.Shed. Setting this to a non-vanilla type will cause a crash when it's written to the save file, and may cause crashes in multiplayer. If you need custom behavior, consider handling it in C# based on the building type instead of creating a custom subclass; otherwise you'll need a framework mod like SpaceCore to handle serialization and multiplayer sync.

    ModData (Optional) A string → string lookup of arbitrary modData values to attach to the building when it's constructed.
    CustomFields The custom fields for this entry.

    Build anywhere

    These docs should be merged into Modding:Blueprint data and Modding:Maps. When copying content, make sure you attribute the original authors.
    • You can now allow building construction for any location using the new CanBuildHere and related map properties. The game will adjust accordingly (e.g. Robin will let you choose where to construct the building).
    • Buildings and animals are no longer hardcoded to the farm location (except cabins and the farmhouse which still are).
    • Scything hay will now add hay to silos in any location, and animals will be auto-fed from hay in any location.

    Other building changes

    These docs should be merged into Modding:Blueprint data. When copying content, make sure you attribute the original authors.
    See also: other location changes for location-related building changes.
    General building changes
    • Building display names & descriptions are now in Strings/Buildings for reuse.
    • Removed Data/Blueprints. This has been replaced by Data/Buildings (building data) and Strings/Buildings (display names & descriptions).
    • Added methods to simplify common operations:
      type method effect
      Building CreateInstanceFromId Create a building instance from its type ID in Data/Buildings. For example:
      Building shippingBin = Building.CreateInstanceFromId("Shipping Bin", Vector2.Zero); // creates an instance of StardewValley.Buildings.ShippingBin
      
      GetData
      TryGetData
      Get the data for the building's type from Data/Building.
      GetMetadata Get a value from the Metadata field in Data/Buildings for this building.
      GetPaintDataKey Get the key in Data/PaintData for this building, if it has any.
      ReloadBuildingData Apply the latest data in Data/Buildings to this building.
      FinishConstruction If the building is being constructed or upgrade, instantly finish doing so.
      UpdateTransparency Update the building transparency on tick for the local player's position.

      This method mainly exists to let mods override/patch the transparency logic.

      Farm GetMainFarmHouse Get the main farmhouse building.
      GameLocation OnParentBuildingUpgraded Called when the building containing this location is upgraded, if applicable.
    • Added building id field, which uniquely identifies each building in the world.
    Junimo hut changes
    • The JunimoHut.cropHarvestRange field is now per-building and editable.
    Fish pond changes
    • In Data/FishPondData, added a Precedence field which sets the order in which entries are checked for a match (with lower values checked first). This ensures that the fallback entries are checked after specific fish. For consistency, vanilla entries use these values:
      precedence used for
      0
      (default value)
      specific fish
      100 custom groups (e.g. desert fish)
      500 broad fish type (e.g. ocean fish)
      1000 fallback (e.g. fish category)
    • In Data/FishPondData, the reward ItemId can now be an item query.
    • Legendary fish can now be added to fish ponds if they have an entry in Data/FishPondData.

    What's new for NPCs

    Custom NPCs

    These docs should be merged into Modding:NPC data. When copying content, make sure you attribute the original authors.

    Custom NPC data has been overhauled in 1.6. The new Data/Characters asset (which replaces Data/NPCDispositions + Data/spousePatios + Data/spouseRooms) uses a data model format that's easier to edit and understand, and has a lot of fields to customize previously-hardcoded data.

    Format

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

    • The key is a unique string ID for the NPC like Example.ModId_NpcName, which will be used as the internal Name (not DisplayName).
    • The value is a model with the following fields.
    Basic info:
    field effect
    DisplayName A tokenizable string for the NPC's display name.
    Language (Optional) The language spoken by the NPC. One of Default (the default language understood by the player) or Dwarvish (which the player can only understand after finding the Dwarvish translation guide). Default Default.
    Gender (Optional) The NPC's gender identity. One of Female, Male, or Undefined. Default Undefined.
    Age (Optional) The general age of the NPC. One of Child, Teen, or Adult. Default Adult.

    This affects generated dialogue lines (e.g. a child might say "stupid" and an adult might say "depressing"), generic dialogue (e.g. a child might respond to dumpster diving with "Eww... What are you doing?" and a teen would say "Um... Why are you digging in the trash?"), and the gift they choose as Feast of the Winter Star gift-giver. Children are also excluded from item delivery quests.

    Manner (Optional) A measure of the character's general politeness, which affects some generic dialogue lines. One of Neutral, Polite, or Rude. Default Neutral.
    SocialAnxiety (Optional) A measure of the character's comfort with social situations, which affects some generic dialogue lines. One of Neutral, Outgoing, or Shy. Default Neutral.
    Optimism (Optional) A measure of the character's overall optimism. One of Neutral, Negative, or Positive. Default Neutral.
    BirthSeason (Optional if non-social) The season name (case-sensitive) for the NPC's birthday. One of spring, summer, fall, or winter. Default none.
    BirthDay (Optional if non-social) The day number for the NPC's birthday. Default 0.
    HomeRegion (Optional) The region of the world in which the NPC lives (one of Desert, Town, or Other). For example, only Town NPCs are counted for the introductions quest, can be selected as a secret santa for the Feast of the Winter Star, or get a friendship boost from the Luau. Default Other.
    IsDarkSkinned (Optional) Whether the NPC has dark skin, which affects the chance of children with the player having dark skin too. Default false.
    Social features:
    field effect
    CanSocialize (Optional) A game state query which indicates whether to enable social features (like birthdays, gift giving, friendship, and an entry in the social tab). Default true.
    CanBeRomanced (Optional) Whether the NPC can be dated and romanced. This enables romance features for this NPC (like a 'single' label in the social menu, bouquet gifting, and marriage). Default false.
    CanReceiveGifts (Optional) Whether players can give gifts to this NPC. Default true.

    The NPC must also be social per CanSocialize and have an entry in Data/NPCGiftTastes to be giftable, regardless of this value.

    CanCommentOnPurchasedShopItems (Optional) Whether this NPC can comment on items that a player sold to a shop which then resold it to them. If null (or omitted), this will default to true if their HomeRegion is set to Town.

    The NPC must also be social per CanSocialize to allow it, regardless of this value.

    CanGreetNearbyCharacters (Optional) Whether this NPC can show a speech bubble greeting nearby players or NPCs, and or be greeted by other NPCs. Default true.
    CanVisitIsland (Optional) A game state query which indicates whether the NPC can visit the Ginger Island resort once it's unlocked. Default true.

    The NPC must also be social per CanSocialize to visit the island, regardless of this value.

    LoveInterest (Optional) Unused.
    Calendar (Optional) Determines when the NPC's birthday is shown in the calendar. Possible values:
    value effect
    HiddenAlways They never appear in the calendar.
    HiddenUntilMet Until the player meets them, they don't appear in the calendar.
    AlwaysShown They always appear in the calendar.

    Defaults to AlwaysShown.

    SocialTab (Optional) Determines how the NPC is shown on the social tab when unlocked. Possible values:
    value effect
    HiddenAlways They never appear in the social tab.
    HiddenUntilMet Until the player meets them, they don't appear on the social tab.
    UnknownUntilMet Until the player meets them, their name on the social tab is replaced with "???".
    AlwaysShown They always appear in the social tab (including their name).

    Defaults to UnknownUntilMet.

    SpouseAdopts (Optional) A game state query which indicates whether the player will need to adopt children with this spouse, instead of either the player or NPC giving birth. If null, defaults to true for same-gender and false for opposite-gender spouses.

    The Target player is the one they're married to.

    SpouseWantsChildren (Optional) A game state query which indicates whether the spouse will ask to have children. Defaults to true.

    The Target player is the one they're married to.

    SpouseGiftJealousy (Optional) A game state query which indicates whether the spouse will get jealous of gifts to other NPCs. Defaults to true.

    The Target player is the one they're married to, and the Target item is the one that was gifted.

    SpouseGiftJealousyFriendshipChange (Optional) The friendship point effect when the SpouseGiftJealously is triggered. Default -30.
    SpouseRoom (Optional) The NPC's spouse room in the farmhouse when the player marries them, if applicable. If this is omitted for a marriageable NPC, they'll use Abigail's spouse room by default.

    This consists of a model with these fields:

    field effect
    MapAsset (Optional) The asset name for the spouse room map. The Map/ prefix is added automatically and shouldn't be included. Defaults to spouseRooms.
    MapSourceRect (Optional) The tile area within the MapAsset containing the spouse's room. This should usually be a 6x9 tile area, though the game will try to adjust to a different size. Specified as a model with X, Y, Width, and Height fields. Defaults to (0, 0, 6, 9).
    SpousePatio (Optional) The NPC's patio area on the farm when the player marries them, if any. Default none.

    This consists of a model with these fields:

    field effect
    MapAsset (Optional) The asset name for the patio area. The Map/ prefix is added automatically and shouldn't be included. Defaults to spousePatios.
    MapSourceRect (Optional) The tile area within the MapAsset containing the spouse's patio area. This must be a 4x4 tile area. Specified as a model with X, Y, Width, and Height fields. Defaults to (0, 0, 4, 4).
    SpriteAnimationFrames (Optional) The spouse's animation frames when they're in the patio. Each frame is an array containing [0] the sprite index in their spritesheet, and [1] the optional duration in milliseconds (default 100). If omitted or empty, the NPC won't be animated.

    For example, here is Abigail playing the flute:

    "SpriteAnimationFrames": [
        [16, 500], // show index 16 for 500ms
        [17, 500],
        [18, 500],
        [19]       // if duration is omitted, defaults to 100ms
    ]
    
    SpriteAnimationPixelOffset (Optional) The pixel offset to apply to the NPC's sprite when they're animated in the patio, specified as a model with X and Y fields. This is ignored if the NPC isn't animated via SpriteAnimationFrames. Default none.
    SpouseFloors
    SpouseWallpapers
    (Optional) The floors and wallpapers which the NPC may randomly apply to the farmhouse when married to the player. If omitted or empty, the NPC will randomly choose a base floor (0–39) or wallpaper (0–111).
    IntroductionsQuest (Optional) Whether to include this NPC in the introductions quest. If null (or omitted), this will default to true if the HomeRegion field is set to Town.
    ItemDeliveryQuests (Optional) A game state query which indicates whether this NPC can give item delivery quests. If null (or omitted), this will default to true if the HomeRegion field is set to Town.

    The NPC must also be social per CanSocialize to allow it, regardless of this value.

    PerfectionScore (Optional) Whether to include this NPC when checking whether the player has max friendships with every NPC for the perfection score. Default true.

    The NPC must also be social per CanSocialize to be counted, regardless of this value.

    EndSlideShow (Optional) How the NPC appears in the end-game perfection slide show. Possible values:
    value effect
    Hidden The NPC doesn't appear in the slide show.
    MainGroup The NPC is added to the main group of NPCs which walk across the screen.
    TrailingGroup The NPC is added to the trailing group of NPCs which follow the main group.

    Defaults to MainGroup.

    FriendsAndFamily (Optional) The NPC's closest friends and family, as a dictionary where the key is the other NPC's internal name and the value is an optional tokenizable string for the name to use in dialogue text (like 'mom'). Default none.

    This affects generic dialogue for revealing likes and dislikes to family members, and may affect inlaw_<NPC> dialogues. This isn't necessarily comprehensive.

    Dumpster diving:
    field effect
    DumpsterDiveEmote (Optional) The emote ID to show above the NPC's head when they see a player rummaging through trash. See emote IDs. If omitted or null, the default depends on the NPC's age: a child will show sad (28), a teen will show a question mark (8), and an adult will show angry (12).
    DumpsterDiveFriendshipEffect (Optional) The friendship point change if this NPC sees a player rummaging through trash. Default -25.
    Festivals:
    field effect
    FlowerDanceCanDance (Optional) Whether players can ask the NPC to dance at the Flower Dance festival. The possible values are true (can always ask), false (can never ask), or null (can ask if they're romanceable). Default null.

    If the NPC can dance, you should also add the dance sprite frames and FlowerDance_Decline dialogue text. You can optionally set the FlowerDance_Accept dialogue too (though NPCs have a default accept dialogue if not).

    WinterStarParticipant (Optional) A game state query which indicates whether this NPC can give and receive gifts at the Feast of the Winter Star. If null (or omitted), this will default to true if the HomeRegion field is set to Town.
    WinterStarGifts At the Feast of the Winter Star, the possible gifts this NPC can give to players. A matching entry is selected at random.

    This consists of a list of models with these fields:

    field effect
    common fields See item spawn fields for the generic item fields.

    If set to an item query which returns multiple items, one of them will be selected at random.

    Spawn rules:
    field effect
    UnlockConditions (Optional) A game state query which indicates whether the NPC should be added to the world, checked when loading a save and when ending each day. This only affects whether the NPC is added when missing; returning false won't remove an NPC that's already been added. Defaults to true.
    SpawnIfMissing (Optional) Whether to add this NPC to the world if they're missing (if the UnlockConditions match and HomeLocation is valid). Default true.
    Home (Optional) The default place where this NPC spawns and returns each day. If there are multiple entries, the first matching one is used.

    This consists of a list of models with these fields:

    field effect
    ID The unique string ID for this entry within the current list.
    Location (Optional) The internal name for the home location where this NPC spawns and returns each day. Default none.
    Tile (Optional) The tile position within the home location where this NPC spawns and returns each day. Specified as a model with X and Y fields. Defaults to (0, 0).
    Direction (Optional) The default direction the NPC faces when they start each day. The possible values are down, left, right, and up. Defaults to up.
    Condition (Optional) A game state query which indicates whether this entry can be selected. Default true.
    Appearance & sprite:
    field effect
    TextureName (Optional) The last segment of the NPC's portrait and sprite asset names. For example, set to Abigail to use Portraits/Abigail and Characters/Abigail respectively. Defaults to the internal NPC name.
    Appearance (Optional) The portrait/sprite textures to use.

    This can list any number of appearance options. They'll be sorted by Precedence value (with lower values taking priority), then filtered to those whose fields match. If multiple matching appearances have precedence, one entry is randomly chosen based on their relative weight. This randomization is stable per day, so the NPC always makes the same choice until the next day. If a portrait/sprite can't be loaded (or no appearances match), the NPC will use the default asset based on TextureName.

    The NPC rechecks this field each time they change location.

    This consists of a list of models with these fields:

    field effect
    Id The unique string ID for this entry within the current list.
    Season (Optional) The season in which this appearance should be used (one of spring, summer, fall, or winter), or omit for any season. Defaults to any season.
    Indoors
    Outdoors
    (Optional) Whether this appearance should be used when indoors and/or outdoors. Both default to true.
    Condition (Optional) A game state query which indicates whether this entry can be selected. Default true.
    Portrait
    Sprite
    (Optional) The asset name for the portraits and/or sprites texture to load. If omitted or it can't be loaded, it will default to the default asset per the Texture field.
    IsIslandAttire (Optional) Whether this is island beach attire worn at the resort. Default false.

    This is mutually exclusive: NPCs will never wear it in other contexts if it's true, and will never wear it as island attire if it's false.

    Precedence (Optional) The order in which this entry should be checked, where lower values are checked first. This can be a negative value. Default 0.
    Weight (Optional) If multiple entries with the same Precedence match, the relative weight to use when randomly choosing one. Default 1.

    For example, let's say two appearance entries match: one has a weight of 2, and the other has a weight of 1. Their probability of being chosen is 2/3 and 1/3 respectively.

    Note: the default textures based on TextureName must still exist, even if you use this field to override them.

    MugShotSourceRect (Optional) The 16x24-pixel area in the character's sprite texture to show as their mug shot icon in the calendar, social menu, and other contexts. Defaults to part of their first sprite.
    Size (Optional) The pixel size of the individual sprites in their overworld sprite spritesheet. Specified as a model with X and Y fields. Defaults to (16, 32).

    Note: sizes bigger than 16×32 will cause issues like broken spawning, pathfinding, misalignment in the perfection end-game slide show, etc.

    Breather (Optional) Whether the chest on the NPC's overworld sprite puffs in and out as they breathe. Default true.
    BreathChestRect (Optional) A rectangle pixel area within the spritesheet which expands and contracts to simulate breathing, relative to the top-left corner of the source rectangle for their current sprite. Omit to calculate it automatically. This should be omitted for most NPCs, unless they have a non-standard size.
    BreathChestPosition (Optional) A point pixel offset to apply to the NPC's BreathChestPosition when drawn over the NPC. Omit to calculate it automatically. This should be omitted for most NPCs, unless they have a non-standard size.
    Shadow (Optional) The options for the shadow to draw under the NPC, or omit to apply the default shadow behavior.

    This consists of a model with these fields:

    field effect
    Visible (Optional) Whether the shadow should be drawn. Default true.
    Offset (Optional) A point pixel offset applied to the shadow position. Default zero.
    Scale (Optional) The scale at which to draw the shadow. Default 1.

    This is a multiplier applied to the default shadow scale, which can change based on factors like whether the NPC is jumping. For example, 0.5 means half the size it'd be drawn if you didn't specify a scale.

    EmoteOffset (Optional) A point pixel offset applied to emote drawn over the NPC. Default zero.
    ShakePortraits (Optional) The portrait indexes which should shake when displayed. Default none.
    KissSpriteIndex (Optional) If the NPC can be married, the sprite index within their Texture to use when kissing a player. Default 28.
    KissSpriteFacingDirection (Optional) Whether the character is facing right (true) or left (false) in their KissSpriteIndex. The sprite will be flipped as needed to face the player. Default true.
    Hidden gift log emote:
    field effect
    HiddenProfileEmoteSound (Optional) For the hidden gift log emote, the cue ID for the sound played when clicking the sprite. Defaults to drumkit6.
    HiddenProfileEmoteDuration (Optional) For the hidden gift log emote, how long the animation plays measured in milliseconds. Defaults to 4000 (4 seconds).
    HiddenProfileEmoteStartFrame (Optional) For the hidden gift log emote, the index within the NPC's overworld sprite spritesheet at which the animation starts. If omitted for a vanilla NPC, the game plays a default animation specific to that NPC; if omitted for a custom NPC, the game just shows them walking while facing down.
    HiddenProfileEmoteFrameCount (Optional) For the hidden gift log emote, the number of frames in the animation. The first frame corresponds to HiddenProfileEmoteStartFrame, and each subsequent frame will use the next sprite in the spritesheet. Default 1.

    This has no effect if HiddenProfileEmoteStartFrame isn't set.

    HiddenProfileEmoteFrameDuration (Optional) For the hidden gift log emote, how long each animation frame is shown on-screen before switching to the next one, measured in milliseconds. Default 200.

    This has no effect if HiddenProfileEmoteStartFrame isn't set.

    Advanced:
    field effect
    CustomFields The custom fields for this entry.
    FormerCharacterNames (Optional) The former NPC names which may appear in save data. If matched, the game will rename the NPC and update related data (e.g. friendship).

    A former name is only applied if:

    1. it doesn't match a current ID in Data/Characters;
    2. the save has an NPC with the former name;
    3. the save doesn't already have an NPC with the new name.

    For example:

    "FormerCharacterNames": [ "SomeOldName" ]
    

    Former names can have any format, but they must be globally unique. They can't match the ID or FormerCharacterNames of any other NPC in Data/Characters (whether vanilla or custom).

    FestivalVanillaActorIndex (Optional, Specialized) The NPC's index in the Maps/characterSheet tilesheet, if applicable. This is used for placing vanilla NPCs in festivals from the map; custom NPCs should use the <layer>_additionalCharacters field in the festival data instead.

    Examples

    For example, this content pack adds a new Amabel NPC with full social features:

    {
        "Format": "2.0.0",
        "Changes": [
            {
                "Action": "EditData",
                "Target": "Data/Characters",
                "Entries": {
                    "{{ModId}}_Amabel": {
                        "DisplayName": "Amabel", // this would normally use {{i18n:}} to support translations
                        "BirthSeason": "Fall",
                        "BirthDay": 14,
                        "HomeRegion": "Town",
                        "Gender": "Female",
                        "Age": "Teen",
                        "Manner": "Rude",
                        "SocialAnxiety": "Outgoing",
                        "Optimism": "Neutral",
    
                        "CanBeRomanced": true,
                        "LoveInterest": "Abigail",
    
                        "Home": [
                            {
                                "Id": "Default",
                                "Location": "SeedShop",
                                "Tile": { "X": 1, "Y": 9 },
                                "Direction": "Left"
                            }
                        ]
                    }
                }
            }
        ]
    }
    

    You can also add non-social NPCs which don't have birthdays or friendship points, accept gifts, give quests, etc:

    {
        "Format": "2.0.0",
        "Changes": [
            {
                "Action": "EditData",
                "Target": "Data/Characters",
                "Entries": {
                    "{{ModId}}_Belwick": {
                        "DisplayName": "Belwick", // this would normally use {{i18n:}} to support translations
    
                        "SocialTab": "HiddenAlways",
                        "CanSocialize": "FALSE",
                        "IntroductionsQuest": false,
                        "PerfectionScore": false,
                        "EndSlideShow": true
                    }
                }
            }
        ]
    }
    

    Custom NPC appearance

    These docs should be merged into Modding:NPC data. When copying content, make sure you attribute the original authors.

    Each NPC can now have any number of custom portraits/sprites in Data/Characters with arbitrary conditions. This lets mods add features like indoor/outdoor outfits without the performance impact of reloading textures. If multiple outfits apply, the game will choose between them with a day-stable randomization.

    For example, you can load indoor/outdoor outfits for a custom NPC to swap between automatically:

    // add base indoor/outdoor sprites
    {
        "Action": "Load",
        "Target": "Characters/Johnny_Indoor, Characters/Johnny_Outdoor, Portraits/Johnny_Indoor, Portraits/Johnny_Outdoor",
        "FromFile": "assets/{{Target}}.png"
    },
    
    // apply any overlays needed
    {
        "Action": "EditImage",
        "Target": "Characters/Johnny_Indoor, Portraits/Johnny_Indoor",
        "FromFile": "assets/overlays/{{Target}}_married.png",
        "When": {
            "Spouse": "Johnny"
        }
    },
    
    // add NPC
    {
        "Action": "EditData",
        "Target": "Data/Characters",
        "Entries": {
            "SomeMod.Id_Johnny": {
                ...,
                "Appearance": [
                    {
                        "Id": "Outdoors",
                        "Indoors": false,
                        "Portrait": "Portraits/Johnny_Outdoor",
                        "Sprite": "Characters/Johnny_Outdoor"
                    },
                    {
                        "Id": "Default",
                        "Portrait": "Portraits/Johnny_Indoor",
                        "Sprite": "Characters/Johnny_Indoor"
                    }
                ]
            }
        }
    }
    

    See the Appearance field in custom NPC data for more info.

    Custom farm animals

    See the updated docs at Modding:Animal data. This section below focuses on what's new in 1.6.

    You can now create and edit farm animals by editing the revamped Data/FarmAnimals asset. This changes to a data model, adds built-in support for custom animals, and allows far more customizability per animal (like its size, growth, produce, appearance and sounds, etc).

    Custom pets

    These docs should be merged into a new doc page. When copying content, make sure you attribute the original authors.

    Format

    You can now create and customize pets & pet breeds by editing the new Data/Pets asset.

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

    • The key is a unique string ID for the pet (not the pet breed). The vanilla IDs are Cat and Dog.
    • The value is a model with the fields listed below.
    Basic info
    field effect
    DisplayName A tokenizable string for the pet type's display name (e.g. "cat" or "dog"). For example, the vanilla adoption events show this when Marnie asks if you want to adopt the cat/dog.
    Audio & sprites
    field effect
    BarkSound The cue ID for the pet's occasional 'bark' sound.
    ContentSound The cue ID for the sound which the pet makes when you pet it.
    RepeatContentSoundAfter (Optional) The number of milliseconds until the ContentSound is repeated once. This is used by the dog, who pants twice when pet. Defaults to -1 (disabled).
    EmoteOffset (Optional) A pixel offset for the emote drawn above the pet sprite, specified as an object with X and Y fields. For example, this affects the heart emote shown after petting it. Default none.
    Events
    field effect
    EventOffset (Optional) The pixel offset for the pet when shown in events like Marnie's adoption event, specified as an object with X and Y fields. Default none.
    AdoptionEventLocation
    AdoptionEventId
    (Optional) If both fields are set, the location and event ID which lets the player adopt this pet. This forces the event to play after 20 days if its preconditions haven't been met yet. Default Farm and none respectively.
    SummitPerfectionEvent (Optional) How to render the pet during the summit perfection slideshow. If this isn't set, the pet won't be shown in the slideshow.

    This consists of a model with these fields:

    field effect
    SourceRect The source rectangle within the pet's texture to draw.
    AnimationLength The number of frames to show starting from the SourceRect.
    Motion The motion to apply to the pet sprite.
    Flipped (Optional) Whether to flip the pet sprite left-to-right. Default false.
    PingPong (Optional) Whether to apply the 'ping pong' effect to the pet sprite animation. Default false.
    Gifts
    field effect
    GiftChance (Optional) The random probability each day that the pet will give the player a gift from the Gifts list when they interact with the pet. Specified as a value between 0 (never) and 1 (always). Default .2 (20% chance).
    Gifts (Optional) The list of gifts that this pet can give if the GiftChance is successful. Default none.

    This consists of a list of models with these fields:

    field effect
    Id The unique string ID for this entry within the list.
    QualifiedItemID The qualified item ID for the gift item to create.
    Stack (Optional) The stack size of the gift item to produce. Default 1.
    MinimumFriendshipThreshold (Optional) The friendship level that this pet must be at before it can give this gift. Defaults to 1000 (max friendship).
    Weight (Optional) The option's weight when randomly choosing a gift, relative to other gifts in the list (e.g. 2 is twice as likely as 1). Default 1.
    Behavior
    field effect
    Id The unique string ID for this entry within the list.
    MoveSpeed (Optional) How quickly the pet can move. Default 2.
    SleepOnBedChance
    SleepNearBedChance
    SleepOnRugChance
    (Optional) The percentage chances for the locations where the pet will sleep each night, as a decimal value between 0 (never) and 1 (always). Each value is checked in the order listed at left until a match is found. If none of them match, the pet will choose a random empty spot in the farmhouse; if none was found, it'll sleep next to its pet bowl outside.
    Behaviors The pet's possible actions and behaviors, defined as the states in a state machine. Essentially the pet will be in one state at any given time, which also determines which state they can transition to next. For example, a cat can transition from Walk to BeginSitDown, but it can't skip instantly from Walk to SitDownLick.

    This consists of a list of models with these fields:

    Required fields:
    field effect
    Id A unique ID for the state. This only needs to be unique within the pet type (e.g. Cat and Dog can have different behaviors with the same ID).
    Direction:
    field effect
    Direction (Optional) The specific direction to face at the start of this state (one of left, right, up, or down), unless overridden by RandomizeDirection.
    RandomizeDirection (Optional) Whether to point the pet in a random direction at the start of this state (overriding the Direction if specified). Default false.
    IsSideBehavior (Optional) Whether to constrain the pet's facing direction to left and right while the state is active. Default false.
    Movement:
    field effect
    WalkInDirection (Optional) Whether to walk in the pet's facing direction. Default false.
    MoveSpeed (Optional) Overrides the pet's MoveSpeed field while this state is active. Default -1 (which uses the pet's MoveSpeed value).
    Audio:
    field effect
    SoundOnStart (Optional) The audio cue ID for the sound to play when the state starts. If set to BARK, the pet's BarkSound (or breed's BarkOverride) field is used. Defaults to none.
    SoundRange
    SoundRangeFromBorder
    (Optional) When set, the SoundOnStart is only audible if the pet is within this many tiles away from the player (SoundRange) or past the border of the screen (SoundRangeFromBorder). Default -1 (no distance check).
    SoundIsVoice (Optional) Whether to mute the SoundOnStart when the 'mute animal sounds' option is set. Default false.
    Behavior transitions:
    field effect
    AnimationEndBehaviorChanges
    TimeoutBehaviorChanges
    PlayerNearbyBehaviorChanges
    RandomBehaviorChanges
    JumpLandBehaviorChanges
    (Optional) A list of possible behavior transitions to start when the criteria are achieved. If multiple transitions are listed, a random one will be selected. If omitted, it won't affect behavior transitions.

    These are triggered when this behavior's animation finishes (AnimationEndBehaviorChanges), when the set duration ends (TimeoutBehaviorChanges), when the player is within 2 tiles of the pet (PlayerNearbyBehaviorChanges), randomly at the start of each frame based on the RandomBehaviorChangeChance field (RandomBehaviorChanges), and when the pet finishes a jump (JumpLandBehaviorChanges).

    These consist of a list of models with these fields:

    field effect
    Behavior
    LeftBehavior
    RightBehavior
    UpBehavior
    DownBehavior
    The ID of the behavior to start. The pet will check for a behavior field matching its current facing direction first, then try the Behavior. If none are specified, the current behavior will continue unchanged.
    OutsideOnly (Optional) Whether the transition can only happen if the pet is outside. Default false.
    Weight (Optional) The option's weight when randomly choosing a behavior, relative to other behaviors in the list (e.g. 2 is twice as likely as 1). Default 1.
    Duration
    MinimumDuration
    MaximumDuration
    (Optional) The millisecond duration until the pet transitions to a behavior in the TimeoutBehaviorChanges field, if set. You must specify either a specific duration, or an inclusive minimum-to-maximum range in which the game will choose a random duration. If omitted, the behavior won't have a duration limit.
    RandomBehaviorChangeChance (Optional) The random probability at the start of each frame that the pet will transition to a behavior in the RandomBehaviorChanges field, if set. Specified as a value between 0 (never) and 1 (always). Default 0.
    Animation and per-frame sounds:
    field effect
    Animation (Optional) The animation frames to play while this state is active. This consists of a list of models with these fields:
    field effect
    Frame The frame index in the animation. This should be an incremental number starting at 0.
    Duration The millisecond duration for which the frame should be kept on-screen before continuing to the next frame.
    HitGround (Optional) Whether to play the footstep sound for the tile under the pet when the frame starts. Default false.
    Jump (Optional) Whether the pet should perform a small hop when the frame starts, including a 'dwop' sound. Default false.
    Sound (Optional) The audio cue ID for the sound to play when the animation starts or loops. If set to BARK, the pet's BarkSound (or breed's BarkOverride) field is used. Defaults to none.
    SoundRange
    SoundRangeFromBorder
    SoundIsVoice
    See description for the equivalent behavior fields, but applies to the frame's Sound field instead.
    Shake (Optional) The millisecond duration for which to shake the pet when the state starts. Default 0.
    LoopMode (Optional) What to do when the last animation frame is reached while the behavior is still active. The possible values are Hold (keep the last frame visible until the animation ends), Loop (restart from the first frame), or None (equivalent to Loop). Default None.
    AnimationMinimumLoops
    AnimationMaximumLoops
    (Optional) The minimum and maximum number of times to play the animation. Both must be specified to have any effect. The game will choose an inclusive random value between them. Both default to -1 (don't repeat animation).
    Breeds
    field effect
    Breeds The cosmetic breeds which can be selected in the character customization menu when creating a save. This consists of a list of models with these fields:
    field effect
    ID The unique ID for the breed within the pet type.
    Texture The asset name for the breed spritesheet for the pet's in-game sprite. This should be 128 pixels wide, and 256 (cat) or 288 (dog) pixels high.
    IconTexture The asset name for the breed icon texture, shown on the character customization screen and in-game menu. This should be a 16x16 pixel icon.
    IconSourceRect The icon's pixel area within the IconTexture, specified as an object with X, Y, Width, and Height fields.
    BarkOverride (Optional) Override the pet's BarkSound field for this breed, if set.
    VoicePitch (Optional) The pitch applied to the pet's bark sound, measured as a decimal value relative to 1. Defaults to 1.
    Advanced
    field effect
    CustomFields The custom fields for this entry.

    Other changes

    • The pet bowl is now a building which can be constructed or moved. Each pet is assigned to an available pet bowl. For C# mods, each pet now has a guid field populated with a unique ID, and each pet bowl has a petGuid field which tracks its owner (see the PetBowl::HasPet() and PetBowl::FindPet() methods).
    • In the event character setup, you can now use pet to add a pet of the player's selected type. Its actor name will be PetActor in other event commands. This supersedes cat (with name Cat) and dog (with name Dog), though those still work too.
    • For C# mods:
      • All pets now use a generic Pet class, instead of Cat or Dog. The pet type is tracked by the pet's petType field.
      • The player's preferred pet type is tracked by Game1.player.whichPetType. The former catPerson field is now readonly and checks that field.
      • Added Pet.type_cat and Pet.type_dog constants for the default pet types.

    Custom monster eradication goals

    These docs should be merged into a new doc page. When copying content, make sure you attribute the original authors.
    See also: Monster eradication goal flag changes.

    You can now add/edit Adventurer's Guild monster eradication goals by editing the new Data/MonsterSlayerQuests data asset.

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

    • The key is a unique string ID for the monster eradication goal.
    • The value is a model with the fields listed below.
    field effect
    DisplayName A tokenizable string for the goal's display name, shown on the board in the Adventurer's Guild.
    Targets A list of monster IDs that are counted towards the Count.
    Count The total number of monsters (matching the Targets) which must be defeated to complete this goal.
    RewardItemId (Optional) The qualified ID for the item that can be collected from Gil when this goal is completed. Default none.
    RewardItemPrice (Optional) The price of the RewardItemId in Marlon's shop after the goal is completed, or -1 to disable buying it from Marlon. Default -1.
    RewardDialogue
    RewardDialogueFlag
    (Optional) A tokenizable string for custom Gil dialogue shown when talking to him after completing the goal, and an optional mail flag to set when the player has seen the dialogue. Both default to none.

    If there are reward items, they're shown after this dialogue.

    If RewardDialogue is used without RewardDialogueFlag, then this dialogue will be shown each time the reward menu is opened after completing the goal, until the player collects the reward items. If the RewardItems isn't set, this can safely be omitted since the goal will be marked collected immediately.

    This doesn't send a letter; see RewardMail or RewardMailAll for that.

    RewardFlag
    RewardFlagAll
    (Optional) The mail flag ID to set for the current player (RewardFlag) or all players (RewardFlagAll) when talking to Gil after completing the goal. Default none.

    Note that RewardFlag is usually not needed, since the game will also set a Gil_<goal ID> flag regardless.

    This doesn't send a letter; see RewardMail or RewardMailAll for that.

    RewardMail
    RewardMailAll
    (Optional) The mail letter ID to add to the mailbox tomorrow for the current player (RewardMail) or all players (RewardMailAll). Default none.
    CustomFields The custom fields for this entry.

    Custom phone calls

    These docs should be merged into a new doc page. When copying content, make sure you attribute the original authors.

    Mods can now extend the telephone with custom calls (both incoming calls, and phone numbers which the player can call).

    Incoming calls

    You can add or customize incoming calls by editing the Data/IncomingPhoneCalls asset.

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

    • The key is a unique string ID for the incoming call data.
    • The value is a model with the fields listed below.
    field effect
    Dialogue The dialogue text to show when the player answers the phone. This can use the full dialogue format (including questions and different dialogue based on the selected answer).
    FromNpc (Optional) The internal name of the NPC making the call. If specified, that NPC's name and portrait will be shown.
    FromPortrait (Optional) The asset name for the portrait spritesheet to display (like Portraits/Abigail). If FromNpc is specified too, this overrides the portrait from that NPC. If both FromNpc and FromDisplayName are null, this portrait will be shown with the display name "???".
    FromDisplayName (Optional) A tokenizable string for the calling NPC's display name. If FromNpc is specified too, this overrides the display name from that NPC.
    MaxCalls (Optional) The maximum number of times a player can receive this phone call, or -1 for no limit. Default 1.
    TriggerCondition
    RingCondition
    (Optional) If set, a game state query which indicates whether to trigger this phone call (TriggerCondition) or whether the phone rings when this call is received (RingCondition).

    Whether a player receives this call depends on both fields: TriggerCondition is checked on the main player before sending the call to all players, then RingCondition is checked on each player to determine whether the phone rings for them.

    IgnoreBaseChance (Optional) Whether to ignore the 1% base chance when checking whether to trigger an incoming call. If true, the game will check if this call can be received regardless of the base chance. Default false.
    SimpleDialogueSplitBy (Optional, specialized) If set, marks the call as having a simple dialogue string without an NPC name and portrait, with lines split into multiple boxes by this substring. For example, "SimpleDialogueSplitBy": "#" will split Box A#Box B#Box C into three consecutive dialogue boxes.

    You should omit this in most cases, and use the regular dialogue format in Dialogue to split lines if needed. This is mainly intended to support some older vanilla phone calls.

    CustomFields The custom fields for this entry.

    Custom handlers in C#

    C# mods can implement StardewValley.PhoneCalls.IPhoneHandler and add it to Phone.PhoneHandlers for full control over both incoming and outgoing calls:

    /// <summary>The mod entry point.</summary>
    internal sealed class ModEntry : Mod
    {
        /// <inheritdoc />
        public override void Entry(IModHelper helper)
        {
            Phone.PhoneHandlers.Add(new CustomPhoneHandler());
        }
    }
    
    /// <summary>A custom phone handler.</summary>
    internal sealed class CustomPhoneHandler : IPhoneHandler
    {
        ...
    }
    

    See StardewValley.PhoneCalls.DefaultPhoneHandler in the decompiled game code for an example implementation.

    Custom shops

    See the updated docs at Modding:Shops. This section below focuses on what's new in 1.6.

    You can now create and edit shops via the new Data/Shops asset. See Modding:Shops for documentation and examples.

    Dialogue changes

    These docs should be merged into Modding:Dialogue. When copying content, make sure you attribute the original authors.
    • Added new dialogue keys:
      asset key format description
      Characters/Dialogue/<name>
      AcceptBirthdayGift_<id>
      AcceptBirthdayGift_<tag>
      AcceptBirthdayGift_<taste>
      AcceptBirthdayGift_Negative
      AcceptBirthdayGift_Positive
      AcceptBirthdayGift
      Shown when receiving a birthday gift from the player. If omitted, defaults to the generic translations for all NPCs.

      The first matching dialogue is used in this order:

      1. by item ID (like AcceptBirthdayGift_(O)128);
      2. by context tag (like AcceptBirthdayGift_category_fish);
      3. by gift taste (one of AcceptBirthdayGift_Loved, AcceptBirthdayGift_Liked, AcceptBirthdayGift_Neutral, AcceptBirthdayGift_Disliked, or AcceptBirthdayGift_Hated);
      4. AcceptBirthdayGift_Negative (hated or disliked gift) or AcceptBirthdayGift_Positive (neutral, liked, or loved gift);
      5. for all items (via AcceptBirthdayGift).
      AcceptBouquet Shown when the NPC accepts a bouquet from the player. Defaults to a generic dialogue.
      AcceptGift_<id>
      AcceptGift_<tag>
      Shown when receiving a non-birthday gift from the player. This can be by item ID (like AcceptGift_(O)128) or context tag (like AcceptGift_category_fish). If omitted, defaults to the dialogue in Data/NPCGiftTastes.
      DumpsterDiveComment Shown when the NPC catches the player digging through a trash can. Defaults to a generic dialogue based on the NPC's age.
      HitBySlingshot Shown when the player shoots them with a slingshot. Defaults to a generic dialogue.
      RejectBouquet_Divorced
      RejectBouquet_NotDatable
      RejectBouquet_NpcAlreadyMarried
      RejectBouquet_VeryLowHearts
      RejectBouquet_LowHearts
      RejectBouquet
      Shown when the NPC rejects a bouquet.

      A specific dialogue is shown if possible:

      • RejectBouquet_Divorced: the NPC won't accept this bouquet because you divorced them.
      • RejectBouquet_NotDatable: the NPC isn't romanceable.
      • RejectBouquet_NpcAlreadyMarried: the NPC is already married to another player. You can use {0} in the dialogue for the other player's name.
      • RejectBouquet_VeryLowHearts: you have less than 4 hearts with the NPC.
      • RejectBouquet_LowHearts: you have less than 8 hearts with the NPC.

      If the specific dialogue isn't set, the game will use the RejectBouquet dialogue (if set), else it'll default to generic dialogue for each case.

      RejectGift_Divorced Shown when the NPC rejects a gift because you divorced them.
      RejectItem_<id>
      RejectItem_<tag>
      If set, the NPC will refuse to accept any matching item and show this dialogue instead. This can be by item ID (like RejectItem_(O)128) or context tag (like RejectItem_category_fish). This can prevent gifting, movie tickets, bouquets, mermaid pendants, etc. However it won't prevent accepting an item for an active quest or special order.
      RejectMermaidPendant_Divorced
      RejectMermaidPendant_NeedHouseUpgrade
      RejectMermaidPendant_NotDatable
      RejectMermaidPendant_NpcWithSomeoneElse
      RejectMermaidPendant_PlayerWithSomeoneElse
      RejectMermaidPendant_Under8Hearts
      RejectMermaidPendant_Under10Hearts
      RejectMermaidPendant_Under10Hearts_AskedAgain
      RejectMermaidPendant
      Shown when the NPC rejects a mermaid's pendant.

      A specific dialogue is shown if possible. The cases are checked in this order:

      1. RejectMermaidPendant_PlayerWithSomeoneElse: the player is already engaged or married to someone else. You can use {0} in the dialogue for the player's spouse name.
      2. RejectMermaidPendant_NotDatable: the NPC isn't romanceable.
      3. RejectMermaidPendant_Divorced: you divorced them, so they won't accept gifts or proposals from you.
      4. RejectMermaidPendant_NpcWithSomeoneElse: the NPC is already engaged or married to someone else. You can use {0} in the dialogue for the other player's name.
      5. RejectMermaidPendant_Under8Hearts: you have under 8 hearts with the NPC.
      6. RejectMermaidPendant_Under10Hearts: you have under 10 hearts with the NPC.
      7. RejectMermaidPendant_Under10Hearts_AskedAgain: you have under 10 hearts with the NPC, and asked again after they already said no. (Defaults to the previous dialogue if not set.)
      8. RejectMermaidPendant_NeedHouseUpgrade: you need to upgrade your house before they can accept.

      If the specific dialogue isn't set, the game will use the RejectMermaidPendant dialogue (if set), else it'll default to generic dialogue for each case.

      RejectMovieTicket_AlreadyInvitedBySomeoneElse
      RejectMovieTicket_AlreadyWatchedThisWeek
      RejectMovieTicket_Divorced
      RejectMovieTicket_DontWantToSeeThatMovie
      RejectMovieTicket
      Show when the NPC rejects a movie ticket.

      A specific dialogue is shown if possible:

      • RejectMovieTicket_AlreadyInvitedBySomeoneElse: someone else already invited the NPC to a movie. You can use {0} in the dialogue for the other player's name.
      • RejectMovieTicket_AlreadyWatchedThisWeek: the NPC already watched a movie this week.
      • RejectMovieTicket_Divorced: you divorced the NPC, so they won't accept gifts from you.
      • RejectMovieTicket_DontWantToSeeThatMovie: the movie data marks that NPC as unwilling to watch it (e.g. kids for horror movies).

      If the specific dialogue isn't set, the game will use the RejectMovieTicket dialogue (if set), else it'll default to generic dialogue for each case.

      SpouseFarmhouseClutter Shown by an NPC spouse when they couldn't pathfind to their kitchen standing spot in the farmhouse.
      SpouseGiftJealous Shown by an NPC spouse when you gave a gift to another eligible NPC of the same gender as your spouse (unless it's their birthday). You can use {0} in the dialogue for the other NPC's name, and {1} for the gifted item name.
      Spouse_MonstersInHouse Shown by an NPC spouse when they're in the farmhouse and there's a monster close to them.
      SpouseStardrop Shown when receiving the stardrop from your spouse.
      Fair_Judging Shown at the Stardew Valley Fair while Lewis is judging the grange displays. If omitted, the NPC will keep their normal festival dialogue.

      If this is set without Fair_Judged*, the NPC will keep this dialogue after judging is done.

      This replaces the previously hardcoded translations in Strings/StringsFromCSFiles: Event.cs.1602 (Marnie), Event.cs.1604 (Pierre), and Event.cs.1606 (Willy).

      Fair_Judged_PlayerLost_PurpleShorts
      Fair_Judged_PlayerLost_Skipped
      Fair_Judged_PlayerLost
      Fair_Judged_PlayerWon
      Fair_Judged
      Shown at the Stardew Valley Fair after Lewis finishes judging the grange displays.

      The first matching dialogue is used in this order:

      1. Fair_Judged_PlayerLost_PurpleShorts: the player put the lucky purple shorts in their display (which is an automatic loss). Defaults to Fair_Judged_PlayerLost if omitted.
      2. Fair_Judged_PlayerLost_Skipped: the player didn't put anything in their display. Defaults to Fair_Judged_PlayerLost if omitted.
      3. Fair_Judged_PlayerLost or Fair_Judged_PlayerWon: the player didn't/did win first place. Defaults to Fair_Judged if omitted.
      4. Fair_Judged: shown if a more specific dialogue didn't match. If omitted, the NPC will keep their current dialogue.

      These replace the previously hardcoded translations in Strings/StringsFromCSFiles: Event.cs.1591 (Pierre when he won), Event.cs.1593 (Pierre when the player won), Event.cs.1595 (Marnie), Event.cs.1597 (Willy), and Event.cs.1600 (Marnie for the purple shorts).

      FlowerDance_Accept_Roommate
      FlowerDance_Accept_Spouse
      FlowerDance_Accept
      Shown at the Flower Dance when the NPC agrees to dance. The game will prefer the _Roommate (if roommates) or _Spouse (if married) variant if applicable, else it'll check for the normal key. If omitted, defaults to a generic accept dialogue.

      This replaces the previously hardcoded translations in Strings/StringsFromCSFiles (Event.cs.1613, Event.cs.1615, Event.cs.1617, Event.cs.1619, Event.cs.1621, Event.cs.1623, Event.cs.1625, Event.cs.1627, Event.cs.1629, and Event.cs.1631).

      FlowerDance_Decline Shown at the Flower Dance when the NPC declines to dance. This replaces the former danceRejection key (which still works as a fallback).
      WinterStar_GiveGift_Before_Roommate
      WinterStar_GiveGift_Before_Spouse
      WinterStar_GiveGift_Before
      WinterStar_GiveGift_After_Roommate
      WinterStar_GiveGift_After_Spouse
      WinterStar_GiveGift_After
      Shown at the Feast of the Winter Star when the NPC gives the player their gift (before and after the player opens it). The game will prefer the _Roommate (if roommates) or _Spouse (if married) variant if applicable, else it'll check for the normal key. If omitted, the before/after dialogues each separately default to a generic translation for all NPCs.
      WinterStar_ReceiveGift_<id>
      WinterStar_ReceiveGift_<tag>
      WinterStar_ReceiveGift
      Shown at the Feast of the Winter Star when receiving their gift from the player. This can be by item ID (like WinterStar_ReceiveGift_(O)128), context tag (like WinterStar_ReceiveGift_category_fish), or for any item (like WinterStar_ReceiveGift). If omitted, defaults to the generic translation for all NPCs.
      WipedMemory Shown the first time you talk to the NPC after erasing their memory using the Dark Shrine of Memory.
    • Added new dialogue commands:
      command description
      ${male^female}$
      ${male^female^non-binary}$
      Change text depending on the player's gender. This largely supersedes the ^ dialogue token (which still works), and is supported in many more places than that token. This is applied before most other commands or parsing, so it can safely be used in cases where ^ might have a different meaning (e.g. mail text). For example: Ahoy there ${lad^lass}$! or Ahoy there ${lad^lass^matey}$!.

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

      Note that 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.

      $action <action> Run a trigger action string, like $action AddMoney 500 to add data-sort-value="500"> 500g to the current player.
      $query <query>#<if true>|<if false> Show different dialogue text depending on the game state query in <query>. For example:
      "Mon": "$query !PLAYER_VISITED_LOCATION Current Mine#Did you know there's an old abandoned mine up in the mountain? Apparently it's crawling with monsters!|I heard you went into the old mines up in the mountain!#Did you find anything tasty?$h"
      
      $t <topic ID> [day length] Add a conversation topic for the next [day length] days (default 4 days).
      $v <event id> [check preconditions] [skip if seen] Immediately start an event and end the current dialogue, subject to the conditions:
      • [check preconditions]: whether to ignore the command if the event's preconditions don't match (one of true or false). Default true.
      • [skip if seen]: whether to ignore the command if the player has already seen the given event. Default true.

      If the event is not played, the dialogue continues to the next line instead.

      For example, $v 60367 false false will replay the bus arrival event from the start of the game. $v SomeMod.Test true false#$b#Wow! Good timing!$1 will play the event "SomeMod.Test" if the player meets the precondition requirements. If they do not, the dialogue "Wow! Good timing!$1" will play instead.

      Note: The command will only work if it is at the very start of the dialogue. Adding any dialogue or other commands before it will cause it not to trigger the event and display the event commands as dialogue instead.

    • Improved dialogue commands:
      command changes
      $p You can now check multiple answer IDs. For example, this will show the first dialogue if the player chose dialogue answer 17, 18, or 19:
      $p 17|18|19#I guess you think nothing would happen, right?$u|Maybe a wicked ghost would appear!
    • Dialogue response IDs are now unique string IDs.
    • Item spawn codes now use string item IDs. That means you can spawn any item using its qualified item ID (like [(F)1664] for a Mystic Rug), but can no longer prepend zeros (e.g. [128] is a pufferfish but [0128] is an error item).
    • For C# mods, Dialogue now tracks the translation key used to build it (when applicable). For example, you can detect when the player is rejected at the Flower Dance (derived from Three-Heart Dance Partner):
      private void OnMenuChanged(object sender, MenuChangedEventArgs e)
      {
          bool isDanceRejection =
              Game1.currentLocation?.currentEvent?.FestivalName == "Flower Dance"
              && e.NewMenu is DialogueBox dialogueBox
              && dialogueBox.characterDialogue is {} dialogue
              && dialogue.TranslationKey == $"Characters\\Dialogue\\{dialogue.speaker?.Name}:danceRejection";
      }
      

      For C# mods that create Dialogue instances directly, there's a few ways to do it now:

      // from a translation key
      var dialogue = new Dialogue(npc, "Strings\\StringsFromCSFiles:Utility.cs.5360");
      
      // from custom text (with or without a translation key)
      var dialogue = new Dialogue(npc, null, "Some arbitrary text to show as-is");
      
      // from a translation with tokens
      var dialogue = Dialogue.FromTranslation(npc, "Data\\ExtraDialogue:PurchasedItem_2_QualityLow_Willy", whatToCallPlayer, particle, i.DisplayName);
      

      You can also easily add fallback logic using Dialogue.TryGetDialogue or npc.TryGetDialogue. For example:

      Dialogue dialogue =
          npc.TryGetDialogue($"rejection_{itemId}_{locationName}_{x}_{y}")
          ?? npc.TryGetDialogue($"rejection_{itemId}_{locationName}")
          ?? npc.TryGetDialogue($"rejection_{itemId}")
          ?? new Dialogue(npc, "Strings\\StringsFromCSFiles:NPC.cs.3971");
      
    • For C# mods, added a dialogue.sideEffects field to run code when the dialogue is displayed.
    • The 'reveal taste' dialogue command now uses the format %revealtaste:<npc name>:<item ID> to support item IDs. (The previous %revealtaste<npc name><item index> format still works to support old content packs, but the item index can only be a number.)
    • NPCs no longer override the portrait for a gift taste dialogue that uses a portrait command explicitly.
    • Fixed unknown dialogue commands starting with $ being parsed as a portrait number when not numeric.
    • Fixed NPCs only using a {day name}{hearts}_{year} dialogue if they also have a {day name}{hearts} one.
    • Fixed NPCs only using the MovieInvitation dialogue key in English.

    Schedule changes

    These docs should be merged into Modding:Schedule data. When copying content, make sure you attribute the original authors.
    • Schedule keys are now case-insensitive.
    • Added a new <day of week>_<min hearts> schedule key.
    • Added an NPC.ScheduleKey field which always matches their loaded schedule.
    • Schedule commands now trim surrounding whitespace, so they can be multilined for readability. For example:
      "Wed": "
          1000 ArchaeologyHouse 11 9 0/
          1800 Town 47 87 0/
          2200 SeedShop 1 9 3 abigail_sleep
      "
      
    • Removed an unintended schedule fallback to a {season}_spring_{hearts} key. It'll skip to the spring default instead.
    • Schedules are now fault-tolerant:
      • Fixed crash if a selected schedule can't be parsed. The NPC now logs an error and continues with the next fallback instead.
      • Fixed crash if certain hardcoded schedules aren't present (like Penny's marriageJob or Pam's bus).
      • Fixed error if a schedule command is empty.

    Other NPC changes

    These docs should be merged into Modding:NPC data as needed. When copying content, make sure you attribute the original authors.
    • Added Game1.characterData and Game1.farmAnimalData to read NPC/animal info without constantly reloading the Data/Characters or Data/FarmAnimals asset.
    • All translated NPC names are now in Strings/NPCNames.
    • Added new fields & methods for C# mods:
      type field/method effect
      AdventureGuild IsComplete(data) Get whether an Adventurer's Guild monster eradication goal has been completed, regardless of whether the player collected its rewards yet.
      HasCollectedReward(player, id) Get whether a given player has completed an Adventurer's Guild monster eradication goal and collected its rewards. For example:
      bool isPhoneUnlocked = AdventureGuild.HasCollectedReward(Game1.player, "Gil_FlameSpirits");
      
      AnimalHouse adoptAnimal Add an animal to this location and set the location as the animal's home.
      AnimatedSprite Owner The NPC which owns the sprite.
      Character IsVillager Whether this is an NPC-type villager (i.e. not a monster, horse, pet, player's child, etc). In other words, this checks whether the NPC would use data from Data/Characters (regardless of whether they currently have an entry in the asset).
      StandingPixel The character's cached pixel position within the current location, based on the center pixel of their bounding box.
      Tile
      TilePoint
      The character's cached tile position within their current location. Tile is their exact non-integer position, and TilePoint is their integer tile position.
      FarmAnimal isAdult Get whether the farm animal is fully grown (opposite of isBaby()).
      CanGetProduceWithTool Get whether the farm animal's produce can be collected with a given tool (e.g. milk pail for a cow).
      CanLiveIn Get whether the animal can be added to a building.
      GetDisplayName
      GetShopDescription
      Get the translated display name or shop description for this animal.
      GetHarvestType Get whether the animal's produce is dropped or collected with a tool.
      growFully Instantly age the animal to adulthood if it's still a baby.
      ReloadTextureIfNeeded Update the animal sprite based on the current state + data.
      Farmer GetDisplayPants
      GetDisplayShirt
      Get the texture and sprite index to draw for the player's pants or shirt. This accounts for override clothing, worn clothing, and the default clothing drawn when the farmer isn't wearing anything.

      For example:

      Game1.player.GetDisplayShirt(out Texture2D texture, out int spriteIndex);
      
      CanDyePants
      CanDyeShirt
      Get whether the currently equipped pants or shirt can be dyed.
      Monster GetDisplayName(name) Get the translated display name for a monster type.
      NPC CanReceiveGifts Get whether this NPC can receive gifts from the player (regardless of whether they've already received one today).
      GetData
      NPC.TryGetData
      Get the underlying data from Data/Characters for this NPC, if any.
      NPC.GetDisplayName(name) Get the translated display name in the current language for an NPC by their internal name.
      hasDarkSkin Whether this character has dark skin for the purposes of child genetics.
      Pet GetPetData
      TryGetData
      Get the underlying data from Data/Pets for this pet, if any.
      ShopMenu ShopId A key which identifies the current shop. This may be the unique shop ID in Data/Shops for a standard shop, Dresser or FishTank for furniture, etc. This is guaranteed to be set to a relevant shop ID.

      This replaces the former shopContext field, and will usually have the same value in cases where that was set to a unique shop ID.

      Utility getAllVillagers Get all villager NPCs (excluding horses, pets, monsters, player children, etc). This works just like getAllCharacters with an added filter.
    • NPCs now update on save loaded when their home data changes.
    • NPC.reloadSprite() now has an argument to only reload the appearance, without changing other data.
    • Utility.getAllCharacters() now returns a plain List<NPC> value instead of a custom DisposableList<NPC>, so you can use normal LINQ querying on it.
    • Utility.GetHorseWarpRestrictionsForFarmer(player) now returns an enum (which is more efficient and easier for mods to patch), and added a new Utility.GetHorseWarpErrorMessage(restrictions) method to get the error message to show for it.
    • Farmer.hasAFriendWithHeartLevel now has an optional max-hearts argument.
    • Removed most FarmAnimal fields/properties which just mirror the underlying data.
    • Removed invalid item IDs in Data/NPCGiftTastes.
    • Fixed NPCs sometimes duplicated on save load (particularly if their home location changed).
    • Fixed child NPCs like Jas or Vincent ignoring relative titles like "mom" in Data/NPCDispositions (now Data/Characters) for reveal-gift-taste dialogues.
    • Fixed custom NPCs ignoring dialogue when they use a subclass of NPC.
    • Fixed monsters not loading their display name from Data/Monsters for English players.
    • Fixed player children not applying the IsInvisible flag.

    What's new for everything else

    Buff overhaul

    These docs should be merged into a new doc page. When copying content, make sure you attribute the original authors.
    See also: custom buffs.

    1.6 rewrites buffs to work more consistently and be more extensible:

    • Buff logic is unified into Game1.player.buffs, which is the single source of truth for buff data. This replaces the previous player.added* and player.appliedBuffs fields, BuffsDisplay logic, enchantment stat bonuses, and boots/ring attribute changes on (un)equip.
    • This also removes limitations on buff types (e.g. buffs can add weapon bonuses and weapons can add attribute buffs) and buffable equipment (e.g. equipped tools can have buffs too).
    • Buff effects are now fully recalculated when they change, to fix a range of longstanding bugs like attribute drift and double-debuffs. Just like before, the buffs are managed locally; only the buff IDs and aggregate attribute effects are synced.

    For C# mods:

    • Each buff now has a unique string ID. You can apply a new buff with the same ID to replace it (so you no longer need to manually find and remove previous instances of the buff).
    • The buff duration can now be set to Buff.ENDLESS to remove the duration. It'll last all day until the player sleeps.
    • You can add standard buff effects to any equipment by overriding Item.AddEquipmentEffects, or add custom behaviour/buffs by overriding Item.onEquip and Item.onUnequip.
    • You can add custom food or drink buffs by overriding Item.GetFoodOrDrinkBuffs().
    • The Buff constructor now supports a custom icon texture, sprite index, display name, description, and millisecond duration to fully support custom buffs.
    • You can change how buff attributes are displayed (or add new attributes) by extending the BuffsDisplay.displayAttributes list.
    • You can have invisible buffs by setting buff.visible = false.

    For example, here's how to add a custom buff which adds +3 speed:

    Buff buff = new Buff(
        id: "Example.ModId_ZoomZoom",
        displayName: "Zoom Zoom", // can optionally specify description text too
        iconTexture: this.Helper.ModContent.Load<Texture2D>("assets/zoom.png"),
        iconSheetIndex: 0,
        duration: 30_000, // 30 seconds
        effects: new BuffEffects()
        {
            Speed = { 10 } // shortcut for buff.Speed.Value = 10
        }
    );
    Game1.player.applyBuff(buff);
    

    You can also implement your own custom effects in code by checking if the buff is active, like Game1.player.hasBuff("Example.ModId_ZoomZoom").

    Custom audio

    See the updated docs at Modding:Audio. This section below focuses on what's new in 1.6.

    You can now add or edit music tracks or sound effects by editing the new Data/AudioChanges asset. New cues are added to the game's soundbank, so they can be used anywhere normal audio can be used (e.g. the Music map property). This supports .ogg and .wav files, and the vanilla audio features (e.g. randomizing audio from one ID).

    Audio is also more fault-tolerant in 1.6: the game no longer crashes when playing audio which doesn't exist, it now logs an error and returns a default quiet click sound instead. (If you use try..catch to check if an audio cue exists, you should check Game1.soundbank.Exists(name) instead.)

    Custom buffs

    These docs should be merged into a new doc page. When copying content, make sure you attribute the original authors.
    See also: buff overhaul.

    You can now define custom buffs by editing the new Data/Buffs asset. You can then use the buff from other places like Data/Object's Buff field or the C# Buff constructor.

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

    • The key is a unique string ID for the buff.
    • The value is a model with the fields listed below.
    field purpose
    DisplayName A tokenizable string for the buff name.
    Description (Optional) A tokenizable string for the buff name. Default none.
    IsDebuff (Optional) >Whether this buff counts as a debuff, so its duration should be halved when wearing a sturdy ring. Default false.
    GlowColor (Optional) The glow color to apply to the player. See color format. Default none.
    Duration The duration in milliseconds for which the buff should be active. This can be set to value -2 for a buff that should last for the rest of the day.
    MaxDuration (Optional) The maximum buff duration in milliseconds. If specified and larger than Duration, a random value between Duration and MaxDuration will be selected for each buff. Default none.
    IconTexture The asset name for the texture containing the buff's sprite.
    IconSpriteIndex (Optional) The sprite index for the buff icon within the IconTexture. Default 0.
    Effects (Optional) The buff attributes to apply. Default none.

    This consists of a model with any combination of these fields:

    field purpose
    FarmingLevel
    FishingLevel
    ForagingLevel
    LuckLevel
    MiningLevel
    (Optional) An amount applied to the matching skill level while the buff is active. This can be negative for a debuff. Default 0.
    Attack
    Defense
    MagneticRadius
    MaxStamina
    Speed
    (Optional) An amount applied to the player's attack, defense, magnetic radius, maximum stamina, or speed while the buff is active. This can be negative for a debuff. Default 0.
    ActionsOnApply (Optional) Run any number of trigger action strings when the buff is applied to the current player. For example, this increments a player stat:
    "ActionsOnApply": [
        "IncrementStat {{ModId}}_NumberEaten 1"
    ]
    
    CustomFields (Optional) The custom fields for this entry.

    Custom data fields

    See the updated docs at Modding:Common data field types#Custom fields. This section below focuses on what's new in 1.6.

    Many data assets now have a CustomFields field. This is ignored by the game, but lets mods add their own data (e.g. to enable mod framework features).

    For example, a content pack can add a crop with custom fields:

    {
        "Format": "2.0.0",
        "Changes": [
            {
                "Action": "EditData",
                "Target": "Data/Crops",
                "Entries": {
                    "Example.Id_CucumberSeeds": {
                        "Seasons": [ "summer" ],
                        "DaysInPhase": [ 1, 2, 2, 2 ],
                        "HarvestItemId": "Example.Id_Cucumber",
                        "Texture": "{{InternalAssetKey: assets/crops.png}}",
                        "SpriteIndex": 0,
    
                        "CustomFields": {
                            "Example.FrameworkMod/WetTexture": "{{InternalAssetKey: assets/crops-wet.png}}"
                        }
                    }
                }
            }
        ]
    }
    

    And then a C# mod could handle the custom field if it's set:

    if (Game1.currentLocation.IsRainingHere())
    {
        CropData data = crop.GetData();
        if (data != null && data.CustomFields.TryGetValue("Example.FrameworkMod/WetTexture", out string textureName))
        {
            // do magic
        }
    }
    

    See CustomFields in the docs for each asset type to see if it's supported. Besides the sections listed on this page, custom fields were also added to Data/AdditionalFarms, Data/AdditionalLanguages, Data/FishPondData, Data/HomeRenovations, Data/Movies, and Data/SpecialOrders.

    See Modding:Common data field types#Custom fields for the main docs.

    Custom giant crops

    These docs should be merged into a new doc page. When copying content, make sure you attribute the original authors.

    You can now add/edit giant crops by editing the Data/GiantCrops data asset.

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

    • The key is a unique string ID for the giant crop.
    • The value is a model with the fields listed below.
    field effect
    FromItemId The item ID (qualified or unqualified) for the harvest ID of the regular crop which can turn into this giant crop. For example, (O)254 is melon.

    Any number of giant crops can use the same FromItemId value. The first giant crop whose other fields match (if any) will spawn.

    HarvestItems The items which can be dropped when you break the giant crop. If multiple items match, they'll all be dropped.

    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 harvest items.

    If set to an item query which returns multiple items, one of them will be selected at random.

    Chance (Optional) The probability that this entry is selected, as a value between 0 (never drops) and 1 (always drops). Default 1 (100% chance).
    ForShavingEnchantment (Optional) Whether this item is only dropped for Shaving enchantment drops (true), only when the giant crop is broken (false), or both (null). Default both.
    ScaledMinStackWhenShaving
    ScaledMaxStackWhenShaving
    (Optional) If set, the min/max stack size when this item is dropped due to the shaving enchantment, scaled to the tool's power level.

    This value is multiplied by the health deducted by the tool hit which triggered the enchantment. For example, an iridium axe which reduced the giant crop's health by 3 points will produce three times this value per hit.

    If both fields are set, the stack size is randomized between them. If only one is set, it's applied as a limit after the generic fields. If neither is set, the generic MinStack/MaxStack fields are applied as usual without scaling.

    Texture The asset name for the texture containing the giant crop's sprite.
    TexturePosition (Optional) The top-left pixel position of the sprite within the Texture, specified as a model with X and Y fields. Defaults to (0, 0).
    TileSize (Optional) The area in tiles occupied by the giant crop, specified as a model with X and Y fields. This affects both its sprite size (which should be 16 pixels per tile) and the grid of crops needed for it to grow. Note that giant crops are drawn with an extra tile's height. Defaults to (3, 3).
    Health (Optional) The health points that must be depleted to break the giant crop. The number of points depleted per axe chop depends on the axe power level. Default 3.
    Chance (Optional) The percentage chance that a given grid of crops will grow into the giant crop each night, as a value between 0 (never) and 1 (always). Default 0.01 (1%).

    Note that the chance is checked for each giant crop that applies. If three giant crops each have a 1% chance of spawning for the same crop, then there's a 3% chance that one of them will spawn.

    Condition (Optional) A game state query which indicates whether this giant crop is available to spawn. Defaults to always true.
    CustomFields The custom fields for this entry.

    Custom jukebox tracks

    These docs should be merged into a new doc page. When copying content, make sure you attribute the original authors.

    You can now change jukebox audio tracks by editing the new Data/JukeboxTracks data asset.

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

    • The key is the audio cue ID to play (case-sensitive).
    • The value is a model with the fields listed below.

    If the player has heard a music track not listed in Data/JukeboxTracks, it's automatically available with the title set to the cue name. To disable a track, add an entry with "Available": false.

    field effect
    Name (Optional) A tokenizable string for the music track's in-game title. Defaults to the ID.
    Available (Optional) Whether the track should be shown in the jukebox menu. This can be true (always shown), false (never shown), or null (show if the player has heard it before). Default null.

    Tracks with "Available": true are listed first in the jukebox menu.

    AlternativeTrackIds (Optional) A list of other cue names for this audio track (not case-sensitive). If the player has heard any of these track IDs, this entry is available in the menu. Default none.

    For example, this can be used when renaming a track to keep it unlocked for existing players:

    "{{ModId}}_TrackName": {
        "Name": "{{i18n: track-name}}",
        "AlternativeTrackIds": [ "OldTrackName" ]
    }
    

    Custom movies

    These docs should be merged into Modding:Movie theater data. When copying content, make sure you attribute the original authors.
    See also: custom movie concessions.

    Movie data was previously very limited and prone to mod conflicts, since (a) we needed incrementing movie IDs like spring_movie_3, (b) we were limited to one movie per season, and (c) all sprites for each movie had to be in the vanilla LooseSprites/Movies spritesheet.

    Stardew Valley 1.6 revamps how movies work to address those limitations.

    Movie selection

    Movies were previously selected based on a specific ID pattern: spring_movie_0 would play in spring the year you built the movie theater, spring_movie_1 would play in spring the next year, etc. That meant it'd take two in-game years to see the first custom movie, and ID conflicts had to be managed manually.

    In 1.6, we can now have multiple movies per month based on the new fields listed below. If multiple movies can play in the same season, each movie will be shown for an equal block of days within the month (e.g. four movies will each play for seven consecutive days). If there are more movies than days, 28 movies will be chosen at random to play that month.
    New data fields
    field effect
    Seasons (Optional) The seasons when the movie should play, or omit for any season. For example:
    "Seasons": [ "Spring", "Summer" ]
    
    YearModulus
    YearRemainder
    (Optional) If set, plays the movie on alternating years based on the formula theater_age % modulus == remainder, where theater_age is the number of years since the movie theater was built. If omitted, the movie plays in any year.

    For example:

    // play in the first year, and every second year thereafter
    "YearModulus": 2,
    "YearRemainder": 0
    
    // play in the second year, and every second year thereafter
    "YearModulus": 2,
    "YearRemainder": 1
    
    Texture (Optional) The asset name for the movie poster and screen images, or omit to use LooseSprites\Movies.

    This must be a spritesheet with one 490×128 pixel row per movie. A 13×19 area in the top-left corner of the row should contain the movie poster. With a 16-pixel offset from the left edge, there should be two rows of five 90×61 pixel movie screen images, with a six-pixel gap between each image. (The movie doesn't need to use all of the image slots.)

    CranePrizes (Optional) The items to add to the crane game prize pool on days when this movie is playing, if any.

    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 ammo items.

    If set to an item query which returns multiple items, one of them will be selected at random.

    Rarity (Optional) The prize pool to add the item to. The possible values are 1 (common), 2 (rare), and 3 (deluxe). Default 1.
    ClearDefaultCranePrizeGroups (Optional) The prize pools whose default items to discard, so only those specified by CranePrizes are available. Default none.

    For example:

    "ClearDefaultCranePrizeGroups": [ 2, 3 ]
    
    Other changes
    • Data/Movies, Data/Concessions, and Data/MoviesReactions no longer have language variants. Instead translations were moved into Strings/* assets, and the data assets use tokenizable strings to get text.
    • Data/Movies is now a list instead of a dictionary. The order determines the order movies are shown within a season. Content packs can edit them the same way as before.
    • Added a debug movieSchedule [year] command to help troubleshoot movie selection.
    • Added methods for C# mods: MovieTheater.GetMovieToday(), GetUpcomingMovie(), and GetUpcomingMovie(afterDate).

    For example, this content pack adds a new 'Pufferchick II' movie which plays in winter every third year:

    {
        "Format": "2.0.0",
        "Changes": [
            {
                "Action": "EditData",
                "Target": "Data/Movies",
                "Entries": {
                    "{{ModId}}_PufferchickII": {
                        "Id": "{{ModId}}_PufferchickII", // must specify ID again when creating a new entry
    
                        "Seasons": [ "winter" ],
                        "YearModulus": 3,
                        "YearRemainder": 0,
    
                        "Title": "Pufferchick II", // display text should usually use {{i18n}} for translations in actual usage
                        "Description": "A sequel to the breakthrough adventure anime Pufferchick. The world is saved; what happens next?",
                        "Tags": [ "family", "adventure" ],
    
                        "Texture": "{{InternalAssetKey: assets/movie.png}}", // an image in your content pack
                        "SheetIndex": 0,
    
                        "Scenes": [ ... ]
                    }
                }
            }
        ]
    }
    

    Custom wedding event

    These docs should be merged into a new doc page. When copying content, make sure you attribute the original authors.

    The wedding event can now be changed by editing the Data\Weddings data asset, which consists of a data model with two relevant fields (listed below).

    field effect
    EventScript The event scripts which play the wedding. The game will use the script for the spouse NPC/player if it exists, otherwise it'll use the default script.

    This consists of a string → string dictionary, where...

    • The key is an NPC internal name (like Abigail), unique player ID, or default for the default script (which handles marrying either an NPC or player);
    • The value is a tokenizable strings for the event script to play.

    The event scripts also have access to three extra tokens:

    token effect
    [SetupContextualWeddingAttendees] The concatenated Setup values for each of the Attendees present in the wedding.
    [ContextualWeddingCelebrations] The concatenated Celebration values for each of the Attendees present in the wedding.
    [SpouseActor] The actor ID for the NPC or other player being married (like Abigail for an NPC or farmer2 for a player). This can be used in event commands like faceDirection [SpouseActor] 1.

    (You can also use spouse as an actor ID, but that will only work when marrying an NPC.)

    Attendees The other NPCs which should attend the wedding (unless they're the spouse). This consists of a string → model lookup, where the key is the internal NPC name, and the value is a model with these fields:
    field effect
    ID The internal NPC name.
    Setup The NPC's tile position and facing direction when they attend. This is equivalent to field index 2 in the event basic data.
    Celebration (Optional) The event script to run during the celebration, like faceDirection Pierre 3 true which makes Pierre turn to face left. This can contain any number of script commands.
    Condition (Optional) A game state query which indicates whether the NPC should attend. Defaults to true.
    IgnoreUnlockConditions (Optional) Whether to add the NPC even if their entry in Data/Characters has an UnlockConditions field which doesn't match. Default false.

    Game state queries

    See the updated docs at Modding:Game state queries. This section below focuses on what's new in 1.6.

    A game state query is a new vanilla way to specify conditions for some content like shop data, inspired by Content Patcher's conditions.

    Gender changes

    These docs should be merged into Modding:Dialogue. When copying content, make sure you attribute the original authors.
    • Added an inline gender-switch token to change text depending on the player's gender. This reduces duplicate text, works in more places than the ^ dialogue token, works in mail and other places where ^ has a different meaning, and supports non-binary gender.
    • For C# mod authors, added a unified Gender field for players and NPCs with the possible values Male, Female, and Unspecified. This replaces Farmer.isMale and the numeric NPC gender constants. Note that vanilla still only sets players to male or female, though mods can override it.
    • Gender-specific clothing variants can now be worn by any gender.
    • Removed French-only support for using ^ dialogue token in non-dialogue text. This is superseded by the new inline gender-switch command.

    Item queries

    See the updated docs at Modding:Item queries. This section below focuses on what's new in 1.6.

    Item queries are a new built-in way to choose one or more items dynamically, instead of specifying a single item ID. These are used in various places like machine data and shop data.

    For example, a shop can sell a random house plant using the RANDOM_ITEMS query:

    {
        "ItemId": "RANDOM_ITEMS (F) 1376 1390",
        "MaxItems": 1
    }
    

    Item spawn fields

    See the updated docs at Modding:Item queries#Item spawn fields. This section below focuses on what's new in 1.6.

    Several data assets (like machines and shops) let you configure items to create using item queries. For consistency, these all share a set of common fields.

    Color fields

    See the updated docs at Modding:Common data field types#Color. This section below focuses on what's new in 1.6.

    1.6 adds a standardized color format used in various data fields. This can be a color name, hexadecimal color code, or 8-bit RGB color code.

    For example, you can set debris color in Data/WildTrees:

    "DebrisColor": "White"
    

    modData field changes

    The modData fields are dictionaries of arbitrary string values which are synchronized in multiplayer and persisted in the save file, so mods can store custom data about the instances. The game already has the field for buildings, characters (including NPCs and players), items, locations, and terrain features.

    Stardew Valley 1.6...

    • Adds modData fields to the Crop, Projectile, and Quest types too.
    • Moves ModDataDictionary into the StardewValley.Mods namespace.
    • Fixes Item.modData not copied when performing special equipment replacement (e.g. for the copper pan work as a hat).

    Quantity modifiers

    These docs should be merged into Modding:Common data field types. When copying content, make sure you attribute the original authors.

    Quantity modifiers apply dynamic changes to a numeric field in a data asset like Data/Shops or Data/Machines. For example, you can multiply a shop item's price or increase a machine output's quality. You can specify any number of modifiers for the same field.

    Modifier format

    These consist of a list of models with these fields:

    field effect
    Id The unique string ID for this modifier within the current list.
    Modification The type of change to apply. The possible values are Add, Subtract, Multiply, Divide, and Set.
    Amount (Optional if RandomAmount specified) The operand applied to the target value (e.g. the multiplier if used with Multiply).
    RandomAmount (Optional) A list of possible amounts to randomly choose from. If set, Amount is optional and ignored. Each entry in the list has an equal probability of being chosen, and the choice is persisted for the current day. For example:
    "RandomAmount": [ 1, 2, 3.5, 4 ]
    
    Condition (Optional) A game state query which indicates whether this change should be applied. Defaults to always true.

    Modifier mode

    Quality modifier fields are often accompanied by a mode field (like PriceModifiers and PriceModifierMode), which indicate what to do when multiple modifiers apply to the same value. Available modes:

    value effect
    Stack Apply each modifier to the result of the previous one. For example, two modifiers which double a value will quadruple it.
    Minimum Apply the modifier which results in the lowest value.
    Maximum Apply the modifier which results in the highest value.

    Examples

    For example, this will double the price of a shop item in Data/Shops:

    "PriceModifiers": [
        {
            "Modification": "Multiply",
            "Amount": 2.0
        }
    ]
    

    This will set the price to a random value between 100–1000, or 3–5 times the item's normal sell price, whichever is higher (like the Traveling Cart):

    "PriceModifierMode": "Maximum",
    "PriceModifiers": [
        {
            "Modification": "Set",
            "RandomAmount": [ 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000 ]
        },
        {
            "Modification": "Multiply",
            "RandomAmount": [ 3, 4, 5 ]
        }
    ]
    

    Tokenizable string format

    See the updated docs at Modding:Tokenizable strings. This section below focuses on what's new in 1.6.

    Stardew Valley 1.6 adds tokenizable strings, which support any combination of literal text and token values. That includes a set of built-in tokens like FarmName, LocalizedText, etc.

    For example, previously you often needed to load text from a translation key. With this new format, you can use the literal text directly in the asset instead (including Content Patcher tokens):

    // before
    "Dialogue": "Strings\\StringsFromCSFiles:ShopMenu.cs.11488",
    
    // after: any combination of literal text and tokens
    "Dialogue": "Welcome to Pierre's, {{PlayerName}}! How is [FarmName] doing?",
    

    Tokenizable strings are only usable in specific fields (as indicated in their wiki or code docs).

    See Modding:Tokenizable strings for usage.

    Event changes

    These docs should be merged into Modding:Event data. When copying content, make sure you attribute the original authors.

    High-level changes

    • Event IDs are now unique string IDs, so mods can use a unique key instead of hoping no other mod uses the same number. Unconditional events must have an empty precondition in their key (like "Example.ModId_EventName/") to distinguish them from forks.
    • Event/festival commands with a direction argument now allow both case-insensitive names (like up) and numeric values.
    • Event script errors are now logged (in addition to being shown in the chatbox like before).
    • For C# mods:
      • You can now add custom event preconditions & commands using new Event methods (RegisterPrecondition, RegisterPreconditionAlias, RegisterCommand, and RegisterCommandAlias).
      • Added Event.fromAssetName, which indicates which data asset (if any) the event was loaded from.
      • Added Game1.eventsSeenSinceLastLocationChange to track the events that played since the player arrived in their current location.

    Precondition changes

    • Added validation for preconditions. If a format or assumption is invalid, the game now logs a detailed error.
    • Added case-insensitive readable names for all preconditions. For example, j 4/t 800 1300/a 0 54/H can now optionally be written daysPlayed 4/time 800 1300/tile 0 54/isHost.
      list of new names 
      List of new event precondition names:
      alias | readable name
      ----- | ------------------------------
      *     | WorldState
      *n    | HostOrLocalMail
      a     | Tile
      b     | ReachedMineBottom
      B     | SpouseBed
      C     | CommunityCenterOrWarehouseDone
      c     | FreeInventorySlots
      D     | Dating
      e     | SawEvent
      f     | Friendship
      g     | Gender
      H     | IsHost
      h     | MissingPet
      Hn    | HostMail
      i     | HasItem
      j     | DaysPlayed
      J     | JojaBundlesDone
      L     | InUpgradedHouse
      m     | EarnedMoney
      M     | HasMoney
      N     | GoldenWalnuts
      n     | LocalMail
      O     | Spouse
      p     | NpcVisibleHere
      q     | ChoseDialogueAnswers
      r     | Random
      R     | Roommate
      S     | SawSecretNote
      s     | Shipped
      t     | Time
      u     | DayOfMonth
      v     | NpcVisible
      w     | Weather
      x     | SendMail
      y     | Year
      

      And for deprecated preconditions (e.g. NotSeason is superseded by !Season):

      alias | readable name
      ----- | ---------------------------------
      *l    | NotHostOrLocalMail
      A     | NotActiveDialogueEvent
      d     | NotDayOfWeek
      F     | NotFestivalDay
      Hl    | NotHostMail
      k     | NotSawEvent
      l     | NotLocalMail
      o     | NotSpouse
      Rf    | NotRoommate
      U     | NotUpcomingFestival
      X     | NotCommunityCenterOrWarehouseDone
      z     | NotSeason
      
    • Event & preconditions are now quote-aware, so you can escape spaces and slashes in arguments like /G "SEASON Spring"/.
    • Added new preconditions:
      precondition description
      ! Prefixing ! to any other precondition will now invert it. For example, !spouse Abigail will match if the player is not married to Abigail.
      ActiveDialogueEvent <id> The special dialogue event with the given ID (including Conversation Topics) is in progress.
      DayOfWeek <day>+ Today is one of the specified days (may specify multiple days). This can be a case-insensitive three-letter abbreviation (like Mon) or full name (like Monday).
      FestivalDay Today is a festival day.
      GameStateQuery <query> A game state query matches, like G !WEATHER Here Sun for 'not sunny in this location'.
      Season <season>+ The current season is one of the given values (may specify multiple seasons).
      Skill <skill name> <min level> The current farmer has reached at least <min level> for the given <skill name> (one of Combat, Farming, Fishing, Foraging, Luck, or Mining).
      UpcomingFestival <day offset> A festival day will occur within the given number of days.
    • Changed specific preconditions:
      name changes
      ChoseDialogueAnswers (q)
      • Fixed precondition ignoring every second answer ID.
      InUpgradedHouse (L)
      • Added optional argument for the min upgrade level.
      MissingPet (h)
      • You can now specify any pet type ID.
      • You can now omit the argument to check for a pet of any type.
      NotDayOfWeek (d)
      • You can now specify a full name like Monday.
      • The day of week is now case-insensitive.
      NotSeason (z)
      • You can now list values (like notSeason spring summer fall instead of notSeason fall/notSeason winter/notSeason fall).
      ReachedMineBottom (b)
      • Argument is now optional (default 1).
      SendMail (x)
      Tile (a)
      • Now also works when the player isn't currently warping, in which case it checks their current tile instead of their warp arrival tile.

    Command changes

    • Added validation for event commands. If a format or assumption is invalid, the game now logs a detailed error and (if applicable) skips the command, instead of crashing or silently ignoring it. This also means event arguments are stricter (e.g. you can no longer set a true/false field to an invalid value, inner quotes in quoted arguments now need to be escaped, etc).
    • Event commands are now quote-aware, so you can escape spaces and slashes in arguments like /speak "I'm running A/B tests"/.
    • Event commands now trim surrounding whitespace, so they can be multilined for readability. Line breaks must be before or after the / delimiter. For example:
      "SomeEventId/": "
          none/
          -1000 -1000/
          farmer 5 7 0/
          ...
      "
      

      This can be also combined with the comment syntax to add notes. For example:

      "SomeEventId/": "
          none/            -- music/
          -1000 -1000/     -- initial viewport position/
          farmer 5 7 0/    -- actor positions/
          ...
      "
      
    • You can now mark NPCs optional in event commands by suffixing their name with ?. For example, jump Kent? won't log an error if Kent is missing. When used in the initial event positions, the NPC is only added in they exist in Data/Characters and their UnlockConditions match.
    • Added new event commands:
      command description
      action <action> Run a trigger action string, like action AddMoney 500 to add data-sort-value="500"> 500g to the current player.
      addItem <item ID> [count] [quality] Add an item to the player inventory (or open a grab menu if their inventory is full). The <item ID> is the qualified or unqualified item ID, and [quality] is a numeric quality value.
      addSpecialOrder <order ID>
      removeSpecialOrder <order ID>
      Add or remove a special order to the player team. This affects all players, since special orders are shared.
      eventSeen <event ID> [seen] Add or remove an event ID from the player's list of seen events, based on [seen] (default true to add).

      An event can mark itself unseen using eventSeen <event ID> false. This takes effect immediately (i.e. the event won't be added to the list when it completes), but the game will prevent the event from playing again until the player changes location to avoid event loops. The event will still replay when re-entering the location.

      mailToday <mail key> Adds a letter to the mailbox immediately, given the <mail key> in Data/Mail.
      questionAnswered <answer ID> [answered] Add or remove an answer ID from the player's list of chosen dialogue answers, based on [answered] (default true to add).
      replaceWithClone <NPC name> Replace an NPC already in the event with a temporary copy. This allows changing the NPC for the event without affecting the real NPC.

      For example, this event changes Marnie's name/portrait only within the event:

      "Some.ModId_ExampleEvent/": "continue/64 15/farmer 64 15 2 Marnie 64 17 0/replaceWithClone Marnie/changeName Marnie Pufferchick/changePortrait Marnie Pufferchick/[...]/end"
      
      setSkipActions [actions] Set trigger actions that should run if the player skips the event. You can list multiple actions delimited with #, or omit [actions] so no actions are run. When the player skips, the last setSkipActions before that point is applied.

      For example, this adds the garden pot recipe and item to the player if the event is skipped, but avoids adding the item if the event already did it:

      /setSkipActions AddCraftingRecipe Current "Garden Pot"#AddItem (BC)62
      /skippable
      /...
      /addItem (BC)62
      /setSkipActions AddCraftingRecipe Current "Garden Pot"
      

      Skip actions aren't applied if the event completes normally without being skipped.

      stopSound <sound ID> [immediate] Stop a sound started with the startSound command. This has no effect if the sound has already stopped playing on its own (or hasn't been started). If you started multiple sounds with the same ID, this will stop all of them (e.g. startSound fuse/startSound fuse/stopSound fuse).

      By default the sound will stop immediately. For looping sounds, you can pass false to the [immediate] argument to stop the sound when it finishes playing the current iteration instead (e.g. stopSound fuse false).

      temporaryAnimatedSprite ... Add a temporary animated sprite to the event, using these space-delimited fields:
      index field effect
      0 texture The asset name for texture to draw.
      1–4 rectangle The pixel area within the texture to draw, in the form <x> <y> <width> <height>.
      5 interval The millisecond duration for each frame in the animation.
      6 frames The number of frames in the animation.
      7 loops The number of times to repeat the animation.
      8–9 tile The tile position at which to draw the sprite, in the form <x> <y>.
      10 flicker Causes the sprite to flicker in and out of view repeatedly. (one of true or false).
      11 flip Whether to flip the sprite horizontally when it's drawn (one of true or false).
      12 sort tile Y The tile Y position to use in the layer depth calculation, which affects which sprite is drawn on top if two sprites overlap. The larger the number, the higher layer the sprite is on.
      13 alpha fade Fades out the sprite based on alpha set. The larger the number, the faster the fade out. 1 is instant.
      14 scale A multiplier applied to the sprite size (in addition to the normal 4× pixel zoom).
      15 scale change Changes the scale based on the multiplier applied on top of the normal zoom. Continues endlessly.
      16 rotation The rotation to apply to the sprite, measured in radians.
      17 rotation change Continuously rotates the sprite, causing it to spin. The speed is determined by input value.
      18+ flags Any combination of these space-delimited flags:
      • color <color>: apply a standard color to the sprite.
      • hold_last_frame: after playing the animation once, freeze the last frame as long as the sprite is shown.
      • ping_pong: Causes the animation frames to play forwards and backwards alternatingly. Example: An animation with the frames 0, 1, 2 will play "0 1 2 0 1 2" without the ping_pong flag and play "0 1 2 1 0" with the ping_pong flag.
      • motion <x> <y>: Sprite moves based on the values set. Numbers can be decimals or negative.
      • acceleration <x> <y>: [TODO: document what this does]
      • acceleration_change <x> <y>: [TODO: document what this does]
      translateName <actor> <translation key> Set the display name for an NPC in the event to match the given translation key.
      warpFarmers [<x> <y> <direction>]+ <default offset> <default x> <default> <direction> Warps connected players to the given tile coordinates and numeric directions. The <x> <y> <direction> triplet is repeated for each connected player (e.g. the first triplet is for the main player, second triplet is for the first farmhand, etc). The triplets are followed by an offset direction (one of up, down, left, or right), and a final triplet which defines the default values used by any other player.
    • Fixed some commands assuming a boolean argument is true if present, regardless of its value. This affects the changeToTemporaryMap, emote, extendSourceRect, faceDirection, globalFade, globalFadeToClear, positionOffset, and warp commands.
    • Fixed some commands assuming any value except the exact case-sensitive string true is false. This affects the animate, glow, hideShadow, ignoreMovementAnimation, temporaryAnimatedSprite, temporarySprite, and viewport commands.
    • Fixed some commands silently ignoring values they can't parse as the expected type. This affects the addItem, makeInvisible, and removeItem commands.
    • Fixed crash when some commands are passed farmer[number] for a player who's not available, or farmer[number] when they expect farmer.
    • Fixed some commands not taking into account custom farmer actors when checking farmer* actor IDs.
    • Fixed warp-out event commands able to use NPC-only or gendered warps. They now use a valid warp for the player if possible.
    • Changed specific commands:
      command changes
      addCookingRecipe Fixed error if player already knows the recipe.
      addMailReceived
      • Renamed to mailReceived. (The old name is now an alias, so it'll still work.)
      • You can now remove a mail received by setting the optional third argument to false, like mailReceived <id> false.
      addTemporaryActor
      • Underscores in the asset name are now only replaced with spaces if an exact match wasn't found. You should quote arguments containing spaces instead, like addTemporaryActor "White Chicken" ….
      • Underscores in the display name are no longer replaced with spaces. You should quote arguments containing spaces instead.
      • Argument 9 ([animal name]) is now [override name], and can be used to set the name for non-animals too.
      animate Underscores in the NPC name are now only replaced with spaces if an exact match wasn't found. You should quote arguments containing spaces instead, like animate "Mr Qi" ….
      ambientLight Removed four-argument form (which was unused and had confusing behavior). The other versions of ambientLight still work like before.
      awardFestivalPrize Added support for arbitrary item IDs, like awardFestivalPrize (O)128 for a pufferfish.
      changeLocation It now updates the event position offset if needed.
      changeName Underscores in the NPC name are no longer replaced with spaces. You should quote arguments containing spaces instead, like changeName Leo "Neo Leo".
      changePortrait
      changeSprite
      You can now omit the suffix argument to reset the NPC back to their normal portrait/sprite.
      faceDirection You can now specify the direction in words, like faceDirection up
      ignoreMovementAnimation
      • Fixed its ignore argument being ignored.
      • Underscores in the NPC name are now only replaced with spaces if an exact match wasn't found. You should quote arguments containing spaces instead, like ignoreMovementAnimation "Mr Qi" ….
      itemAboveHead Added support for arbitrary item IDs, like itemAboveHead (O)128 for a pufferfish.
      makeInvisible Fixed terrain features not hidden when using the default area size.
      playSound Sounds started via playSound now stop automatically when the event ends.
      removeItem Added argument for an optional count, like removeItem (O)128 10 to remove 10 pufferfish.
      speak Fixed friendship & socialize quest not updated when calling it with a translation key.
    • Removed some commands:
      command changes
      addToTable Removed (it was unused and worked in counterintuitive ways).
      addTool Removed (it was unused and only supported the return scepter). Use addItem instead, which supports adding tools.
      grabObject Removed (it was unused and broken).
      showRivalFrame
      taxVote
      Removed (they were part of unimplemented features).
      weddingSprite Removed (it was broken and unused).

    Festival changes

    • Festivals can now have a custom festival-started notification message by setting the startedMessage field in Data/Festivals/* to a tokenizable string.
    • Festivals now set the event ID to a value like festival_fall16, instead of -1.
    • All in-festival data fields now support year variants.
    • Fixed NPCs getting duplicated in festivals if they're added to the set-up fields multiple times. Subsequent entries now move them instead.
    • Fixed year variants for festival set-up field being appended to the main script instead of replacing it.

    Send-mail (x) precondition deprecated

    Using the x event precondition as a way to send mail is now deprecated (but still works). You should use trigger actions instead to perform actions like that.

    All vanilla events which used it have been replaced by equivalent trigger actions. This event IDs below no longer exist; if you check them (e.g. via HasSeenEvent), you'll need to check the new action or the mail flag they set instead.

    old event ID new action ID mail flag
    68 Mail_Mom_5K mom1
    69 Mail_Mom_15K mom2
    70 Mail_Mom_32K mom3
    71 Mail_Mom_120K mom4
    72 Mail_Dad_5K dad1
    73 Mail_Dad_15K dad2
    74 Mail_Dad_32K dad3
    75 Mail_Dad_120K dad4
    76 Mail_Tribune_UpAndComing newsstory
    706 Mail_Pierre_Fertilizers fertilizers
    707 Mail_Pierre_FertilizersHighQuality fertilizers2
    909 Mail_Robin_Woodchipper WoodChipper
    2111194 Mail_Emily_8heart EmilyClothingTherapy
    2111294 Mail_Emily_10heart EmilyCamping
    2346091 Mail_Alex_10heart joshMessage
    2346092 Mail_Sam_10heart samMessage
    2346093 Mail_Harvey_10heart harveyBalloon
    2346094 Mail_Elliott_10heart elliottBoat
    2346095 Mail_Elliott_8heart elliottReading
    2346096 Mail_Penny_10heart pennySpa
    2346097 Mail_Abigail_8heart abbySpiritBoard
    3333094 Mail_Pierre_ExtendedHours pierreHours
    3872126 Mail_Willy_BackRoomUnlocked willyBackRoomInvitation

    Mail changes

    These docs should be merged into Modding:Mail data. When copying content, make sure you attribute the original authors.
    • Mail can now have multiple items attached (using multiple %item commands). When the player grabs the top item, the next one will appear in the slot to grab next.
    • Added mail commands:
      command effect
      %action <action>%% Run a trigger action string, like %action AddMoney 500%% to add data-sort-value="500"> 500g to the current player.
    • Improved mail commands:
      command changes
      %item
      • Added %item id <item id> [count] form which accepts a qualified or unqualified item ID. If multiple items are listed (e.g., %item id (BC)12 3 (O)34 5 %%) one set will be picked randomly. This deprecates the bigobject, furniture, object, and tools options.
      • Added %item specialOrder <order id> [immediately] form to attach a special order to the letter.
      • Added optional <key> argument to %item cookingRecipe <key>, to learn a specific cooking recipe. The previous %item cookingRecipe form (without a key) works the same way as before.
      • The type argument is now case-insensitive.
      • Fixed %item craftingRecipe not supporting recipe IDs containing underscores. It now checks for an exact match first, then tries replacing underscores with spaces like before, then logs a warning if neither was found instead of adding an invalid recipe.
    • All wallet items are now tracked via mail flags. That adds these mail flags: HasClubCard, HasDarkTalisman, HasDwarvishTranslationGuide, HasMagicInk, HasMagnifyingGlass, HasRustyKey, HasSkullKey, HasSpecialCharm, HasTownKey, and HasUnlockedSkullDoor.
    • Fixed letter viewer error when opening an invalid letter.

    Stat changes for C# mods

    The tracked stats API (e.g. Game1.stats and Game1.player.stats) has been overhauled.

    In particular, all stats are now in the underlying stat dictionary. If you use a stat field directly (like stats.dirtHoed), you'll need to use the property (like stats.DirtHoed) or method (like stats.Get(StatsKey.DirtHoed)). This lets the game or mods access all stats in a standard way without reflection. 1.6 also adds StatsKey constants for all stats tracked by the game.

    The stats API has also been redesigned:

    member comments
    Values The numeric metrics tracked by the game. This replaces stats_dictionary.
    Get(key) Get the value of a tracked stat. This replaces getStat.

    For example:

    uint daysPlayed = Game1.stats.Get(StatKeys.DaysPlayed);
    
    Set(key, value) Set the new value of a tracked stat. This method is new.

    For example:

    Game1.stats.Set(StatKeys.ChildrenTurnedToDoves, 5);
    
    Increment(key)
    Increment(key, amount)
    Add the given amount to the stat (default 1), and return the new stat value. This improves on the original incrementStat.

    For example:

    uint stepsTaken = Game1.stats.Increment(StatKeys.StepsTaken);
    

    This can also be used to track custom mod stats, they doesn't need to be stats normally tracked by the game. Custom stats should be prefixed with your mod's unique ID to avoid conflicts:

    Game1.stats.Set("Your.ModId_CustomStat", 5);
    

    And finally, setting a stat to 0 now removes it from the stats dictionary (since that's the default for missing stats).

    New C# utility methods

    Stardew Valley 1.6 adds several new methods to simplify common logic.

    Argument handling

    The new ArgUtility class handles splitting, reading, and validating string[] argument lists. The main methods are:

    Splitting arrays:
    ArgUtility method effect
    SplitBySpace Split space-separated arguments in a string. This automatically ignores extra spaces, so " x  y " and "x y" are equivalent. For example:
    string[] fields = ArgUtility.SplitBySpace("a b c");
    string secondField = fields[1]; // "b"
    
    SplitBySpaceAndGet Get the value at an index in a space-delimited string (if found), else return the default value. For example:
    string thirdField = ArgUtility.SplitBySpaceAndGet("a b c", 2); // "c"
    string invalidFieldA = ArgUtility.SplitBySpaceAndGet("a b c", 5); // null
    string invalidFieldB = ArgUtility.SplitBySpaceAndGet("a b c", 5, defaultValue: "boop"); // "boop"
    

    This is more efficient than SplitBySpace when you only need a single value, but it's slower if you need multiple values.

    SplitBySpaceQuoteAware Split space-separated arguments in a string, with support for using quotes to protect spaces within an argument. See SplitQuoteAware below for info on quote handling.

    For example:

    string buildingName = ArgUtility.SplitBySpaceQuoteAware("BUILDINGS_CONSTRUCTED Here \"Junimo Hut\"")[1]; // Junimo Hut
    
    SplitQuoteAware Split delimited arguments in a string, with support for using quotes to protect delimiters within an argument.

    A quote in the text causes any delimiter to be ignored until the next quote, unless it's escaped like \". Unescaped quotes are removed from the string. (Remember that backslashes need to be escaped in C# or JSON strings, like "\\" for a single backslash.)

    For example:

    ArgUtility.SplitQuoteAware("A,B,C", ',');        // [ "A", "B", "C" ]
    ArgUtility.SplitQuoteAware("A,\"B,C\",D", ','); // [ "A", "B,C", "D" ]
    ArgUtility.SplitQuoteAware("A,\\\"B,C", ',');    // [ "A", "\"B", "C" ]
    

    You can also set the optional arguments for more advanced cases. For example, game state queries use this to split twice:

    string gameStateQuery = "BUILDINGS_CONSTRUCTED Here \"Junimo Hut\", SEASON Spring";
    
    string[] queries = ArgUtility.SplitQuoteAware(gameStateQuery, ',', StringSplitOptions.RemoveEmptyEntries, keepQuotesAndEscapes: true); // [ "BUILDINGS_CONSTRUCTED Here \"Junimo Hut\"", "SEASON Spring" ]
    string buildingName = ArgUtility.SplitBySpaceQuoteAware(queries[0]); // Junimo Hut
    
    EscapeQuotes Escape quotes in a string so they're ignored by methods like SplitQuoteAware.

    This isn't idempotent (e.g. calling it twice will result in double-escaped quotes).

    UnsplitQuoteAware Combine an array of arguments into a single string with a custom delimiter, using quotes where needed to escape delimiters within an argument. Calling SplitQuoteAware on the resulting string with the same delimiter will produce the original values.

    For example:

    string args = ArgUtility.UnsplitQuoteAware(new[] { "A", "B C", "D" }, ' '); // A "B C" D
    

    This isn't idempotent (e.g. calling it twice will result in double-escaped quotes).

    Reading arrays:
    ArgUtility method effect
    HasIndex Get whether an index is within the bounds of the array. For example:
    string[] fields = ArgUtility.SplitByString("10 5");
    bool inRange = ArgUtility.HasIndex(fields, 1); // true (index 1 has the value '5')
    
    Get
    GetBool
    GetDirection
    GetEnum
    GetFloat
    GetInt
    Get the value at a position in an array, parsed as the relevant type (e.g. a string, boolean, direction, enum, etc). If the index isn't in the array or the value can't be parsed as the expected type, returns a default value.

    For example, code like this:

    int value = fields.Length > 4 && int.TryParse(fields[4], out int parsed)
        ? parsed
        : -1;
    

    Can now be rewritten like this:

    int value = ArgUtility.GetInt(fields, 4, -1);
    
    TryGet
    TryGetBool
    TryGetDirection
    TryGetEnum
    TryGetFloat
    TryGetInt
    TryGetPoint
    TryGetRectangle
    TryGetVector2
    Try to get a parsed value from an array by its index. If it's not found or can't be converted to the expected value, it sets the out string error argument so you can log an error if needed.

    For example, this parses a numeric value from a space-delimited string:

    string[] fields = ArgUtility.SplitByString("10 35");
    if (ArgUtility.TryGetInt(fields, 1, out int value, out string error))
        this.Helper.Monitor.Log($"Parsed value: {value}"); // "Parsed value: 35"
    else
        this.Helper.Monitor.Log($"Failed parsing value: {error}", LogLevel.Warn);
    
    TryGetOptional
    TryGetOptionalBool
    TryGetOptionalDirection
    TryGetOptionalEnum
    TryGetOptionalFloat
    TryGetOptionalInt
    TryGetOptionalRemainder
    Equivalent to TryGet*, except that it'll return a default value if the argument is missing. For example:
    string[] fields = ArgUtility.SplitByString("10");
    if (ArgUtility.TryGetOptionalInt(fields, 1, out int value, out error, defaultValue: 99))
        this.Helper.Monitor.Log($"Parsed value: {value}"); // "Parsed value: 99"
    else
        this.Helper.Monitor.Log($"Failed parsing value: {error}", LogLevel.Warn);
    
    GetRemainder
    TryGetRemainder
    TryGetOptionalRemainder
    Similar to the previous methods, but gets arguments starting from an index as a concatenated string. For example:
    string[] fields = ArgUtility.SplitByString("A B C D E F");
    if (ArgUtility.TryGetRemainder(fields, 2, out string remainder, out string error))
        this.Helper.Monitor.Log($"Remainder: {remainder}"); // "Remainder: C D E F"
    else
        this.Helper.Monitor.Log($"Failed getting remainder: {error}", LogLevel.Warn);
    
    GetSubsetOf Get a slice of the input array. For example:
    string[] subset1 = ArgUtility.GetSubsetOf(new[] { "A", "B", "C", "D" }, startAt: 1); // B, C, D
    string[] subset2 = ArgUtility.GetSubsetOf(new[] { "A", "B", "C", "D" }, startAt: 1, length: 2); // B, C
    

    This is fault-tolerant as long as startAt isn't negative. For example:

    string[] subset2 = ArgUtility.GetSubsetOf(new[] { "A", "B", "C", "D" }, startAt: 100); // <empty array>
    string[] subset1 = ArgUtility.GetSubsetOf(new[] { "A", "B", "C", "D" }, startAt: 1, length: 100); // B, C, D
    

    Content assets

    method effect
    LocalizedContentManager.DoesAssetExist Get whether an asset exists in the game's Content folder or is provided through SMAPI's content API. For example:
    bool exists = Game1.content.DoesAssetExist<Map>("Maps/Town");
    
    LocalizedContentManager.IsValidTranslationKey Get whether a string is a translation key in the form <asset name>:<key>, and the asset and key both exist. For example:
    bool exists = Game1.content.IsValidTranslationKey("Strings\\NPCNames:Abigail");
    

    Filtering

    The game now has an optimized RemoveWhere method for O(n) filtering on NetCollection, NetDictionary, NetList, and (via extension) IDictionary. This also deprecates Filter methods where they existed.

    For example:

    int dirtTilesRemoved = Game1.currentLocation.terrainFeatures.RemoveWhere(pair => pair.Value is HoeDirt);
    

    Game paths

    The game folder paths were previously hardcoded throughout the code. These are now centralized with a few methods:

    method effect
    Program.GetLocalAppDataFolder
    Program.GetAppDataFolder
    Get the absolute path to the game's app data folder (which contains the Saves folder) or local app data folder (which contains ErrorLogs and Screenshots). These methods are equivalent on Windows, but different on Linux/macOS.
    Program.GetSavesFolder Get the absolute path to the game's Saves folder.
    Game1.GetScreenshotFolder Get the absolute path to the game's Screenshots folder.
    options.GetFilePathForDefaultOptions Get the absolute path to the game's default_options file.

    Hash sets

    Since the game now uses hash sets, it has a few extensions for working with them:

    method effect
    AddRange Add all the values from a list or enumerable to the set.
    RemoveWhere Remove all values matching a condition.
    Toggle Add or remove a value in the set based on a boolean. For example:
    public bool hasClubCard
    {
        get { return mailReceived.Contains("HasClubCard"); }
        set { mailReceived.Toggle("HasClubCard", value); }
    }
    

    Iteration

    The new Utility.ForEach* methods let you check every thing of a type in the game world quickly and efficiently (with minimal allocations, boxing, etc). These are significantly faster than equivalent code using LINQ or yield methods.

    method effect
    Utility.ForEachBuilding Perform an action for each building in the game world.
    Utility.ForEachCharacter
    Utility.ForEachVillager
    Perform an action for each NPC in the game world. ForEachCharacter matches all NPC types (villagers, horses, pets, monsters, player children, etc), while ForEachVillager only matches villager NPCs like Abigail.
    Utility.ForEachCrop Perform an action for each crop in the game world planted in the ground or in a garden pot.
    Utility.ForEachItem Perform an action for each item in the game world, including items within items (e.g. in a chest or on a table), hats placed on children, items in player inventories, etc.
    Utility.ForEachItemIn Perform an action for each item within a given location, including items within items (e.g. in a chest or on a table).
    Utility.ForEachLocation Perform an action for each location in the game world, optionally including building interiors and generated mine or volcano levels.

    For example, this code counts how many parsnips are planted everywhere in the world:

    int parsnips = 0;
    Utility.ForEachCrop(crop =>
    {
        if (crop.IndexOfHarvest == "24")
            parsnips++;
        return true; // whether to keep iterating after this crop
    });
    

    Or you could replace all instances of an obsolete item with a new one:

    Utility.ForEachItem((item, remove, replaceWith) =>
    {
        if (item.QualifiedItemId == "(O)OldId")
        {
            Item newItem = ItemRegistry.Create("(O)NewId", item.Stack, item.Quality);
            replaceWith(newItem);
        }
    
        return true;
    });
    

    C# mods which add custom item types can override Item.ForEachItem to add support for nested items.

    Randomization

    method effect
    Utility.CreateDaySaveRandom Creates a Random instance using the most common seed (based on the save ID and total days played).
    Utility.CreateRandom
    Utility.CreateRandomSeed
    Creates a Random (or seed for a Random) by combining the given seed values, which can be any numeric type.
    Utility.TryCreateIntervalRandom Get an RNG which produces identical results for all RNGs created with the same sync key during the given interval (one of tick, day, season, or year), including between players in multiplayer mode.

    For example, this will return the same number each time it's called until the in-game day changes:

    public int GetDailyRandomNumber()
    {
        Utility.TryCreateIntervalRandom("day", "example sync key", out Random random, out _);
        return random.Next();
    }
    
    Utility.TryGetRandom Get a random entry from a dictionary.
    random.Choose Choose a random option from the values provided:
    string npcName = Game1.random.Choose("Abigail", "Penny", "Sam");
    
    random.ChooseFrom Choose a random option from a list or array:
    string[] names = new[] { "Abigail", "Penny", "Sam" };
    string npcName = Game1.random.ChooseFrom(names);
    
    random.NextBool Randomly choose true or false. For example:
    bool flipSprite = Game1.random.NextBool();
    

    You can optionally set the probability of true:

    bool flipSprite = Game1.random.NextBool(0.8);
    

    Other

    Here are some of the other new methods:

    method effect
    Game1.getOfflineFarmhands() Get all farmhands who aren't connected to the game.
    Game1.PerformActionWhenPlayerFree Calls the provided callback next time the player is free (e.g. no menu or event is up, not using a tool, etc). If the player is already free, it's run immediately.

    For example, if you receive your first geode from a fishing chest, this is used to show the geode-received animation & animation when it closes.

    Game1.createRadialDebris_MoreNatural Scatter item debris around a position with a more randomized distribution than createRadialDebris.
    Object.GetCategoryColor
    Object.GetCategoryDisplayName
    Get the color and display name for the given category number when it's shown in a tooltip.
    Utility.distanceFromScreen Get the pixel distance between a position in the world and the player's screen viewport, where 0 is within the viewport.
    Utility.DrawErrorTexture Draw the game's missing-texture image (🚫) to the screen, stretched to fit a given pixel area.
    Utility.DrawSquare Draw a square to the screen with a background color and/or borders.
    Utility.GetEnumOrDefault Get an enum value if it's valid, else get a default value. This is mainly used to validate input from data files.

    For example:

    NpcGender gender = (NPCGender)999999;
    gender = Utility.GetEnumOrDefault(gender, Gender.Male); // returns Gender.Male since there's no enum constant with value 999999
    
    Utility.getRandomNpcFromHomeRegion Get a random social NPC based on their HomeRegion value in Data/Characters. For example, this gets a random NPC for the Town home region:
    NPC npc = Utility.getRandomNpcFromHomeRegion(NPC.region_town);
    
    Utility.isFestivalDay This method existed before 1.6, but you can now omit arguments to check today instead of a specific date:
    bool festivalToday = Utility.isFestivalToday();
    

    Or check for a festival in specific location context:

    bool desertFestivalToday = Utility.isFestivalToday(LocationContexts.DesertId);
    
    Utility.IsPassiveFestivalDay This method existed before 1.6, but now can now omit arguments to check today instead of a specific date:
    bool passiveFestivalToday = Utility.IsPassiveFestivalDay();
    

    Or check for a specific passive festival:

    bool nightMarketToday = Utility.IsPassiveFestivalDay("NightMarket");
    
    Utility.TryGetPassiveFestivalData
    Utility.TryGetPassiveFestivalDataForDay
    Get the passive festival data for the given ID or date.
    Utility.TryParseDirection Parse a string into a direction value (like Game1.down), if it's valid. This supports case-insensitive direction names (one of down, left, right, or up) or numeric values.
    Utility.TryParseEnum Parse a string into an enum value if possible, case-insensitively. Unlike Enum.TryParse, an invalid numeric value won't be cast:
    Enum.TryParse("999999", out DayOfWeek day);        // true, even though there's no matching DayOfWeek value
    Utility.TryParseEnum("999999", out DayOfWeek day); // false
    
    Utility.fuzzyCompare Get whether a term is a fuzzy match for a search query. Returns the numeric match priority (where lower values are a better match), or null if the term doesn't match the query.
    rectangle.GetPoints
    rectangle.GetVectors
    Get all the integer coordinates within a given Rectangle. For example:
    var tileArea = new Rectangle(0, 0, 2, 2);
    Point[] tiles = tileArea.GetPoints(); // (0, 0), (1, 0), (0, 1), (1, 1)
    
    Utility.GetDeterministicHashCode (Specialized) Get a hash code for a string key or numeric values. Unlike string.GetHashCode or HashCode.Combine, this produces a consistent hash for the same inputs between sessions and connected players.
    Utility.WrapIndex Constrain an index to a range by wrapping out-of-bounds values to the other side (e.g. last index + 1 is the first index, and first index - 1 is the last one).

    For example:

    string[] values = new[] { "0", "1", "2" };
    int index = Utility.WrapIndex(-1, values.Length); // 2
    

    Static delegate builder

    For C# mods, StaticDelegateBuilder is a specialized class which converts a method name into an optimized delegate which can be called by code. This is used by vanilla code to optimize methods referenced in assets like Data/Machines.

    For example, given a static method like this:

    public static bool OutputDeconstructor(Object machine, Item inputItem, bool probe, MachineItemOutput outputData, out int? overrideMinutesUntilReady) { ... }
    

    And a delegate which matches it:

    public delegate bool MachineOutputDelegate(Object machine, Item inputItem, bool probe, MachineItemOutput outputData, out int? overrideMinutesUntilReady);
    

    You can create an optimized delegate and call it like this:

    if (StaticDelegateBuilder.TryCreateDelegate("StardewValley.Object.OutputDeconstructor", out MachineOutputDelegate method, out string error))
        return method(this, inputItem, probe, outputData, out minutesUntilMorning);
    else
        Game1.log.Warn($"Machine {ItemId} has invalid output method: {error}");
    

    The TryCreateDelegate method will cache created delegates, so calling it again will just return the same delegate instance.

    Game logging changes

    The game now writes debug output through an internal Game1.log wrapper, instead of using Console.WriteLine directly. For example:

    // old code
    Console.WriteLine("Error playing sound: " + ex);
    
    // new code
    Game1.log.Error("Error playing sound.", ex);
    

    This has a few benefits:

    • For vanilla players, the game no longer uses time & resources writing to a console that's not visible anyway.
    • For modded players, SMAPI can now...
      • distinguish between the game's debug/warn/error messages (so many warnings/errors that would previously appear as hidden TRACE messages will now be shown with the correct level);
      • apply its formatting rules to exceptions logged by the game too;
      • redirect game output much more efficiently without console interception.

    Other changes

    Audio

    • Added Game1.sounds, which unifies the high-level sound effect logic (e.g. distance fading and multiplayer sync).
    • Added silence audio cue for music. This is different from none in that it suppresses both town music and ambient sounds.
    • Added Game1.soundBank.Exists(cueName) method to check if an audio cue exists.
    • Added Game1.playSound overloads to get the audio cue being played.
    • Added character.playNearbySoundAll and playNearbySoundAllLocal methods to play a sound for players near the player/character.
    • Added position argument to DelayedAction.playSoundAfterDelay.
    • Removed NetAudioCueManager and Game1.locationCues (unused).
    • Unified the methods for playing normal/pitched/positional sounds (which also adds support for pitched non-synced & pitched positional sounds):
      old methods new method
      Game1.playSound
      Game1.playSoundAt
      Game1.playSoundPitched
      Game1.playSound
      GameLocation.playSound
      GameLocation.playSoundAt
      GameLocation.playSoundPitched
      GameLocation.playSound
      GameLocation.localSound
      GameLocation.localSoundAt
      GameLocation.localSound
      NetAudio.Play
      NetAudio.PlayAt
      NetAudio.PlayPitched
      NetAudio.Play
      NetAudio.PlayLocal
      NetAudio.PlayLocalAt
      NetAudio.PlayLocal

    Debug commands

    These docs should be merged into Modding:Console commands. When copying content, make sure you attribute the original authors.
    • All debug commands are now quote-aware, so you can pass spaces in arguments like debug build "Junimo Hut".
    • Added new debug commands:
      command description
      action <action> Run a trigger action string, like action AddMoney 500 to add data-sort-value="500"> 500g to the current player.
      artifactSpots Spawn an artifact spot in each empty tile around the player.
      endEvent / ee Immediately end the current event or festival, applying the event's skip logic (if any). The event is marked seen, but you can rewatch it using the eventById command if needed.

      This replaces the pre-1.6 commands (ee, endEvent/leaveEvent, and eventOver) which worked in different ways and had side-effects like restarting the event or clearing the player's mail.

      exportShops Export a summary of what's in every shop in the game, taking into account their current conditions. This is saved to a file on disk, and the file path shown in the console.
      filterLoadMenu / flm Syntax: filterLoadMenu <search text>

      Filter the current list of saves to those whose player name or farm name contains the given text.

      forcebuild Equivalent to build, but disables all safety checks so you can build in a location that wouldn't normally allow buildings, build on top of farm animals or placed objects, etc.
      gamequery / gq Syntax: gq <query>

      Check whether the given game state query matches in the current context. For example:

      gq !SEASON Spring, WEATHER Here Sun
      > Result: true.
      
      itemquery / iq Syntax: iq <query>

      Open a shop menu with all the items matching an item query (all items free). For example:

      • debug iq ALL_ITEMS shows all items;
      • debug iq ALL_ITEMS (W) shows all weapons;
      • debug iq (O)128 shows a pufferfish (object 128);
      • debug iq FLAVORED_ITEM Wine (O)128 shows Pufferfish Wine.
      logFile Begin writing debug messages to a log file at %appdata%/StardewValley/ErrorLogs/game-latest.txt to simplify troubleshooting. You can also enter /logtext into the in-game chatbox to enable it.

      This does nothing if SMAPI is installed, since the debug messages are already saved to SMAPI's log.

      logSounds Log info about each sound effect played to the SMAPI console window.
      movieSchedule [year] Lists the movies that will play in a given [year] (default this year), with the dates they'll play.
      qualifiedid Print the held item's display name and qualified item ID.
      search Syntax: search [term]

      List all debug commands that match the given search term (or all debug commands if the search term is omitted). For example:

      debug search backpack
      > Found 2 debug commands matching search term 'backpack':
          - Backpack
          - FillBackpack (fbp, fill, fillbp)
      setFarmEvent / sfe Syntax: setFarmEvent <event id>

      Queue an overnight farm event if one doesn't plan naturally instead. The <event id> can be one of...

      Note that even if the farm event runs, it may exit without doing anything (e.g. rare events like ufo have extra condition checks when the start).

      shop Syntax: shop <shop ID> [owner name]

      Open a shop defined in Data/Shops, regardless of whether one of the owners is nearby. Specifying [owner name] will use that NPC, otherwise the command will find the closest valid NPC if possible (else open with no NPC).

      skinBuilding / bsm If the player is standing right under a building, open a menu to change the building appearance.
      testwedding Immediately play the wedding event. This requires the player to be married first - to test specific NPCs, debug marry the NPC followed by this command.
      thishouseupgrade / thishouse / thu Equivalent to houseupgrade, but can be used to upgrade another player's house by running it from inside or just south of its exterior.
      toggleCheats Enable or disable entering debug commands into the in-game chat (prefixed with /).
      tokens Syntax: tokens <tokenized string>

      Parses a tokenizable string and prints its output. For example:

      tokens [LocalizedText Strings\StringsFromCSFiles:MapPage.cs.11064 [EscapedText [FarmName]]]
      > Result: "Lon Lon Farm"
      
      worldMapLines Toggles the world map's debug view.
    • Improved existing debug commands:
      command changes
      build Removed custom space handling; quote arguments with spaces instead of replacing them with 9 (e.g. Junimo9Hut"Junimo Hut").
      clearFurniture Now works outside the farmhouse too.
      dialogue Removed custom space handling; quote NPC names containing spaces instead, with all text after the first argument treated as part of the dialogue (e.g. debug dialogue "Some NPC" Some dialogue text$h).
      ebi Fixed event not played correctly if called from the same location as the event.
      fish Fixed error if you're not holding a fishing rod. It now opens the fishing minigame with no tackle instead.
      frameOffset
      • Simplified usage. You can now pass negative offsets directly (like debug frameOffset -5 -10) instead of using the s number prefix.
      • Fixed command only taking the last digit in each number.
      getStat
      setStat
      Added argument validation.
      grass Now applies to the current location, instead of the farm.
      growAnimals
      growAnimalsFarm
      Merged into one growAnimals command that supports any location and doesn't reset the age of animals which are already adults.
      growCrops Fixed error growing mixed seeds or giant crops.
      itemNamed Removed custom space handling; quote arguments with spaces instead of removing them (e.g. EelRoe"Eel Roe").
      junimoGoodbye
      junimoStar
      Added validation to check that you're inside the community center.
      killAll
      killAllHorses
      killNpc
      These now remove matching NPCs inside constructed buildings too.
      killMonsterStat Removed custom space handling; quote arguments with spaces instead of replacing them with 0 (e.g. Dust0Spirit"Dust Spirit").
      mailForTomorrow Fixed zeros in the mail ID getting replaced with underscores.
      monster Added validation for the monster name.
      moveBuilding Now applies to the current location, instead of the farm.
      movie Rewritten; it's now simpler, applies the normal game logic, defaults to today's movie, and avoids depending on NPC indexes in Data/NPCDispositions since those can change with custom NPCs.

      New usage:

      debug movie [movie ID] [invite NPC name]
      debug movie current [invite NPC name]

      The movie ID defaults to today's movie, and the NPC name can be omitted to watch the movie without an invitee. Specifying current as the movie uses the default value.

      panMode The command no longer overrides debug command handling while it's active. Instead you can now turn it back off by running debug panMode again, clear with debug panMode clear, or set a time with debug panMode {time}.
      paintBuilding
      • Now applies to the current location, instead of the farm.
      • Added validation for the target building.
      playSound Added an optional pitch argument, like debug playSound barrelBreak 1200. The pitch is a value from 1 (low pitch) to 2400 (high pitch) inclusively.
      question You can now forget a selected answer (instead of adding it) by setting the second argument to false, like question <id> false.
      runTestEvent Fixed support for Unix line endings.
      seenEvent You can now forget an event (instead of adding it) by setting the second argument to false, like seenEvent <id> false.
      seenMail You can now remove a mail received (instead of adding it) by setting the second argument to false, like seenMail <id> false.
      skinBuilding
      • Now applies to the current location, instead of the farm.
      • Added validation for the target building.
      skullGear
      • Fixed command setting 32 slots instead of 36.
      • Fixed command not adding empty inventory slots as expected by some game code.
      setupFishPondFarm Fixed error if the farm already has non-fish-pond buildings constructed.
      speech Removed custom space handling; quote NPC names containing spaces instead, with all text after the first argument treated as part of the dialogue (e.g. debug speech "Some NPC" Some dialogue text$h).
      spreadDirt Now applies to the current location, instead of the farm.
      spreadSeeds Now applies to the current location, instead of the farm.
      thisHouseUpgrade Now applies to the current location, instead of the farm.
      warpToPlayer Removed custom space handling; quote arguments with spaces instead of removing them (e.g. JohnSmith"John Smith").
      whereIs
      • Now lists all matching NPCs instead of the first one.
      • Now searches the current event or festival, if any.
    • Removed some debug commands:
      command notes
      ax
      bigItem/b/bi/big
      boots
      clothes
      hoe
      milkPail/mp
      pan
      pickaxe/pick/pickax
      ring/addRing
      shears/scissors
      slingshot
      tool
      wateringCan/can
      wand
      weapon
      These are replaced by more general commands like item (O)128 (spawn item by ID), fuzzyItemNamed pufferfish (spawn by item name), or itemQuery FLAVORED_ITEM Wine (O)128 (spawn by item query).
      addQuartz
      blueBook
      blueprint
      end
      These were part of unused features removed in 1.6.
      changeStat Removed; use setStat instead.
      ee
      endEvent/leaveEvent
      eventOver
      Replaced by the new endEvent command.
      everythingshop Removed. You can get all items like debug iq ALL_ITEMS, or all items of a given type like debug iq ALL_ITEMS (O).
      oldMineGame Removed along with the pre-1.4 Junimo Kart code.
      pathSpouseToMe/pstm Removed along with the unimplemented farm activities code.
    • Added alternative names for some debug commands (new names in parentheses): bpm + bsm (paintBuilding + skinBuilding), craftingRecipe (addCraftingRecipe), db (speakTo), dialogue (addDialogue), pdb (printGemBirds), r (resetForPlayerEntry), removeLargeTf (removeLargeTerrainFeature), sb (showTextAboveHead), sl + sr (shiftToolbarLeft + shiftToolbarRight), sn (secretNote), and tls (toggleLightingScale).
    • Reworked how debug commands log output. This fixes an issue where they don't always log to the right place (e.g. a command run through the chatbox might log to the console or vice-versa), and lets mods pass a custom logger to capture or redirect output.

    Location logic

    • The desert no longer assumes the player arrived by bus unless their previous location was the bus stop.
    • The ticket price for the bus and Willy's boat can now be edited by C# mods via BusStop.TicketPrice and BoatTunnel.TicketPrice respectively.

    Menus & UI

    • Rewrote calendar menu (Billboard) to simplify custom events & event types. C# mods can now edit billboard.calendarDayData or patch billboard.GetEventsForDay to add new events.
    • Added Game1.textShadowDarkerColor field for the colors previously hardcoded in Utility.drawTextWithShadow.
    • Added MoneyDial.ShouldShakeMainMoneyBox field to simplify custom dials.
    • Partly de-hardcoded ShopMenu filter tabs. You can now change filter tabs by setting the shopMenu.tabButtons field with arbitrary Func<ISalable, bool> Filter values, or by using a predefined set of tabs like shopMenu.UseDresserTabs().
    • The SpriteText methods now accept arbitrary Color tints instead of a few predefined color IDs.
    • The DiscreteColorPicker.getColorFromSelection methods are now static for reuse.
    • Fixed DiscreteColorPicker constructor ignoring the initial color argument, and added a constructor which takes a Color value.
    • Fixed an edge case where a custom language's fonts wouldn't be loaded when switching language.

    Net fields

    • Removed implicit conversion operators for most types due to their sometimes counter-intuitive behavior. The only ones left are NetBool, NetInt, and NetString; those are now marked obsolete and will raise build warnings on use.
    • NetLocationRef now has a public LocationName and IsStructure, and its Update method allows forcing an update.

    Quests

    These docs should be merged into Modding:Quest data. When copying content, make sure you attribute the original authors.
    • Quests now have string IDs, to simplify custom quest frameworks.
    • Added validation for quest data parsing.
    • In Data/SpecialOrders, the Duration and Repeatable fields are now strongly-typed and case-insensitive.
    • For C# mods, fixed DescriptionElement not allowing more than four translation token substitutions.

    Dates & seasons

    • Added a Season enum for strongly-typed, case-insensitive season checks (like Game1.season == Season.Spring instead of Game1.currentSeason == "spring").
    • Added Game1.season, Game1.GetSeasonForLocation, Game1.WorldDate.Season, and location.GetSeason() to get the season enum.
    • Added Utility.getSeasonKey to get the key form from a season enum.
    • Improved WorldDate:
      • added Now() to get a new instance matching the current date;
      • added WorldDate.Equals and GetHashCode implementations;
      • added code docs;
      • TotalDays is no longer written to the save file.
    • Renamed some members for clarity (Game1.GetSeasonForLocationGetSeasonKeyForLocation, location.GetSeasonForLocationGetSeasonKey, WorldDate.SeasonSeasonKey).
    • Fixed location.GetSeasonKey() not applying the greenhouse logic.

    Time

    • For C# mods, the Game1.realMilliSecondsPerGame and Game1.realMilliSecondsPerGameTenMinutes fields are no longer marked const, and the GameLocation.getExtraMillisecondsPerInGameMinuteForThisLocation() method has been replaced with a settable ExtraMillisecondsPerInGameMinute property. That lets you change the time rate used by the vanilla game code, but you should be careful doing this since it may cause unintended effects.

    Other

    • Error stack traces on Linux/macOS now have line numbers.
    • All space-delimited fields now ignore extra spaces instead of crashing. This affects map/tile properties, data assets, event commands, game state queries, etc.
    • All players and NPCs now have Tile & TilePoint properties (their cached tile position) and a StandingPixel property (the cached pixel coordinate at the center of their bounding box). These replace various deleted methods.
    • All terrain features now have Tile and Location properties, and their methods no longer have location/tile parameters in most cases.
    • All net fields now have Name and Owner fields, which are used to show informative error messages when there's a sync issue and validate common mistakes (e.g. a net field not added to the NetFields collection).
    • The game now tracks the locations a player has visited. Mods can check the list in C# (via Game1.player.locationsVisited) or game state queries (via PLAYER_VISITED_LOCATION). For pre-existing saves, the list is retroactively populated based on accessible locations, events seen, mail flags set, etc.
    • Added menu queuing (via Game1.nextClickableMenu in C#). For example, this applies if you try to take an item from a mail letter when your inventory is full.
    • Added C# code docs in many places.
    • Added Id fields to simplify content pack edits in fish pond, movie concession, random bundle, and tailoring recipe data.
    • Added Game1.Multiplayer to get the game's low-level handler. (Most code should still use SMAPI's multiplayer API though.)
    • Added Game1.versionBuildNumber with the build number (like 26039).
    • Added field-changed events to NetPosition.
    • Added LocalizedContentManager.CurrentLanguageString, which caches the language code like pt-BR).
    • The game now uses [XmlInclude] on its types more consistently. That means the default save serializer can handle more types (e.g. all monsters), and it's easier to create custom serializers.
    • Refactored many parts of the code to make it more moddable for C# mods. This includes marking all classes public, changing private members to protected or public, marking members virtual, rewriting or splitting code so it's easier to extend, etc.
    • The startup_preferences file is now formatted to simplify troubleshooting.
    • Fixed many cases where the game used Game1.player instead of the provided player.

    Breaking changes for C# mods

    This section only describes how this update may break existing mods. See the what's new sections above for more info, including new functionality mods can use.

    See also Breaking changes for content packs, which affect C# mods too.

    .NET 6

    See also: .NET 6 under what's new.

    Stardew Valley 1.6 updates from .NET 5 to .NET 6. SMAPI can still load .NET 5 mods fine, but you'll get a build error when compiling them. To update a C# mod:

    1. Make sure you have Visual Studio Community 2022 or later. (Compiling .NET 6 with earlier versions of Visual Studio isn't officially supported.)
    2. In Visual Studio, click Help > Check For Updates and install the latest version.
    3. Fully exit Visual Studio.
    4. Open each mod's .csproj file in a text editor, then find this line:
      <TargetFramework>net5.0</TargetFramework>
      

      And change it to this:

      <TargetFramework>net6.0</TargetFramework>
      
    5. Delete your solution's hidden .vs folder, and every project's bin and obj folders.
    6. Reopen the solution in Visual Studio, click Build > Rebuild Solution, and make sure it still loads into the game fine.

    Item ID changes

    See also: custom items in what's new.

    The main Item properties have changed. To migrate existing code:

    • Don't use ParentSheetIndex to compare items. For example, item.ParentSheetIndex == 0 will match both weeds and any custom item whose sprite is the first one in its custom spritesheet. You should compare items using their new ItemId and QualifiedItemId properties instead. For example, here's how to migrate various common forms:
      old code new code
      item.ParentSheetIndex == 848 item.QualifiedItemId == "(O)848"
      IsNormalObjectAtParentSheetIndex(item, 74) item.QualifiedItemId == "(O)74"
      !item.bigCraftable && item.ParentSheetIndex == 128 item.QualifiedItemId == "(O)128"
      item is Boots && item.ParentSheetIndex == 505 item.QualifiedItemId == "(B)505"
    • Don't assume item sprites are in the vanilla spritesheets. For example, instead of rendering Game1.objectSpriteSheet for an object, call ItemRegistry.GetMetadata(item.QualifiedItemId).GetTexture() to get its texture.
    • Creating items works just like before, except that you now specify the item's ItemId (not QualifiedItemId) instead of its ParentSheetIndex. This is the same value for vanilla items. For example:
      new Object("634", 1);                      // vanilla item
      new Object("Example.ModId_Watermelon", 1); // custom item
      

      You can also use the new ItemRegistry API to construct items from their QualifiedItemId:

      Item item = ItemRegistry.Create("(B)505"); // Rubber Boots
      

    Other ID changes

    Many other things in the game now have unique string IDs too (including buffs, events, and fruit trees). To migrate existing code:

    • When referencing numeric IDs, you usually just need to convert them into a string (like Game1.player.hasBuff("1590166") or Game1.player.eventsSeen.Contains("1590166")).
    • When creating buffs, see buff overhaul for how to create buffs now.
    • For pre-existing content pack data, see migration steps in the unique string IDs section.

    Building and animal changes

    See also: build anywhere in what's new.
    • Since all locations now allow buildings and animals, mod code which handles BuildableGameLocation and IAnimalLocation won't detect all buildable locations. You can replace them with location.IsBuildableLocation() (or just access location.buildings directly) and location.animals.Any() instead. Mods should no longer have any reference at all to BuildableGameLocation and IAnimalLocation.
    • Since buildings can be built anywhere, you can no longer assume a building is on the farm. You can check the new building.buildingLocation field instead.
    • You should review direct references to the farm (like Game1.getFarm() or Game1.getLocationFromName("Farm")) to see if it needs to be rewritten to allow other locations.
    • Utility.numSilos() should no longer be used to calculate available hay, since it doesn't account for custom buildings with hay storage. Use Game1.getFarm().GetHayCapacity() instead.
    • The Cat and Dog classes are now unused; all pets are now Pet directly.

    Player changes

    See also: buff overhaul in what's new.
    • Several Game1.player / Farmer fields changed as part of the buff overhaul:
      old field how to migrate
      appliedBuffs
      appliedSpecialBuffs
      Use Game1.player.hasBuff(id) instead.
      attack
      immunity
      Use Attack and Immunity instead.
      addedCombatLevel
      addedFarmingLevel
      addedFishingLevel
      addedForagingLevel
      addedLuckLevel
      addedMiningLevel
      attackIncreaseModifier
      critChanceModifier
      critPowerModifier
      knockbackModifier
      weaponPrecisionModifier
      weaponSpeedModifier
      Use equivalent properties under Game1.player.buffs instead (e.g. Game1.player.buffs.CombatLevel).
      resilience Use buffs.Defense instead.
      addedSpeed
      CombatLevel
      CraftingTime
      FarmingLevel
      FishingLevel
      ForagingLevel
      LuckLevel
      MagneticRadius
      MaxStamina
      MiningLevel
      Stamina
      These are now readonly and can't be set directly. You can change them by adding a buff (which can be invisible), equipment bonus, etc instead.
    • Buffs are now recalculated automatically, and you can reset a buff by just reapplying it. See buff overhaul for more info.
    • Buff logic has been centralized into Game1.player.buffs. This replaces a number of former fields/methods like Game1.buffsDisplay.

    Collision changes

    The game's tile collision logic has been overhauled and merged into a simpler set of methods on GameLocation instances:

    method effect
    CanSpawnCharacterHere Get whether NPCs can be placed on the given tile (e.g. it's within the map bounds and tile is walkable), there's no placed object there, and the NoFurniture tile property isn't set.
    CanItemBePlacedHere Get whether items can be placed on the given tile in non-floating form (e.g. it's within the map bounds and not blocked by a non-walkable item), and the NoFurniture tile property isn't set.
    isBuildable Get whether buildings can be placed on the given tile.
    IsTilePassable Get whether the tile can be walked on (ignoring collisions with in-game objects, NPCs, etc).
    IsTileOccupiedBy Get whether the tile contains a player, object, NPC/monster/pet/etc, terrain feature, building, etc. You can choose which entities to check, and which ones to ignore if they don't block movement.
    IsTileBlockedBy Equivalent to calling both IsTilePassable and IsTileOccupiedBy.
    IsLocationSpecificOccupantOnTile
    IsLocationSpecificPlacementRestriction
    Generally shouldn't be used directly. Checks for location-specific collisions (e.g. ladders in the mines or parrot platforms on Ginger Island).

    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 unused code

    1.6 removes a lot of unused code. That includes these classes:

    namespace class name
    StardewValley
    • BuildingUpgrade
    • DisposableList
    • FurniturePlacer
    • ListPool
    • OneTimeRandom
    StardewValley.Characters
    • BotchedNetBool
    • BotchedNetField
    • BotchedNetInt
    • BotchedNetLong
    StardewValley.Menus
    • FarmInfoPage
    • MiniatureTerrainFeature
    StardewValley.Monsters
    • LavaCrab
    StardewValley.Objects
    StardewValley.TerrainFeatures
    • Quartz
    StardewValley.Tools

    And these class members:

    type members
    Axe
    • StumpStrength
    Bush
    • alpha
    • lastPlayerToHit
    Chest
    • chestType
    • coins
    CosmeticPlant
    • scale
    CraftingRecipe
    • itemType
    Critter
    • InitShared()
    Crop
    • daysOfUnclutteredGrowth
    Dialogue
    • dialogueToBeKilled
    Farm
    • GetSpouseOutdoorAreaSpritesheetIndex()
    FarmAnimal
    • homeLocation
    Farmer
    • barnUpgradeLevel and BarnUpgradeLevel
    • blueprints
    • coalPieces and CoalPieces
    • coopUpgradeLevel and CoopUpgradeLevel
    • copperPieces and CopperPieces
    • eyeColor
    • feed and Feed
    • furnitureOwned
    • goldPieces and GoldPieces
    • hasBusTicket
    • hasGreenhouse
    • iridiumPieces and IridiumPieces
    • ironPieces and IronPieces
    • newSkillPointsToSpend
    • overallsColor
    • ownsFurniture
    • quartzPieces and QuartzPieces
    • shirtColor
    • skinColor
    • stonePieces and StonePieces
    • theaterBuildDate
    • woodPieces and WoodPieces
    Game1
    • boardingBus
    • chanceToRainTomorrow
    • checkForNewLevelPerks
    • cloud
    • coopDwellerBorn
    • cropsOfTheWeek
    • currentBarnTexture
    • currentBillboard
    • currentCoopTexture
    • currentFloor
    • currentHouseTexture
    • currentWallpaper
    • dealerCalicoJackTotal
    • FarmerFloor
    • farmerWallpaper
    • fertilizer
    • floorPrice
    • greenhouseTexture
    • inMine
    • jukeboxPlaying
    • keyHelpString
    • listeningForKeyControlDefinitions
    • littleEffect
    • logoScreenTexture
    • mailboxTexture
    • menuChoice
    • menuUp
    • nameSelectUp
    • nameSelectType
    • numberOfSelectedItems
    • particleRaining
    • pickingTool
    • pickToolDelay
    • pickToolInterval
    • priceOfSelectedItem
    • progressBar
    • removeSquareDebrisFromTile(…)
    • selectedItemsType
    • shiny
    • shippingTax
    • showKeyHelp
    • slotResult
    • startedJukeboxMusic
    • tinyFontBorder
    • toolHeld
    • toolIconBox
    • tvStation
    • tvStationTexture
    • wallpaperPrice
    GameLocation
    • boardBus(…)
    • checkForMapChanges()
    • getWallDecorItem(…)
    • removeBatch(…)
    • removeDirt(…)
    • removeStumpOrBoulder(…)
    • tryToBuyNewBackpack()
    GiantCrop
    • forSale
    IClickableMenu
    • currentRegion
    MeleeWeapon
    • attackSwordCooldownTime
    • doStabbingSwordFunction(…)
    Monster
    • doHorizontalMovement(…)
    • durationOfRandomMovements
    • coinsToDrop
    NPC
    • idForClones
    Object
    • attachToSprinklerAttachment(…)
    • canBePlacedInWater()
    • consumeRecipe(…)
    • copperBar
    • goldBar
    • iridiumBar
    • ironBar
    • isHoeDirt and IsHoeDirt
    PathFindController
    • CheckClearance(…)
    • limit
    SaveGame
    • cropsOfTheWeek
    • currentFloor
    • currentWallpaper
    • FarmerFloor
    • farmerWallpaper
    • shippingTax
    Spiker
    • GetSpawnPosition
    Stats
    • barsSmelted and BarsSmelted
    • coalFound and CoalFound
    • coinsFound and coinsFound
    • starLevelCropsShipped and starLevelCropsShipped
    Tool
    • batteredSwordSpriteIndex
    • copperColor
    • GetSecondaryEnchantmentCount()
    • goldColor
    • iridiumColor
    • nonUpgradeable
    • parsnipSpriteIndex
    • Stackable
    • startOfNegativeWeaponIndex
    • steelColor
    Utility
    • buyFloor()
    • buyWallpaper()
    • cropsOfTheWeek()
    • facePlayerEndBehavior(…)
    • getRandomSlotCharacter()
    • plantCrops(…)
    • showLanternBar()

    Renamed classes

    These classes were renamed in 1.6:

    old name new name
    Game1.MusicContext MusicContext (in StardewValley.GameData)
    LocationContext LocationContexts
    SpecialOrder.QuestStatus SpecialOrderStatus (in StardewValley.SpecialOrders)

    And these were moved to a different namespace:

    type old namespace new namespace
    AmethystEnchantment
    AquamarineEnchantment
    ArchaeologistEnchantment
    ArtfulEnchantment
    AutoHookEnchantment
    AxeEnchantment
    BaseEnchantment
    BaseWeaponEnchantment
    BottomlessEnchantment
    BugKillerEnchantment
    CrusaderEnchantment
    DiamondEnchantment
    EfficientToolEnchantment
    EmeraldEnchantment
    FishingRodEnchantment
    GalaxySoulEnchantment
    GenerousEnchantment
    HaymakerEnchantment
    HoeEnchantment
    JadeEnchantment
    MagicEnchantment
    MasterEnchantment
    MilkPailEnchantment
    PanEnchantment
    PickaxeEnchantment
    PowerfulEnchantment
    PreservingEnchantment
    ReachingToolEnchantment
    RubyEnchantment
    ShavingEnchantment
    ShearsEnchantment
    SwiftToolEnchantment
    TopazEnchantment
    VampiricEnchantment
    WateringCanEnchantment
    StardewValley StardewValley.Enchantments
    Extensions StardewValley StardewValley.Extensions
    ModDataDictionary
    ModHooks
    StardewValley StardewValley.Mods
    PathFindController
    PathNode
    PriorityQueue
    SchedulePathDescription
    StardewValley StardewValley.Pathfinding
    SpecialOrder StardewValley StardewValley.SpecialOrders
    CollectObjective
    DeliverObjective
    DonateObjective
    FishObjective
    GiftObjective
    JKScoreObjective
    OrderObjective
    ReachMineFloorObjective
    ShipObjective
    SlayObjective
    StardewValley StardewValley.SpecialOrders.Objectives
    FriendshipReward
    GemsReward
    MailReward
    MoneyReward
    OrderReward
    ResetEventReward
    StardewValley StardewValley.SpecialOrders.Rewards

    Other API changes

    These class members changed in 1.6:

    type member migration
    BigSlime heldObject Replaced by heldItem, which allows non-object items too.
    Bush overrideSeason Removed; use bush.Location.GetSeason() instead.
    greenhouseBush Removed; use bush.IsSheltered() or bush.currentLocation.IsGreenhouse instead.
    inBloom Remove the arguments, like bush.inBloom(Game1.currentSeason, Game1.dayOfMonth)bush.inBloom().
    Character getStandingX
    getStandingY
    getStandingXY
    Removed; use character.StandingPixel instead.
    getTileLocation
    getTileX
    getTileY
    Removed; use character.Tile instead.
    getTileLocationPoint Removed; use character.TilePoint instead.
    Chest MoveToSafePosition Replaced by the simpler TryMoveToSafePosition
    Dialogue dialogues Changed from List<string> to List<DialogueLine>. The Text field on each dialogue line is equivalent to the old value.
    isOnFinalDialogue() This now indicates whether it's showing the last dialogue with message text; there may still be entries in dialogues which apply side-effects without message text.
    Farmer changePants(…) Renamed to changePantsColor(…) for consistency with change[Eye|Hair|Shoe]Color.
    isMarried() Renamed to isMarriedOrRoommates() for clarity.
    visibleQuestCount Replaced by hasVisibleQuests.
    Flooring GetFloorPathLookup Use Game1.floorPathData instead.
    Forest log Moved into Forest.resourceClumps.
    FruitTree GreenHouseTree Replaced by IgnoresSeasonsHere().
    Game1 bigCraftableInformation Overhauled into Game1.bigCraftableData.
    clothingInformation Overhauled into Game1.shirtData and Game1.pantsData.
    objectInformation Overhauled into Game1.objectData.
    GameLocation getCharacters Removed; use the characters field instead.
    GetMapPropertyPosition Replaced by TryGetMapPropertyAs, which supports multiple data types (not just Point).
    isTileOccupied
    isTileOccupiedForPlacement
    isTileOccupiedIgnoreFloors
    isTileLocationOpenIgnoreFrontLayers
    isTileLocationTotallyClearAndPlaceable
    isTileLocationTotallyClearAndPlaceableIgnoreFloors
    Removed. The collision logic has been significantly rewritten and uses a new set of methods (mainly isTilePassable, IsTileOccupiedBy, and CanItemBePlacedHere). Mods should ideally be updated to use the new methods.

    Here's a drop-in set of extension methods which re-add the older methods. This lets you temporarily fix code until you can update it properly, but depending on these isn't recommended since they won't be maintained in future versions.

    expand for non-recommended code 
    public static class GameLocationExtensions
    {
        public static bool isTileOccupiedForPlacement(this GameLocation location, Vector2 tileLocation, Object toPlace = null)
        {
            return location.CanItemBePlacedHere(tileLocation, toPlace != null && toPlace.isPassable());
        }
    
        public static bool isTileOccupied(this GameLocation location, Vector2 tileLocation, string characterToIgnore = "", bool ignoreAllCharacters = false)
        {
            CollisionMask mask = ignoreAllCharacters ? CollisionMask.All & ~CollisionMask.Characters & ~CollisionMask.Farmers : CollisionMask.All;
            return location.IsTileOccupiedBy(tileLocation, mask);
        }
    
        public static bool isTileOccupiedIgnoreFloors(this GameLocation location, Vector2 tileLocation, string characterToIgnore = "")
        {
            return location.IsTileOccupiedBy(tileLocation, CollisionMask.Buildings | CollisionMask.Furniture | CollisionMask.Objects | CollisionMask.Characters | CollisionMask.TerrainFeatures, ignorePassables: CollisionMask.Flooring);
        }
    
        public static bool isTileLocationOpenIgnoreFrontLayers(this GameLocation location, Location tile)
        {
            return location.map.RequireLayer("Buildings").Tiles[tile.X, tile.Y] == null && !location.isWaterTile(tile.X, tile.Y);
        }
    
        public static bool isTileLocationTotallyClearAndPlaceable(this GameLocation location, int x, int y)
        {
            return location.isTileLocationTotallyClearAndPlaceable(new Vector2(x, y));
        }
    
        public static bool isTileLocationTotallyClearAndPlaceableIgnoreFloors(this GameLocation location, Vector2 v)
        {
            return location.isTileOnMap(v) && !location.isTileOccupiedIgnoreFloors(v) && location.isTilePassable(new Location((int)v.X, (int)v.Y), Game1.viewport) && location.isTilePlaceable(v);
        }
    
        public static bool isTileLocationTotallyClearAndPlaceable(this GameLocation location, Vector2 v)
        {
            Vector2 pixel = new Vector2((v.X * Game1.tileSize) + Game1.tileSize / 2, (v.Y * Game1.tileSize) + Game1.tileSize / 2);
            foreach (Furniture f in location.furniture)
            {
                if (f.furniture_type != Furniture.rug && !f.isPassable() && f.GetBoundingBox().Contains((int)pixel.X, (int)pixel.Y) && !f.AllowPlacementOnThisTile((int)v.X, (int)v.Y))
                    return false;
            }
    
            return location.isTileOnMap(v) && !location.isTileOccupied(v) && location.isTilePassable(new Location((int)v.X, (int)v.Y), Game1.viewport) && location.isTilePlaceable(v);
        }
    }
    
    GiantCrop which Replaced by itemId.
    Item SanitizeContextTag Replaced by ItemContextTagManager.SanitizeContextTag.
    LocalizedContentManager LanguageCodeString Now static.
    LocationContextData Name Removed; use its dictionary key in Game1.locationContextData instead.
    NetFields AddFields Removed; use AddField instead. For example:
    // old code
    NetFields.AddFields(textureName, spriteWidth, spriteHeight);
    
    // new code
    NetFields
        .AddField(textureName)
        .AddField(spriteWidth)
        .AddField(spriteHeight);
    

    Note that the second argument (name) should usually be omitted, since it'll be auto-populated from the value passed to the first argument.

    NPC canReceiveThisItemAsGift(…) Removed. The closest equivalent is item.canBeGivenAsGift(), or you can check if the NPC will accept the player's held object (as a gift or otherwise) using npc.tryReceiveActiveObject(Game1.player, probe: true).
    Gender
    female
    male
    undefined
    The Gender field now uses a Gender enum instead of numeric constants. For example, npc.Gender == NPC.female becomes npc.Gender == Gender.Female in 1.6.
    homeRegion Removed; use npc.GetData()?.HomeRegion instead. Change 0 to "Other" or NPC.region_other, 1 to "Desert" or NPC.region_desert, and 2 to "Town" or NPC.region_town.
    isBirthday Remove the arguments, like npc.isBirthday(Game1.currentSeason, Game1.dayOfMonth)npc.isBirthday().
    isVillager() Deprecated; use the character.IsVillager property instead.
    populateRoutesFromLocationToLocationList Replaced by WarpPathfindingCache.PopulateCache.
    Schedule No longer assignable, use one of the TryLoadSchedule overloads instead.
    Object GetContextTagList() Replaced by GetContextTags(), which returns a hash set instead of a list.
    HasBeenPickedUpByPlayer Removed; use HasBeenInInventory instead.
    isPotentialBasicShippedCategory The second argument should now be an integer (like -75 or Object.VegetableCategory) instead of a string (like "-75").
    Utility doesItemWithThisIndexExistAnywhere Replace with Utility.doesItemExistAnywhere, which takes a string item ID. For example:
    • Utility.doesItemWithThisIndexExistAnywhere(128)Utility.doesItemExistAnywhere("(O)128");
    • Utility.doesItemWithThisIndexExistAnywhere(128, true)Utility.doesItemExistAnywhere("(BC)128").
    ForAllLocations
    iterateAllCrops
    iterateAllItems
    Removed; use the equivalent Utility.ForEach* methods instead.
    GetHorseWarpRestrictionsForFarmer This now returns a flag enum instead of a list of integer values. The equivalent values are 1 → NoOwnedHorse, 2 → Indoors, 3 → NoRoom, and 4 → InUse.

    For example:

    // old code
    bool inUse = Utility.GetHorseWarpRestrictionsForFarmer(player).Any(p => p == 4);
    
    // new code
    bool inUse = Utility.GetHorseWarpRestrictionsForFarmer(player).HasFlag(Utility.HorseWarpRestrictions.InUse);
    

    Or to check if no restrictions apply:

    bool canSummon = Utility.GetHorseWarpRestrictionsForFarmer(player) == Utility.HorseWarpRestrictions.None;
    

    C# mods can patch Utility.GetHorseWarpErrorMessage if they need to add an error message for a custom restriction value.

    getRandomTownNPC(…) Replaced by either Utility.GetRandomWinterStartParticipant(…) or Utility.getRandomNpcFromHomeRegion(NPC.region_town).
    getTodaysBirthdayNPC Remove the arguments, like Utility.getTodaysBirthdayNPC(Game1.currentSeason, Game1.dayOfMonth)Utility.getTodaysBirthdayNPC().
    getPooledList
    returnPooledList
    The game no longer uses a list pool. In most cases you should use the Utility.ForEach* methods instead, which don't need it.
    numObelisksOnFarm Renamed to GetObeliskTypesBuilt, which searches all locations.
    numSilos Removed.

    If you're using this to calculate hay capacity, it's a bit more complicated in 1.6 since hay storage can be enabled for custom buildings and building construction can be enabled for any location. To get capacity for the current location, use Game1.currentLocation.GetHayCapacity() instead. To get total hay capacity in the world, use Utility.ForEachLocation to call it on every location.

    If you actually need the number of silos, use location.getNumberBuildingsConstructed("Silo") (one location) or Game1.GetNumberBuildingsConstructed("Silo") (all locations).

    removeThisCharacterFromAllLocations Removed; use Game1.removeCharacterFromItsLocation instead.
    ShopMenu storeContext Replaced by ShopId.
    Stats averageBedtime
    beveragesMade
    bouldersCracked
    caveCarrotsFound
    cheeseMade
    chickenEggsLayed
    copperFound
    cowMilkProduced
    cropsShipped
    daysPlayed
    diamondsFound
    dirtHoed
    duckEggsLayed
    fishCaught
    geodesCracked
    giftsGiven
    goatCheeseMade
    goatMilkProduced
    goldFound
    goodFriends
    individualMoneyEarned
    iridiumFound
    ironFound
    itemsCooked
    itemsCrafted
    itemsForaged
    itemsShipped
    monstersKilled
    mysticStonesCrushed
    notesFound
    otherPreciousGemsFound
    piecesOfTrashRecycled
    preservesMade
    prismaticShardsFound
    questsCompleted
    rabbitWoolProduced
    rocksCrushed
    seedsSown
    sheepWoolProduced
    slimesKilled
    stepsTaken
    stoneGathered
    stumpsChopped
    timesFished
    timesUnconscious
    totalMoneyGifted
    trufflesFound
    weedsEliminated
    Removed; use the equivalent property or methods. For example, Game1.stats.daysPlayed can be replaced with Game1.stats.DaysPlayed or methods like Game1.stats.Get(StatKeys.DaysPlayed). See stat changes for C# mods.
    getStat(…)
    incrementStat(…)
    Replaced by Get(…) and Increment(…). See stat changes for C# mods.
    stat_dictionary Renamed to Values. See stat changes for C# mods.
    Woods stumps Moved into resourceClumps.

    Check for obsolete code

    Perform a full rebuild of your mod (in Visual Studio, click Build > Rebuild Solution), then check the Error List pane for any warnings like "'X' is obsolete". Anything from the vanilla game code which is marked obsolete won't work anymore and is only kept for save migrations. Usually the warning will include an explanation of what you should use instead.

    Breaking changes for content packs

    This section only describes how this update may break existing mods. See the what's new sections above for more info, including new functionality mods can use.

    Standardized ID fields

    Stardew Valley 1.6 adds an Id field to these assets. For Content Patcher content packs, these replace the previous synthetic ID:

    asset old key new key migration steps
    Data/ConcessionTastes
    Data/MovieReactions
    Data/RandomBundles (area)
    Data/RandomBundles (bundle)
    Name
    NPCName
    AreaName
    none
    Id None. The Id field is set automatically to the same value (or Name for bundles), so there's no change for content packs. Omit the new field when creating a new entry.
    Data/FishPondData
    Data/RandomBundles (bundle set)
    RequiredTags
    none
    Id Use the new Id field to target an entry, and add it when creating a new entry. Required.
    Data/TailoringRecipes FirstItemTags and SecondItemTags Id Use the new Id field to target an entry, and add it when creating a new entry. Defaults to the CraftedItemIds (comma-delimited) or CraftedItemId value if omitted, but there's a high chance of conflicts so mods should always specify a unique ID.

    For example, let's say you have a patch like this using Content Patcher:

    {
        "Format": "2.0.0",
        "Changes": [
            {
                "Action": "EditData",
                "Target": "Data/TailorRecipes",
                "Entries": {
                    "item_cloth|item_pufferchick": {
                        "FirstItemTags": [ "item_cloth" ],
                        "SecondItemTags": [ "item_pufferchick" ],
                        "CraftedItemId": "(S)1260"
                    }
                }
            }
        ]
    }
    

    When updating to Stardew Valley 1.6, replace the synthetic ID (item_cloth|item_pufferchick) with a real one:

    • To edit an existing entry, unpack the asset and get its new Id value.
    • To add a custom entry, use a unique string ID.

    For example:

    {
        "Format": "2.0.0",
        "Changes": [
            {
                "Action": "EditData",
                "Target": "Data/TailorRecipes",
                "Entries": {
                    "ExampleAuthor.ModId_RainCoatFromPufferchick": {
                        "Id": "ExampleAuthor.ModId_RainCoatFromPufferchick", // need to specify ID again when creating it
                        "FirstItemTags": [ "item_cloth" ],
                        "SecondItemTags": [ "item_pufferchick" ],
                        "CraftedItemId": "(S)1260"
                    }
                }
            }
        ]
    }
    

    Event ID changes

    These docs should be merged into Modding:Event data. When copying content, make sure you attribute the original authors.
    See also: string event IDs in what's new.

    Events now have unique string IDs.

    When creating an event:

    • New events should use a globally unique ID in the form Your.ModId_EventName. Existing events should be fine as-is, but it may be worth migrating them to avoid future conflicts.
    • Every non-fork event must have a precondition in its key (even if it's empty). For example, change "Your.ModId_EventName": "..." to "Your.ModId_EventName/": "...". This is needed for the game to distinguish between events and fork scripts.
      "Example.ModId_EventName/": "...", // event: loaded automatically by the game
      "SomeFork": "..."                  // event fork: ignored unless it's loaded through an event script
      

    Monster eradication goal flag changes

    These docs should be merged into a new doc page. When copying content, make sure you attribute the original authors.
    See also: Custom monster eradication goals.

    The game now tracks Adventurer's Guild monster eradication goal completion by the goal ID, instead of the produced item. You'll need to replace these mail flags if you check them:

    old flag new flag
    Gil_Slime Charmer Ring Gil_Slimes
    Gil_Savage Ring Gil_Shadows
    Gil_Vampire Ring Gil_Bats
    Gil_Skeleton Mask Gil_Skeletons
    Gil_Insect Head Gil_Insects
    Gil_Hard Hat Gil_Duggy
    Gil_Burglar's Ring Gil_DustSpirits
    Gil_Crabshell Ring Gil_Crabs
    Gil_Arcane Hat Gil_Mummies
    Gil_Knight's Helmet Gil_Dinos
    Gil_Napalm Ring Gil_Serpents
    Gil_Telephone Gil_FlameSpirits

    XNB impact

    Overview

    This section provides a summary of the XNB files which changed in Stardew Valley 1.6. 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.6 (e.g. typo fixes).
    • "✓ mostly unaffected": mods will only be affected if they replace the entire asset, or edit specific entries or fields.
    • Blank: no expected impact for the vast majority of mods.
    content asset changes in 1.6 compatibility for pre-1.6 mods
    XNB mods Content Patcher packs
    Buildings/houses
    • fixed missing pixels
    ✘ will remove changes ✓ mostly unaffected
    Characters/Dialogue/Abigail
    Characters/Dialogue/Alex
    ✘ broken ✓ mostly unaffected
    Characters/Dialogue/Caroline
    Characters/Dialogue/Demetrius
    • fixed typos
    ✘ will remove changes ✓ mostly unaffected
    Characters/Dialogue/Elliott ✘ broken ✓ mostly unaffected
    Characters/Dialogue/Emily ✘ broken ✓ mostly unaffected
    Characters/Dialogue/George ✘ broken ✓ mostly unaffected
    Characters/Dialogue/Gus
    • fixed typos
    ✘ will remove changes ✓ mostly unaffected
    Characters/Dialogue/Haley ✘ broken ✓ mostly unaffected
    Characters/Dialogue/Harvey ✘ broken ✓ mostly unaffected
    Characters/Dialogue/Jas
    Characters/Dialogue/Jodi
    • fixed typos
    ✘ will remove changes ✓ mostly unaffected
    Characters/Dialogue/Krobus ✘ broken ✓ mostly unaffected
    Characters/Dialogue/Leah ✘ broken ✓ mostly unaffected
    Characters/Dialogue/Lewis
    • updated %revealtaste format (backwards-compatible)
    Characters/Dialogue/Linus ✘ broken ✓ mostly unaffected
    Characters/Dialogue/Marnie ✘ broken ✓ mostly unaffected
    Characters/Dialogue/MarriageDialogue
    Characters/Dialogue/MarriageDialogueAbigail
    Characters/Dialogue/MarriageDialogueElliott
    • fixed typos
    ✘ will remove changes ✓ mostly unaffected
    Characters/Dialogue/MarriageDialogueEmily
    • changed spring_Maru key to spring_Emily
    • fixed typos
    ✘ broken ✓ mostly unaffected
    Characters/Dialogue/MarriageDialogueKrobus
    Characters/Dialogue/MarriageDialogueLeah
    Characters/Dialogue/MarriageDialogueMaru
    Characters/Dialogue/MarriageDialoguePenny
    Characters/Dialogue/MarriageDialogueSam
    • fixed typos
    ✘ will remove changes ✓ mostly unaffected
    Characters/Dialogue/Maru ✘ broken ✓ mostly unaffected
    Characters/Dialogue/Penny ✘ broken ✓ mostly unaffected
    Characters/Dialogue/Pierre ✘ broken ✓ mostly unaffected
    Characters/Dialogue/Robin
    • fixed typos
    ✘ will remove changes ✓ mostly unaffected
    Characters/Dialogue/Sam ✘ broken ✓ mostly unaffected
    Characters/Dialogue/Sandy
    • fixed typos
    ✘ will remove changes ✓ mostly unaffected
    Characters/Dialogue/Sebastian ✘ broken ✓ mostly unaffected
    Characters/Dialogue/Willy ✘ broken ✓ mostly unaffected
    Characters/Dialogue/Shane ✘ broken ✓ mostly unaffected
    Characters/Farmer/hats
    • removed stray pixel on chicken mask
    ✘ will remove changes ✓ mostly unaffected
    Characters/schedules/Elliott
    • fixed order of Fri_6 and Fri entries
    ✘ broken
    Characters/schedules/Lewis
    • fixed winter_Sun schedule
    ✘ broken ✓ mostly unaffected
    Characters/schedules/Maru
    • fixed summer_Mon and summer_Sun schedules
    ✘ broken ✓ mostly unaffected
    Characters/schedules/Penny
    • fixed summer_Sun schedule
    ✘ broken ✓ mostly unaffected
    Characters/Schedules/Shane
    • fixed dialogue key
    ✘ will remove changes ✓ mostly unaffected
    Data/animationDescriptions
    • fixed frame in Lewis' Saloon drinking animation
    ✘ will remove changes ✓ mostly unaffected
    Data/AquariumFish ✘ broken ✓ mostly unaffected
    Data/BigCraftablesInformation ✘ broken ✓ mostly unaffected
    (covered by runtime migration)
    Data/Blueprints
    • asset replaced by Data/Buildings:
      • migrated to data model format
      • added new features
    ✘ broken ✓ mostly unaffected
    (covered by runtime migration)
    Data/Boots ✘ broken ✓ mostly unaffected
    (covered by runtime migration)
    Data/Bundles
    • can no longer omit empty fields before display name
    • added display name field in English
    • removed meat items in animal bundle
    ✘ broken ✘ likely broken
    Data/ClothingInformation ✘ broken ✘ likely broken
    Data/Concessions ✘ broken ✘ likely broken
    Data/ConcessionTastes
    • added automatic ID field
    ✘ broken ✓ mostly unaffected
    Data/CookingRecipes
    • replaced translations with tokenizable strings
    • display names can now be omitted to use item name
    ✘ will remove changes ✓ may remove unaffected
    Data/CraftingRecipes
    • replaced translations with tokenizable strings
    • display names can now be omitted to use item name
    • added default unlock condition
    • fixed typo in Cookout Kit entry
    ✘ broken ✓ mostly unaffected
    Data/Crops ✘ broken ✓ mostly unaffected
    (covered by runtime migration)
    Data/Events/AnimalShop
    • updated command syntax (backwards-compatible)
    Data/Events/Farm
    • replaced send-mail events with trigger actions
    • updated pet event to support custom pet types
    ✘ broken ✓ mostly unaffected
    (✘ may cause duplicate mail if they edit
    send-mail events)
    Data/Events/FishShop
    • fixed typos
    ✘ will remove changes ✓ mostly unaffected
    Data/Events/Forest
    • fixed typos
    • updated Jas faceDirection command for sewer event
    ✘ will remove changes ✓ mostly unaffected
    Data/Events/IslandHut
    • updated how Leo's name is translated
    ✘ will remove changes ✓ mostly unaffected
    Data/Events/IslandNorth
    • updated quote format
    • fixed blank music field (backwards-compatible)
    ✘ broken ✓ mostly unaffected
    (✘ likely broken if they edit the 6497421 event)
    Data/Events/IslandSouth
    • fixed blank music field (backwards-compatible)
    • fixed typos
    ✘ will remove changes ✓ mostly unaffected
    Data/Events/JoshHouse
    • fixed typos
    ✘ will remove changes ✓ mostly unaffected
    Data/Events/LeahHouse
    • fixed move command format in Leah's 2-heart event
    • fixed typos
    ✘ broken ✓ mostly unaffected
    Data/Events/Mountain
    • fixed skipped dialogue in Maru's 14-heart event
    • fixed typos
    ✘ will remove changes ✓ mostly unaffected
    Data/Events/Saloon
    Data/Events/ScienceHouse
    Data/Events/SebastianRoom
    • fixed typos
    ✘ will remove changes ✓ mostly unaffected
    Data/Events/Town
    • fixed warp command format in community center completed event
    • fixed typos
    ✘ broken ✓ mostly unaffected
    Data/Events/WizardHouse
    • fixed typos
    ✘ will remove changes ✓ mostly unaffected
    Data/ExtraDialogue ✘ broken ✓ mostly unaffected
    Data/FarmAnimals ✘ broken ✘ broken
    Data/Festivals/fall16
    • updated command syntax (backwards-compatible)
    • fixed typos
    ✘ will remove changes ✓ mostly unaffected
    Data/Festivals/fall27 ✓ mostly unaffected ✓ mostly unaffected
    Data/Festivals/spring13
    • migrated to new warpFarmers command
    • removed shop field (moved into Data/Shops)
    • updated faceDirection syntax
    • fixed typos
    ✘ broken ✓ mostly unaffected
    (✘ broken if they edit mainEvent or
    afterEggHunt fields)
    Data/Festivals/spring24
    Data/Festivals/summer11
    Data/Festivals/summer28
    • migrated to new warpFarmers command
    • removed shop field (moved into Data/Shops)
    ✘ broken ✓ mostly unaffected
    (✘ broken if they edit mainEvent field)

    Data/Festivals/winter8
    • migrated to new warpFarmers command
    • removed shop field (moved into Data/Shops)
    • removed broken loadActors MainEvent command
    ✘ broken ✓ mostly unaffected
    (✘ broken if they edit mainEvent or
    afterIceFishing field)
    Data/Festivals/winter25 ✓ mostly unaffected ✓ mostly unaffected
    Data/Fish
    • no longer has per-language versions
    • changed key type
    • field 13 now refers to whether fish can be tutorial catch
    ✘ broken ✘ likely broken
    Data/FishPondData
    • added required Id & optional Precedence fields
    • standardized IDId naming
    • changed to qualified item IDs
    • moved fallback entries to bottom
    ✘ broken ✘ likely broken
    Data/fruitTrees ✘ broken ✘ broken
    Data/Furniture ✘ broken ✓ mostly unaffected
    (covered by runtime migration)
    Data/hats
    • changed key type
    • can no longer omit empty fields before display name
    • added display name field in English
    ✘ broken ✘ likely broken
    Data/Locations ✘ broken ✓ mostly unaffected
    (covered by runtime migration)
    Data/mail
    • migrated to %item id (backwards-compatible)
    • removed unused entries
    • fixed typos
    ✘ will remove changes ✓ mostly unaffected
    Data/Monsters
    • changed Dust Spirit display name to Dust Sprite
    ✘ will remove changes ✓ mostly unaffected
    Data/Movies ✘ broken ✘ broken
    Data/MoviesReactions ✘ broken ✓ mostly unaffected
    Data/NPCDispositions ✘ broken ✓ mostly unaffected
    (covered by runtime migration)
    Data/NPCGiftTastes
    • removed invalid item IDs
    ✘ will remove changes ✓ mostly unaffected
    Data/ObjectContextTags ✘ broken ✓ mostly unaffected
    (covered by runtime migration,
    except context tags defined
    before their objects and context
    tags for bigcraftables.)

    Data/ObjectInformation
    • asset replaced by Data/Objects:
      • migrated to data model format
      • added new features
      • added new entries
      • adjusted litter items
      • fixed typos
    ✘ broken ✓ mostly unaffected
    (covered by runtime migration)
    Data/PaintData
    • fixed trailing slash in Deluxe Barn entry
    Data/Quests
    • changed key type to string
    • migrated to use item IDs (backwards-compatible)
    • fixed typo
    ✘ broken ✓ mostly unaffected
    Data/RandomBundles
    • add optional Id field
    ✘ broken ✓ mostly unaffected
    Data/SecretNotes
    • updated %revealtaste format (backwards-compatible)
    ✘ will remove changes ✓ mostly unaffected
    Data/SpecialOrders
    • changed type of Repeatable and Duration fields
    • added optional CustomFields and Conditions fields
    ✘ broken
    Data/SpousePatios
    Data/SpouseRooms
    ✘ broken ✘ broken
    Data/TailoringRecipes
    • changed to string item IDs (backwards-compatible)
    • added optional Id and CraftedItemIdFeminine fields
    • removed CraftedItemColor field
    • adjusted recipes for gender-variant shirts
    • standardized IDId naming
    ✘ broken ✓ mostly unaffected
    (MoveEntries may break, but fallback entries
    are now checked last automatically)
    Data/TV/CookingChannel
    Data/TV/TipChannel
    • fixed typos
    ✘ will remove changes ✓ mostly unaffected
    Data/weapons ✘ broken ✓ mostly unaffected
    (covered by runtime migration)
    LooseSprites/Cursors
    • new sprites in empty area
    • moved mailbox to Buildings/Mailbox
    ✘ broken ✓ mostly unaffected
    LooseSprites/Cursors2
    • new sprite in empty area
    ✘ broken ✓ mostly unaffected
    LooseSprites/map
    • redrawn to better match in-game locations
    • added more detail
    ✘ broken ✘ likely broken
    Maps/AbandonedJojaMart
    Maps/AdventureGuild
    • moved Music property into Data/Locations
    ✘ will remove changes ✓ mostly unaffected
    Maps/AnimalShop
    • removed unused pathfinding tiles
    Maps/ArchaeologyHouse
    • removed unused pathfinding tiles
    • moved Music property into Data/Locations
    Maps/Backwoods
    Maps/Backwoods_GraveSite
    Maps/Backwoods_Staircase
    • removed unused tile properties
    • standardized T for boolean tile property values (backwards-compatible)
    Maps/Barn
    Maps/Barn2
    • removed unused map properties
    Maps/Barn3
    • added AutoFeed map property
    • removed unused map properties
    ✘ broken
    Maps/BathHouse_Entry
    Maps/BathHouse_MensLocker
    • moved Music property into Data/Locations
    • removed unused pathfinding tiles
    ✘ will remove changes ✓ mostly unaffected
    Maps/BathHouse_Pool
    • removed unused pathfinding tiles
    • removed unused map & tile properties
    Maps/BathHouse_WomensLocker
    • moved Music property into Data/Locations
    • removed unused pathfinding tiles
    ✘ will remove changes ✓ mostly unaffected
    Maps/Beach
    • removed unused map properties
    • removed unused pathfinding tiles
    • standardized T for boolean tile property values (backwards-compatible)
    Maps/Beach-Jellies
    Maps/Beach-Luau
    Maps/Beach-NightMarket
    • updated for festival shops now in Data/Shops
    • removed unused map/tile properties
    • removed unused pathfinding tiles
    • standardized T for boolean tile property values (backwards-compatible)
    ✘ broken ✓ mostly unaffected
    Maps/Blacksmith
    • removed unused pathfinding tiles
    Maps/BoatTunnel
    • standardized T for boolean tile property values (backwards-compatible)
    Maps/BugLand
    • moved Music property into Data/Locations
    • standardized T for boolean tile property values (backwards-compatible)
    ✘ will remove changes ✓ mostly unaffected
    Maps/BusStop
    • removed unused map/tile properties
    • removed unused pathfinding tiles
    • changed Action BusTicket to Action None
    • standardized T for boolean tile property values (backwards-compatible)
    Maps/Caldera
    • removed unused map property
    Maps/Cellar
    • standardized T for boolean tile property values (backwards-compatible)
    Maps/Club
    • added LocationContext map property
    • moved Music property into Data/Locations
    ✘ broken ✓ mostly unaffected
    Maps/Coop
    Maps/Coop2
    • removed unused map properties
    Maps/Coop3
    • added AutoFeed map property
    • removed unused map properties
    ✘ broken
    Maps/Desert
    • added LocationContext map property
    • removed unused map/tile properties
    • removed unused pathfinding tiles
    • standardized T for boolean tile property values (backwards-compatible)
    ✘ broken
    Maps/ElliottHouse
    • removed unused pathfinding tiles
    Maps/Farm
    Maps/Farm_Combat
    Maps/Farm_Fishing
    Maps/Farm_Foraging
    Maps/Farm_FourCorners
    Maps/Farm_Island
    Maps/Farm_Mining
    • added new tilesheet
    • added cabin positions for players 5–8
    • added PetBowlLocation map property (for Maps/Four_Corners and Farm/Island only)
    • added SpouseAreaLocation map property (for Maps/Farm_Island only)
    • significant tile & tile property changes
    • removed farmhouse + pet bowl areas (now moveable)
    • removed unused map/tile properties
    • standardized T for boolean tile property values (backwards-compatible)
    ✘ broken ✘ may remove changes
    Maps/Farm_Greenhouse_Dirt
    Maps/Farm_Greenhouse_Dirt_FourCorners
    • removed unused map properties
    • standardized T for boolean tile property values (backwards-compatible)
    Maps/FarmHouse
    Maps/FarmHouse_Bedroom_Normal
    Maps/FarmHouse_Bedroom_Open
    Maps/FarmHouse_Cellar
    Maps/FarmHouse_ChildBed_0
    Maps/FarmHouse_ChildBed_1
    Maps/FarmHouse_CornerRoom_Add
    Maps/FarmHouse_CornerRoom_Remove
    Maps/FarmHouse_SouthernRoom_Add
    Maps/FarmHouse_SouthernRoom_Remove
    Maps/FarmHouse1
    Maps/FarmHouse1_marriage
    Maps/FarmHouse2
    Maps/FarmHouse2_marriage
    • removed unused map properties
    • standardized T for boolean tile property values (backwards-compatible)
    Maps/FishingGame
    • standardized T for boolean tile property values (backwards-compatible)
    Maps/FishShop
    • fixed broken DayTiles and NightTiles values
    • removed unused pathfinding tiles
    ✘ will remove changes ✓ mostly unaffected
    Maps/Forest
    • removed unused map/tile properties
    • removed unused pathfinding tiles
    • standardized T for boolean tile property values (backwards-compatible)
    Maps/Forest-FlowerFestival
    • updated for festival shops now in Data/Shops
    • removed unused map/tile properties
    • standardized T for boolean tile property values (backwards-compatible)
    ✘ broken ✓ mostly unaffected
    Maps/Forest-IceFestival
    • updated for festival shops now in Data/Shops
    • fixed warp positions
    • removed unused map/tile properties
    • removed unused pathfinding tiles
    • standardized T for boolean tile property values (backwards-compatible)
    ✘ broken ✓ mostly unaffected
    Maps/Forest-SewerClean
    • removed unused map/tile properties
    • standardized T for boolean tile property values (backwards-compatible)
    Maps/HaleyHouse
    Maps/HarveyRoom
    • removed unused pathfinding tiles
    Maps/Hospital
    • removed deprecated UniquePortrait & UniqueSprite map properties
    • removed unused pathfinding tiles
    ✘ will remove changes
    (This may cause mod conflicts)
    ✓ mostly unaffected
    Maps/Island_Bridge_Broken
    Maps/Island_Bridge_Repaired
    Maps/Island_House_Cave
    • removed unused map properties
    Maps/Island_N
    • update walnut bush tile so it still works in 1.6
    • removed unused tile property
    ✘ broken ✓ mostly unaffected
    Maps/IslandNorthCave1
    Maps/IslandSouthEastCave
    Maps/IslandSouthEastCave_pirates
    Maps/IslandWestCave1
    • moved Music property into Data/Locations
    ✘ will remove changes ✓ mostly unaffected
    Maps/Island_Bridge_Broken
    Maps/Island_Bridge_Repaired
    • removed unused map property
    • standardized T for boolean tile property values (backwards-compatible)
    Maps/Island_E
    Maps/IslandFarmCave
    • moved Music property into Data/Locations
    ✘ will remove changes ✓ mostly unaffected
    Maps/Island_House_Cave
    • removed unused map property
    • standardized T for boolean tile property values (backwards-compatible)
    Maps/Island_Hut
    • moved Music property into Data/Locations
    • standardized T for boolean tile property values (backwards-compatible)
    ✘ will remove changes ✓ mostly unaffected
    Maps/Island_N
    • added a NowSpawn False tile property to fix tree that hides a golden walnut
    • removed unused tile property
    • standardized T for boolean tile property values (backwards-compatible)
    ✘ will remove changes ✓ mostly unaffected
    Maps/Island_N_Trader
    Maps/Island_Secret
    • removed unused tile property
    • standardized T for boolean tile property values (backwards-compatible)
    Maps/Island_Shrine
    • moved Music property into Data/Locations
    ✘ will remove changes ✓ mostly unaffected
    Maps/Island_W
    • removed unused tile property
    • standardized T for boolean tile property values (backwards-compatible)
    Maps/IslandFarmHouse
    • removed unused tile properties
    • standardized T for boolean tile property values (backwards-compatible)
    Maps/JojaMart
    Maps/JoshHouse
    Maps/LeahHouse
    Maps/ManorHouse
    • removed unused pathfinding tiles
    Maps/MarnieBarn
    • removed unused map properties
    Maps/Mine ✘ broken ✓ mostly unaffected
    Maps/Mountain
    • removed unused map/tile properties
    • removed unused pathfinding tiles
    • standardized T for boolean tile property values (backwards-compatible)
    Maps/Mountain-BridgeFixed
    Maps/Mountain_Shortcuts
    • removed unused map/tile properties
    • standardized T for boolean tile property values (backwards-compatible)
    Maps/MovieTheater
    • moved Music property into Data/Locations
    ✘ will remove changes ✓ mostly unaffected
    Maps/MovieTheaterScreen
    • updated for tilesheet changes
    ✘ broken visuals (e.g. missing chairs) ✓ mostly unaffected
    (✘ broken visuals if they edit the affected tiles)
    Maps/MovieTheaterScreen_TileSheet
    • improved light cone
    • moved chair sprite to make room for new light cone
    ✘ broken visuals (e.g. missing chairs) ✓ mostly unaffected
    (✘ broken visuals if they edit the affected sprites)
    Maps/paths
    Maps/QiNutRoom
    • moved Music property into Data/Locations
    • standardized T for boolean tile property values (backwards-compatible)
    ✘ will remove changes ✓ mostly unaffected
    Maps/Railroad
    • removed unused map property
    • removed unused pathfinding tiles
    • standardized T for boolean tile property values (backwards-compatible)
    Maps/Saloon
    Maps/SamHouse
    • removed unused pathfinding tiles
    Maps/SandyHouse
    • added LocationContext map property
    ✘ broken
    Maps/ScienceHouse
    Maps/SebastianRoom
    • removed unused pathfinding tiles
    Maps/SeedShop
    • removed unused tile properties
    • removed unused pathfinding tiles
    Maps/Sewer
    • moved Music property into Data/Locations
    ✘ will remove changes ✓ mostly unaffected
    Maps/Shed
    Maps/Shed2
    • added FloorIDs and WallIDs map properties
    ✘ broken
    Maps/SkullCave
    • added LocationContext map property
    • moved Music property into Data/Locations
    ✘ broken ✓ mostly unaffected
    Maps/SlimeHutch
    • removed unused tile property
    • standardized T for boolean tile property values (backwards-compatible)
    Maps/spousePatios
    • removed unused map/tile properties
    • standardized T for boolean tile property values (backwards-compatible)
    Maps/spring_outdoorsTileSheet
    Maps/summer_outdoorsTileSheet
    Maps/fall_outdoorsTileSheet
    Maps/winter_outdoorsTileSheet
    • pet bowl moved to Buildings/Pet Bowl
    ✓ mostly unaffected ✓ mostly unaffected
    Maps/Submarine
    • removed unused tile property
    Maps/Sunroom
    • added IsGreenhouse</samp map property
    ✘ broken
    Maps/Tent
    • removed unused pathfinding tiles
    Maps/Town
    • updated garbage can IDs (backwards-compatible)
    • removed unused map/tile properties
    • removed unused pathfinding tiles
    • standardized T for boolean tile property values (backwards-compatible)
    Maps/Town-Christmas
    • updated for festival shops now in Data/Shops
    • removed unused map/tile properties
    • removed unused pathfinding tiles
    • standardized T for boolean tile property values (backwards-compatible)
    ✘ broken ✓ mostly unaffected
    Maps/Town-DogHouse
    • removed unused map/tile properties
    • standardized T for boolean tile property values (backwards-compatible)
    Maps/Town-EggFestival
    • updated for festival shops now in Data/Shops
    • fixed Elliott appearing twice during egg hunt
    • removed unused map/tile properties
    • standardized T for boolean tile property values (backwards-compatible)
    ✘ broken ✓ mostly unaffected
    Maps/Town-Fair
    • removed unused map/tile properties
    • standardized T for boolean tile property values (backwards-compatible)
    Maps/Town-Halloween
    • updated for festival shops now in Data/Shops
    • removed unused map/tile properties
    • removed unused pathfinding tiles
    • standardized T for boolean tile property values (backwards-compatible)
    ✘ broken ✓ mostly unaffected
    Maps/Town-Theater
    Maps/Town-TheaterCC
    Maps/Town-TrashGone
    • removed unused tile properties
    • standardized T for boolean tile property values (backwards-compatible)
    Maps/Trailer
    • removed unused tile property
    • removed unused pathfinding tiles
    Maps/Trailer_big
    • removed unused pathfinding tiles
    Maps/Tunnel
    • moved Music property into Data/Locations
    • removed unused map property
    ✘ will remove changes ✓ mostly unaffected
    Maps/WitchHut
    • moved Music property into Data/Locations
    ✘ will remove changes ✓ mostly unaffected
    Maps/WitchSwamp
    • moved Music property into Data/Locations
    • standardized T for boolean tile property values (backwards-compatible)
    ✘ will remove changes ✓ mostly unaffected
    Maps/WitchWarpCave
    • moved Music property into Data/Locations
    ✘ will remove changes ✓ mostly unaffected
    Maps/WizardHouse
    • moved Music property into Data/Locations
    • removed unused pathfinding tiles
    ✘ will remove changes ✓ mostly unaffected
    Maps/WizardHouseBasement
    • moved Music property into Data/Locations
    • removed unused map property
    ✘ will remove changes ✓ mostly unaffected
    Maps/Woods
    • removed unused tile property
    • standardized T for boolean tile property values (backwards-compatible)
    Minigames/boatJourneyMap
    • asset replaced by redrawn seasonal variants like fall_boatJourneyMap
    ✘ broken ✘ broken
    Strings/Characters
    • added new entries
    ✘ broken
    Strings/BundleNames
    • removed unused entries
    Strings/Characters
    • added new entries
    • removed unused entry
    ✘ broken
    Strings/credits
    • updated for 1.6
    • various changes
    ✘ will remove changes ✘ will remove changes
    Strings/Events ✓ mostly unaffected ✓ mostly unaffected
    Strings/FarmAnimals
    • added new entries
    ✘ broken
    Strings/Lexicon
    • removed unused entries
    Strings/Locations
    • added new entries
    • added placeholder to BusStop_BuyTicketToDesert
    • renamed BoatTunnel_BuyTicket to BuyTicket
    • updated how Professor Snail's name is translated, removed unused entries
    • fixed typos
    ✘ broken ✓ mostly unaffected
    Strings/NPCNames
    • added new entries
    • removed unused entry
    ✘ broken
    Strings/Notes
    • trimmed trailing whitespace
    Strings/Objects
    • added new entries
    • removed unused entries
    ✘ broken
    Strings/schedules/Caroline
    • fixed typo
    ✘ will remove changes ✓ mostly unaffected
    Strings/SpecialOrderStrings
    • renamed Dust Spirits to Dust Sprites
    • fixed typos
    ✘ will remove changes ✓ mostly unaffected
    Strings/StringsFromCSFiles
    • added new entries
    • removed unused entries
    • reworked FarmComputer_* translations
    • merged some gendered translations
    • merged ItemDeliveryQuest.cs.13533 into ItemDeliveryQuest.cs.1353413536
    • changed some player names from {0} to @
    • fixed typo
    ✘ broken ✓ mostly unaffected
    Strings/StringsFromMaps
    • fixed typos
    • removed unused entries
    ✘ will remove changes
    Strings/UI
    • added new entries
    • added placeholder for cabin count in Character_CoopHelpString
    • fixed typos
    • removed unused entries
    ✘ broken ✓ mostly unaffected

    Removed unused assets

    Stardew Valley 1.6 deletes assets which weren't used by the game. Mods usually aren't affected by this.

    Removed assets:

    • Characters/Dana
    • Characters/Dick
    • Characters/femaleRival
    • Characters/maleRival
    • Characters/shirts
    • Characters/WeddingOutfits
    • Data/TV/InterviewShow
    • Effects/BrightWhite
    • Fonts/tinyFontBorder
    • Maps/Cabin
    • Maps/Cabin1
    • Maps/Cabin1_marriage
    • Maps/Cabin2
    • Maps/Cabin2_marriage
    • Maps/Island_Boulder_Removed
    • Maps/qiNutRoom_tilesheet_0
    • Maps/spring_outrdoorsTileSheet_lightergrass
    • Portraits/Dobson
    • TerrainFeatures/DiggableWall_basic
    • TerrainFeatures/DiggableWall_basic_dark
    • TerrainFeatures/DiggableWall_frost
    • TerrainFeatures/DiggableWall_frost_dark
    • TerrainFeatures/DiggableWall_lava
    • TerrainFeatures/DiggableWall_lava_dark
    • TerrainFeatures/Quartz

    Vanilla release notes

    Moved to Version History#1.6.

    See also