Changes

m
Pet behaviour Name key renamed to Id
Line 2: Line 2:     
{{Modder compatibility header}}
 
{{Modder compatibility header}}
{{upcoming|1.6.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 18: Line 15:     
===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 architecturally?==
 
==What's new architecturally?==
Line 32: Line 44:  
* [https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/record record structs];
 
* [https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/record record structs];
 
* and support for ARM64 on macOS.
 
* 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).
 +
 +
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''":
 +
<syntaxhighlight lang="js">
 +
{
 +
    "Trigger": "LocationChanged",
 +
    "Location": "Farm",
 +
    "Condition": "PLAYER_HAS_FLAG Host leoMoved",
 +
    "Actions": [
 +
        "AddMail Current Abigail_LeoMoved Today",
 +
        "AddConversationTopic LeoMoved 5"
 +
    ]
 +
}
 +
</syntaxhighlight>
 +
 +
===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"
 +
|-
 +
! type
 +
! 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>FarmerTeam</samp>
 +
| <samp>acceptedSpecialOrderTypes</samp><br /><samp>broadcastedMail</samp><br /><samp>completedSpecialOrders</samp><br /><samp>collectedNutTracker</samp>
 +
|-
 +
| <samp>Game1</samp>
 +
| <samp>worldStateIDs</samp>
 +
|-
 +
| <samp>NetWorldState</samp>
 +
| <samp>ActivePassiveFestivals</samp><br /><samp>CheckedGarbage</samp><br /><samp>FoundBuriedNuts</samp><br /><samp>IslandVisitors</samp><br /><samp>LocationsWithBuildings</samp>
 +
|}
 +
 +
Usage is very similar, and many list methods like <samp>Contains</samp> work the same way with hash sets. Here are the main differences:
 +
<ul>
 +
<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>
 +
<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>
 +
</li>
 +
</ul>
 +
 +
===DataLoader===
 +
<samp>DataLoader</samp> 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 <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.
 +
 +
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.
 +
 +
===Unique string IDs===
 +
{{/doc status|[[Modding:Common data field types#Unique string ID]]|done=true}}
 +
 +
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]].
 +
 +
For mods, it's '''strongly recommended''' to...
 +
* 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.
 +
* 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]]).
 +
 +
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;
 +
{{{!}} class="wikitable"
 +
{{!}}-
 +
! 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==
 
==What's new for items==
 
===Custom items===
 
===Custom items===
 +
{{/doc status|[[Modding:Items]]|done=false}}
 +
 
====Overview====
 
====Overview====
 
Stardew Valley 1.6 makes three major changes to how items work in the game:
 
Stardew Valley 1.6 makes three major changes to how items work in the game:
Line 52: Line 192:  
| <samp>ItemId</samp>
 
| <samp>ItemId</samp>
 
| <samp>string</samp>
 
| <samp>string</samp>
| An item key which should be globally unique, but may not be for existing vanilla items. For example, <samp>128</samp> (vanilla item) or <samp>Example.ModId_Watermelon</samp> (custom item). This should only have alphanumeric, underscore, and dot characters so it's safe to use in delimited fields, file names, etc. By convention this should include your mod ID or author name, like <samp>ExampleAuthor.ModId_ItemName</samp>.</p>
+
| 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>QualifiedItemId</samp>
Line 87: Line 227:  
| &#32;
 
| &#32;
 
* Ingredients: both supported.
 
* 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) or an item type identifier like <samp>BC</samp>.
+
* 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>]]
 
| [[#Custom fruit trees|<samp>Data/fruitTrees</samp>]]
Line 109: Line 249:  
| [[Modding:Items|big craftables]]
 
| [[Modding:Items|big craftables]]
 
| <samp>(BC)</samp>
 
| <samp>(BC)</samp>
| <samp>Data/BigCraftablesInformation</samp><br /><small>Each item can set a custom texture name in field 11, and sprite index in field 10. The default texture is <samp>TileSheets/Craftables</samp>.</small>
+
| <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>
 
|-
 
|-
 
| boots
 
| boots
Line 137: Line 277:  
| [[Modding:Items|objects]]
 
| [[Modding:Items|objects]]
 
| <samp>(O)</samp>
 
| <samp>(O)</samp>
| <samp>Data/ObjectInformation</samp><br /><small>Each item can set a custom texture name in field 10, and sprite index in field 9. The default texture is <samp>Maps/springobjects</samp>.</small>
+
| <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>
 
|-
 
|-
 
| [[#Custom pants|pants]]
 
| [[#Custom pants|pants]]
 
| <samp>(P)</samp>
 
| <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> and <samp>SpriteIndexFemale</samp> fields. The default texture is <samp>Characters/Farmer/pants</samp>.</small>
+
| <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]]
 
| [[#Custom shirts|shirts]]
 
| <samp>(S)</samp>
 
| <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> and <samp>SpriteIndexFemale</samp> fields. The default texture is <samp>Characters/Farmer/shirts</samp>.</small>
+
| <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>
 
<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>
Line 188: 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 202: 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 213: 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 220: 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>. See also specific info for [[#Custom fruit trees|custom fruit trees]], [[#Custom tools|custom tools]], and [[#Custom melee weapon data|melee weapons]].
+
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]].
    
====Error items====
 
====Error items====
Line 408: Line 565:  
</dl>
 
</dl>
   −
===Custom crops===
+
===Custom big craftables:===
[[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.
+
{{/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...
 
This consists of a string → model lookup, where...
* The key is the unqualified [[#Custom items|item ID]] for the seed item.
+
* The key is the unqualified [[#Custom items|item ID]].
* The value is model with the fields listed below.
+
* The value is a model with the fields listed below.
    +
====Basic info====
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
 
! field
 
! field
! effect
+
! purpose
 
|-
 
|-
!colspan="2"| Growth
+
| <samp>Name</samp>
 +
| The internal item name.
 
|-
 
|-
| <samp>Seasons</samp>
+
| <samp>DisplayName</samp><br /><samp>Description</samp>
| The seasons in which this crop can grow (any combination of <samp>spring</samp>, <samp>summer</samp>, <samp>fall</samp>, and <samp>winter</samp>).
+
| A [[Modding:Tokenizable strings|tokenizable string]] for the item's in-game display name and description.
 
|-
 
|-
| <samp>DaysInPhase</samp>
+
| <samp>Price</samp>
| 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>).
+
| ''(Optional)'' The price when sold by the player. This is not the price when bought from a shop. Default 0.
 +
|}
   −
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.
+
====Behavior====
 +
{| class="wikitable"
 
|-
 
|-
| <samp>RegrowDays</samp>
+
! field
| ''(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.
+
! purpose
 
|-
 
|-
| <samp>IsRaised</samp>
+
| <samp>Fragility</samp>
| ''(Optional)'' Whether this is a raised crop on a trellis that can't be walked through. Default false.
+
| ''(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>IsPaddyCrop</samp>
+
| <samp>CanBePlacedIndoors</samp><br /><samp>CanBePlacedOutdoors</samp>
| ''(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.
+
| ''(Optional)'' Whether the item can be placed indoors or outdoors. Default true.
 
|-
 
|-
!colspan="2"| Harvest
+
| <samp>IsLamp</samp>
 +
| ''(Optional)'' Whether this is a lamp and should produce light when dark. Default false.
 +
|}
 +
 
 +
====Appearance====
 +
{| class="wikitable"
 
|-
 
|-
| <samp>HarvestItemId</samp>
+
! field
| The item ID produced when this crop is harvested.
+
! purpose
 
|-
 
|-
| <samp>HarvestMethod</samp>
+
| <samp>Texture</samp>
| ''(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>.
+
| ''(Optional)'' The asset name for the texture containing the item's sprite. Defaults to <samp>TileSheets/Craftables</samp>.
 
|-
 
|-
| <samp>HarvestMinStack</samp><br /><samp>HarvestMaxStack</samp>
+
| <samp>SpriteIndex</samp>
| ''(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.
+
| ''(Optional)'' The sprite's index within the <samp>Texture</samp>, where 0 is the top-left sprite.
 +
|}
 +
 
 +
====Context tags====
 +
{| class="wikitable"
 
|-
 
|-
| <samp>HarvestMinQuality</samp><br /><samp>HarvestMaxQuality</samp>
+
! field
| ''(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.
+
! purpose
 
|-
 
|-
| <samp>HarvestMaxIncreasePerFarmingLevel</samp>
+
| <samp>ContextTags</samp>
| ''(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.
+
| ''(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>
 +
|}
   −
For example, a value of 0.2 is equivalent to +1 max at level 5 and +2 at level 10.
+
====Advanced====
 +
{| class="wikitable"
 +
|-
 +
! field
 +
! purpose
 
|-
 
|-
| <samp>ExtraHarvestChance</samp>
+
| <samp>CustomFields</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.
+
| ''(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"
 
|-
 
|-
!colspan="2"| Appearance
+
! field
 +
! effect
 
|-
 
|-
| <samp>Texture</samp>
+
!colspan="2"| Growth
| 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>SpriteIndex</samp>
+
| <samp>Seasons</samp>
| ''(Optional)'' The index of this crop in the <samp>Texture</samp>, one crop per row, where 0 is the top row. Default 0.
+
| 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>TintColors</samp>
+
| <samp>DaysInPhase</samp>
| ''(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.
+
| 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.
 
|-
 
|-
!colspan="2"| Advanced
+
| <samp>RegrowDays</samp>
 +
| ''(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>CustomFields</samp>
+
| <samp>IsRaised</samp>
| The [[#Custom data fields|custom fields]] for this entry.
+
| ''(Optional)'' Whether this is a raised crop on a trellis that can't be walked through. Default false.
|}
  −
 
  −
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>
  −
{
  −
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
  −
    "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
  −
                }
  −
            }
  −
        }
  −
    ]
  −
}</nowiki>|lang=javascript}}
  −
 
  −
===Custom fences===
  −
You can now add or customize [[Crafting#Fences|fences]] by editing the <samp>Data/Fences</samp> asset.
  −
 
  −
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"
   
|-
 
|-
! field
+
| <samp>IsPaddyCrop</samp>
! effect
+
| ''(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>Health</samp>
+
| <samp>NeedsWatering</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)'' Whether this crop needs to be watered to grow (e.g. [[Fiber Seeds|fiber seeds]] don't). Default true.
 
  −
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>Texture</samp>
+
!colspan="2"| Harvest
| 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>RemovalToolIds</samp><br /><samp>RemovalToolTypes</samp>
+
| <samp>HarvestItemId</samp>
| 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.
+
| The item ID produced when this crop is harvested.
 
  −
For example, this will let the player break the fence with an iridium axe and any pickaxe:
  −
<syntaxhighlight lang="json">
  −
"RemovalToolIds": ["IridiumAxe"],
  −
"RemovalToolTypes": ["StardewValley.Tools.Pickaxe"]
  −
</syntaxhighlight>
  −
 
  −
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.
   
|-
 
|-
| <samp>PlacementSound</samp>
+
| <samp>HarvestMethod</samp>
| The [[#Custom audio|audio cue ID]] played when the fence is placed or repaired (e.g. <samp>axe</samp> used by [[Wood Fence]]).
+
| ''(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>RemovalSound</samp>
+
| <samp>HarvestMinStack</samp><br /><samp>HarvestMaxStack</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)'' 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>RemovalDebrisType</samp>
+
| <samp>HarvestMinQuality</samp><br /><samp>HarvestMaxQuality</samp>
| ''(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).
+
| ''(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>RepairHealthAdjustmentMinimum</samp><br /><samp>RepairHealthAdjustmentMaximum</samp>
+
| <samp>HarvestMaxIncreasePerFarmingLevel</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 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.
|-
  −
| <samp>HeldObjectDrawOffset</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.
  −
|-
  −
| <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 floors (craftable) & paths===
+
For example, a value of 0.2 is equivalent to +1 max at level 5 and +2 at level 10.
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"
   
|-
 
|-
! field
+
| <samp>ExtraHarvestChance</samp>
! effect
+
| ''(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>ID</samp>
+
!colspan="2"| Appearance
| 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>.
  −
|-
  −
| <samp>ItemId</samp>
  −
| The unqualified [[#Custom items|item ID]] for the corresponding object-type item.
   
|-
 
|-
 
| <samp>Texture</samp>
 
| <samp>Texture</samp>
| 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>.
+
| 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>Corner</samp>
+
| <samp>SpriteIndex</samp>
| 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.
+
| ''(Optional)'' The index of this crop in the <samp>Texture</samp>, one crop per row, where 0 is the top row. Default 0.
 
|-
 
|-
| <samp>PlacementSound</samp>
+
| <samp>TintColors</samp>
| The [[#Custom audio|audio cue ID]] played when the item is applied/placed (e.g. <samp>axchop</samp> used by [[Wood Floor]]).
+
| ''(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>FootstepSound</samp>
+
!colspan="2"| Achievements
| The [[#Custom audio|audio cue ID]] played when the player steps on the tile (e.g. <samp>woodyStep</samp> used by [[Wood Floor]]).
   
|-
 
|-
| <samp>WinterTexture</samp><br /><samp>Corner</samp>
+
| <samp>CountForMonoculture</samp>
| ''(Optional)'' Equivalent to <samp>Texture</samp> and <samp>Corner</samp>, but applied if the current location is in winter.
+
| ''(Optional)'' Whether the player can ship 300 of this crop's harvest item to unlock the monoculture [[achievements|achievement]]. Default false.
 
|-
 
|-
| <samp>RemovalSound</samp>
+
| <samp>CountForPolyculture</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 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>RemovalDebrisType</samp>
+
!colspan="2"| Advanced
| ''(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>ShadowType</samp>
+
| <samp>PlantableLocationRules</samp>
| ''(Optional)'' The type of shadow to draw under the tile sprite. Default <samp>None</samp>.
+
| ''(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:
   −
The possible values are:
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! value
+
! field
 
! effect
 
! effect
 
|-
 
|-
| <samp>None</samp>
+
| <samp>Id</samp>
| Don't draw a shadow.
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the list.
 +
|-
 +
| <samp>Result</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>Square</samp>
+
| <samp>Condition</samp>
| Draw a shadow under the entire tile.
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this entry applies. Default true.
 +
|-
 +
| <samp>PlantedIn</samp>
 +
| ''(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>.
 
|-
 
|-
| <samp>Contoured</samp>
+
| <samp>DeniedMessage</samp>
| raw a shadow that follows the lines of the path sprite.
+
| ''(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>ConnectType</samp>
+
| <samp>CustomFields</samp>
| ''(Optional)'' When drawing the flooring across multiple tiles, how the flooring sprite for each tile is selected. Defaults to <samp>Default</samp>.
+
| The [[#Custom data fields|custom fields]] for this entry.
 +
|}
 +
 
 +
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>
 +
{
 +
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
 +
    "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
 +
                }
 +
            }
 +
        }
 +
    ]
 +
}</nowiki>|lang=javascript}}
 +
 
 +
===Custom fences===
 +
{{/doc status|a new doc page|done=false}}
 +
 
 +
You can now add or customize [[Crafting#Fences|fences]] by editing the <samp>Data/Fences</samp> asset.
   −
The possible values are:
+
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"
 
|-
 
|-
! value
+
! field
! usage
+
! effect
 
|-
 
|-
| <samp>Default</samp>
+
| <samp>Health</samp>
| For normal floors, intended to cover large square areas. This uses some logic to draw inner corners.
+
| 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>Path</samp>
+
| <samp>Texture</samp>
| For floors intended to be drawn as narrow paths. These are drawn without any consideration for inner corners.
+
| 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>CornerDecorated</samp>
+
| <samp>RemovalToolIds</samp><br /><samp>RemovalToolTypes</samp>
| For floors that have a decorative corner. Use <samp>CornerSize</samp> to change the size of this corner.
+
| 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:
 +
<syntaxhighlight lang="json">
 +
"RemovalToolIds": ["IridiumAxe"],
 +
"RemovalToolTypes": ["StardewValley.Tools.Pickaxe"]
 +
</syntaxhighlight>
 +
 
 +
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.
 +
|-
 +
| <samp>PlacementSound</samp>
 +
| The [[#Custom audio|audio cue ID]] played when the fence is placed or repaired (e.g. <samp>axe</samp> used by [[Wood Fence]]).
 +
|-
 +
| <samp>RemovalSound</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>.
 +
|-
 +
| <samp>RemovalDebrisType</samp>
 +
| ''(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>Random</samp>
+
| <samp>RepairHealthAdjustmentMinimum</samp><br /><samp>RepairHealthAdjustmentMaximum</samp>
| For floors that don't connect. When placed, one of the tiles is randomly selected.
+
| ''(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>CornerSize</samp>
+
| <samp>HeldObjectDrawOffset</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)'' 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>FarmSpeedBuff</samp>
+
| <samp>LeftEndHeldObjectDrawX</samp><br /><samp>RightEndHeldObjectDrawX</samp>
| ''(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.
+
| ''(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 machines===
+
===Custom floors (craftable) & paths===
You can now add/edit machine logic by editing the <samp>Data/Machines</samp> asset.
+
{{/doc status|a new doc page|done=false}}
   −
This consists of a string → model lookup, where...
+
You can now add or customize [[Crafting#Decor|craftable floors & paths]] by editing the <samp>Data/FloorsAndPaths</samp> asset.
* The key is the [[#Custom items|'''qualified''' item ID]] for the item which acts as a machine (like <samp>(BC)127</samp> for [[The Cave|mushroom boxes]]).
  −
* The value is a model with the fields listed below.
     −
====Item processing rules====
+
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"
 
|-
 
|-
Line 643: Line 837:  
! effect
 
! effect
 
|-
 
|-
| <samp>OutputRules</samp>
+
| <samp>ID</samp>
| The output produced by this machine. If multiple output rules can be produced, the first available one is selected. This consists of a list of models with these fields:
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this floor/path.
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>ItemId</samp>
! effect
+
| The unqualified [[#Custom items|item ID]] for the corresponding object-type item.
 
|-
 
|-
| <samp>Id</samp>
+
| <samp>Texture</samp>
| A key which uniquely identifies this rule for the current machine (it doesn't need to be unique between machines). The ID should only contain alphanumeric/underscore/dot characters. For custom rules, this should be prefixed with your mod ID like <samp>Example.ModId_RuleId</samp>.
+
| 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>Triggers</samp>
+
| <samp>Corner</samp>
| When to apply this output rule. This can list any number of triggers; the output will apply if any of them match.
+
| 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.
 
  −
This consists of a list of models with these fields:
  −
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>PlacementSound</samp>
! effect
+
| The [[#Custom audio|audio cue ID]] played when the item is applied/placed (e.g. <samp>axchop</samp> used by [[Wood Floor]]).
 
|-
 
|-
| <samp>Id</samp>
+
| <samp>FootstepSound</samp>
| A key which uniquely identifies this trigger within the current rule. The ID should only contain alphanumeric/underscore/dot characters. For custom rules on machines added by vanilla or another mod, this should be prefixed with your mod ID like <samp>Example.ModId_TriggerId</samp>.
+
| The [[#Custom audio|audio cue ID]] played when the player steps on the tile (e.g. <samp>woodyStep</samp> used by [[Wood Floor]]).
 
|-
 
|-
| <samp>Trigger</samp>
+
| <samp>WinterTexture</samp><br /><samp>Corner</samp>
| ''(Optional)'' When this output rule applies. Defaults to <samp>ItemPlacedInMachine</samp>. The possible values are...
+
| ''(Optional)'' Equivalent to <samp>Texture</samp> and <samp>Corner</samp>, but applied if the current location is in winter.
* <samp>ItemPlacedInMachine</samp>: apply this rule when an item is placed into the machine. This is the most common machine behavior.
  −
* <samp>OutputCollected</samp>: apply this rule when the machine's previous output is collected. An output-collected rule won't require or consume the input items, and the input item will be the previous output. For example, this is used to reload the [[crystalarium]].
  −
* <samp>MachinePutDown</samp>: apply this rule when the machine is put down. For example, this is used to start the [[Worm Bin|worm bin]].
  −
* <samp>DayUpdate</samp>: apply this rule when a new day starts, if it isn't already processing output. For example, this is used for the [[Soda Machine|soda machine]].
   
|-
 
|-
| <samp>RequiredItemId</samp>
+
| <samp>RemovalSound</samp>
| ''(Optional)'' The qualified or unqualified item ID for the item to match, if the trigger is <samp>ItemPlacedInMachine</samp> or <samp>OutputCollected</samp>. Defaults to allowing any item ID.
+
| ''(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>.
 
|-
 
|-
| <samp>RequiredTags</samp>
+
| <samp>RemovalDebrisType</samp>
| ''(Optional)'' The [[Modding:Context tags|context tags]] to match against input items, if the trigger is <samp>ItemPlacedInMachine</samp> or <samp>OutputCollected</samp>. An item must have all of the listed tags to select this rule. You can negate a tag with <samp>!</samp> (like <code>"RequiredTags": [ "bone_item", "!fossil_item" ]</code> for bone items that aren't fossils).
+
| ''(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>RequiredCount</samp>
+
| <samp>ShadowType</samp>
| ''(Optional)'' The required stack size for the input item, if the trigger is <samp>ItemPlacedInMachine</samp> or <samp>OutputCollected</samp>. Default 1.
+
| ''(Optional)'' The type of shadow to draw under the tile sprite. Default <samp>None</samp>.
|-
+
 
| <samp>Condition</samp>
+
The possible values are:
| ''(Optional)'' A [[#Game state queries|game state query]] which indicates whether this trigger should be checked. Item-only tokens are valid for this check if the trigger is <samp>ItemPlacedInMachine</samp> or <samp>OutputCollected</samp>. Defaults to always true.
  −
|}
  −
|-
  −
| <samp>OutputItem</samp>
  −
| The items produced by this machine. 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:
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! value
 
! effect
 
! effect
 
|-
 
|-
| ''common fields''
+
| <samp>None</samp>
| See [[#Item spawn fields|item spawn fields]] for the generic item fields supported by machine output.
+
| Don't draw a shadow.
 
  −
Notes:
  −
<ul>
  −
<li>If <samp>ItemId</samp> or <samp>RandomItemId</samp> is set to an [[#Item queries|item query]] which returns multiple items, one item will be selected at random.</li>
  −
<li>The <samp>ItemId</samp> and <samp>RandomItemId</samp> can optionally contain special tokens, which will be replaced before the item ID is parsed. For example, you can use <code>FLAVORED_ITEM Wine DROP_IN_ID</code> to create a wine for whatever item was placed in the machine.
  −
{| class="wikitable"
   
|-
 
|-
! token
+
| <samp>Square</samp>
! replaced with
+
| Draw a shadow under the entire tile.
 
|-
 
|-
| <samp>DROP_IN_ID</samp>
+
| <samp>Contoured</samp>
| The qualified item ID for the item placed in the machine.
+
| raw a shadow that follows the lines of the path sprite.
|-
  −
| <samp>DROP_IN_PRESERVE</samp>
  −
| If the item placed into the machine is a flavored item like Apple Juice or Tuna Roe, the ''unqualified'' item ID for the flavor item (e.g. the apple in Apple Wine). Otherwise <samp>0</samp>.
  −
|-
  −
| <samp>NEARBY_FLOWER_ID</samp>
  −
| The item ID for a flower within 5 tiles of the machine, or <samp>-1</samp> if no flower is found. For example, [[Bee House|bee houses]] produce <code>FLAVORED_ITEM Honey NEARBY_FLOWER_ID</code>.
   
|}
 
|}
</li>
  −
<li>The <samp>ObjectInternalName</samp> can optionally contain <samp>{0}</samp>, which will be replaced with the input item's internal name. This is used to prevent flavored items from stacking (''e.g.'' apple [[wine]] and blueberry wine).</li>
  −
<li>The <samp>Condition</samp> field will check the ''input'' (not output) item for item-related conditions.</li>
  −
</ul>
   
|-
 
|-
| <samp>PreserveType</samp>
+
| <samp>ConnectType</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.
+
| ''(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"
 
|-
 
|-
| <samp>PreserveId</samp>
+
! value
| ''(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.
+
! usage
 
|-
 
|-
| <samp>CopyColor</samp>
+
| <samp>Default</samp>
| ''(Optional)'' Whether to inherit the color of the input item if it was a <samp>ColoredObject</samp>. This mainly affects [[roe]]. Default false.
+
| For normal floors, intended to cover large square areas. This uses some logic to draw inner corners.
 
|-
 
|-
| <samp>CopyPrice</samp>
+
| <samp>Path</samp>
| ''(Optional)'' Whether to inherit the quality of the input item (before <samp>PriceModifiers</samp> are applied). This is ignored if the input or output aren't both object (<samp>(O)</samp>)-type.
+
| For floors intended to be drawn as narrow paths. These are drawn without any consideration for inner corners.
 
|-
 
|-
| <samp>CopyQuality</samp>
+
| <samp>CornerDecorated</samp>
| ''(Optional)'' Whether to inherit the quality of the input item (before <samp>QualityModifiers</samp> are applied).
+
| For floors that have a decorative corner. Use <samp>CornerSize</samp> to change the size of this corner.
 
|-
 
|-
| <samp>PriceModifiers</samp><br /><samp>PriceModifiers</samp>
+
| <samp>Random</samp>
| ''(Optional)'' [[#Quantity modifiers|Quantity modifiers]] applied to the output item's price. Default none.
+
| For floors that don't connect. When placed, one of the tiles is randomly selected.
 +
|}
 
|-
 
|-
| <samp>IncrementMachineParentSheetIndex</samp>
+
| <samp>CornerSize</samp>
| ''(Optional)'' Whether to increment the machine's spritesheet index by one while it's processing this output. This stacks with the <samp>ShowNextIndexWhenLoaded</samp> field (''i.e.'' setting both to true will increment the index by two). Default false.
+
| ''(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>OutputMethod</samp>
+
| <samp>FarmSpeedBuff</samp>
| ''(Optional, specialized)'' A C# method which decides which item to produce. If set, the <samp>ItemId</samp> field is optional and ignored.
+
| ''(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.
 +
|}
   −
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 and match the game's <samp>MachineOutputDelegate</samp> method signature:
+
===Custom machines===
<syntaxhighlight lang="c#">
+
{{/doc status|[[Modding:Machines]]|done=true}}
/// <summary>Get the output item to produce.</summary>
+
 
/// <param name="machine">The machine instance for which to produce output.</param>
+
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.
/// <param name="inputItem">The item being dropped into the machine, if applicable.</param>
+
 
/// <param name="probe">Whether the machine is only checking whether the input is valid. If so, the input/machine shouldn't be changed and no animations/sounds should play.</param>
+
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.
/// <param name="outputData">The item output data from <c>Data/Machines</c> for which output is being created, if applicable.</param>
+
 
/// <param name="overrideMinutesUntilReady">The in-game minutes until the item will be ready to collect, if set. This overrides the equivalent fields in the machine data if set.</param>
+
===Custom melee weapons===
/// <returns>Returns the item to produce, or <c>null</c> if none should be produced.</returns>
+
{{/doc status|[[Modding:Items#Weapons]]|done=false}}
public static Item GetOutput(Object machine, Item inputItem, bool probe, MachineItemOutput outputData, out int? overrideMinutesUntilReady);
+
 
</syntaxhighlight>
+
[[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).
   −
If this method returns null, the machine won't output anything.
+
This consists of a string → model lookup, where...
|-
+
* The key is the unqualified [[#Custom items|item ID]] for the weapon.
| <samp>CustomData</samp>
+
* The value is model with the fields listed below.
| Machine-specific data provided to the machine logic, if applicable.
     −
For example, the cask uses this to set the aging rate for each item:
+
====Basic weapon info====
<syntaxhighlight lang="js">
+
{| class="wikitable"
"OutputItem": {
  −
    "OutputMethod": "StardewValley.Objects.Cask.OutputCask",
  −
    "CustomData": {
  −
        "AgingMultiplier": 4
  −
    }
  −
}
  −
</syntaxhighlight>
  −
|}
   
|-
 
|-
| <samp>UseFirstValidOutput</samp>
+
! field
| ''(Optional)'' If multiple <samp>OutputItem</samp> entries match, whether to use the first match instead of choosing one randomly. Default false.
+
! effect
 
|-
 
|-
| <samp>MinutesUntilReady</samp><br /><samp>DaysUntilReady</samp>
+
| <samp>Name</samp>
| ''(Optional)'' The number of in-game minutes or days until the output is ready to collect. If both days and minutes are specified, days are used. If none are specified, the item will be ready instantly.
+
| The internal weapon name.
 
|-
 
|-
| <samp>InvalidCountMessage</samp>
+
| <samp>DisplayName</samp><br /><samp>Description</samp>
| ''(Optional)'' If set, overrides the machine's main <samp>InvalidCountMessage</samp> field.
+
| A [[Modding:Tokenizable strings|tokenizable string]] for the translated display name & description.
 
|-
 
|-
| <samp>RecalculateOnCollect</samp>
+
| <samp>Type</samp>
| ''(Optional)'' Whether to regenerate the output right before the player collects it, similar to [[Bee House|bee houses]]. If the new item is null, the original output is returned instead.
+
| 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).
 
|}
 
|}
|-
  −
| <samp>AdditionalConsumedItems</samp>
  −
| ''(Optional)'' A list of extra items required before <samp>OutputRules</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:
+
====Appearance====
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 792: Line 950:  
! effect
 
! effect
 
|-
 
|-
| <samp>ItemId</samp>
+
| <samp>Texture</samp>
| The [[#Custom items|qualified or unqualified item ID]] for the required item.
+
| The asset name for the spritesheet containing the weapon's sprite.
 
|-
 
|-
| <samp>RequiredCount</samp>
+
| <samp>SpriteIndex</samp>
| ''(Optional)'' The required stack size for the item matching <samp>ItemId</samp>. Default 1.
+
| The index within the <samp>Texture</samp> for the weapon sprite, where 0 is the top-left sprite.
|-
  −
| <samp>InvalidCountMessage</samp>
  −
| ''(Optional)'' If set, overrides the machine's main <samp>InvalidCountMessage</samp> field.
  −
|}
  −
|-
  −
| <samp>AllowFairyDust</samp>
  −
| ''(Optional)'' Whether the player can add [[Fairy Dust|fairy dust]] to speed up the machine. Default true.
  −
|-
  −
| <samp>ReadyTimeModifiers</samp>
  −
| ''(Optional)'' [[#Quantity modifiers|Quantity modifiers]] applied to the produced item's processing time. The modifier conditions can use item-only tokens, which will check the ''input'' (not output) item.
  −
|-
  −
| <samp>ReadyTimeModifierMode</samp>
  −
| ''(Optional)'' A [[#Quantity modifiers|quantity modifier mode]] which indicates what to do if multiple modifiers apply at the same time. Default <samp>Stack</samp>.
   
|}
 
|}
   −
====Behavior tweaks====
+
====Stats====
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 818: Line 963:  
! effect
 
! effect
 
|-
 
|-
| <samp>PreventTimePass</samp>
+
| <samp>MinDamage</samp><br /><samp>MaxDamage</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:
+
| The minimum and maximum based damage caused when hitting a monster with this weapon.
{| class="wikitable"
   
|-
 
|-
! value
+
| <samp>Knockback</samp>
! effect
+
| ''(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.
 
|-
 
|-
| <samp>Outside</samp><br /><samp>Inside</samp>
+
| <samp>Speed</samp>
| Pause when placed in an outside or inside location. For example, [[Bee House|bee houses]] don't work inside.
+
| ''(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.
 
|-
 
|-
| <samp>Spring</samp><br /><samp>Summer</samp><br /><samp>Fall</samp><br /><samp>Winter</samp>
+
| <samp>Precision</samp>
| Pause in the given season. For example, [[Bee House|bee houses]] don't work in winter.
+
| ''(Optional)'' Reduces the chance that a strike will miss. Default 0.
 
|-
 
|-
 +
| <samp>Defense</samp>
 +
| ''(Optional)'' Reduces damage received by the player. Default 0.
 
|-
 
|-
| <samp>Sun</samp><br /><samp>Rain</samp>
+
| <samp>AreaOfEffect</samp>
| Pause on days with the given weather.
+
| ''(Optional)'' Slightly increases the area of effect. Default 0.
|-
  −
| <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>AllowLoadWhenFull</samp>
+
| <samp>CritChance</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.
+
| ''(Optional)'' The chance of a critical hit, as a decimal value between 0 (never) and 1 (always). Default 0.02.
 
|-
 
|-
| <samp>ClearContentsOvernightCondition</samp>
+
| <samp>CritMultiplier</samp>
| ''(Optional)'' A [[#Game state queries|game state query]] which indicates whether the machine should be emptied overnight, so any current output will be lost. Defaults to always false.
+
| ''(Optional)'' A multiplier applied to the base damage for a critical hit. This can be a decimal value. Default 3.
 
|}
 
|}
   −
====Audio & visuals====
+
====Game logic====
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 852: Line 994:  
! effect
 
! effect
 
|-
 
|-
| <samp>LoadEffects</samp><br /><samp>WorkingEffects</samp>
+
| <samp>CanBeLostOnDeath</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:
+
| Whether the player can [[Adventurer's Guild#Item Recovery Service|lose this tool when they die]]. Default true.
 +
|-
 +
| <samp>MineBaseLevel</samp><br /><samp>MineMinLevel</samp>
 +
| ''(Optional)'' The base and minimum mine level, which affect [[#Mine container drops|mine container drops]]. Both default to -1, which disables automatic mine drops.
 +
|}
 +
 
 +
====Advanced====
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 859: Line 1,007:  
! effect
 
! effect
 
|-
 
|-
| <samp>RequiredItemId</samp>
+
| <samp>Projectiles</samp>
| ''(Optional)'' If set, only apply this effect if the main input item has this qualified or unqualified item ID.
+
| ''(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>RequiredTags</samp>
+
This consists of a list of models with these fields (one projectile will fire for each entry in the list):
| ''(Optional)'' If set, only apply this effect if the main input item has ''all'' of these [[Modding:Context tags|context tags]]. You can negate a tag with <samp>!</samp> (like <code>"RequiredTags": [ "bone_item", "!fossil_item" ]</code> for bone items that aren't fossils).
  −
|-
  −
| <samp>Sound</samp>
  −
| ''(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"
 
|-
 
|-
Line 875: Line 1,016:  
! effect
 
! effect
 
|-
 
|-
| <samp>Sound</samp>
+
| <samp>Id</samp>
| The [[#Custom audio|audio cue ID]] to play.
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for the projectile within the current weapon's data.
 
|-
 
|-
| <samp>Delay</samp>
+
| <samp>Damage</samp>
| The number of milliseconds until the sound should play.
+
| ''(Optional)'' The amount of damage caused when the projectile hits a monster. Default 10.
|}
   
|-
 
|-
| <samp>ShakeDuration</samp>
+
| <samp>Explodes</samp>
| ''(Optional)'' A duration in milliseconds during which the machine sprite should shake. Default none.
+
| ''(Optional)'' Whether the projectile explodes when it collides with something. Default false.
 
|-
 
|-
| <samp>Frames</samp>
+
| <samp>Bounces</samp>
| ''(Optional)'' The animation to apply to the machine sprite, specified as a list of offsets relative to the base sprite index. Default none.
+
| ''(Optional)'' The number of times the projectile can bounce off walls before being destroyed. Default 0.
 
|-
 
|-
| <samp>Interval</samp>
+
| <samp>MaxDistance</samp>
| ''(Optional)'' The number of milliseconds for which each frame in <samp>Frames</samp> is kept on-screen. Default 100.
+
| ''(Optional)'' The maximum tile distance the projectile can travel. Default 4.
 
|-
 
|-
| <samp>TemporarySprites</samp>
+
| <samp>Velocity</samp>
| ''(Optional)'' The temporary animated sprites to show. This consists of a list of models with these fields:
+
| ''(Optional)'' The speed at which the projectile moves. Default 10.
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>RotationVelocity</samp>
! effect
+
| ''(Optional)'' The rotation velocity. Default 32.
 
|-
 
|-
| <samp>Texture</samp>
+
| <samp>TailLength</samp>
| The asset name for the texture (under the game's <samp>Content</samp> folder) for the animated sprite.
+
| ''(Optional)'' The length of the tail which trails behind the main projectile. Default 1.
 
|-
 
|-
| <samp>SourceRect</samp>
+
| <samp>FireSound</samp><br /><samp>BounceSound</samp><br /><samp>CollisionSound</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.
+
| ''(Optional)'' The sound played when the projectile is fired, bounces off a wall, or collides with something. All three default to none.
 
|-
 
|-
| <samp>PositionOffset</samp>
+
| <samp>MinAngleOffset</samp><br /><samp>MaxAngleOffset</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).
+
| ''(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>Color</samp>
+
| <samp>SpriteIndex</samp>
| ''(Optional)'' A tint color to apply to the sprite. See [[#Color fields|color format]]. Default <samp>White</samp> (no tint).
+
| ''(Optional)'' The sprite index in the <samp>TileSheets/Projectiles</samp> asset to draw for this projectile. Defaults to 11 (a glowing-yellow-ball sprite).
 
|-
 
|-
| <samp>AlphaFade</samp><br /><samp>Loops</samp><br /><samp>Rotation</samp><br /><samp>RotationChange</samp><br /><samp>ScaleChange</samp><br /><samp>SortOffset</samp>
+
| <samp>Item</samp>
| ''(Optional)'' See equivalent fields in the [[#Event changes|<samp>temporaryAnimatedSprite</samp> event command]]. Default 0.
+
| ''(Optional)'' The item to shoot. If set, this overrides <samp>SpriteIndex</samp>.
|-
  −
| <samp>Frames</samp><br /><samp>Scale</samp>
  −
| ''(Optional)'' See equivalent fields in the [[#Event changes|<samp>temporaryAnimatedSprite</samp> event command]]. Default 1.
  −
|-
  −
| <samp>Interval</samp>
  −
| ''(Optional)'' See equivalent fields in the [[#Event changes|<samp>temporaryAnimatedSprite</samp> event command]]. Default 100.
  −
|-
  −
| <samp>Flicker</samp><br /><samp>Flip</samp>
  −
| ''(Optional)'' See equivalent fields in the [[#Event changes|<samp>temporaryAnimatedSprite</samp> event command]]. Default false.
  −
|}
  −
|}
  −
|-
  −
| <samp>WorkingEffectChance</samp>
  −
| ''(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.
  −
|-
  −
| <samp>LightWhileWorking</samp>
  −
| ''(Optional)'' The light emitted by the machine while it's processing an item. Default none.
     −
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 936: Line 1,058:  
! effect
 
! effect
 
|-
 
|-
| <samp>Radius</samp>
+
| ''common fields''
| ''(Optional)'' The size of the area covered by the light effect, as a multiplier of the default radius (like <samp>1.5</samp> for an area 50% wider than the default). Default 1.
+
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields supported for ammo items.
|-
+
 
| <samp>Color</samp>
+
If set to an [[Modding:Item queries|item query]] which returns multiple items, one of them will be selected at random.
| ''(Optional)'' A tint color to apply to the light. See [[#Color fields|color format]]. Default <samp>White</samp> (no tint).
   
|}
 
|}
|-
  −
| <samp>WobbleWhileWorking</samp>
  −
| ''(Optional)'' Whether the machine sprite should bulge in & out while it's processing an item. Default false.
  −
|-
  −
| <samp>ShowNextIndexWhileWorking</samp><br /><samp>ShowNextIndexWhenReady</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.
   
|}
 
|}
   −
====Player interaction messages====
+
Note that these are magic projectiles fired when the weapon is used, they're not aimed directly like [[slingshot]] projectiles.
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"
   
|-
 
|-
! field
+
| <samp>CustomFields</samp>
! effect
+
| The [[#Custom data fields|custom fields]] for this entry.
|-
  −
| <samp>InvalidItemMessage</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.
  −
|-
  −
| <samp>InvalidItemMessageCondition</samp>
  −
| ''(Optional)'' A [[#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.
  −
|-
  −
| <samp>InvalidCountMessage</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>OutputRules</samp>.
  −
 
  −
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====
+
===Custom movie concessions===
{| class="wikitable"
+
{{/doc status|[[Modding:Movie theater data]]|done=false}}
|-
+
: ''See also: [[#Custom movies|custom movies]].''
! field
  −
! effect
  −
|-
  −
| <samp>InteractMethod</samp>
  −
| ''(Optional)'' A C# method invoked when the player interacts with the machine when it doesn't have output ready to harvest.
     −
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 and match the game's <samp>MachineInteractDelegate</samp> method signature:
+
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.
<syntaxhighlight lang="c#">
  −
/// <summary>The method signature for a custom <see cref="MachineData.InteractMethod"/> method.</summary>
  −
/// <param name="machine">The machine instance for which to produce output.</param>
  −
/// <param name="location">The location containing the machine.</param>
  −
/// <param name="player">The player using the machine.</param>
  −
/// <returns>Returns whether the interaction was handled.</returns>
  −
public static bool InteractWithMachine(Object machine, GameLocation location, Farmer player);
  −
</syntaxhighlight>
  −
|-
  −
| <samp>HasInput</samp><br /><samp>HasOutput</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 <samp>OutputRules</samp> field. Default false.
  −
|-
  −
| <samp>IsIncubator</samp>
  −
| ''(Optional)'' Whether this machine acts as an incubator when placed in a building, so players can incubate eggs in it. Default false.
     −
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 that can be built in a vanilla [[barn]] or [[coop]].
+
Stardew Valley 1.6 addresses that with two changes:
|-
+
<ul>
| <samp>StatsToIncrementWhenLoaded</samp><br /><samp>StatsToIncrementWhenHarvested</samp>
+
<li>The <samp>Id</samp> field is now a [[Modding:Common data field types#Unique string ID|unique string ID]].</li>
| ''(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:
+
<li>You can now use a different texture with two new required fields:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 1,005: Line 1,086:  
! effect
 
! effect
 
|-
 
|-
| <samp>StatName</samp>
+
| <samp>Texture</samp>
| The name of the stat counter field on <samp>Game1.stats</samp>.
+
| The asset name for the texture containing the concession's sprite.
 
|-
 
|-
| <samp>RequiredItemId</samp>
+
| <samp>SpriteIndex</samp>
| ''(Optional)'' If set, only increment the stat if the main input item has this qualified or unqualified item ID.
+
| The index within the <samp>Texture</samp> for the concession sprite, where 0 is the top-left sprite.
|-
  −
| <samp>RequiredTags</samp>
  −
| ''(Optional)'' If set, only increment the stat if the main input item has ''all'' of these [[Modding:Context tags|context tags]]. You can negate a tag with <samp>!</samp> (like <code>"RequiredTags": [ "bone_item", "!fossil_item" ]</code> for bone items that aren't fossils).
   
|}
 
|}
 +
</li>
 +
</ul>
   −
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]].
+
For example, this content pack adds a new 'Pufferchick Pop' concession with a custom image:
|-
+
{{#tag:syntaxhighlight|<nowiki>
| <samp>CustomFields</samp>
+
{
| The [[#Custom data fields|custom fields]] for this entry.
+
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
|}
+
    "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
 +
                }
 +
            }
 +
        }
 +
    ]
 +
}</nowiki>|lang=javascript}}
 +
 
 +
===Custom museum donations & rewards===
 +
{{/doc status|a new doc page|done=false}}
 +
 
 +
You can now add/edit the items which the [[museum]] 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 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.
   −
====Interacting with machines in C#====
  −
Stardew Valley 1.6 adds two <samp>Object</samp> fields for reference:
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 1,028: Line 1,133:  
! effect
 
! effect
 
|-
 
|-
| <samp>lastOutputRuleId</samp>
+
| <samp>TargetContextTags</samp>
| If this is a machine, the output rule ID for the rule being processed by the machine (if any).
+
| 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:
|-
  −
| <samp>lastInputItem</samp>
  −
| If this is a machine, the item that was dropped into the machine to start the current output (if any).
  −
|}
  −
 
  −
And a few methods for processing items:
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 1,041: Line 1,140:  
! effect
 
! effect
 
|-
 
|-
| <samp>IsMachineWorking()</samp>
+
| <samp>Tag</samp>
| Get whether the machine is currently processing an item.
+
| The [[Modding:Context tags|context tag]] for the items to require.
 
|-
 
|-
| <samp>ShouldTimePassForMachine(location)</samp>
+
| <samp>Count</samp>
| Get whether the machine should be updated in the given location. For example, this will return false for [[Solar Panel|solar panels]] placed indoors, or outdoors on a cloudy day.
+
| The minimum number of items matching the context tags that must be donated.
|-
  −
| <samp>GetMachineData()</samp>
  −
| Get the underlying machine data from <samp>Data/Machines</samp>.
  −
|-
  −
| <samp>PlaceInMachine(…)</samp>
  −
| Try to place an item in the machine using the rules from <samp>Data/Machines</samp>. This returns a boolean which indicates whether the machine was successfully started.
  −
|-
  −
| <samp>OutputMachine(…)</samp>
  −
| Try to set the machine output given the input item and an optional output rule to apply. Most code should call <samp>PlaceInMachine</samp> instead.
   
|}
 
|}
   −
A lot of the generic machine logic is also handled by a new <samp>MachineDataUtility</samp> class, which lets C# mods interact with machine data more directly. For example, you can check which output a machine would produce without actually updating the machine.
+
For example, an entry with the tag <samp>forage_item</samp> and count 2 will require donating any two forage items.
   −
===Custom melee weapons===
+
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).
[[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).
+
|-
 +
| <samp>FlagOnCompletion</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.
   −
This consists of a string → model lookup, where...
+
After the reward is collected, you can check this value using the <samp><nowiki>HasFlag</nowiki></samp> condition in [[Modding:Content Patcher|Content Patcher]].
* 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
+
| <samp>RewardActions</samp>
! effect
+
| 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>Name</samp>
+
| <samp>RewardItemId</samp>
| The internal weapon name.
+
| ''(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>RewardItemCount</samp>
 +
| ''(Optional)'' The stack size for the <samp>RewardItemId</samp> (if the item supports stacking). Default 1.
 +
|-
 +
| <samp>RewardItemIsSpecial</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.
 
|-
 
|-
| <samp>DisplayName</samp><br /><samp>Description</samp>
+
| <samp>RewardItemIsRecipe</samp>
| A [[#Tokenizable string format|tokenizable string]] for the translated display name & description.
+
| ''(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>Type</samp>
+
| <samp>CustomFields</samp>
| 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).
+
| The [[#Custom data fields|custom fields]] for this entry.
 
|}
 
|}
   −
====Appearance====
+
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"
 
{| class="wikitable"
 
|-
 
|-
Line 1,088: Line 1,236:  
! effect
 
! effect
 
|-
 
|-
| <samp>Texture</samp>
+
| <samp>DisplayName</samp>
| The asset name for the spritesheet containing the weapon's sprite.
+
| 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>SpriteIndex</samp>
+
| <samp>Seasons</samp>
| The index within the <samp>Texture</samp> for the weapon sprite, where 0 is the top-left sprite.
+
| 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>).
|}
     −
====Stats====
+
'''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]]).
{| class="wikitable"
+
|-
 +
| <samp>Fruit</samp>
 +
| 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:
 +
{| class="wikitable"
 
|-
 
|-
 
! field
 
! field
 
! effect
 
! effect
 
|-
 
|-
| <samp>MinDamage</samp><br /><samp>MaxDamage</samp>
+
| ''common fields''
| The minimum and maximum based damage caused when hitting a monster with this weapon.
+
| 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>Knockback</samp>
+
| <samp>Season</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.
+
| ''(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>Speed</samp>
+
| <samp>Chance</samp>
| ''(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.
+
| ''(Optional)'' The probability that this entry is selected, as a value between 0 (never drops) and 1 (always drops). Default 1 (100% chance).
 +
|}
 
|-
 
|-
| <samp>Precision</samp>
+
| <samp>Texture</samp>
| ''(Optional)'' Reduces the chance that a strike will miss. Default 0.
+
| 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>.
 
|-
 
|-
| <samp>Defense</samp>
+
| <samp>TextureSpriteRow</samp>
| ''(Optional)'' Reduces damage received by the player. Default 0.
+
| 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>AreaOfEffect</samp>
+
| <samp>PlantableLocationRules</samp>
| ''(Optional)'' Slightly increases the area of effect. Default 0.
+
| ''(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.
|-
+
 
| <samp>CritChance</samp>
+
This consists of a list of models with these fields:
| ''(Optional)'' The chance of a critical hit, as a decimal value between 0 (never) and 1 (always). Default 0.02.
  −
|-
  −
| <samp>CritMultiplier</samp>
  −
| ''(Optional)'' A multiplier applied to the base damage for a critical hit. This can be a decimal value. Default 3.
  −
|}
     −
====Game logic====
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 1,132: Line 1,283:  
! effect
 
! effect
 
|-
 
|-
| <samp>CanBeLostOnDeath</samp>
+
| <samp>Id</samp>
| Whether the player can [[Adventurer's Guild#Item Recovery Service|lose this tool when they die]]. Default true.
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the list.
 +
|-
 +
| <samp>Result</samp>
 +
| 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>Condition</samp>
 +
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this entry applies. Default true.
 
|-
 
|-
| <samp>MineBaseLevel</samp><br /><samp>MineMinLevel</samp>
+
| <samp>PlantedIn</samp>
| ''(Optional)'' The base and minimum mine level, which affect [[#Mine container drops|mine container drops]]. Both default to -1, which disables automatic mine drops.
+
| ''(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>.
|}
     −
====Advanced====
+
Note that saplings can't be planted in garden pots.
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>DeniedMessage</samp>
! effect
+
| ''(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>Projectiles</samp>
+
| <samp>CustomFields</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.
+
| The [[#Custom data fields|custom fields]] for this entry.
 +
|}
   −
This consists of a list of models with these fields (one projectile will fire for each entry in the list):
+
For example, this content pack adds a custom fruit tree, including [[#Custom items|custom items]] for the sapling and fruit:
{| class="wikitable"
  −
|-
  −
! field
  −
! effect
  −
|-
  −
| <samp>Id</samp>
  −
| A unique identifier for the projectile within the current weapon's data. The ID should only contain alphanumeric/underscore/dot characters. For custom projectiles, this should be prefixed with your mod ID like Example.ModId_ProjectileId.
  −
|-
  −
| <samp>Damage</samp>
  −
| ''(Optional)'' The amount of damage caused when the projectile hits a monster. Default 10.
  −
|-
  −
| <samp>Explodes</samp>
  −
| ''(Optional)'' Whether the projectile explodes when it collides with something. Default false.
  −
|-
  −
| <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>SpriteIndex</samp>
  −
| ''(Optional)'' The sprite index in the <samp>TileSheets/Projectiles</samp> asset to draw for this projectile. Defaults to 11 (a glowing-yellow-ball sprite).
  −
|-
  −
| <samp>Item</samp>
  −
| ''(Optional)'' The item to shoot. If set, this overrides <samp>SpriteIndex</samp>.
     −
This consists of a list of models with these fields:
+
{{#tag:syntaxhighlight|<nowiki>
{| class="wikitable"
+
{
|-
+
     "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
! field
+
     "Changes": [
! effect
+
        // add fruit + sapling items
|-
+
        // note: sapling must have an edibility under 0 (usually -300) to be plantable
| ''common fields''
  −
| See [[#Item spawn fields|item spawn fields]] for the generic item fields supported for ammo items.
  −
 
  −
If set to an [[#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>CustomFields</samp>
  −
| The [[#Custom data fields|custom fields]] for this entry.
  −
|}
  −
 
  −
===Custom movie concessions===
  −
: ''See also: [[#Custom movies|custom movies]].''
  −
 
  −
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.
  −
 
  −
Stardew Valley 1.6 addresses that with two changes:
  −
<ul>
  −
<li>The <samp>Id</samp> field is now a string, so you can use a globally unique ID like <samp>ExampleAuthor.ModId_ItemName</samp>.</li>
  −
<li>You can now use a different texture with two new required fields:
  −
{| class="wikitable"
  −
|-
  −
! field
  −
! effect
  −
|-
  −
| <samp>Texture</samp>
  −
| The asset name for the texture containing the concession's sprite.
  −
|-
  −
| <samp>SpriteIndex</samp>
  −
| The index within the <samp>Texture</samp> for the concession sprite, where 0 is the top-left sprite.
  −
|}
  −
</li>
  −
</ul>
  −
 
  −
For example, this content pack adds a new 'Pufferchick Pop' concession with a custom image:
  −
{{#tag:syntaxhighlight|<nowiki>
  −
{
  −
     "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
  −
     "Changes": [
   
         {
 
         {
 
             "Action": "EditData",
 
             "Action": "EditData",
             "Target": "Data/Concessions",
+
             "Target": "Data/Objects",
 
             "Entries": {
 
             "Entries": {
                 "Example.ModId_PufferchickPop": {
+
                 "{{ModId}}_Pufferfruit": {
                     "Id": "Example.ModId_PufferchickPop", // must specify ID again when creating a new entry
+
                     "Name": "{{ModId}}_Pufferfruit", // best practice to match the ID, since it's sometimes used as an alternate ID
                     "Name": "PufferchickPop",
+
                     "DisplayName": "Pufferfruit",
                     "DisplayName": "Pufferchick Pop",
+
                     "Description": "An example fruit item.",
                     "Description": "A cute cake pop shaped like a pufferchick.",
+
                     "Type": "Basic",
                     "Price": 25,
+
                    "Category": -6,
                     "Texture": "{{InternalAssetKey: assets/pufferchick-pop.png}}" // an image in your content pack
+
                     "Price": 1200,
 +
 
 +
                     "Texture": "Mods/{{ModId}}/Objects",
 
                     "SpriteIndex": 0
 
                     "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
 
                 }
 
                 }
 
             }
 
             }
         }
+
         },
    ]
  −
}</nowiki>|lang=javascript}}
     −
===Custom museum donations & rewards===
+
        // add fruit tree
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.
+
        {
 
+
            "Action": "EditData",
====Format====
+
            "Target": "Data/FruitTrees",
The data asset consists of a string → model lookup, where...
+
            "Entries": {
* The key is a unique identifier for the reward group. The ID should only contain alphanumeric/underscore/dot characters. For custom reward entries, this should be prefixed with your mod ID like <samp>Example.ModId_RewardName</samp>.
+
                "{{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.
 
* The value is a model with the fields listed below.
    +
====Basic info====
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
 
! field
 
! field
! effect
+
! purpose
 +
|-
 +
| <samp>Name</samp>
 +
| The internal item name.
 
|-
 
|-
| <samp>TargetContextTags</samp>
+
| <samp>DisplayName</samp><br /><samp>Description</samp>
| 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:
+
| A [[Modding:Tokenizable strings|tokenizable string]] for the item's in-game display name and description.
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>Type</samp>
! effect
+
| The item's general type, like <samp>Arch</samp> (artifact) or <samp>Minerals</samp>. See details at [[Modding:Items#Objects]].
 
|-
 
|-
| <samp>Tag</samp>
+
| <samp>Category</samp>
| The [[Modding:Context tags|context tag]] for the items to require.
+
| The [[Modding:Items#Categories|item category]].
 
|-
 
|-
| <samp>Count</samp>
+
| <samp>Price</samp>
| The minimum number of items matching the context tags that must be donated.
+
| ''(Optional)'' The price when sold by the player. This is not the price when bought from a shop. Default 0.
 
|}
 
|}
   −
For example, an entry with the tag <samp>forage_item</samp> and count 2 will require donating any two forage items.
+
====Appearance====
 
+
{| class="wikitable"
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).
+
|-
 +
! field
 +
! purpose
 
|-
 
|-
| <samp>FlagOnCompletion</samp>
+
| <samp>Texture</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.
+
| The asset name for the texture containing the item's sprite. Defaults to <samp>Maps/springobjects</samp>.
 
  −
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>SpriteIndex</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.)
+
| The sprite's index within the <samp>Texture</samp>, where 0 is the top-left sprite.
 +
|}
   −
After the reward is collected, you can check this value using the <samp><nowiki>HasSeenEvent</nowiki></samp> condition in [[Modding:Content Patcher|Content Patcher]].
+
====Edibility====
 +
{| 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.
+
! purpose
|-
  −
| <samp>RewardItemCount</samp>
  −
| ''(Optional)'' The stack size for the <samp>RewardItemId</samp> (if the item supports stacking). Default 1.
  −
|-
  −
| <samp>RewardItemIsSpecial</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.
   
|-
 
|-
| <samp>RewardItemIsRecipe</samp>
+
| <samp>Edibility</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.
+
| ''(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>RewardMail</samp>
+
| <samp>IsDrink</samp>
| ''(Optional)'' A [[Modding:Mail data|mail ID]] to add to the player's mailbox tomorrow.
+
| ''(Optional)'' Whether to drink the item instead of eating it. Default false.
 
|-
 
|-
| <samp>CustomFields</samp>
+
| <samp>Buffs</samp>
| The [[#Custom data fields|custom fields]] for this entry.
+
| ''(Optional)'' The buffs to apply to the player when this item is eaten, if any. Default none.
|}
  −
 
  −
 
  −
For example, this content pack adds two rewards, one in form of a mail, the other a machine :
  −
 
  −
{{#tag:syntaxhighlight|<nowiki>
  −
{
  −
    "Format": "1.28.0",
  −
"Changes": [
  −
{
  −
"Action": "EditData",
  −
"Target": "Data/MuseumRewards",
  −
"Entries": {
  −
//Send a mail when a specific item is donated
  −
"Example.ModId_ShinyArtifact": {
  −
"TargetContextTags": [
  −
{
  −
"Tag": "id_example.modid_shinyartifact",//The unique context tag identifying the item
  −
"Count": 1
  −
},
  −
],
  −
"FlagOnCompletion": true,
  −
"RewardMail": "Example.ModId_ShinyArtifact"
  −
},
  −
//Gives a machine as reward when 18 minerals are donated.
  −
"Example.ModId_18MineralItems": {
  −
"TargetContextTags": [
  −
{
  −
"Tag": "item_type_minerals",
  −
"Count": 18
  −
},
  −
],
  −
"RewardItemId": "(BC)Example.ModId_SuperMachine",
  −
"RewardItemCount": 1,
  −
"FlagOnCompletion": true,
  −
  −
},
  −
},
  −
}
  −
]
  −
}</nowiki>|lang=javascript}}
  −
 
  −
The mail entry would then be added to [[Modding:Mail_data|mail data]] using the same key. See [[#Custom_items|Custom Items]] and [[#Custom_machines|Custom Machines]] to add the items themselves.
  −
 
  −
====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===
  −
====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/ObjectInformation</samp>.
  −
* The value is a model with the fields listed below.
      +
This consists of a list of models with these fields:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
 
! field
 
! field
! effect
+
! purpose
 
|-
 
|-
| <samp>DisplayName</samp>
+
| <samp>Id</samp>
| A [[#Tokenizable string format|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''".
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the list.
 
|-
 
|-
| <samp>Seasons</samp>
+
| <samp>Duration</samp>
| 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>).
+
| ''(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.
 
  −
'''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>Fruit</samp>
+
| <samp>BuffId</samp>
| 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.
+
| ''(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.
   −
This consists of a list of models with these fields:
+
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"
 
{| class="wikitable"
 
|-
 
|-
 
! field
 
! field
! effect
+
! result
 
|-
 
|-
| ''common fields''
+
| <samp>Duration</samp><br /><samp>IconTexture</samp><br /><samp>SpriteIndex</samp><br /><samp>GlowColor</samp>
| See [[#Item spawn fields|item spawn fields]] for the generic item fields supported for fruit items.
+
| 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>.
 
  −
Notes:
  −
* If set to an [[#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>Season</samp>
+
| <samp>CustomAttributes</samp>
| ''(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]].
+
| 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>Chance</samp>
+
| <samp>IsDebuff</samp>
| ''(Optional)'' The probability that this entry is selected, as a value between 0 (never drops) and 1 (always drops). Default 1 (100% chance).
+
| The value in <samp>Data/Objects</samp> is used.
 
|}
 
|}
 
|-
 
|-
| <samp>Texture</samp>
+
| <samp>IsDebuff</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, vanilla fruit trees use <samp>TileSheets\fruitTrees</samp>.
+
| ''(Optional)'' Whether this buff counts as a debuff, so its duration should be halved when wearing a Sturdy Ring. Default false.
 +
|-
 +
| <samp>IconTexture</samp>
 +
| ''(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>
 +
| ''(Optional)'' The buff's icon index within the <samp>IconTexture</samp>, where 0 is the top-left icon. Default 0.
 +
|-
 +
| <samp>GlowColor</samp>
 +
| ''(Optional)'' The glow color to apply to the player. See [[#Color fields|color format]]. Default none.
 +
|-
 +
| <samp>CustomAttributes</samp>
 +
| The custom buff attributes to apply, if any.
 +
 
 +
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>TextureSpriteRow</samp>
+
| <samp>Attack</samp><br /><samp>Defense</samp><br /><samp>MagneticRadius</samp><br /><samp>MaxStamina</samp><br /><samp>Speed</samp>
| The tree's row index in the <samp>Texture</samp> spritesheet (e.g. 0 for the first tree, 1 for the second tree, etc).
+
| ''(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>CustomFields</samp>
 
| <samp>CustomFields</samp>
| The [[#Custom data fields|custom fields]] for this entry.
+
| ''(Optional)'' The [[#Custom data fields|custom fields]] for this entry.  
 +
|}
 
|}
 
|}
   −
For example, this content pack adds a custom fruit tree, including [[#Custom items|custom items]] for the sapling and fruit:
+
====Geodes & artifact spots====
 +
{| class="wikitable"
 +
|-
 +
! field
 +
! purpose
 +
|-
 +
| <samp>GeodeDrops</samp><br /><samp><samp>GeodeDropsDefaultItems</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.
   −
{{#tag:syntaxhighlight|<nowiki>
+
You can specify one or both fields:
{
+
<ul>
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
+
<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:
    "Changes": [
+
{| class="wikitable"
        // add fruit + sapling items
+
|-
        // note: sapling must have an edibility under 0 (usually -300) to be plantable
+
! field
        {
+
! purpose
            "Action": "EditData",
+
|-
            "Target": "Data/ObjectInformation",
+
|-
            "Entries": {
+
| ''common fields''
                "Example.ModId_Pufferfruit": "Pufferfruit/1200/100/Basic -6/Pufferfruit/An example fruit item.////1/Mods\\Example.ModId\\Objects",
+
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields supported by geode drops.
                "Example.ModId_Puffersapling": "Puffersapling/1200/-300/Basic -74/Puffersapling/An example tree sapling.////2/Mods\\Example.ModId\\Objects"
  −
            }
  −
        },
     −
        // add fruit tree
+
If set to an [[Modding:Item queries|item query]] which returns multiple items, one of them will be selected at random.
        {
+
|-
            "Action": "EditData",
+
| <samp>Chance</samp>
            "Target": "Data/FruitTrees",
+
| ''(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.
            "Entries": {
+
|-
                "Example.ModId_Puffersapling": {
+
| <samp>SetFlagOnPickup</samp>
                    "DisplayName": "[DataString Data\ObjectInformation Example.ModId_Pufferfruit 4]", // field 4 (display name) for our fruit item
+
| ''(Optional)'' The mail flag to set for the current player when this drop is picked up.
                    "Seasons": [ "spring" ],
+
|-
                    "Fruit": [
+
| <samp>Precedence</samp>
                        {
+
| ''(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.
                            "Id": "Example.ModId_Pufferfruit",
+
 
                            "ItemId": "Example.ModId_Pufferfruit"
+
For consistency, vanilla drops mostly use these values:
                        }
+
* <samp>-1000</samp>: special overrides like the [[Golden Helmet]];
                    ],
+
* <samp>0</samp>: normal items.
                    "Texture": "Mods\\Example.ModId\\FruitTrees",
+
|}</li>
                    "TextureSpriteRow": 0
+
<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>
            }
  −
        },
     −
        // add images
+
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.
        {
+
|-
            "Action": "Load",
+
| <samp>ArtifactSpotChances</samp>
            "Target": "Mods/Example.ModId/FruitTrees, Mods/Example.ModId/Objects",
+
| ''(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.
            "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]]).
+
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).
 +
|}
   −
====Fruit items====
+
====Context tags & exclusions====
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).
+
{| class="wikitable"
 +
|-
 +
! field
 +
! purpose
 +
|-
 +
| <samp>ContextTags</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": [ "color_yellow", "fish_ocean", "fish_upright", "season_summer" ]
 +
</syntaxhighlight>
 +
|-
 +
| <samp>ExcludeFromRandomSale</samp>
 +
| ''(Optional)'' Whether to exclude this item from shops when selecting random items to sell. Default false.
 +
|-
 +
| <samp>ExcludeFromFishingCollection</samp><br /><samp>ExcludeFromShippingCollection</samp>
 +
| ''(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).
 +
|}
   −
====Spawning wild trees====
+
====Advanced====
Custom trees can be added to the game in two ways:
+
{| class="wikitable"
* Spawn them on [[Modding:Maps|map tiles]] when the location is created, using the new <samp>SpawnTree: fruit {{t|tree ID}}</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).
+
! field
 +
! purpose
 +
|-
 +
| <samp>CustomFields</samp>
 +
| ''(Optional)'' The [[#Custom data fields|custom fields]] for this entry.  
 +
|}
    
===Custom pants===
 
===Custom pants===
 +
{{/doc status|[[Modding:Items]]|done=false}}
 +
 
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...
 
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 key is the unqualified [[#Custom items|item ID]].
Line 1,483: Line 1,609:  
|-
 
|-
 
| <samp>DisplayName</samp><br /><samp>Description</samp>
 
| <samp>DisplayName</samp><br /><samp>Description</samp>
| ''(Optional)'' A [[#Tokenizable string format|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'').
+
| ''(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>Price</samp>
 
| <samp>Price</samp>
Line 1,500: Line 1,626:  
| <samp>SpriteIndex</samp>
 
| <samp>SpriteIndex</samp>
 
| The pants' sprite index within the <samp>Texture</samp>, where 0 is the top-left set.
 
| The pants' sprite index within the <samp>Texture</samp>, where 0 is the top-left set.
|-
  −
| <samp>SpriteIndexFemale</samp>
  −
| ''(Optional)'' If set, overrides <samp>SpriteIndex</samp> for female farmers.
   
|-
 
|-
 
| <samp>DefaultColor</samp>
 
| <samp>DefaultColor</samp>
Line 1,528: Line 1,651:     
===Custom shirts===
 
===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...
 
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 key is the unqualified [[#Custom items|item ID]].
Line 1,542: Line 1,667:  
|-
 
|-
 
| <samp>DisplayName</samp><br /><samp>Description</samp>
 
| <samp>DisplayName</samp><br /><samp>Description</samp>
| ''(Optional)'' A [[#Tokenizable string format|tokenizable string]] for the item's in-game display name and description. Defaults to the generic shirt text (''Shirt'' and ''A wearable shirt'').
+
| ''(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>Price</samp>
 
| <samp>Price</samp>
Line 1,587: Line 1,712:     
===Custom tools===
 
===Custom tools===
 +
{{/doc status|[[Modding:Items]]|done=false}}
 +
 
You can now create/edit [[tools]] by editing the new <samp>Data/Tools</samp> asset. This consists of a string → model lookup, where...
 
You can now create/edit [[tools]] by editing the new <samp>Data/Tools</samp> asset. This consists of a string → model lookup, where...
 
* The key is the unqualified [[#Custom items|item ID]].
 
* The key is the unqualified [[#Custom items|item ID]].
Line 1,609: Line 1,736:  
|-
 
|-
 
| <samp>DisplayName</samp><br /><samp>Description</samp>
 
| <samp>DisplayName</samp><br /><samp>Description</samp>
| A [[#Tokenizable string format|tokenizable string]] for the tool's in-game display name and description.
+
| A [[Modding:Tokenizable strings|tokenizable string]] for the tool's in-game display name and description.
 
|-
 
|-
 
| <samp>AttachmentSlots</samp>
 
| <samp>AttachmentSlots</samp>
Line 1,723: Line 1,850:  
|-
 
|-
 
| <samp>Condition</samp>
 
| <samp>Condition</samp>
| ''(Optional)'' A [[#Game state queries|game state query]] which indicates whether this upgrade is available. Defaults to always true.
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this upgrade is available. Defaults to always true.
 
|}
 
|}
   Line 1,785: Line 1,912:     
===Custom wild trees===
 
===Custom wild trees===
 +
{{/doc status|a new doc page|done=false}}
 +
 
====Data format====
 
====Data format====
 
You can now create/edit [[Trees|wild trees]] by editing the <samp>Data/WildTrees</samp> asset.
 
You can now create/edit [[Trees|wild trees]] by editing the <samp>Data/WildTrees</samp> asset.
    
This consists of a string → model lookup, where...
 
This consists of a string → model lookup, where...
* The asset key is the unique tree type identifier. 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). For custom trees, this should be prefixed with your mod ID like <samp>Example.ModId_TreeType</samp>. This should only contain alphanumeric/underscore/dot characters.
+
* 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).
 
* The asset value is a model with thee fields listed below.
 
* The asset value is a model with thee fields listed below.
   Line 1,813: Line 1,942:  
|-
 
|-
 
| <samp>Condition</samp>
 
| <samp>Condition</samp>
| ''(Optional)'' A [[#Game state queries|game state query]] which indicates whether this texture should be applied for a tree. Defaults to always enabled.
+
| ''(Optional)'' A [[Modding:Game state queries|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.
 
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.
Line 1,819: Line 1,948:  
|-
 
|-
 
| <samp>SeedItemId</samp>
 
| <samp>SeedItemId</samp>
| ''(Optional)'' The [[#Custom items|qualified item ID]] for the seed item. If omitted, the tree can't be planted and <samp>SeedChance</samp> will be ignored.
+
| ''(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.
 
|-
 
|-
 
| <samp>SeedPlantable</samp>
 
| <samp>SeedPlantable</samp>
Line 1,830: Line 1,959:  
| ''(Optional)'' Equivalent to <samp>GrowthChance</samp>, but with [[Tree Fertilizer|tree fertilizer]]. Defaults to 1 (100% chance).
 
| ''(Optional)'' Equivalent to <samp>GrowthChance</samp>, but with [[Tree Fertilizer|tree fertilizer]]. Defaults to 1 (100% chance).
 
|-
 
|-
| <samp>SeedChance</samp>
+
| <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).
 +
|-
 +
| <samp>SeedOnShakeChance</samp>
 
| ''(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).
 
| ''(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).
 
|-
 
|-
Line 1,868: Line 2,000:  
|-
 
|-
 
| <samp>SeedDropItems</samp>
 
| <samp>SeedDropItems</samp>
| ''(Optional)'' When a seed is dropped subject to <samp>SeedChance</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.
+
| ''(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.
    
This consists of a list of models with these fields:
 
This consists of a list of models with these fields:
Line 1,877: Line 2,009:  
|-
 
|-
 
| ''common fields''
 
| ''common fields''
| See [[#Item spawn fields|item spawn fields]] for the generic item fields supported for chop drops.
+
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields supported for chop drops.
   −
If set to an [[#Item queries|item query]] which returns multiple items, one of them will be selected at random.
+
If set to an [[Modding:Item queries|item query]] which returns multiple items, one of them will be selected at random.
 
|-
 
|-
 
| <samp>Season</samp>
 
| <samp>Season</samp>
Line 1,901: Line 2,033:  
|-
 
|-
 
| ''common fields''
 
| ''common fields''
| See [[#Item spawn fields|item spawn fields]] for the generic item fields supported for chop drops.
+
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields supported for chop drops.
   −
If set to an [[#Item queries|item query]] which returns multiple items, one of them will be selected at random.
+
If set to an [[Modding:Item queries|item query]] which returns multiple items, one of them will be selected at random.
 
|-
 
|-
 
| <samp>Season</samp>
 
| <samp>Season</samp>
Line 1,928: Line 2,060:  
|-
 
|-
 
| ''common fields''
 
| ''common fields''
| See [[#Item spawn fields|item spawn fields]] for the generic item fields supported for shake items.
+
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields supported for shake items.
   −
If set to an [[#Item queries|item query]] which returns multiple items, one of them will be selected at random.
+
If set to an [[Modding:Item queries|item query]] which returns multiple items, one of them will be selected at random.
 
|-
 
|-
 
| <samp>Season</samp>
 
| <samp>Season</samp>
Line 1,949: Line 2,081:  
|-
 
|-
 
| ''common fields''
 
| ''common fields''
| See [[#Item spawn fields|item spawn fields]] for the generic item fields supported for tapper items.
+
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields supported for tapper items.
   −
If set to an [[#Item queries|item query]] which returns multiple items, one of them will be selected at random.
+
If set to an [[Modding:Item queries|item query]] which returns multiple items, one of them will be selected at random.
 
|-
 
|-
 
| <samp>Season</samp>
 
| <samp>Season</samp>
Line 1,971: Line 2,103:  
|-
 
|-
 
| <samp>DaysUntilReadyModifiersMode</samp>
 
| <samp>DaysUntilReadyModifiersMode</samp>
| ''(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>.
+
| ''(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>PlantableLocationRules</samp>
 +
| ''(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:
 +
 +
{| 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>Result</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>Condition</samp>
 +
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this entry applies. Default true.
 +
|-
 +
| <samp>PlantedIn</samp>
 +
| ''(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 trees can't be planted in garden pots.
 +
|-
 +
| <samp>DeniedMessage</samp>
 +
| ''(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>CustomFields</samp>
 
| <samp>CustomFields</samp>
Line 1,981: Line 2,143:  
====Spawning wild trees====
 
====Spawning wild trees====
 
Custom trees can be added to the game in two ways:
 
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}}</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.
+
* 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).
 
* 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===
 
===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.
 
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.
   Line 1,998: Line 2,162:     
===Hats on aquarium fish===
 
===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>:
 
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>:
   Line 2,009: Line 2,175:  
| hat position
 
| hat position
 
| The pixel position of the hat on the sprite, specified as an object with <samp>X</samp> and <samp>Y</samp> values.
 
| The pixel position of the hat on the sprite, specified as an object with <samp>X</samp> and <samp>Y</samp> values.
  −
'''Note:''' currently this is only used to check if the fish can wear a hat, and has no effect on its position.
   
|}
 
|}
    
===Context tag changes===
 
===Context tag changes===
 +
{{/doc status|[[Modding:Items#Context tags]]|done=false}}
 +
 
====New context tags====
 
====New context tags====
 
1.6 adds several new [[Modding:Items#Context tags|item context tags]]:
 
1.6 adds several new [[Modding:Items#Context tags|item context tags]]:
Line 2,029: Line 2,195:  
| <samp>fish_pond_ignore</samp>
 
| <samp>fish_pond_ignore</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>.
 
| Prevents players from adding this fish to [[Fish Pond|fish ponds]], even if it would otherwise match an entry in <samp>Data/FishPondData</samp>.
|-
  −
| <samp>geode</samp>
  −
| Marks the item as a [[geode]] item, which can be broken open at [[Blacksmith|Clint's blacksmith shop]] or using a [[Geode Crusher|geode crusher]].
   
|-
 
|-
 
| <samp>geode_crusher_ignored</samp>
 
| <samp>geode_crusher_ignored</samp>
| If the item also has <samp>geode</samp>, prevents breaking it open in a geode crusher.
+
| 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>]].
 
|-
 
|-
 
| <samp>item_type_{{t|type}}</samp>
 
| <samp>item_type_{{t|type}}</samp>
Line 2,049: Line 2,212:  
| <samp>not_placeable</samp><br /><samp>placeable</samp>
 
| <samp>not_placeable</samp><br /><samp>placeable</samp>
 
| Sets whether the item can be placed on the ground.
 
| Sets whether the item can be placed on the ground.
|-
  −
| <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>
  −
| See [[#Custom planting restrictions|''custom planting restrictions'']].
   
|-
 
|-
 
| <samp>prevent_loss_on_death</samp>
 
| <samp>prevent_loss_on_death</samp>
Line 2,098: Line 2,258:  
| <samp>fish_legendary</samp><br /><samp>fish_legendary_family</samp>
 
| <samp>fish_legendary</samp><br /><samp>fish_legendary_family</samp>
 
| 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>]].
 
| 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>geode</samp>
 +
| ''(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>id_{{t|item id}}</samp>
 
| <samp>id_{{t|item id}}</samp>
Line 2,126: Line 2,289:  
|-
 
|-
 
| <code>GetBaseContextTags(id)</code>
 
| <code>GetBaseContextTags(id)</code>
| Get the base context tags for an item from the <samp>Data/ObjectContextTags</samp> asset. This doesn't include dynamic context tags added by the instance, which you can get via <code>item.GetContextTags()</code>.
+
| 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>.
 
|-
 
|-
 
| <code>DoesTagQueryMatch(query, tags)</code>
 
| <code>DoesTagQueryMatch(query, tags)</code>
Line 2,189: Line 2,352:  
|-
 
|-
 
|rowspan="6"| <samp>Farmer</samp>
 
|rowspan="6"| <samp>Farmer</samp>
| <code>getItemCount(id)</code><br /><code>GetTallyOfObject(id)</code><br /><code>GetTallyOfObject(id, isBigCraftable)</code>
+
| <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>
| Use <code>items.CountId(id)</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>hasItemInInventory(id, count)</code><br /><code>hasItemInInventoryNamed(name)</code><br /><code>hasItemWithNameThatContains(name)</code>
+
| <code>hasItemInInventoryNamed(name)</code><br /><code>hasItemWithNameThatContains(name)</code>
| Use <code>Items.ContainsId(id, count)</code>.
+
| In most cases, you should match items by ID instead (see the previous row).
|-
+
 
| <code>hasItemInList(list, id, count)</code>
+
If you really need to match items by name, you can replace it like this:
| Use <code>list.ContainsId(id, count)</code>.
+
<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>
 
| <code>areAllItemsNull()</code>
Line 2,204: Line 2,376:  
| 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.
 
| 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.
 
|-
 
|-
| <code>consumeObject(id, count)</code><br /><code>removeItemsFromInventory(id, count)</code>
+
| <code>consumeObject(id, count)</code>
 
| Use <code>items.ReduceId(id, count)</code>.
 
| Use <code>items.ReduceId(id, count)</code>.
 +
|-
 +
| <code>removeItemsFromInventory(id, count)</code>
 +
| &#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.
 
|-
 
|-
 
|rowspan="2"| <samp>Object</samp>
 
|rowspan="2"| <samp>Object</samp>
 
| <code>ConsumeInventoryItem(player, id, count)</code>
 
| <code>ConsumeInventoryItem(player, id, count)</code>
| This was somewhat specialized and shouldn't be called by mod code, but the equivalent would be <code>(obj.autoLoadChest?.items ?? player.items).ReduceId(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>.
 
|-
 
|-
 
| <code>GetTallyOfObject(player, id)</code>
 
| <code>GetTallyOfObject(player, id)</code>
| This was somewhat specialized and shouldn't be called by mod code, but the equivalent would be <code>(obj.autoLoadChest?.items ?? player.items).CountId(id)</code>.
+
| 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>.
 
|}
 
|}
    
It implements a new <samp>IInventory</samp> interface, which lets mods pass their own implementations to code which works on inventories.
 
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"
 +
|-
 +
! 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 <samp>TileSheets/furniture</samp>.
 +
|-
 +
| 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 [[Modding:Items#Context tags|context tags]] which apply to this furniture. Default none.
 +
|}</li>
 +
</ul>
 +
</li>
 +
</ul>
    
===Other item changes for C# mods===
 
===Other item changes for C# mods===
Line 2,232: Line 2,447:  
** 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.
 
** 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>.
 
** 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.
 
** Removed <samp>crop.InferSeedIndex()</samp>. This was used to support old crops, which are now fixed by a save migration instead.
 
* Tool changes:
 
* Tool changes:
Line 2,248: Line 2,464:  
! field/method
 
! field/method
 
! effect
 
! effect
 +
|-
 +
| <samp>Chest</samp>
 +
| <samp>GetItemsForPlayer()</samp>
 +
| Shortcut for <samp>chest.GetItemsForPlayer(Game1.player.UniqueMultiplayerID)</samp>.
 
|-
 
|-
 
| rowspan="2"| <samp>Crop</samp>
 
| rowspan="2"| <samp>Crop</samp>
Line 2,256: Line 2,476:  
| Whether the crop can grow in the location's current season (or true if crops ignore seasons in the location, like the [[greenhouse]]).
 
| Whether the crop can grow in the location's current season (or true if crops ignore seasons in the location, like the [[greenhouse]]).
 
|-
 
|-
| rowspan="7"| <samp>HoeDirt</samp>
+
| rowspan="8"| <samp>HoeDirt</samp>
 
| <samp>HasFertilizer()</samp>
 
| <samp>HasFertilizer()</samp>
 
| Get whether the dirt has any fertilizer applied.
 
| Get whether the dirt has any fertilizer applied.
Line 2,279: Line 2,499:     
(This method existed before, but no longer requires the fertilizer ID argument.)
 
(This method existed before, but no longer requires the fertilizer ID argument.)
 +
|-
 +
| <samp>isWatered()</samp>
 +
| Get whether the dirt is currently watered.
 
|-
 
|-
 
|rowspan="5"| <samp>Item</samp>
 
|rowspan="5"| <samp>Item</samp>
Line 2,317: Line 2,540:  
| Simplifies working with the fishing rod's [[bait]] and [[tackle]].
 
| Simplifies working with the fishing rod's [[bait]] and [[tackle]].
 
|-
 
|-
| <samp>Furniture</samp>
+
|rowspan="2"| <samp>Furniture</samp>
 
| <samp>SetPlacement</samp><br /><samp>SetHeldObject</samp>
 
| <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.
 
| 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.
Line 2,329: Line 2,552:  
     .SetHeldObject(ItemRegistry.Create<Furniture>("(F)1364"));
 
     .SetHeldObject(ItemRegistry.Create<Furniture>("(F)1364"));
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
|-
 +
| <samp>IsTable()</samp>
 +
| Get whether this furniture is a table.
 
|-
 
|-
 
|rowspan="2"| <samp>FruitTree</samp>
 
|rowspan="2"| <samp>FruitTree</samp>
Line 2,362: Line 2,588:  
<li>Modularized <samp>Object.CheckForAction</samp> to simplify mod patches.</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>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>
 
</ul>
    
===Other item changes===
 
===Other item changes===
* Added per-object display names (''e.g.'' for custom flavored items). See the <samp>ObjectDisplayName</samp> [[#Item spawn fields|item spawn field]], or <samp>object.displayNameFormat</samp> in C#.
+
* 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.
 
* [[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> [[#Game state queries|game state query]] field to <samp>Data/SpecialOrders</samp>.
+
* Added optional <samp>Condition</samp> [[Modding:Game state queries|game state query]] field to <samp>Data/SpecialOrders</samp>.
 
* Item data changes:
 
* 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>, and <samp>Data/Weapons</samp>.
+
** 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>Game1.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/ObjectInformation</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.)
+
** 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.
 
** [[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>]].
 
** 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:
 
* 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.
 
** 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>.
 
** 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:
 
* 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/ObjectInformation</samp>.
+
** <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.
 
** 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>:
 
* Recipe changes in <samp>Data/CookingRecipes</samp> and <samp>Data/CraftingRecipes</samp>:
 
** These assets no longer have language variants.
 
** These assets no longer have language variants.
** The display name now supports [[#Tokenizable string format|tokenizable strings]].
+
** 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.
 
** The display name can now be left blank to get it from the first item in the output list.
 
* Other item logic:
 
* 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>
 
** <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 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==
 
==What's new for locations & weather==
 
===Custom locations===
 
===Custom locations===
You can now add/edit locations by editing the revamped <samp>Data/Locations</samp> asset.
+
{{/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]].
   −
====Location format====
+
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:
The asset consists of a string → model lookup, where...
  −
* The key is the internal name of the location to change, which will also be used as the location's <samp>Name</samp> (not <samp>DisplayName</samp>) field. This should only contain alphanumeric/underscore/dot characters, and custom locations' names should be prefixed with your mod ID like <samp>Example.ModId_LocationName</samp>. (The farm will use <samp>Farm_{{t|type key}}</samp> for a vanilla farm type, or <samp>Farm_{{t|type ID}}</samp> for a custom farm type, or <samp>Farm_Standard</samp> if no type-specific entry was found.)
  −
* The value is a model with the fields listed below.
     −
'''Basic info''':
+
<dl style="margin-left: 2em;">
{| class="wikitable" style="margin-left: 2em;"
+
<dt>Required fields:</dt>
 +
<dd>
 +
{| class="wikitable"
 
|-
 
|-
 
! field
 
! field
 
! effect
 
! effect
 
|-
 
|-
| <samp>DisplayName</samp>
+
| <samp>Name</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.
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for the location context.
|-
  −
| <samp>DefaultArrivalTile</samp>
  −
| ''(Optional but strongly recommended)'' The default tile position where the player should be placed when they arrive in the location, if arriving from a warp that didn't specify a tile position. Default none, which usually places the player at (0, 0).
  −
|-
  −
| <samp>ExcludeFromNpcPathfinding</samp>
  −
| ''(Optional)'' Whether NPCs should ignore this location when pathfinding between locations. Default false.
   
|}
 
|}
 +
</dd>
   −
'''Creation''':
+
<dt>Player actions:</dt>
{| class="wikitable" style="margin-left: 2em;"
+
<dd>
|-
  −
! field
  −
! effect
  −
|-
  −
| <samp>CreateOnLoad</samp>
  −
| ''(Optional)'' If set, the location will be created automatically when the save is loaded using this data.
  −
 
  −
This consists of a model with these fields:
  −
 
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 2,428: Line 2,662:  
! effect
 
! effect
 
|-
 
|-
| <samp>MapPath</samp>
+
| <samp>AllowRainTotem</samp>
| The asset name for the map to use for this location.
+
| ''(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>AlwaysActive</samp>
+
| <samp>RainTotemAffectsContext</samp>
| ''(Optional)'' Whether this location is always synchronized to farmhands in multiplayer, even if they're not in the location. Any location which allows building cabins '''must''' have this enabled to avoid breaking game logic.
+
| ''(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>Type</samp>
+
| <samp>MaxPassOutCost</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>.
+
| ''(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).
|}
  −
|}
  −
 
  −
'''Contents''':
  −
{| class="wikitable" style="margin-left: 2em;"
   
|-
 
|-
! field
+
| <samp>PassOutMail</samp>
! effect
+
| ''(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>).
|-
  −
| <samp>ArtifactSpots</samp>
  −
| ''(Optional)'' The items that can be found when digging [[Artifact Spot|artifact spots]] in this location.
  −
 
  −
An artifact spot is selected by combining this field with the equivalent field on the <samp>Default</samp> entry, sorting by <samp>Precedence</samp> value, and then choosing the first entry whose fields match. (Artifact spot drops can also be listed in [[Modding:Items#Objects|<samp>Data/ObjectInformation</samp>]]'s 'miscellaneous' field; those are applied by the <samp>RANDOM_ARTIFACT_FOR_DIG_SPOT</samp> entry in <samp>DefaultArtifactSpots</samp>.)
      
This consists of a list of models with these fields:
 
This consists of a list of models with these fields:
Line 2,456: Line 2,680:  
! effect
 
! effect
 
|-
 
|-
| ''common fields''
+
| <samp>Id</samp>
| See [[#Item spawn fields|item spawn fields]] for the generic item fields supported by artifact spot drops.
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry in the list.
 
  −
If set to an [[#Item queries|item query]] which returns multiple items, one of them will be selected at random.
   
|-
 
|-
| <samp>Chance</samp>
+
| <samp>Mail</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.
+
| 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>ApplyGenerousEnchantment</samp>
+
| <samp>MaxPassOutCost</samp>
| ''(Optional)'' Whether to apply the 'Generous' [[Forge#Enchantments|enchantment]], which adds a 50% chance of the item dropping twice. If the enchantment is applied, the item's fields are rerolled for the second drop (e.g. a new random value between <samp>MinStack</samp> and <samp>MaxStack</samp> is selected). Default true.
+
| ''(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>OneDebrisPerDrop</samp>
+
| <samp>Condition</samp>
| ''(Optional)'' Whether to split the dropped item stack into multiple floating debris that each have a stack size of one. For example, if the dropped item has a stack size of 3, this will spawn three separate item stacks. Default true.
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this entry is active. Defaults to always true.
 
|-
 
|-
| <samp>ContinueOnDrop</samp>
+
| <samp>SkipRandomSelection</samp>
| ''(Optional)'' Whether to continue checking for more items to drop when this item is dropped. Default false.
+
| ''(Optional)'' If true, send this mail if the <samp>Condition</samp> matches instead of choosing a random valid mail. Default false.
 +
|}
 
|-
 
|-
| <samp>Precedence</samp>
+
| <samp>PassOutLocations</samp>
| ''(Optional)'' The order in which this entry should be checked, where lower values are checked first. This can be a negative value. Artifact spots with the same precedence are checked in the order listed. Default 0.
+
| ''(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.)
   −
For consistency, vanilla artifact drops mostly use these values:
+
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.
* <samp>-1000</samp>: location items which should override the global priority items (e.g. fossils on Ginger Island);
  −
* <samp>-100</samp>: global priority items (e.g. Qi Beans);
  −
* <samp>0</samp>: normal items;
  −
* <samp>100</samp>: global fallback items (e.g. clay).
  −
|}
     −
For example, a location with this field will drop 2-4 pufferfish with a 50% chance on summer days:
+
This consists of a list of models with these fields:
<syntaxhighlight lang="js">
  −
"ArtifactSpots": [
  −
    {
  −
          "Condition": "LOCATION_SEASON Here summer",
  −
          "ItemId": "(O)128",
  −
          "MinStack": 2,
  −
          "MaxStack": 4
  −
    }
  −
]
  −
</syntaxhighlight>
  −
|-
  −
| <samp>FishAreas</samp>
  −
| ''(Optional)'' The distinct [[fishing]] areas within the location. These can be referenced by fish via <samp>FishAreaId</samp>, and determine which fish are collected by [[Crab Pot|crab pots]].
  −
 
  −
This consists of a string → model lookup, where the key is the fish area ID and the value consists of a list of models with these fields:
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
 
! field
 
! field
 
! effect
 
! effect
 +
|-
 +
| <samp>Id</samp>
 +
| 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>
 
| <samp>Position</samp>
| ''(Optional)'' The tile position and size covered by this fishing area, specified as an object with <samp>X</samp>, <samp>Y</samp>, <samp>Width</samp>, and <samp>Height</samp> fields. This area will apply for crab pots placed within it, or when the fishing rod bobber lands within it. Default null (anywhere).
+
| 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.
 
  −
Areas with a <samp>Position</samp> value have priority over those without.
   
|-
 
|-
| <samp>CrabPotFishTypes</samp>
+
| <samp>Condition</samp>
| ''(Optional)'' A list of fish types that can be caught by crab pots within the area. This is matched against field index 4 in [[Modding:Fish data|<samp>Data/Fish</samp>]] for 'trap' (i.e. crab pot) fish. The vanilla types are <samp>freshwater</samp> and <samp>ocean</samp>. If omitted, defaults to <samp>freshwater</samp>.
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this entry is active. Defaults to always applied.
|-
  −
| <samp>CrabPotJunkChance</samp>
  −
| ''(Optional)'' The chance that crab pots within the area will find junk instead of a fish each time they produce a harvest. This is ignored if the player has the [[Fishing#Fishing Skill|Mariner]] profession. Default <samp>0.2</samp> (20%).
   
|}
 
|}
 +
 +
If no locations are specified or none match, the player will wake up in their bed at home.
 
|-
 
|-
| <samp>Fish</samp>
+
| <samp>ReviveLocations</samp>
| ''(Optional)'' The fish that can be caught in the location.
+
| ''(Optional)'' If the player just got knocked out in combat, the location names where they'll wake up.
 
  −
A fish is selected by combining this field with the equivalent field on the <samp>Default</samp> entry, sorting by <samp>Precedence</samp> value (and randomly shuffling entries with the same precedence), and then choosing the first entry whose fields match.
  −
 
  −
Note: the produced item ID is saved to recreate the fish later. Any item info that's not based on the item ID is ignored (like stack size, quality, flavored variants like Blueberry Wine vs Wine, and the is-recipe flag).
      
This consists of a list of models with these fields:
 
This consists of a list of models with these fields:
Line 2,529: Line 2,740:  
! effect
 
! effect
 
|-
 
|-
| ''common fields''
+
| <samp>Id</samp>
| See [[#Item spawn fields|item spawn fields]] for the generic item fields supported by forage items.
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry in the list.
 
  −
This must return an <samp>Object</samp> item (or subclass of <samp>Object</samp>). If set to an [[#Item queries|item query]] which returns multiple items, one of them will be selected at random.
   
|-
 
|-
| <samp>Chance</samp>
+
| <samp>Location</samp>
| ''(Optional)'' The probability that the fish will spawn if selected, as a decimal value between 0 (never) and 1 (always). Default 1.
+
| The internal location name.
 
|-
 
|-
| <samp>Season</samp>
+
| <samp>Position</samp>
| ''(Optional)'' If set, the specific season when the fish can be caught. This is much more efficient than using <samp>Condition</samp>, but only supports a single season. Defaults to <samp>null</samp> (all seasons).
+
| The tile position within the location, specified as an object with <samp>X</samp> and <samp>Y</samp> fields.
 
|-
 
|-
| <samp>FishAreaId</samp>
+
| <samp>Condition</samp>
| ''(Optional)'' If set, the fish area in which the fish can be caught (as an area ID defined under <samp>FishAreas</samp>). Defaults to <samp>null</samp> (all zones).
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this entry is active. Defaults to always applied.
|-
+
|}
| <samp>BobberPosition</samp>
+
 
| ''(Optional)'' If set, the tile area within the location where the fishing rod's bobber must land to catch the fish. Default <samp>null</samp> (anywhere).
+
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.
|-
+
 
| <samp>PlayerPosition</samp>
+
If no locations are specified or none match, the player will wake up at [[Harvey's Clinic|Harvey's clinic]].
| ''(Optional)'' If set, the tile area within the location where the player must be standing to catch the fish. Default <samp>null</samp> (anywhere).
+
|}
 +
</dd>
 +
 
 +
<dt>Season:</dt>
 +
<dd>
 +
{| class="wikitable"
 
|-
 
|-
| <samp>MinFishingLevel</samp>
+
! field
| ''(Optional)'' The minimum fishing level needed for the fish to appear. Default 0.
+
! effect
 
|-
 
|-
| <samp>ApplyDailyLuck</samp>
+
| <samp>SeasonOverride</samp>
| ''(Optional)'' Whether to add the player's [[Luck|daily luck]] to the spawn chance. This affects both the <samp>Chance</samp> field and the <samp>Data\Fish</samp> chance, if applicable. Default false.
+
| ''(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.
 +
|}
 +
</dd>
 +
 
 +
<dt>Weather:</dt>
 +
<dd>
 +
{| class="wikitable"
 
|-
 
|-
| <samp>CuriosityLureBuff</samp>
+
! field
| ''(Optional)'' The value to add to the spawn chance when the player has the [[Curiosity Lure]] equipped, if set to 0 or higher. This affects both the <samp>Chance</samp> field and the <samp>Data\Fish</samp> chance, if applicable. Default -1, which keeps the default behavior (i.e. no effect on the <samp>Chance</samp> field and a scaled boost to the <samp>Data\Fish</samp> chance).
+
! effect
 
|-
 
|-
| <samp>CatchLimit</samp>
+
| <samp>WeatherConditions</samp>
| ''(Optional)'' The maximum number of this fish which can be caught by each player. This limit is permanent (i.e. once it's reached, that fish will never appear again). For example, legendary fish set this to one. Default -1 (no limit).
+
| ''(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.
 +
 
 +
This consists of a list of models with these fields:
 +
{| class="wikitable"
 
|-
 
|-
| <samp>IsBossFish</samp>
+
! field
| ''(Optional)'' Whether this is a 'boss fish' catch. This shows a crowned fish sprite in the fishing minigame and gives five times normal XP, like [[Legendary Fish|legendary fish]].
+
! effect
 
|-
 
|-
| <samp>RequireMagicBait</samp>
+
| <samp>Id</samp>
| ''(Optional)'' Whether the player must fish with Magic Bait for this fish to spawn. Default false.
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry in the list.
 
|-
 
|-
| <samp>MinDistanceFromShore</samp>
+
| <samp>Weather</samp>
| ''(Optional)'' The minimum distance from the nearest shore (measured in tiles) at which the fish can be caught, where zero is water directly adjacent to shore.
+
| The [[#Custom weather|weather ID]] to set.
 
|-
 
|-
| <samp>MaxDistanceFromShore</samp>
+
| <samp>Condition</samp>
| ''(Optional)'' The maximum distance from the nearest shore (measured in tiles) at which the fish can be caught, where zero is water directly adjacent to shore. Default -1 (no limit).
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether to apply the weather. Defaults to always applied.
 +
|}
 
|-
 
|-
| <samp>Precedence</samp>
+
| <samp>CopyWeatherFromLocation</samp>
| ''(Optional)'' The order in which this entry should be checked, where lower values are checked first. This can be a negative value. Fish with the same precedence are shuffled randomly. Default 0.
+
| ''(Optional)'' The <samp>Name</samp> (i.e. unique ID) of the location context from which to inherit weather.
 +
|}
 +
 
 +
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.
   −
For consistency, vanilla fish mostly use values in these ranges:
+
</dd>
* <samp>-1100</samp> to <samp>-1000</samp>: global priority items (e.g. Qi Beans);
  −
* <samp>-200</samp> to <samp>-100</samp>: unique location items (e.g. legendary fish or secret items);
  −
* <samp>-50</samp> to <samp>-1</samp>: normal high-priority items;
  −
* <samp>0</samp>: normal items;
  −
* <samp>1</samp> to <samp>100</samp>: normal low-priority items;
  −
* <samp>1000+</samp>: global fallback items (e.g. trash).
  −
|-
  −
| <samp>IgnoreFishDataRequirements</samp>
  −
| ''(Optional)'' Whether to ignore spawn requirements listed in [[Modding:Fish data|<samp>Data/Fish</samp>]], if applicable.
     −
The <samp>Data/Fish</samp> requirements are ignored regardless of this field for non-object (<samp>(O)</samp>)-type items, or objects whose ID isn't listed in <samp>Data/Fish</samp>.
+
<dt>Music:</dt>
 +
<dd>
 +
{| class="wikitable"
 
|-
 
|-
| <samp>CanBeInherited</samp>
+
! field
| ''(Optional)'' Whether this fish can be spawned in another location via the <samp>LOCATION_FISH</samp> [[#Item queries|item query]]. Default true.
+
! effect
 
|-
 
|-
| <samp>SetFlagOnCatch</samp>
+
| <samp>DefaultMusic</samp>
| ''(Optional)'' The mail flag to set for the current player when this fish is successfully caught. Default none.
+
| ''(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>ChanceModifiers</samp>
+
| <samp>DefaultMusicCondition</samp>
| ''(Optional)'' [[#Quantity modifiers|Quantity modifiers]] applied to the <samp>Chance</samp> value. Default none.
+
| ''(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>ChanceModifierMode</samp>
+
| <samp>DefaultMusicDelayOneScreen</samp>
| ''(Optional)'' [[#Quantity modifiers|quantity modifier modes]] which indicate what to do if multiple modifiers in the <samp>ChanceModifiers</samp> field apply at the same time. Default <samp>Stack</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.
|}
   
|-
 
|-
| <samp>Forage</samp>
+
| <samp>Music</samp>
| ''(Optional)'' The [[forage]] that can spawn in the location.
+
| ''(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.
 
  −
Notes:
  −
* Unlike other item spawn lists, these entries aren't checked sequentially. Instead, the game...
  −
*# combines this list with any forage in the <samp>Default</samp> location entry;
  −
*# adds every forage entry whose <samp>Condition</samp> and <samp>Season</samp> match to a spawn pool;
  −
*# chooses a random number of spawn ''opportunities'' (between 1 and 4);
  −
*# for each spawn opportunity, chooses a random tile position and forage to spawn. If the spawn fails (e.g. the tile is water/occupied or the forage's <samp>Chance</samp> doesn't pass), the game will make nine other attempts with a re-randomized tile & forage before skipping this spawn opportunity.
  −
* The stack size is ignored.
      
This consists of a list of models with these fields:
 
This consists of a list of models with these fields:
Line 2,619: Line 2,830:  
! effect
 
! effect
 
|-
 
|-
| ''common fields''
+
| <samp>Id</samp>
| See [[#Item spawn fields|item spawn fields]] for the generic item fields supported by forage items.
+
| ''(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.
 
  −
This must return an <samp>Object</samp> (<samp>(O)</samp>)-type item. If it uses an [[#Item queries|item query]] that returns multiple items, one will be selected at random. If it returns null or a non-<samp>Object</samp> item, the spawn attempt will be skipped (with a logged warning if the item type is invalid).
   
|-
 
|-
| <samp>Chance</samp>
+
| <samp>Track</samp>
| ''(Optional)'' The probability that the item will spawn if selected, as a decimal value between 0 (never) and 1 (always). Default 1.
+
| The [[Modding:Migrate to Stardew Valley 1.6#Custom audio|audio track ID]] to play.
 
|-
 
|-
| <samp>Season</samp>
+
| <samp>Condition</samp>
| ''(Optional)'' The specific season when the forage should apply. This is more efficient than using <samp>Condition</samp>, but only supports a single season. Defaults to <samp>null</samp> (all seasons).
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this entry applies. Default true.
 
|}
 
|}
 
|-
 
|-
| <samp>MinDailyWeeds</samp><br /><samp>MaxDailyWeeds</samp>
+
| <samp>DayAmbience</samp><br /><samp>NightAmbience</samp>
| ''(Optional)'' The minimum and maximum number of weeds to spawn in a day, if applicable. Default 1 and 5 respectively.
+
| ''(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>FirstDayWeedMultiplier</samp>
+
| <samp>PlayRandomAmbientSounds</samp>
| ''(Optional)'' On the first day of each year, a multiplier to apply to the number of daily weeds spawned. Default 15.
+
| ''(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.
 +
|}
 +
</dd>
 +
 
 +
<dt>Advanced:</dt>
 +
<dd>
 +
{| class="wikitable"
 
|-
 
|-
| <samp>MinDailyForageSpawn</samp><br /><samp>MaxDailyForageSpawn</samp>
+
! field
| ''(Optional)'' The minimum and maximum number of forage to try spawning in one day, if applicable and the location has fewer than <samp>MaxSpawnedForageAtOnce</samp> forage. Default 1 and 4 respectively.
+
! effect
|-
  −
| <samp>MaxSpawnedForageAtOnce</samp>
  −
| ''(Optional)'' The maximum number of spawned forage that can be present at once on the map before they stop spawning. Default 6.
  −
|-
  −
| <samp>ChanceForClay</samp>
  −
| ''(Optional)'' The probability that digging a tile will produce clay, as a value between 0 (never) and 1 (always).
   
|-
 
|-
 
| <samp>CustomFields</samp>
 
| <samp>CustomFields</samp>
 
| The [[#Custom data fields|custom fields]] for this entry.
 
| The [[#Custom data fields|custom fields]] for this entry.
 
|}
 
|}
 +
</dd>
 +
</dl>
   −
====<samp>Default</samp> entry====
+
===Custom garbage cans===
The asset has a location with the key <samp>Default</samp>. The <samp>ArtifactSpots</samp>, <samp>Fish</samp>, and <samp>Forage</samp> fields for this entry are added to every other location's equivalent fields, so this lets you add artifact spots / fish / forage in all locations.
+
{{/doc status|a new doc page|done=false}}
 
  −
===Custom location contexts===
  −
====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====
 
====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]].
+
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 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:
+
The asset consists of a data model with these fields:
   −
<dl style="margin-left: 2em;">
  −
<dt>Required fields:</dt>
  −
<dd>
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 2,671: Line 2,874:  
! effect
 
! effect
 
|-
 
|-
| <samp>Name</samp>
+
| <samp>DefaultBaseChance</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>.
+
| 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.
|}
+
|-
</dd>
+
| <samp>BeforeAll</samp><br /><samp>AfterAll</samp>
 +
| 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:
   −
<dt>Player actions:</dt>
  −
<dd>
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 2,683: Line 2,888:  
! effect
 
! effect
 
|-
 
|-
| <samp>DefaultValidPlantableLocations</samp>
+
| ''entry key''
| ''(Optional)'' The internal names of the locations where crops can be planted and grown by default (see also [[#Custom planting restrictions|custom planting restrictions]]).
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this garbage can.
 
|-
 
|-
| <samp>AllowRainTotem</samp>
+
| <samp>BaseChance</samp>
| ''(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.
+
| ''(Optional)'' If set, overrides the root <samp>DefaultBaseChance</samp> field for this garbage can. Defaults to <samp>DefaultBaseChance</samp>.
 
|-
 
|-
| <samp>RainTotemAffectsContext</samp>
+
| <samp>Items</samp>
| ''(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.
+
| ''(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>MaxPassOutCost</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).
  −
|-
  −
| <samp>PassOutMail</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>).
      
This consists of a list of models with these fields:
 
This consists of a list of models with these fields:
Line 2,704: Line 2,903:  
! effect
 
! effect
 
|-
 
|-
| <samp>Mail</samp>
+
| ''common fields''
| The [[Modding:Mail data|letter ID]] to add.
+
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields supported by garbage cans.
 
  −
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.
+
If set to an [[Modding:Item queries|item query]] which returns multiple items, one of them will be selected at random.
 
|-
 
|-
| <samp>MaxPassOutCost</samp>
+
| <samp>IgnoreBaseChance</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 this item can spawn even if the <samp>BaseChance</samp> probability check didn't pass. Default false.
 
|-
 
|-
| <samp>Condition</samp>
+
| <samp>IsMegaSuccess</samp>
| ''(Optional)'' A [[#Game state queries|game state query]] which indicates whether this entry is active. Defaults to always true.
+
| ''(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>SkipRandomSelection</samp>
+
| <samp>IsDoubleMegaSuccess</samp>
| ''(Optional)'' If true, send this mail if the <samp>Condition</samp> matches instead of choosing a random valid mail. Default false.
+
| ''(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>PassOutLocations</samp>
+
| <samp>AddToInventoryDirectly</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.)
+
| ''(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.
 
  −
This consists of a list of models with these fields:
  −
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>CreateMultipleDebris</samp>
! effect
+
| ''(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.
|-
+
|}
| <samp>Location</samp>
  −
| The internal location name.
  −
|-
  −
| <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.
+
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>ReviveLocations</samp>
+
| <samp>CustomFields</samp>
| ''(Optional)'' If the player just got knocked out in combat, the location names where they'll wake up.
+
| The [[#Custom data fields|custom fields]] for this entry.
 +
|}
 +
 
 +
====Example new garbage can====
 +
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>:
 +
 
 +
{{#tag:syntaxhighlight|<nowiki>
 +
{
 +
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
 +
    "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"
 +
                        },
   −
This consists of a list of models with these fields:
+
                        // else guaranteed random House Plant item
{| class="wikitable"
+
                        {
|-
+
                            "ID": "{{ModId}}_RandomHousePlant",
! field
+
                            "ItemID": "RANDOM_ITEMS (F) 1376 1390"
! effect
+
                        }
|-
+
                    ]
| <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.
+
}</nowiki>|lang=javascript}}
|-
  −
| <samp>Condition</samp>
  −
| ''(Optional)'' A [[#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.
+
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.
   −
If no locations are specified or none match, the player will wake up at [[Harvey's Clinic|Harvey's clinic]].
+
====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.
</dd>
     −
<dt>Season:</dt>
+
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.
<dd>
+
 
{| class="wikitable"
+
{{#tag:syntaxhighlight|<nowiki>
|-
+
{
! field
+
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
! effect
+
    "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}}
 +
 
 +
====Changes for C# mods====
 +
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"
 +
|-
 +
! action
 +
! code in 1.5.6
 +
! code in 1.6
 +
|-
 +
| check if a garbage can was searched
 +
| <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>SeasonOverride</samp>
+
| mark a garbage can searched
| ''(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.
+
| <syntaxhighlight lang="js">
 +
Town town = (Town)Game1.getLocationFromName("Town");
 +
town.garbageChecked[5] = true;
 +
</syntaxhighlight>
 +
| <syntaxhighlight lang="js">
 +
Game1.netWorldState.Value.CheckedGarbage.Add("Saloon");
 +
</syntaxhighlight>
 
|}
 
|}
</dd>
     −
<dt>Weather:</dt>
+
To migrate former vanilla trash can IDs:
<dd>
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! position
! effect
+
! ID in 1.5.6
 +
! ID in 1.6
 +
|-
 +
| Near [[Jodi]] and [[Kent]]'s house
 +
| <code>0</code>
 +
| <code>JodiAndKent</code>
 +
|-
 +
| Near [[Emily]] and [[Haley]]'s house
 +
| <code>1</code>
 +
| <code>EmilyAndHaley</code>
 +
|-
 +
| Near [[Lewis]]' house
 +
| <code>2</code>
 +
| <code>Mayor</code>
 
|-
 
|-
| <samp>WeatherConditions</samp>
+
| Near [[Museum]]
| ''(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.
+
| <code>3</code>
 
+
| <code>Museum</code>
This consists of a list of models with these fields:
  −
{| class="wikitable"
   
|-
 
|-
! field
+
| Near [[Blacksmith|Clint's blacksmith]]
! effect
+
| <code>4</code>
 +
| <code>Blacksmith</code>
 
|-
 
|-
| <samp>Weather</samp>
+
| Near [[The Stardrop Saloon|the Saloon]]
| The [[#Custom weather|weather ID]] to set.
+
| <code>5</code>
 +
| <code>Saloon</code>
 
|-
 
|-
| <samp>Condition</samp>
+
| Near [[Evelyn]] and [[George]]'s house
| ''(Optional)'' A [[#Game state queries|game state query]] which indicates whether to apply the weather. Defaults to always applied.
+
| <code>6</code>
|}
+
| <code>Evelyn</code>
 
|-
 
|-
| <samp>CopyWeatherFromLocation</samp>
+
| Near [[JojaMart]]
| ''(Optional)'' The <samp>Name</samp> (i.e. unique ID) of the location context from which to inherit weather.
+
| <code>7</code>
 +
| <code>JojaMart</code>
 
|}
 
|}
   −
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.
+
===Custom map actions===
 +
{{/doc status|[[Modding:Maps]]|done=false}}
   −
</dd>
+
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.
   −
<dt>Music:</dt>
+
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:
<dd>
+
<syntaxhighlight lang="c#">
{| class="wikitable"
+
internal class ModEntry : Mod
|-
+
{
! field
+
    /// <inheritdoc />
! effect
+
    public override void Entry(IModHelper helper)
|-
+
    {
| <samp>DefaultMusic</samp>
+
        GameLocation.RegisterTouchAction("Example.ModId_UnlockGate", this.HandleUnlockGate);
| ''(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>DefaultMusicCondition</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.
  −
|-
  −
| <samp>DefaultMusicDelayOneScreen</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.
  −
|-
  −
| <samp>SpringMusic</samp><br /><samp>SummerMusic</samp><br /><samp>FallMusic</samp><br /><samp>WinterMusic</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.
  −
|-
  −
| <samp>DayAmbience</samp><br /><samp>NightAmbience</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.
  −
|-
  −
| <samp>PlayRandomAmbientSounds</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.
  −
|}
  −
</dd>
     −
<dt>Advanced:</dt>
+
    private void HandleUnlockGate(GameLocation location, string[] args, Farmer player, Vector2 tile)
<dd>
+
    {
{| class="wikitable"
+
        const string mailFlag = "Example.ModId_GateUnlocked";
|-
+
        const string keyId = "Example.ModId_GateKey";
! field
  −
! effect
  −
|-
  −
| <samp>CustomFields</samp>
  −
| The [[#Custom data fields|custom fields]] for this entry.
  −
|}
  −
</dd>
  −
</dl>
     −
===Custom garbage cans===
+
        // unlock gate if locked
====Format====
+
        if (!player.mailReceived.Contains(mailFlag))
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).
+
        {
 +
            if (!Game1.player.Items.ContainsId(id, count))
 +
            {
 +
                Game1.activeClickableMenu = new DialogueBox("This gate is locked. I wonder where the key is?");
 +
                return;
 +
            }
   −
The asset consists of a data model with these fields:
+
            player.removeFirstOfThisItemFromInventory(keyId);
 +
            player.mailReceived.Add(mailFlag);
 +
        }
   −
{| class="wikitable"
+
        // apply open-gate map edit
|-
+
        // NOTE: this is a quick example which changes the location's current map. If another mod reloads the map
! field
+
        // (e.g. a content pack editing it), the change will be lost. For persistent changes, you should use the
! effect
+
        // AssetRequested event to apply the change when the map is reloaded.
|-
+
        IAssetDataForMap mapHelper = this.Helper.GameContent.GetPatchHelper(location.map).AsMap();
| <samp>DefaultBaseChance</samp>
+
        mapHelper.PatchMap(
| 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.
+
            this.Helper.Content.Load<Map>("assets/unlocked-gate.tmx"),
|-
+
            targetArea: new Rectangle((int)tile.X - 1, (int)tile.Y - 1, 2, 2)
| <samp>BeforeAll</samp><br /><samp>AfterAll</samp>
+
        );
| 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>
+
</syntaxhighlight>
| The data for individual garbage cans. This consists of a string → model lookup with these fields:
     −
{| class="wikitable"
+
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#">
! field
+
internal class ModEntry : Mod
! effect
+
{
|-
+
    /// <inheritdoc />
| ''entry key''
+
    public override void Entry(IModHelper helper)
| A key which uniquely identifies this garbage can. The key should only contain alphanumeric/underscore/dot characters. For custom garbage cans, this should be prefixed with your mod ID like <samp>Example.ModId_GarbageCanId</samp>.
+
    {
|-
+
        GameLocation.RegisterTileAction("Example.ModId_UnlockGate", this.HandleUnlockGate);
| <samp>BaseChance</samp>
+
    }
| ''(Optional)'' If set, overrides the root <samp>DefaultBaseChance</samp> field for this garbage can. Defaults to <samp>DefaultBaseChance</samp>.
  −
|-
  −
| <samp>Items</samp>
  −
| ''(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.
     −
This consists of a list of models with these fields:
+
    private bool HandleUnlockGate(GameLocation location, string[] args, Farmer player, Microsoft.Xna.Framework.Point point)
{| class="wikitable"
+
    {
 +
        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;
 +
    }
 +
}
 +
</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.
 +
 
 +
{| class="wikitable"
 
|-
 
|-
 
! field
 
! field
 
! effect
 
! effect
 
|-
 
|-
| ''common fields''
+
| <samp>Destinations</samp>
| See [[#Item spawn fields|item spawn fields]] for the generic item fields supported by garbage cans.
+
| 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"
If set to an [[#Item queries|item query]] which returns multiple items, one of them will be selected at random.
   
|-
 
|-
| <samp>IgnoreBaseChance</samp>
+
! field
| ''(Optional)'' Whether this item can spawn even if the <samp>BaseChance</samp> probability check didn't pass. Default false.
+
! effect
 
|-
 
|-
| <samp>IsMegaSuccess</samp>
+
| <samp>Id</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.
+
| A [[Modding:Common data field types#Unique string ID|unique string ID]] for this destination within the network.
 
|-
 
|-
| <samp>IsDoubleMegaSuccess</samp>
+
| <samp>DisplayName</samp>
| ''(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.
+
| 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>AddToInventoryDirectly</samp>
+
| <samp>TargetLocation</samp>
| ''(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.
+
| The [[#Custom locations|location ID]] for the destination.
 
|-
 
|-
| <samp>CreateMultipleDebris</samp>
+
| <samp>TargetTile</samp>
| ''(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.
+
| The destination tile position within the location, specified as a model with <samp>X</samp> and <samp>Y</samp> fields.
 +
|-
 +
| <samp>TargetDirection</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>Condition</samp>
 +
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this minecart destination is available. Defaults to always available.
 +
|-
 +
| <samp>Price</samp>
 +
| ''(Optional)'' The gold price that must be paid each time to use this destination. Default none.
 +
|-
 +
| <samp>BuyTicketMessage</samp>
 +
| ''(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>CustomFields</samp>
 +
| ''(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.
 
|}
 
|}
   −
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.
+
====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>.
| <samp>CustomFields</samp>
+
 
| The [[#Custom data fields|custom fields]] for this entry.
+
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 new garbage can====
+
====Example====
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 [[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>
 
{{#tag:syntaxhighlight|<nowiki>
Line 2,930: Line 3,236:  
     "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
 
     "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
 
     "Changes": [
 
     "Changes": [
 +
        // add minecart destination
 
         {
 
         {
 
             "Action": "EditData",
 
             "Action": "EditData",
             "Target": "Data/GarbageCans",
+
             "Target": "Data/Minecarts",
             "TargetField": [ "GarbageCans" ],
+
             "TargetField": [ "Default", "Destinations" ], // for the "Default" network, edit the "Destinations" field
 
             "Entries": {
 
             "Entries": {
                 "Example.ModId_Carpenter": {
+
                 "Railroad": {
                     "Items": [
+
                     "Id": "Railroad",
                        // 25% chance of pufferfish
+
                    "DisplayName": "[LocationName Railroad]",
                        {
+
                    "Condition": "LOCATION_ACCESSIBLE Railroad",
                            "ID": "Example.ModId_Pufferfish",
  −
                            "Condition": "RANDOM 0.25",
  −
                            "ItemId": "(O)128"
  −
                        },
     −
                        // else guaranteed random House Plant item
+
                    "TargetLocation": "Railroad",
                        {
+
                    "TargetTile": { "X": 16, "Y": 39 },
                            "ID": "Example.ModId_RandomHousePlant",
+
                     "TargetDirection": "down",
                            "ItemID": "RANDOM_ITEMS (F) @has_id_in_base_range 1376 1390"
  −
                        }
  −
                     ]
   
                 }
 
                 }
 
             }
 
             }
 +
        },
 +
 +
        // 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}}
 
}</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.
+
===Custom passive festivals===
 +
{{/doc status|[[Modding:Festival data]] or a new doc page|done=false}}
   −
====Example change for existing garbage can====
+
You can now add or modify passive festivals by editing the <samp>Data/PassiveFestivals</samp> asset.
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.
+
(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.)
   −
{{#tag:syntaxhighlight|<nowiki>
+
====Data format====
{
+
The <samp>Data/PassiveFestivals</samp> asset consists of a string → model lookup, where...
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
+
* The key is a [[Modding:Common data field types#Unique string ID|unique string ID]] for the festival.
    "Changes": [
+
* The value is a model with the fields listed below.
        {
+
{| class="wikitable"
            "Action": "EditData",
+
|-
            "Target": "Data/GarbageCans",
+
! field
            "TargetField": [ "GarbageCans", "Saloon", "Items" ],
+
! effect
            "Entries": {
+
|-
                // 25% chance of pufferfish
+
| <samp>DisplayName</samp>
               
+
| A [[Modding:Tokenizable strings|tokenizable string]] for the display name shown on the [[calendar]].
                "Example.ModId_Pufferfish":{
+
|-
                    "ID": "Example.ModId_Pufferfish",
+
| <samp>Season</samp>
                    "Condition": "RANDOM 0.25",
+
| The [[season]] when the festival becomes active.
                    "ItemId": "(O)128"
+
|-
                }
+
| <samp>StartDay</samp><br /><samp>EndDay</samp>
            },
+
| The days of month when the festival becomes active.
            "MoveEntries": [
+
|-
                { "ID": "Example.ModId_Pufferfish", "BeforeId": "Base_DishOfTheDay" }
+
| <samp>StartTime</samp>
            ]
+
| The time of day when the festival opens each day.
        }
+
|-
    ]
+
| <samp>StartMessage</samp>
}</nowiki>|lang=javascript}}
+
| A [[Modding:Tokenizable strings|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.
   −
===Custom map actions===
+
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]]:
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.
+
<syntaxhighlight lang="js">
 
+
"MapReplacements": {
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:
+
    "Beach": "BeachNightMarket"
<syntaxhighlight lang="c#">
+
}
internal class ModEntry : Mod
+
</syntaxhighlight>
{
+
|-
    /// <inheritdoc />
+
| <samp>Condition</samp>
    public override void Entry(IModHelper helper)
+
| ''(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.
    {
+
|-
        GameLocation.RegisterTouchAction("Example.ModId_UnlockGate", this.HandleUnlockGate);
+
| <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>).
   −
    private void HandleUnlockGate(GameLocation location, string[] args, Farmer player, Vector2 tile)
+
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.
    {
+
|-
        const string mailFlag = "Example.ModId_GateUnlocked";
+
| <samp>CustomFields</samp>
        const string keyId = "Example.ModId_GateKey";
+
| The [[#Custom data fields|custom fields]] for this entry.
 +
|}
   −
        // unlock gate if locked
+
====NPC schedules====
        if (!player.mailReceived.Contains(mailFlag))
+
When a passive festival is active, NPCs will check for [[Modding:Schedule data|a schedule entry]] in this order:
        {
  −
            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
  −
        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 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\Minecarts</samp> data asset, which consists of a data model with two relevant fields (listed below).
      
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! syntax
! effect
+
! summary
 
|-
 
|-
| <samp>MinecartsUnlocked</samp>
+
| <samp>{{t|festival ID}}_{{t|festival day}}</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).
+
| 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>Destinations</samp>
+
| <samp>{{t|festival ID}}</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:
+
| 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.
 +
 
 +
===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>Location</samp>
+
| <samp>CanBuildHere T</samp><br />''(valid in any outdoor location)''
| The [[#Custom locations|location ID]] for the destination.
+
| 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>Tile</samp>
+
| <samp>BuildConditions {{t|query}}</samp><br />''(valid in any outdoor location)''
| The destination tile position within the location, specified as a model with <samp>X</samp> and <samp>Y</samp> fields.
+
| If <samp>CanBuildHere</samp> is set, an optional [[Modding:Game state queries|game state query]] which indicates whether building is allowed currently.
 
|-
 
|-
| <samp>Direction</samp>
+
| <samp>LooserBuildRestrictions T</samp><br />''(valid in any outdoor location)''
| The direction the player should face after arrival (one of <samp>down</samp>, <samp>left</samp>, <samp>right</samp>, or <samp>up</samp>).
+
| 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>DisplayName</samp>
+
| <samp>ValidBuildRect {{t|x}} {{t|y}} {{t|width}} {{t|height}}</samp><br />''(valid in any outdoor location)''
| 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]]).
+
| 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"
 
|-
 
|-
| <samp>Network</samp>
+
! property
| ''(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.
+
! explanation
 
|-
 
|-
| <samp>Condition</samp>
+
| <samp>AllowGiantCrops T</samp>
| ''(Optional)'' A [[#Game state queries|game state query]] which indicates whether this minecart destination is available. Defaults to always available.
+
| 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>CustomFields</samp>
+
| <samp>DirtDecayChance {{t|chance}}</samp>
| The [[#Custom data fields|custom fields]] for this entry.
+
| 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).
|}
   
|}
 
|}
   −
====Example====
+
====Farmhouse interior====
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 occured and minecarts have been unlocked.
+
{| class="wikitable"
 +
|-
 +
! property
 +
! explanation
 +
|-
 +
| <samp>FarmHouseStarterGift [{{t|id}} {{o|count}}]+</samp>
 +
| 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.
   −
{{#tag:syntaxhighlight|<nowiki>
+
For example, this will add 10 pufferfish (object 128) and a blobfish mask (hat 56):
{
+
<pre>FarmHouseStarterGift (O)128 10 (H)56 1</pre>
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
  −
    "Changes": [
  −
        // add minecart destination
  −
        {
  −
            "Action": "EditData",
  −
            "Target": "Data/Minecarts",
  −
            "TargetField": [ "Destinations" ],
  −
            "Entries": {
  −
                "Railroad": {
  −
                    "Location": "Railroad",
  −
                    "Tile": { "X": 16, "Y": 39 },
  −
                    "Direction": "down",
  −
                    "DisplayName": "[LocationName Railroad]"
  −
                }
  −
            },
  −
            "When": {
  −
                "HasFlag": "ccBoilerRoom",
  −
                "query: {{DaysPlayed}} </nowiki>><nowiki>= 32": true
  −
            }
  −
        },
     −
        // add decorative minecart
+
If omitted, the default items (usually a 15 parsnip seeds) are added instead.
        {
+
|}
            "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===
+
====Warps & map positions====
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 the unique festival ID. This should only contain alphanumeric/underscore/dot characters. For custom festivals, it should ideally be prefixed with your mod ID like <samp>Example.ModId_FestivalName</samp>.
  −
* The value is a model with the fields listed below.
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! property
! effect
+
! explanation
 
|-
 
|-
| <samp>DisplayName</samp>
+
| <samp>AllowWakeUpWithoutBed {{t|allow}}</samp>
| A [[#Tokenizable string format|tokenizable string]] for the display name shown on the [[calendar]].
+
| 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>Season</samp>
+
| <samp>DefaultWarpLocation {{t|x}} {{t|y}}</samp><br />''(valid in any location)''
| The [[season]] when the festival becomes active.
+
| 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>StartDay</samp><br /><samp>EndDay</samp>
+
| <samp>PetBowlLocation {{t|x}} {{t|y}}</samp><br />''(valid in the farm)''
| The days of month when the festival becomes active.
+
| The default position of the pet bowl
 
|-
 
|-
| <samp>StartTime</samp>
+
| <samp>SpouseRoomPosition {{t|x}} {{t|y}}</samp><br />''(valid in farmhouse)''
| The time of day when the festival opens each day.
+
| The top-left position at which to place the [[Marriage#Spouse Rooms|spouse room]].
 
|-
 
|-
| <samp>StartMessage</samp>
+
| <samp>TravelingCartPosition {{t|x}} {{t|y}}</samp><br />''(valid in the forest)''
| A [[#Tokenizable string format|tokenizable string]] for the in-game [[wikipedia:Pop-up notification|toast notification]] shown when the festival begins each day.
+
| 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.
|-
+
|}
| <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]]:
+
===Other map property changes===
<syntaxhighlight lang="js">
+
{{/doc status|[[Modding:Maps]]|done=false}}
"MapReplacements": {
+
 
    "Beach": "BeachNightMarket"
+
{| class="wikitable"
}
  −
</syntaxhighlight>
   
|-
 
|-
| <samp>Condition</samp>
+
! map property
| ''(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.
+
! changes
 
|-
 
|-
| <samp>ShowOnCalendar</samp>
+
| <samp>Arch</samp><br /><samp>asdf</samp><br /><samp>Debris</samp><br /><samp>Fish</samp>
| ''(Optional)'' Whether the festival appears on the [[calendar]], using the same iridium-star icon as the [[Calendar#Winter|Night Market]]. Default true.
+
| Removed (these were unused).
 
|-
 
|-
| <samp>DailySetupMethod</samp><br /><samp>CleanupMethod</samp>
+
| <samp>FarmHouseFlooring</samp><br /><samp>FarmHouseFurniture</samp><br /><samp>FarmHouseStarterSeedsPosition</samp><br /><samp>FarmHouseWallpaper</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 now work independently. For example, you can now use <samp>FarmHouseFlooring</samp> without needing to set <samp>FarmHouseFurniture</samp> too.
 
  −
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.
   
|-
 
|-
| <samp>CustomFields</samp>
+
| <samp>Music</samp>
| The [[#Custom data fields|custom fields]] for this entry.
+
| 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.
|}
  −
 
  −
====NPC schedules====
  −
When a passive festival is active, NPCs will check for [[Modding:Schedule data|a schedule entry]] in this order:
  −
 
  −
{| class="wikitable"
   
|-
 
|-
! syntax
+
| <samp>NPCWarp</samp><br /><samp>Warp</samp>
! summary
+
| 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>{{t|festival ID}}_{{t|festival day}}</samp>
+
| <samp>Stumps</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>
+
| Now works in all locations.
 
|-
 
|-
| <samp>{{t|festival ID}}</samp>
+
| <samp>UniquePortrait</samp><br /><samp>UniqueSprite</samp>
| Applies if there's no date-specific entry.<br /><small>Example: <samp>NightMarket</samp> or <samp>marriage_NightMarket</samp></small>
+
| Deprecated; use [[#Custom NPC appearance|custom NPC appearances]] instead. These properties will override NPC appearances. This was removed from all vanilla maps.
 
|}
 
|}
   −
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.
+
===Tile property changes===
 
+
{{/doc status|[[Modding:Maps]]|done=false}}
===Custom planting restrictions===
  −
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:
      +
<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"
 
{| class="wikitable"
 +
! layer
 +
! property
 +
! explanation
 
|-
 
|-
! tag
+
| <samp>Paths</samp>
! effect
+
| <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>plantable_greenhouse</samp>
  −
| Can always be planted in a [[greenhouse]] (''i.e.,'' locations with <samp>IsGreenhouse</samp>), regardless of any other context tag.
  −
|-
  −
| <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.
   
|}
 
|}
 
+
</li>
When multiple tags are specified, they're applied in this precedence order:
+
<li>Added new <samp>Action</samp> [[Modding:Maps|tile properties]]:
 
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! precedence
+
! layer
! rule
+
! property
! result
+
! explanation
 
|-
 
|-
| 1
+
| <samp>Buildings</samp>
| <samp>plantable_greenhouse</samp> matches
+
| <samp>Action BuildingSilo</samp>
| plantable
+
| 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>.
 
|-
 
|-
| 2
+
| <samp>Buildings</samp>
| <samp>plantable_location_*</samp> matches
+
| <samp>Action BuildingToggleAnimalDoor</samp>
| plantable
+
| If a building covers this tile, opens or closes its animal door.
 +
|-
 +
| <samp>Buildings</samp>
 +
| <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>Buildings</samp>
 +
| <samp>Action Forge</samp>
 +
| Opens the [[Forge]] menu.
 
|-
 
|-
| 2
+
| <samp>Buildings</samp>
| <samp>not_plantable_location_*</samp> matches<br />''or'' <samp>not_plantable_context_*</samp> matches
+
| <samp>Action None</samp>
| not plantable
+
| Does nothing. This is used to mark the tile interactive if the click will be handled separately.
 
|-
 
|-
| 3
+
| <samp>Buildings</samp>
| <samp>plantable_context_*</samp> or <samp>plantable_location_*</samp> specified but didn't match<br /><small>(<samp>not_*</samp> doesn't affect this rule)
+
| <samp>Action ObeliskWarp {{t|location name}} {{t|x}} {{t|y}} {{o|whether to dismount}}</samp>
| not plantable
+
| Warps the player to the specified location name and position with the [[Warp Totem|Obelisk]] animation/sound effects.
 
|-
 
|-
| 4
+
| <samp>Buildings</samp>
| current location listed in the context's <samp>DefaultValidPlantableLocations</samp> field
+
| <samp>Action OpenShop {{t|shop id}} {{o|from direction}} {{o|open time}} {{o|close time}} {{o|owner tile area}}</samp>
| plantable
+
| 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.
 
|-
 
|-
| 5
+
| <samp>Buildings</samp>
| colspan="2"| ''defaults to normal planting logic''
+
| <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:
 +
* {{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 doesn't start for any reason (including the preceding conditions):
 +
* 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 example, <code>Action PlayEvent 60367 false false</code> will replay the bus arrival event from the start of the game.
 
|}
 
|}
 
+
</li>
For example:
+
<li>Added new <samp>TouchAction</samp> [[Modding:Maps|tile properties]]:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! tags
+
! layer
! effect
+
! property
! plantable
+
! explanation
! reason
   
|-
 
|-
|rowspan="4"| ''none''
+
| <samp>Back</samp>
| [[The Farm|Farm]]
+
| <samp>TouchAction PlayEvent {{t|event id}} {{o|check preconditions}} {{o|skip if seen}} {{o|fallback action}}</samp>
| ☑ plantable
+
| 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.
|rowspan="4"| default behavior
+
|}</li>
 +
<li>Changed existing tile properties:
 +
{| class="wikitable"
 
|-
 
|-
| [[Greenhouse]]
+
! layer
| ☑ plantable
+
! property
 +
! reason
 
|-
 
|-
| location listed in its context's <samp>DefaultValidPlantableLocations</samp>
+
|rowspan="4"| <samp>Back</samp>
| ☑ plantable
+
| <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.
 
|-
 
|-
| [[Bus Stop]]
+
| <samp>TouchAction Bus</samp>
|
+
| Removed. This wasn't used by the game or mods.
 
|-
 
|-
|rowspan="2"| <samp>plantable_greenhouse, not_plantable_context_default</samp>
+
| <samp>TouchAction Emote</samp>
| [[The Farm|Farm]]
+
| Fixed error if the specified NPC isn't found.
| ☐
  −
| matches <samp>not_plantable_context_default</samp>
   
|-
 
|-
| [[Greenhouse]]
+
| <samp>Treasure</samp>
| ☑ plantable
+
| Added <samp>Treasure Item {{t|item ID}}</samp> form which accepts a [[#Custom items|qualified or unqualified item ID]].
| overridden by <samp>plantable_greenhouse</samp>
   
|-
 
|-
|rowspan="3"| <samp>plantable_location_islandwest</samp>
+
|rowspan="2"| <samp>Buildings</samp>
| [[Ginger Island|Island West]]
+
| <samp>Action ItemChest</samp><br /><samp>Action Minecart</samp><br /><samp>Action RemoveChest</samp>
| ☑ plantable
+
| Removed. These weren't used by the game or mods.
| matches <samp>plantable_location_islandwest</samp></samp>
   
|-
 
|-
| [[Ginger Island|Island South]]
+
| <samp>Action Kitchen</samp>
|
+
| Now works in any location (including those without a fridge).
|rowspan="2"| doesn't match <samp>plantable_location_islandwest</samp></samp>
+
|}
 +
</li>
 +
</ul>
 +
 
 +
===Other location/map changes===
 +
{{/doc status|[[Modding:Maps]] and other pages as needed|done=false}}
 +
 
 +
* 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"
 
|-
 
|-
| [[The Farm|Farm]]
+
! type
| ☐
+
! method
 +
! effect
 
|-
 
|-
|rowspan="3"| <samp>plantable_context_island</samp>
+
|rowspan="7"| <samp>Building</samp>
| [[Ginger Island|Island West]]
+
| <samp>GetParentLocation</samp>
| ☑ plantable
+
| Get the location which contains this building.
|rowspan="2"| matches <samp>plantable_context_island</samp>
   
|-
 
|-
| [[Ginger Island|Island South]]
+
| <samp>IsInCurrentLocation</samp>
| ☑ plantable
+
| Get whether the building is in the same location as the current player.
 
|-
 
|-
| [[The Farm|Farm]]
+
| <samp>HasIndoors</samp>
| ☐
+
| Get whether the building has an interior location.
| doesn't match <samp>plantable_context_island</samp>
   
|-
 
|-
|rowspan="3"| <samp>not_plantable_context_island</samp>
+
| <samp>GetIndoors</samp>
| [[Ginger Island|Island West]]
+
| Get the location within this building, if applicable.
| ☐
  −
|rowspan="2"| matches <samp>not_plantable_context_island</samp>
   
|-
 
|-
| [[Ginger Island|Island South]]
+
| <samp>HasIndoorsName</samp>
|
+
| Get whether the building has an interior location and its unique name matches the given value (like <code>building.HasIndoorsName("FarmHouse")</code>).
 
|-
 
|-
| [[The Farm|Farm]]
+
| <samp>GetIndoorsName</samp>
| ☑ plantable
+
| Get the unique name of the location within this building, if applicable.
| default behavior
   
|-
 
|-
|rowspan="3"| <samp>plantable_location_town, plantable_location_mountain</samp>
+
| ...
| [[Pelican Town|Town]]
+
| ''see also [[#Other building changes|other building changes]] for non-location methods.''
| ☑ plantable
  −
| matches <samp>plantable_location_town</samp>
   
|-
 
|-
| [[The Mountain|Mountain]]
+
|rowspan="7"|<samp>Cabin</samp><br /><samp>FarmHouse</samp>
| ☑ plantable
+
| <samp>GetCellar</samp>
| matches <samp>plantable_location_mountain</samp>
+
| Get the [[cellar]] location linked to this cabin, if any.
 
|-
 
|-
| [[The Farm|Farm]]
+
| <samp>CanAssignFarmhand</samp><br /><samp>AssignFarmhand</samp>
| ☐
+
| ''(Cabin only)'' Check whether the cabin is available to assign to a farmhand, or perform the assignment.
| doesn't match any <samp>plantable_location_*</samp> tags
  −
|}
  −
 
  −
===Custom weather===
  −
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===
  −
[[File:Modding map area.png|thumb|The default world map. The entire map is the Valley region, and the highlighted portion is an area with its own texture, tooltip/name, and player marker positioning.]]
  −
 
  −
You can now change the world map by editing the <samp>Data/WorldMap</samp> asset. You can add custom maps for certain locations, apply texture overlays, add/edit tooltips, set player marker positioning, etc. The default map for the valley is fully defined in <samp>Data/WorldMap</samp>.
  −
 
  −
====Overview====
  −
The game divides the world map into three main concepts (see example at right):
  −
 
  −
* A '''region''' is a large-scale part of the world containing everything shown on the map. For example, the default world map is the Valley region.
  −
* A '''map area''' is a subset of the world map which optionally add tooltips, scroll text, texture overlays, and player marker positioning info.
  −
* A '''map area position''' matches in-game locations and tile coordinates to the drawn world map. The game uses this to automatically position player markers at a relative position on the world map (e.g. so you can watch other players move across the location on the map).
  −
 
  −
In the data model:
  −
* each entry is a region;
  −
* each entry's <samp>MapAreas</samp> are the region's map area;
  −
* and each map area's <samp>WorldPositions</samp> are the world map positions.
  −
 
  −
The game will find the first <samp>WorldPositions</samp> entry which matches the current location, and assume you're in the region and map area which contains it. If there's none found, it defaults to the farm.
  −
 
  −
====Format====
  −
The <samp>Data/WorldMap</samp> data asset consists of a string → model lookup, where...
  −
* The key is a unique identifier for the region. This should only contain alphanumeric/underscore/dot characters. For custom regions, this should be prefixed with your mod ID like <samp>Example.ModId_RegionName</samp>.
  −
* The value is a model with the fields listed below.
  −
 
  −
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>HasOwner</samp>
! effect
+
| Get whether the home has an assigned player, regardless of whether they've finished creating their character.
 
|-
 
|-
| <samp>BaseTexture</samp>
+
| <samp>OwnerId</samp>
| ''(Optional)'' The base texture to draw for the map, if any. The first matching texture is applied. If map areas provide their own texture too, they're drawn on top of this base texture.
+
| Get the unique ID of the player who owns this home, if any.
 
  −
This consists of a list of models with these fields:
  −
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>IsOwnedByCurrentPlayer</samp>
! effect
+
| Get whether the cabin belongs to the current player.
 
|-
 
|-
| <samp>Id</samp>
+
| <samp>IsOwnerActivated</samp>
| A unique identifier for the texture entry. This should only contain alphanumeric/underscore/dot characters. For custom entries, this should be prefixed with your mod ID like <samp>Example.ModId_TextureName</samp>.
+
| Get whether the home has an assigned player and they've finished creating their character.
 
|-
 
|-
| <samp>Texture</samp>
+
| <samp>HasNpcSpouse</samp>
| The asset name for the texture to draw.
+
| 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>.
 
|-
 
|-
| <samp>SourceRect</samp>
+
|rowspan="2"| <samp>Farm</samp>
| ''(Optional)'' The pixel area within the <samp>Texture</samp> to draw, specified as an object with <samp>X</samp>, <samp>Y</samp>, <samp>Width</samp>, and <samp>Height</samp> fields. Defaults to the entire texture image.
+
| <samp>GetStarterFarmhouseLocation</samp>
 +
| Get the default tile position for the farmhouse. (See also <samp>farm.GetMainFarmHouseEntry()</samp>.)
 
|-
 
|-
| <samp>MapPixelArea</samp>
+
| <samp>GetStarterPetBowlLocation</samp>
| ''(Optional)'' The pixel area within the map which is covered by this area, specified as an object with <samp>X</samp>, <samp>Y</samp>, <samp>Width</samp>, and <samp>Height</samp> fields. If omitted, draws the entire <samp>SourceRect</samp> area starting from the top-left corner of the map.
+
| Get the default tile position for the pet bowl.
 
|-
 
|-
| <samp>Condition</samp>
+
|rowspan="19"| <samp>GameLocation</samp>
| ''(Optional)'' A [[#Game state queries|game state query]] which indicates whether this texture should be selected. Defaults to always selected.
+
| <samp>AddDefaultBuildings</samp>
|}
+
| 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).
|-
  −
| <samp>MapAreas</samp>
  −
| The areas to draw on top of the <samp>BaseTexture</samp>. These can provide tooltips, scroll text, texture overlays, and player marker positioning info.
     −
This consists of a list of models with these fields:
+
This replaces the former <samp>farm.AddModularShippingBin()</samp> method.
 
  −
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>GetFridge</samp><br /><samp>GetFridgePosition</samp>
! effect
+
| Get the fridge's chest or tile position, if the location has one.
 
|-
 
|-
| <samp>Id</samp>
+
| <samp>GetSeason</samp><br /><samp>GetSeasonIndex</samp><br /><samp>GetSeasonKey</samp>
| A unique identifier for the map area. This should only contain alphanumeric/underscore/dot characters. For custom entries, this should be prefixed with your mod ID like <samp>Example.ModId_MapAreaName</samp>.
+
| 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>PixelArea</samp>
+
| <samp>GetWeather</samp><br /><samp>IsDebrisWeatherHere</samp><br /><samp>IsLightningHere</samp><br /><samp>IsRainingHere</samp><br /><samp>IsSnowingHere</samp>
| The pixel area within the map which is covered by this area. This is used to set the default player marker position, and is the default value for pixel areas in other fields below.
+
| Get the current weather in this location's context, regardless of whether the player is indoors and sheltered from it.
 
|-
 
|-
| <samp>ScrollText</samp>
+
| <samp>InDesertContext</samp><br /><samp>InIslandContext</samp><br /><samp>InValleyContext</samp>
| ''(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 none.
+
| Get whether this location is within the <samp>Island</samp> or <samp>Default</samp> location context respectively.
 
|-
 
|-
| <samp>Textures</samp>
+
| <samp>IsActiveLocation</samp>
| ''(Optional)'' The image overlays to apply to the map. All matching textures are applied.
+
| Get whether this location is actively synced to the current player (see [[Modding:Modder Guide/Game Fundamentals#Farmhand shadow world|farmhand shadow world]]).
 
  −
This consists of a list of models with these fields:
  −
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>IsTemporary</samp>
! effect
+
| 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>Id</samp>
+
| <samp>GetLocationContextId</samp>
| A unique identifier for the texture entry within the area. This should only contain alphanumeric/underscore/dot characters. For custom entries, this should be prefixed with your mod ID like <samp>Example.ModId_TextureName</samp>.
+
| Get the ID of the location context in <samp>Data/LocationContexts</samp> which contains this building.
 
|-
 
|-
| <samp>Texture</samp>
+
| <samp>GetContainingBuilding</samp>
| The asset name for the texture to draw.
+
| Get the building instance which contains this location (like the cabin for a cabin interior), if applicable.
 
  −
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). This should usually be used with <code>"MapPixelArea": "0 43 131 61"</code> (the farm area on the default map).
   
|-
 
|-
| <samp>SourceRect</samp>
+
| <samp>GetParentLocation</samp>
| ''(Optional)'' The pixel area within the <samp>Texture</samp> to draw, specified as an object with <samp>X</samp>, <samp>Y</samp>, <samp>Width</samp>, and <samp>Height</samp> fields. Defaults to the entire texture image.
+
| 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>MapPixelArea</samp>
+
| <samp>GetRootLocation</samp>
| ''(Optional)'' The pixel area within the map which is covered by this area, specified as an object with <samp>X</samp>, <samp>Y</samp>, <samp>Width</samp>, and <samp>Height</samp> fields. If omitted, defaults to the map area's <samp>PixelArea</samp>.
+
| 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>Condition</samp>
+
| <samp>GetInstancedBuildingInteriors</samp>
| ''(Optional)'' A [[#Game state queries|game state query]] which indicates whether this texture should be selected. Defaults to always selected.
+
| Get all building interiors within this location which are instanced to the building (i.e. not in <samp>Game1.locations</samp> separately).
|}
   
|-
 
|-
| <samp>Tooltips</samp>
+
| <samp>GetMapPropertySplitBySpaces</samp><br /><samp>GetTilePropertySplitBySpaces</samp>
| ''(Optional)'' The tooltips to show when hovering over parts of this area on the world map.
+
| 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.
   −
This consists of a list of models with these fields:
+
For example:
{| class="wikitable"
+
<syntaxhighlight lang="c#">
 +
string[] fields = Game1.currentLocation.GetMapPropertySplitBySpaces("ScreenshotRegion");
 +
</syntaxhighlight>
 
|-
 
|-
! field
+
| <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>Id</samp>
+
| <samp>StoreHayInAnySilo</samp>
| A unique identifier for the tooltip within the area. This should only contain alphanumeric/underscore/dot characters. For custom entries, this should be prefixed with your mod ID like <samp>Example.ModId_TooltipName</samp>.
+
| Add hay to any silo with free space (preferring silos in the current location, then the farm, then anywhere).
 
|-
 
|-
| <samp>Text</samp>
+
| <samp>TryGetMapProperty</samp>
| ''(Optional)'' A [[#Tokenizable string format|tokenizable string]] for the text to show in a tooltip.
+
| Get a map property value as a string, if it's defined.
|-
  −
| <samp>PixelArea</samp>
  −
| ''(Optional)'' The pixel area within the map which can be hovered to show this tooltip. Defaults to the area's <samp>PixelArea</samp>.
  −
|-
  −
| <samp>Condition</samp>
  −
| ''(Optional)'' A [[#Game state queries|game state query]] which indicates whether this tooltip should be available. Defaults to always available.
  −
|-
  −
| <samp>KnownCondition</samp>
  −
| ''(Optional)'' A [[#Game state queries|game state query]] which indicates whether the area is known by the player, so the <samp>Text</samp> is shown as-is. If this is false, the tooltip text is replaced with <samp>???</samp>. Defaults to always known.
  −
|-
  −
| <samp>LeftNeighbor</samp><br /><samp>RightNeighbor</samp><br /><samp>UpNeighbor</samp><br /><samp>DownNeighbor</samp>
  −
| ''(Optional)'' When navigating the world map with a controller, the tooltip to snap to when the player moves the cursor while it's on this tooltip.
     −
This must specify the area and tooltip formatted like <samp>areaId/tooltipId</samp> (not case-sensitive). If there are multiple possible neighbors, they can be specified in comma-delimited form; the first valid one will be used.
+
For example:
 
+
<syntaxhighlight lang="c#">
For example, this will snap to the community center when the user moves the cursor to the right:
+
if (this.TryGetMapProperty("Warps", out string warps))
<syntaxhighlight lang="js">
+
{
"RightNeighbor": "Town/CommunityCenter"
+
    // ...
 +
}
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
|-
 +
| <samp>TryGetMapPropertyAs</samp>
 +
| 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.
   −
A blank value will be ignored, but the game will log a warning if you specify neighbor IDs and none of them match. To silently ignore them instead (e.g. for a conditional location), you can add 'ignore' as an option:
+
For example:
<syntaxhighlight lang="js">
+
<syntaxhighlight lang="c#">
"RightNeighbor": "Town/SomeOptionalLocation, ignore"
+
if (!this.TryGetMapPropertyAs("MailboxLocation", out Point position))
 +
{
 +
    position = new Point(68, 16); // default value
 +
}
 
</syntaxhighlight>
 
</syntaxhighlight>
  −
See also the <samp>MapNeighborIdAliases</samp> field in the region data.
  −
|}
   
|-
 
|-
| <samp>WorldPositions</samp>
+
| <samp>removeObjectsAndSpawned</samp>
| ''(Optional)'' The in-world locations and tile coordinates to match to this map area. The game uses this to automatically position player markers at a relative position on the world map (e.g. so you can watch other players move across the location on the map).
+
| Remove all objects, bushes, resource clumps, and terrain features within a tile area.
 
  −
This consists of a list of models with these fields:
  −
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>OnBuildingConstructed</samp><br /><samp>OnBuildingMoved</samp><br /><samp>OnBuildingDemolished</samp>
! effect
+
| These methods are called for all players when any player constructs, moves, or demolishes a building.
 
|-
 
|-
| <samp>Id</samp>
+
|rowspan="3"| <samp>LibraryMuseum</samp>
| A unique identifier for this entry within the area. This should only contain alphanumeric/underscore/dot characters. For custom entries, this should be prefixed with your mod ID like <samp>Example.ModId_PositionName</samp>.
+
| <samp>HasDonatedArtifacts()</samp>
 +
| Get whether any items have been donated to the [[museum]].
 
|-
 
|-
| <samp>LocationContext</samp>
+
| <samp>HasDonatedArtifactAt(tile)</samp>
| ''(Optional)'' The location context in which this world position applies. The vanilla contexts are <samp>Default</samp> (valley) and <samp>Island</samp> ([[Ginger Island]]).
+
| Get whether any donated item is currently placed at the given tile position within the [[museum]].
 
|-
 
|-
| <samp>LocationName</samp>
+
| <samp>HasDonatedArtifact(itemId)</samp>
| ''(Optional)'' The location name to which this world position applies. 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 (like <samp>Town-EggFestival</samp>).
+
| Get whether an artifact with the given qualified or unqualified item ID has been donated to the [[museum]].
 
|-
 
|-
| <samp>LocationNames</samp>
+
|rowspan="2"| <samp>MineShaft</samp>
| ''(Optional)'' Equivalent to <samp>LocationName</samp>, but you can specify multiple locations as an array.
+
| <samp>GetLevelName</samp>
|-
+
| Get the location name for a generated [[The Mines|mine]] or [[Skull Cavern]] level.
| <samp>TileArea</samp><br /><samp>MapPixelArea</samp>
  −
| ''(Optional)'' The tile area within the in-game location (<samp>TileArea</samp>) and the equivalent pixel area on the world map (<samp>MapPixelArea</samp>). These are used to calculate the position of a character or player within the map view, given their real position in-game. For example, if the player is in the top-right corner of the tile area in-game, they'll be shown in the top-right corner of the drawn area on the world map.
     −
Both are specified as an object with <samp>X</samp>, <samp>Y</samp>, <samp>Width</samp>, and <samp>Height</samp> fields. <samp>TileArea</samp> defaults to the entire location, and <samp>MapPixelArea</samp> defaults to the map area's <samp>PixelArea</samp>.
+
For example:
 +
<syntaxhighlight lang="c#">
 +
string locationName = MineShaft.GetLevelName(10); // returns "UndergroundMine10"
 +
Game1.warpFarmer(locationName, 0, 0, false);
 +
</syntaxhighlight>
 
|-
 
|-
| <samp>ScrollText</samp>
+
| <samp>IsGeneratedLevel</samp>
| ''(Optional)'' A [[#Tokenizable string format|tokenizable string]] for the scroll text shown at the bottom of the map when the player is within this position. Defaults to the map area's <samp>ScrollText</samp>, if any.
+
| Get whether a location or location name is a generated [[The Mines|mine]] or [[Skull Cavern]] level.
|-
  −
| <samp>Condition</samp>
  −
| ''(Optional)'' A [[#Game state queries|game state query]] which indicates whether this entry should be applied. Defaults to always applied.
  −
|-
  −
| <samp>ExtendedTileArea</samp>
  −
| ''(Optional, specialized)'' The tile area within the in-game location to which this position applies, including tiles that are outside the <samp>TileArea</samp>. The <samp>ExtendedTileArea</samp> must fully contain <samp>TileArea</samp>, since the latter won't be checked for the initial detection anymore.
     −
For example, let's say we have this <samp>ExtendedTileArea</samp> (the larger box) and <samp>TileArea</samp> (the smaller box inside it), and the player is at position X:
+
For example:
<pre>
+
<syntaxhighlight lang="c#">
┌────────────────────┐
+
string locationName = "UndergroundMine10";
│    ┌────────┐      │
+
bool isMine = MineShaft.IsGeneratedLevel(locationName, out int level); // returns true, 10
│ X  │        │      │
+
</syntaxhighlight>
│    │        │      │
+
|-
│    └────────┘      │
+
| <samp>VolcanoDungeon</samp>
└────────────────────┘
+
| <samp>GetLevelName</samp><br /><samp>IsGeneratedLevel</samp>
</pre>
+
| Equivalent to the matching <samp>MineShaft</samp> methods, but for the [[Volcano Dungeon]].
 +
|}
 +
</li>
 +
</ul>
 +
* 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.
 +
 
 +
==What's new for buildings==
 +
===Custom buildings===
 +
{{/doc status|[[Modding:Blueprint data]]|done=false}}
   −
In this case, the entry would be selected (since the player is inside the <samp>ExtendedTileArea</samp>), and their coordinates would be shifted into the nearest <samp>TileArea</samp> position:
+
You can now add custom buildings by editing the <samp>Data/Buildings</samp> asset. This consists of a string → model lookup, where...
<pre>
+
* 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.
│    ┌────────┐      │
  −
│    │X      │      │
  −
│    │        │      │
  −
│    └────────┘      │
  −
└────────────────────┘
  −
</pre>
     −
This is used for complex locations that use multiple tile areas to match a drawn map with a different layout. This can be omitted in most cases.
+
====Required fields====
|}
+
{| class="wikitable"
 +
|-
 +
! field
 +
! effect
 
|-
 
|-
| <samp>CustomFields</samp>
+
| <samp>Name</samp><br /><samp>Description</samp>
| The [[#Custom data fields|custom fields]] for this entry.
+
| A [[Modding:Tokenizable strings|tokenizable string]] for the display name and description (e.g. shown in the construction menu).
|}
   
|-
 
|-
| <samp>MapNeighborIdAliases</samp>
+
| <samp>Texture</samp>
| ''(Optional)'' A set of aliases that can be used in tooltip fields like <samp>LeftNeighbor</samp> instead of the specific values they represent. Aliases can't be recursive.
+
| The asset name for the texture under the game's Content folder.
 
  −
For example, this lets you use <samp>Beach/FishShop</samp> in neighbor fields instead of specifying the specific tooltip IDs each time:
  −
<syntaxhighlight lang="js">
  −
"MapNeighborIdAliases": {
  −
    "Beach/FishShop": "Beach/FishShop_DefaultHours, Beach/FishShop_ExtendedHours"
  −
}
  −
</syntaxhighlight>
   
|}
 
|}
   −
====Example====
+
====Construction====
This [[Modding:Content Patcher|Content Patcher]] content pack adds a new world map for [[Ginger Island]]. If the player unlocked the [[Ginger Island#Beach Resort|beach resort]], it applies the beach resort texture.
+
{| class="wikitable"
 
+
|-
{{#tag:syntaxhighlight|<nowiki>
+
! field
{
+
! effect
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
+
|-
    "Changes": [
+
| <samp>Builder</samp>
        // add world map edits
+
| ''(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.
        {
  −
            "Action": "EditData",
  −
            "Target": "Data/WorldMap",
  −
            "Entries": {
  −
                "GingerIsland": {
  −
                    "BaseTexture": [
  −
                        {
  −
                            "Id": "Default",
  −
                            "Texture": "{{InternalAssetKey: assets/ginger-island.png}}"
  −
                        }
  −
                    ],
  −
                    "MapAreas": [
  −
                        // the Island South (dock) area
  −
                        {
  −
                            // basic info for the area within the map
  −
                            "Id": "IslandSouth",
  −
                            "PixelArea": { "X": 105, "Y": 105, "Width": 231, "Height": 240 },
  −
                            "ScrollText": "Dock", // example only, should usually be translated
  −
 
  −
                            // a tooltip shown when hovering over the area on the map
  −
                            "Tooltips": [
  −
                                {
  −
                                    "Id": "Dock",
  −
                                    "Text": "Dock" // example only, should usually be translated
  −
                                }
  −
                            ],
  −
 
  −
                            // if the resort is unlocked, overlay a custom texture on top of the default Ginger Island map
  −
                            "Textures": [
  −
                                {
  −
                                    "Id": "Resort",
  −
                                    "Texture": "{{InternalAssetKey: assets/resort.png}}",
  −
                                    "Condition": "PLAYER_HAS_FLAG Any Island_Resort"
  −
                                }
  −
                            ],
  −
 
  −
                            // the in-game locations that are part of this world map area
  −
                            "WorldAreas": [
  −
                                {
  −
                                    "LocationName": "IslandSouth"
  −
                                }
  −
                            ]
  −
                        }
  −
                    ]
  −
                }
  −
            }
  −
        }
  −
    ]
  −
}</nowiki>|lang=javascript}}
  −
 
  −
====Real-time positioning====
  −
In Stardew Valley 1.6, the world map now shows players' actual positions within the world in real-time (instead of showing them at a fixed point for each location like 1.5.4). In multiplayer, you'll see other players' position in real-time too.
  −
 
  −
For custom locations, this usually happens automatically based on your <samp>PixelArea</samp> and <samp>LocationName</samp> fields in <samp>Data/WorldMap</samp>. For complex locations whose tile layout doesn't match the drawn map, you can specify pixel + tile areas in the <samp>WorldLocations</samp> field to allow real-time positions.
  −
 
  −
⚠ Current limitations:
  −
* The [[Cindersap Forest|forest]] (outside), [[Pelican Town|town]] (outside), and [[Ginger Island]] (all) temporarily have a fixed marker position like in 1.5.4. Their locations' layouts are very different from the drawn map, so they'll be migrated during the 1.6 late alpha.
  −
* Building interiors temporarily show a fixed marker position on the farm, like in 1.5.4. Dynamically mapping those to the building's exterior position will be added during the late alpha.
  −
 
  −
===New map properties===
  −
1.6 adds several new [[Modding:Maps|map properties]].
  −
 
  −
====Warps & map positions====
  −
{| class="wikitable"
   
|-
 
|-
! property
+
| <samp>BuildCost</samp>
! explanation
+
| ''(Optional)'' The gold cost to construct the building. Defaults to {{price|0}}.
 
|-
 
|-
| <samp>DefaultWarpLocation {{t|x}} {{t|y}}</samp><br />''(valid in any location)''
+
| <samp>BuildMaterials</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)'' The materials you must provide to start construction, as a list of models with these fields:
 +
{| class="wikitable"
 
|-
 
|-
| <samp>SpouseRoomPosition {{t|x}} {{t|y}}</samp><br />''(valid in farmhouse)''
+
! field
| The top-left position at which to place the [[Marriage#Spouse Rooms|spouse room]].
+
! effect
|}
  −
 
  −
====Audio====
  −
{| class="wikitable"
   
|-
 
|-
! property
+
| <samp>Id</samp>
! explanation
+
| ''(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>MusicContext {{t|context}}</samp><br />''(valid in any location)''
+
| <samp>ItemId</samp>
| The music context for this location. The recommended values are <samp>Default</samp> or <samp>SubLocation</samp>.
+
| The required item ID (qualified or unqualified).
 
  −
Setting <samp>SubLocation</samp> has two effects:
  −
* <samp>SubLocation</samp> has a lower priority than <samp>Default</samp>. In split-screen mode, that means if player A is at a location with a <samp>Default</samp> music context, and player B is a location with a <samp>SubLocation</samp> context, the game will choose player A's music.
  −
* When the player leaves a location with <samp>SubLocation</samp> music, the music will be stopped unless the new location has the same music and music context set.
   
|-
 
|-
| <samp>MusicIgnoreInRain T²</samp><br />''(valid in any outdoor location)''
+
| <samp>Amount</samp>
| If set, the <samp>Music</samp> property is ignored when it's raining in this location.
+
| The number of the item required.
 +
|}
 
|-
 
|-
| <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>BuildDays</samp>
| If set, the <samp>Music</samp> property is ignored in the given season.
+
| ''(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>MusicIgnoreInFallDebris T²<br />''(valid in any outdoor location)''
+
| <samp>BuildCondition</samp>
| If set, the <samp>Music</samp> property is ignored in fall during windy weather.
+
| ''(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>MusicIsTownTheme T²</samp><br />''(valid in any location)''
+
| <samp>BuildMenuDrawOffset</samp>
| If set, 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)'' A pixel offset to apply to the building sprite when drawn in the construction menu. Default none.
|}
+
|-
 
+
| <samp>AdditionalPlacementTiles</samp>
====Crops====
+
| ''(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:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! property
+
! field
! explanation
+
! effect
 +
|-
 +
| <samp>TileArea</samp>
 +
| 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>AllowGiantCrops T</samp>
+
| <samp>OnlyNeedsToBePassable</samp>
| 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]].)
+
| ''(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.
 
|}
 
|}
 
+
|-
====Building construction====
+
| <samp>IndoorItems</samp>
 +
| ''(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"
 
|-
 
|-
! property
+
! field
! explanation
+
! effect
 +
|-
 +
| <samp>Id</samp>
 +
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the current list.
 +
|-
 +
| <samp>ItemId</samp>
 +
| The [[#Custom items|qualified item ID]] for the item to place.
 
|-
 
|-
| <samp>CanBuildHere T</samp><br />''(valid in any outdoor location)''
+
| <samp>Tile</samp>
| 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]].
+
| The tile position at which to place the item, specified as an object with <samp>X</samp> and <samp>Y</samp> fields.
 
|-
 
|-
| <samp>BuildConditions {{t|query}}</samp><br />''(valid in any outdoor location)''
+
| <samp>Indestructible</samp>
| If <samp>CanBuildHere</samp> is set, an optional [[#Game state queries|game state query]] which indicates whether building is allowed currently.
+
| ''(Optional)'' Whether to prevent the player from destroying, picking up, or moving the item. Default false.
 +
|}
 
|-
 
|-
| <samp>LooserBuildRestrictions T</samp><br />''(valid in any outdoor location)''
+
| <samp>MagicalConstruction</samp>
| 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.
+
| ''(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>ValidBuildRect {{t|x}} {{t|y}} {{t|width}} {{t|height}}</samp><br />''(valid in any outdoor location)''
+
| <samp>AddMailOnBuild</samp>
| The tile area within the map where buildings may be placed. If omitted, buildings may be placed in any open space in the map.
+
| ''(Optional)'' A list of [[Modding:Mail data|letter IDs]] to send to all players when the building is constructed for the first time.
 
|}
 
|}
   −
===Other map property changes===
+
====Upgrades====
* The <samp>NPCWarp</samp> and <samp>Warp</samp> properties are 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.
  −
* The <samp>Stumps</samp> map property now works in all locations.
  −
* Removed many unused map/tile properties like <samp>Arch</samp>, <samp>Debris</samp>, <samp>Fish</samp>, and <samp>asdf</samp>.
  −
 
  −
===Tile property changes===
  −
<ul>
  −
<li>You can now override a tile index property by setting it as a tile property.</li>
  −
<li>Added new <samp>Action</samp> [[Modding:Maps|tile properties]]:
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! layer
+
! field
! property
+
! effect
! explanation
   
|-
 
|-
| <samp>Buildings</samp>
+
| <samp>BuildingToUpgrade</samp>
| <samp>Action BuildingSilo</samp>
+
| ''(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.
| 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>Buildings</samp>
+
| <samp>IndoorItemMoves</samp>
| <samp>Action BuildingToggleAnimalDoor</samp>
+
| ''(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:
| If a building covers this tile, opens or closes its animal door.
+
{| class="wikitable"
 
|-
 
|-
| <samp>Buildings</samp>
+
! field
| <samp>Action Forge</samp>
+
! effect
| Opens the [[Forge]] menu.
   
|-
 
|-
| <samp>Buildings</samp>
+
| <samp>Id</samp>
| <samp>Action None</samp>
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the current list.
| Does nothing. This is used to mark the tile interactive if the click will be handled separately.
   
|-
 
|-
| <samp>Buildings</samp>
+
| <samp>Source</samp>
| <samp>Action ObeliskWarp {{t|location name}} {{t|x}} {{t|y}} {{o|whether to dismount}}</samp>
+
| The tile position on which any item will be moved.
| Warps the player to the specified location name and position with the [[Warp Totem|Obelisk]] animation/sound effects.
   
|-
 
|-
| <samp>Buildings</samp>
+
| <samp>Destination</samp>
| <samp>Action OpenShop {{t|shop id}} {{o|from direction}} {{o|open time}} {{o|close time}} {{o|owner tile area}}</samp>
+
| The tile position to which to move the item.
| 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>Size</samp>
| <samp>Action PlayEvent {{t|event id}} {{o|check preconditions}} {{o|skip if seen}}</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.
| 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.
  −
 
  −
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"
   
|-
 
|-
! layer
+
| <samp>UpgradeSignTile</samp>
! property
+
| ''(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>.
! explanation
   
|-
 
|-
| <samp>Back</samp>
+
| <samp>UpgradeSignHeight</samp>
| <samp>TouchAction PlayEvent {{t|event id}} {{o|check preconditions}} {{o|skip if seen}} {{o|fallback action}}</samp>
+
| ''(Optional)'' The pixel height of the upgrade sign when Robin is building an upgrade. Defaults to 0.
| 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>
+
 
<li>Changed existing tile properties:
+
====Exterior behavior====
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! layer
+
! field
! property
+
! effect
! reason
+
|-
 +
| <samp>Size</samp>
 +
| ''(Optional)'' The building's width and height when constructed, measured in tiles. Defaults to a 1 x 1 area.
 
|-
 
|-
|rowspan="3"| <samp>Back</samp>
+
| <samp>CollisionMap</samp>
| <samp>NoSpawn</samp>
+
| ''(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.
| 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.
+
 
 +
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>TouchAction Bus</samp>
+
| <samp>HumanDoor</samp>
| Removed. This wasn't used by the game or mods.
+
| ''(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>Treasure</samp>
+
| <samp>AnimalDoor</samp>
| Added <samp>Treasure Item {{t|item ID}}</samp> form which accepts a [[#Custom items|qualified or unqualified item ID]].
+
| ''(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.
 
|-
 
|-
|rowspan="2"| <samp>Buildings</samp>
+
| <samp>AnimalDoorOpenDuration</samp><br /><samp>AnimalDoorCloseDuration</samp>
| <samp>Action ItemChest</samp><br /><samp>Action Minecart</samp><br /><samp>Action RemoveChest</samp>
+
| ''(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.
| Removed. These weren't used by the game or mods.
   
|-
 
|-
| <samp>Action Kitchen</samp>
+
| <samp>AnimalDoorOpenSound</samp><br /><samp>AnimalDoorCloseSound</samp>
| Now works in any location (including those without a fridge).
+
| ''(Optional)'' The sound which is played once each time the animal door is opened/closed. Disabled by default.
 
|}
 
|}
</li>
  −
<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>
  −
</ul>
     −
===Other location/map changes===
+
====Exterior appearance====
* Farm data:
+
{| class="wikitable"
** 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.
+
! field
* General location data:
+
! effect
** 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).
+
| <samp>SourceRect</samp>
** 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.
+
| ''(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.
** 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.
+
| <samp>Skins</samp>
** Finished migrating <samp>DecoratableLocation</samp> flooring/wallpaper areas to string IDs (started in Stardew Valley 1.5.5).
+
| ''(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:
* 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"
 
|-
 
|-
! type
+
! field
! method
   
! effect
 
! effect
 
|-
 
|-
|rowspan="7"| <samp>Building</samp>
+
| <samp>Id</samp>
| <samp>GetParentLocation</samp>
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for the skin.
| Get the location which contains this building.
   
|-
 
|-
| <samp>IsInCurrentLocation</samp>
+
| <samp>Name</samp><br /><samp>Description</samp>
| Get whether the building is in the same location as the current player.
+
| [[Modding:Tokenizable strings|Tokenizable strings]] for the skin's display name and description.
 
|-
 
|-
| <samp>HasIndoors</samp>
+
| <samp>Texture</samp>
| Get whether the building has an interior location.
+
| The asset name for the texture under the game's Content folder.
 
|-
 
|-
| <samp>GetIndoors</samp>
+
| <samp>Condition</samp>
| Get the location within this building, if applicable.
+
| ''(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>HasIndoorsName</samp>
+
| <samp>BuildDays</samp><br /><samp>BuildCost</samp><br /><samp>BuildMaterials</samp>
| Get whether the building has an interior location and its unique name matches the given value (like <code>building.HasIndoorsName("FarmHouse")</code>).
+
| ''(Optional)'' If set, overrides the equivalent field in the building data.
 
|-
 
|-
| <samp>GetIndoorsName</samp>
+
| <samp>ShowAsSeparateConstructionEntry</samp>
| Get the unique name of the location within this building, if applicable.
+
| ''(Optional)'' Whether this skin should be shown as a separate building option in the construction menu (like cabins). Default false.
 
|-
 
|-
| ...
+
| <samp>Metadata</samp>
| ''see also [[#Other building changes|other building changes]] for non-location methods.''
+
| ''(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.
 +
|}
 
|-
 
|-
|rowspan="7"|<samp>Cabin</samp><br /><samp>FarmHouse</samp>
+
| <samp>FadeWhenBehind</samp>
| <samp>GetCellar</samp>
+
| ''(Optional)'' Whether the building should become semi-transparent when the player is behind it. Default true.
| Get the [[cellar]] location linked to this cabin, if any.
   
|-
 
|-
| <samp>CanAssignFarmhand</samp><br /><samp>AssignFarmhand</samp>
+
| <samp>DrawOffset</samp>
| ''(Cabin only)'' Check whether the cabin is available to assign to a farmhand, or perform the assignment.
+
| ''(Optional)'' A pixel offset applied to the building sprite's placement in the world. Default 0.
 
|-
 
|-
| <samp>HasOwner</samp>
+
| <samp>SeasonOffset</samp>
| Get whether the home has an assigned player, regardless of whether they've finished creating their character.
+
| ''(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>OwnerId</samp>
+
| <samp>SortTileOffset</samp>
| Get the unique ID of the player who owns this home, if any.
+
| ''(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>IsOwnedByCurrentPlayer</samp>
+
| <samp>DrawLayers</samp>
| Get whether the cabin belongs to the current player.
+
| ''(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>IsOwnerActivated</samp>
+
! field
| Get whether the home has an assigned player and they've finished creating their character.
+
! effect
 
|-
 
|-
| <samp>HasNpcSpouse</samp>
+
| <samp>Id</samp>
| 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>.
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the current list.
 
|-
 
|-
|rowspan="2"| <samp>Farm</samp>
+
| <samp>SourceRect</samp>
| <samp>GetStarterFarmhouseLocation</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 the default tile position for the farmhouse. (See also <samp>farm.GetMainFarmHouseEntry()</samp>.)
   
|-
 
|-
| <samp>GetStarterPetBowlLocation</samp>
+
| <samp>DrawPosition</samp>
| Get the default tile position for the pet bowl.
+
| The tile position at which to draw the top-left corner of the texture, relative to the building's top-left corner tile.
 
|-
 
|-
|rowspan="18"| <samp>GameLocation</samp>
+
| <samp>Texture</samp>
| <samp>AddDefaultBuildings</samp>
+
| ''(Optional)'' The asset name of the texture to draw. Defaults to the building's default <samp>Texture</samp> field.
| 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 <samp>farm.AddModularShippingBin()</samp> method.
   
|-
 
|-
| <samp>GetFridge</samp><br /><samp>GetFridgePosition</samp>
+
| <samp>DrawInBackground</samp>
| Get the fridge's chest or tile position, if the location has one.
+
| ''(Optional)'' Whether to draw the texture behind the building sprite (i.e. underlay) instead of over it.
 
|-
 
|-
| <samp>GetSeason</samp><br /><samp>GetSeasonIndex</samp><br /><samp>GetSeasonKey</samp>
+
| <samp>SortTileOffset</samp>
| 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]].
+
| ''(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>GetWeather</samp><br /><samp>IsDebrisWeatherHere</samp><br /><samp>IsLightningHere</samp><br /><samp>IsRainingHere</samp><br /><samp>IsSnowingHere</samp>
+
| <samp>OnlyDrawIfChestHasContents</samp>
| Get the current weather in this location's context, regardless of whether the player is indoors and sheltered from it.
+
| ''(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>InDesertContext</samp><br /><samp>InIslandContext</samp><br /><samp>InValleyContext</samp>
+
| <samp>FrameCount</samp><br /><samp>FramesPerRow</samp><br /><samp>FrameDuration</samp>
| Get whether this location is within the <samp>Island</samp> or <samp>Default</samp> location context respectively.
+
| ''(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>IsActiveLocation</samp>
+
| <samp>AnimalDoorOffset</samp>
| Get whether this location is actively synced to the current player (see [[Modding:Modder Guide/Game Fundamentals#Farmhand shadow world|farmhand shadow world]]).
+
| ''(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>GetLocationContextId</samp>
+
| <samp>DrawShadow</samp>
| Get the ID of the location context in <samp>Data/LocationContexts</samp> which contains this building.
+
| ''(Optional)'' Whether to draw an automatic shadow along the bottom edge of the building's sprite. Default true.
 +
|}
 +
 
 +
====Interior====
 +
{| class="wikitable"
 
|-
 
|-
| <samp>GetContainingBuilding</samp>
+
! field
| Get the building instance which contains this location (like the cabin for a cabin interior), if applicable.
+
! effect
 
|-
 
|-
| <samp>GetParentLocation</samp>
+
| <samp>IndoorMap</samp>
| Get the parent location which contains this one (like the farm for a cabin interior), or <samp>null</samp> if it has no parent.
+
| ''(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>GetRootLocation</samp>
+
| <samp>IndoorMapType</samp>
| Get the parent location which contains this one (like the farm for a cabin interior), or the location itself if it has no parent.
+
| ''(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>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.Shed</samp>;
 +
* and <samp>StardewValley.SlimeHutch</samp>.
 +
Defaults to the generic <samp>StardewValley.GameLocation</samp> class.
 
|-
 
|-
| <samp>GetInstancedBuildingInteriors</samp>
+
| <samp>NonInstancedIndoorLocation</samp>
| Get all building interiors within this location which are instanced to the building (i.e. not in <samp>Game1.locations</samp> separately).
+
| ''(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.
 +
 
 +
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>GetMapPropertySplitBySpaces</samp><br /><samp>GetTilePropertySplitBySpaces</samp>
+
| <samp>MaxOccupants</samp>
| 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.
+
| ''(Optional)'' The maximum number of animals who can live in this building.
 
+
|-
For example:
+
| <samp>AllowAnimalPregnancy</samp>
<syntaxhighlight lang="c#">
+
| ''(Optional)'' Whether animals can get pregnant and produce offspring in this building. Default false.
string[] fields = Game1.currentLocation.GetMapPropertySplitBySpaces("ScreenshotRegion");
  −
</syntaxhighlight>
   
|-
 
|-
| <samp>HasMapPropertyWithValue</samp>
+
| <samp>ValidOccupantTypes</samp>
| Get whether a map property is defined and has a non-empty value.
+
| ''(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.
 +
|}
   −
For example:
+
====Item processing====
<syntaxhighlight lang="c#">
+
{| class="wikitable"
bool canUseCasks = Game1.currentLocation.HasMapPropertyWithValue("CanCaskHere");
  −
</syntaxhighlight>
   
|-
 
|-
| <samp>StoreHayInAnySilo</samp>
+
! field
| Add hay to any silo with free space (preferring silos in the current location, then the farm, then anywhere).
+
! effect
 
|-
 
|-
| <samp>TryGetMapProperty</samp>
+
| <samp>HayCapacity</samp>
| Get a map property value as a string, if it's defined.
+
| ''(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.
 
  −
For example:
  −
<syntaxhighlight lang="c#">
  −
if (this.TryGetMapProperty("Warps", out string warps))
  −
{
  −
    // ...
  −
}
  −
</syntaxhighlight>
   
|-
 
|-
| <samp>TryGetMapPropertyAs</samp>
+
| <samp>ItemConversions</samp>
| Get a map property and parse it into into a <samp>Point</samp>, <samp>Rectangle</samp>, or <samp>Vector2</samp> value.
+
| ''(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"
For example:
  −
<syntaxhighlight lang="c#">
  −
if (!this.TryGetMapPropertyAs("MailboxLocation", out Point position))
  −
{
  −
    position = new Point(68, 16); // default value
  −
}
  −
</syntaxhighlight>
   
|-
 
|-
| <samp>removeObjectsAndSpawned</samp>
+
! field
| Remove all objects, bushes, resource clumps, and terrain features within a tile area.
+
! effect
 
|-
 
|-
| <samp>OnBuildingConstructed</samp><br /><samp>OnBuildingMoved</samp><br /><samp>OnBuildingDemolished</samp>
+
| <samp>Id</samp>
| These methods are called for all players when any player constructs, moves, or demolishes a building.
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this rule within the current list.
 
|-
 
|-
|rowspan="3"| <samp>LibraryMuseum</samp>
+
| <samp>RequiredTags</samp>
| <samp>HasDonatedArtifacts()</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.
| Get whether any items have been donated to the [[museum]].
   
|-
 
|-
| <samp>HasDonatedArtifactAt(tile)</samp>
+
| <samp>SourceChest</samp>
| Get whether any donated item is currently placed at the given tile position within the [[museum]].
+
| The ID of the inventory defined in <samp>Chests</samp> from which to take input items.
 
|-
 
|-
| <samp>HasDonatedArtifact(itemId)</samp>
+
| <samp>DestinationChest</samp>
| Get whether an artifact with the given qualified or unqualified item ID has been donated to the [[museum]].
+
| The ID of the inventory defined in <samp>Chests</samp> in which to store output items.
 
|-
 
|-
|rowspan="2"| <samp>MineShaft</samp>
+
| <samp>ProducedItems</samp>
| <samp>GetLevelName</samp>
+
| The output items produced when an input item is converted. This consists of a list of models with these fields:
| 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>
  −
|-
  −
| <samp>IsGeneratedLevel</samp>
  −
| 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>VolcanoDungeon</samp>
  −
| <samp>GetLevelName</samp><br /><samp>IsGeneratedLevel</samp>
  −
| Equivalent to the matching <samp>MineShaft</samp> methods, but for the [[Volcano Dungeon]].
  −
|}
  −
</li>
  −
</ul>
  −
* <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.
  −
 
  −
==What's new for buildings==
  −
===Custom buildings===
  −
You can now add custom buildings by editing the <samp>Data/Buildings</samp> asset. This consists of a string → model lookup, where...
  −
* The key is a unique building ID. The ID should only contain alphanumeric/underscore/dot characters, and should ideally be prefixed with your mod ID like <samp>Example.ModId_BuildingName</samp>.
  −
* The value is a model with the fields listed below.
  −
 
  −
====Required fields====
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 3,978: Line 4,125:  
! effect
 
! effect
 
|-
 
|-
| <samp>Name</samp><br /><samp>Description</samp>
+
| ''common fields''
| A [[#Tokenizable string format|tokenizable string]] for the display name and description (e.g. shown in the construction menu).
+
| 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>Texture</samp>
+
| <samp>Chance</samp>
| The asset name for the texture under the game's Content folder.
+
| ''(Optional)'' The probability that the item will be produced, as a value between 0 (never drops) and 1 (always drops). Default 1 (100% chance).
 
|}
 
|}
  −
====Construction====
  −
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>RequiredCount</samp>
! effect
+
| ''(Optional)'' The number of the input item to consume. Default 1.
 
|-
 
|-
| <samp>Builder</samp>
+
| <samp>MaxDailyConversions</samp>
| ''(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.
+
| ''(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>BuildCost</samp>
+
| <samp>Chests</samp>
| ''(Optional)'' The gold cost to construct the building. Defaults to {{price|0}}.
+
| ''(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:
|-
  −
| <samp>BuildMaterials</samp>
  −
| ''(Optional)'' The materials you must provide to start construction, as a list of models with these fields:
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 4,005: Line 4,149:  
|-
 
|-
 
| <samp>Id</samp>
 
| <samp>Id</samp>
| ''(Optional)'' A key which uniquely identifies this entry within the current list. The ID should only contain alphanumeric/underscore/dot characters. Defaults to the <samp>ItemId</samp> if not specified.
+
| 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>ItemId</samp>
+
| <samp>Type</samp>
| The required item ID (qualified or unqualified).
+
| 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>Amount</samp>
+
| <samp>Sound</samp>
| The number of the item required.
+
| ''(Optional)'' The sound to play once when the player clicks the chest.
|}
   
|-
 
|-
| <samp>BuildDays</samp>
+
| <samp>InvalidItemMessage</samp><br /><samp>InvalidCountMessage</samp><br /><samp>ChestFullMessage</samp>
| ''(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.
+
| ''(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.
 
|-
 
|-
| <samp>BuildCondition</samp>
+
| <samp>InvalidItemMessageCondition</samp>
| ''(Optional)'' A [[#Game state queries|game state query]] which indicates whether the building should be available in the construction menu. Defaults to always available.
+
| ''(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.
 
|-
 
|-
| <samp>BuildMenuDrawOffset</samp>
+
| <samp>DisplayTile</samp>
| ''(Optional)'' A pixel offset to apply to the building sprite when drawn in the construction menu. Default none.
+
| ''(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>AdditionalPlacementTiles</samp>
+
| <samp>DisplayHeight</samp>
| ''(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:
+
| ''(Optional)'' If <samp>DisplayTile</samp> is set, the chest's tile height like <samp>1.5</samp>.
{| class="wikitable"
+
|}
 +
|}
 +
 
 +
====Tile interactions====
 +
{| class="wikitable"
 
|-
 
|-
 
! field
 
! field
 
! effect
 
! effect
 
|-
 
|-
| <samp>TileArea</samp>
+
| <samp>ActionTiles</samp>
| 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.
+
| ''(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:
|-
  −
| <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>IndoorItems</samp>
  −
| ''(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 4,045: Line 4,194:  
|-
 
|-
 
| <samp>Id</samp>
 
| <samp>Id</samp>
| A key which uniquely identifies this entry within the current list. The ID should only contain alphanumeric/underscore/dot characters. For custom entries, this should be prefixed with your mod ID like <samp>Example.ModId_EntryId</samp>.
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the current list.
|-
  −
| <samp>ItemId</samp>
  −
| The [[#Custom items|qualified item ID]] for the item to place.
   
|-
 
|-
 
| <samp>Tile</samp>
 
| <samp>Tile</samp>
| The tile position at which to place the item, specified as an object with <samp>X</samp> and <samp>Y</samp> fields.
+
| The tile position, relative to the building's top-left corner tile.
 
|-
 
|-
| <samp>Indestructible</samp>
+
| <samp>Action</samp>
| ''(Optional)'' Whether to prevent the player from destroying, picking up, or moving the item. Default false.
+
| 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.
 
|}
 
|}
 
|-
 
|-
| <samp>MagicalConstruction</samp>
+
| <samp>DefaultAction</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.
+
| ''(Optional)'' The default tile action if the clicked tile isn't in <samp>ActionTiles</samp>. Default none.
 
|-
 
|-
| <samp>AddMailOnBuild</samp>
+
| <samp>TileProperties</samp>
| ''(Optional)'' A list of [[Modding:Mail data|letter IDs]] to send to all players when the building is constructed for the first time.
+
| ''(Optional)'' The [[Modding:Maps|map tile properties]] to set. This consists of a list of models with these fields:
|}
  −
 
  −
====Upgrades====
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 4,070: Line 4,213:  
! effect
 
! effect
 
|-
 
|-
| <samp>BuildingToUpgrade</samp>
+
| <samp>Id</samp>
| ''(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.
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the current list.
 +
|-
 +
| <samp>Name</samp>
 +
| The tile property name to set.
 +
|-
 +
| <samp>Value</samp>
 +
| ''(Optional)'' The tile property value to set, or omit to set a null value.
 +
|-
 +
| <samp>Layer</samp>
 +
| The name of the map layer whose tiles to change.
 +
|-
 +
| <samp>TileArea</samp>
 +
| 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>IndoorItemMoves</samp>
+
| <samp>AdditionalTilePropertyRadius</samp>
| ''(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:
+
| ''(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.
 +
|}
 +
 
 +
====Advanced====
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 4,080: Line 4,239:  
! effect
 
! effect
 
|-
 
|-
| <samp>Id</samp>
+
| <samp>Metadata</samp>
| A key which uniquely identifies this entry within the current list. The ID should only contain alphanumeric/underscore/dot characters. For custom entries, this should be prefixed with your mod ID like <samp>Example.ModId_EntryId</samp>.
+
| ''(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.
 +
 
 +
The base game recognizes these properties:
 +
{| class="wikitable"
 
|-
 
|-
| <samp>Source</samp>
+
! property
| The tile position on which any item will be moved.
+
! description
 
|-
 
|-
| <samp>Destination</samp>
+
| <samp>ChimneyPosition: {{t|x}} {{t|y}}</samp>
| The tile position to which to move the item.
+
| ''(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>Size</samp>
+
| <samp>ChimneyPosition{{o|upgrade level}}: {{t|x}} {{t|y}}</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.
+
| ''(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>UpgradeSignTile</samp>
+
| <samp>ModData</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>.
+
| ''(Optional)'' A string → string lookup of arbitrary <samp>modData</samp> values to attach to the building when it's constructed.
 
|-
 
|-
| <samp>UpgradeSignHeight</samp>
+
| <samp>CustomFields</samp>
| ''(Optional)'' The pixel height of the upgrade sign when Robin is building an upgrade. Defaults to 0.
+
| The [[#Custom data fields|custom fields]] for this entry.
 
|}
 
|}
   −
====Exterior behavior====
+
===Build anywhere===
 +
{{/doc status|[[Modding:Blueprint data]] and [[Modding:Maps]]|done=false}}
 +
 
 +
* 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).
 +
* Buildings and animals are no longer hardcoded to the [[The Farm|farm]] location (except [[cabin]]s 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===
 +
{{/doc status|[[Modding:Blueprint data]]|done=false}}
 +
 
 +
: ''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"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! type
 +
! method
 
! effect
 
! effect
 
|-
 
|-
| <samp>Size</samp>
+
|rowspan="7"| <samp>Building</samp>
| ''(Optional)'' The building's width and height when constructed, measured in tiles. Defaults to a 1 x 1 area.
+
| <samp>CreateInstanceFromId</samp>
|-
+
| Create a building instance from its type ID in <samp>Data/Buildings</samp>. For example:
| <samp>CollisionMap</samp>
+
<syntaxhighlight lang="c#">
| ''(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.
+
Building shippingBin = Building.CreateInstanceFromId("Shipping Bin", Vector2.Zero); // creates an instance of StardewValley.Buildings.ShippingBin
 
  −
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>
 
</syntaxhighlight>
 
|-
 
|-
| <samp>HumanDoor</samp>
+
| <samp>GetData</samp><br /><samp>TryGetData</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.
+
| Get the data for the building's type from <samp>Data/Building</samp>.
 
|-
 
|-
| <samp>AnimalDoor</samp>
+
| <samp>GetMetadata</samp>
| ''(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.
+
| Get a value from [[#Custom buildings|the <samp>Metadata</samp> field in <samp>Data/Buildings</samp>]] for this building.
 
|-
 
|-
| <samp>AnimalDoorOpenDuration</samp><br /><samp>AnimalDoorCloseDuration</samp>
+
| <samp>GetPaintDataKey</samp>
| ''(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.
+
| Get the key in <samp>Data/PaintData</samp> for this building, if it has any.
 
|-
 
|-
| <samp>AnimalDoorOpenSound</samp><br /><samp>AnimalDoorCloseSound</samp>
+
| <samp>ReloadBuildingData</samp>
| ''(Optional)'' The sound which is played once each time the animal door is opened/closed. Disabled by default.
+
| Apply the latest data in <samp>Data/Buildings</samp> to this building.
|}
  −
 
  −
====Exterior appearance====
  −
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>FinishConstruction</samp>
! effect
+
| If the building is being constructed or upgrade, instantly finish doing so.
 
|-
 
|-
| <samp>SourceRect</samp>
+
| <samp>UpdateTransparency</samp>
| ''(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.
+
| 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>Skins</samp>
+
| <samp>Farm</samp>
| ''(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:
+
| <samp>GetMainFarmHouse</samp>
{| class="wikitable"
+
| Get the main [[farmhouse]] building.
 
|-
 
|-
! field
+
| <samp>GameLocation</samp>
! effect
+
| <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.
 +
 
 +
; [[Fish Pond|Fish pond]] changes
 +
<ul>
 +
<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"
 
|-
 
|-
| <samp>Id</samp>
+
! precedence
| A key which uniquely identifies the skin. The ID should only contain alphanumeric/underscore/dot characters. For custom skins, it should be prefixed with your mod ID like <samp>Example.ModId_SkinName</samp>.
+
! used for
 
|-
 
|-
| <samp>Name</samp><br /><samp>Description</samp>
+
| 0<br /><small>(default value)</small>
| [[#Tokenizable string format|Tokenizable strings]] for the skin's display name and description.
+
| specific fish
 
|-
 
|-
| <samp>Texture</samp>
+
| 100
| The asset name for the texture under the game's Content folder.
+
| custom groups (e.g. desert fish)
 
|-
 
|-
| <samp>Condition</samp>
+
| 500
| ''(Optional)'' A [[#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.
+
| broad fish type (e.g. ocean fish)
 
|-
 
|-
| <samp>BuildDays</samp><br /><samp>BuildCost</samp><br /><samp>BuildMaterials</samp>
+
| 1000
| ''(Optional)'' If set, overrides the equivalent field in the building data.
+
| fallback (e.g. fish category)
 +
|}
 +
</li>
 +
<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>
 +
</ul>
 +
 
 +
==What's new for NPCs==
 +
===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.
 +
 
 +
====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.
 +
 
 +
<dl style="margin-left: 2em;">
 +
<dt>Basic info:</dt>
 +
<dd>
 +
{| class="wikitable"
 
|-
 
|-
| <samp>ShowAsSeparateConstructionEntry</samp>
+
! field
| ''(Optional)'' Whether this skin should be shown as a separate building option in the construction menu (like cabins). Default false.
+
! effect
 
|-
 
|-
| <samp>Metadata</samp>
+
| <samp>DisplayName</samp>
| ''(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.
+
| A [[Modding:Tokenizable strings|tokenizable string]] for the NPC's display name.
|}
   
|-
 
|-
| <samp>FadeWhenBehind</samp>
+
| <samp>Language</samp>
| ''(Optional)'' Whether the building should become semi-transparent when the player is behind it. Default true.
+
| ''(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>.
 +
|-
 +
| <samp>Gender</samp>
 +
| ''(Optional)'' The NPC's gender identity. One of <samp>Female</samp>, <samp>Male</samp>, or <samp>Undefined</samp>. Default <samp>Undefined</samp>.
 +
|-
 +
| <samp>Age</samp>
 +
| ''(Optional)'' The general age of the NPC. One of <samp>Child</samp>, <samp>Teen</samp>, or <samp>Adult</samp>. Default <samp>Adult</samp>.
 +
 
 +
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>.
 +
|-
 +
| <samp>SocialAnxiety</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>.
 +
|-
 +
| <samp>Optimism</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>.
 
|-
 
|-
| <samp>DrawOffset</samp>
+
| <samp>BirthSeason</samp>
| ''(Optional)'' A pixel offset applied to the building sprite's placement in the world. Default 0.
+
| ''(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.
 
|-
 
|-
| <samp>SeasonOffset</samp>
+
| <samp>BirthDay</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.
+
| ''(Optional if non-social)'' The day number for the NPC's birthday. Default 0.
 
|-
 
|-
| <samp>SortTileOffset</samp>
+
| <samp>HomeRegion</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.
+
| ''(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>.
 
|-
 
|-
| <samp>DrawLayers</samp>
+
| <samp>IsDarkSkinned</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:
+
| ''(Optional)'' Whether the NPC has dark skin, which affects the chance of children with the player having dark skin too. Default false.
 +
|}
 +
</dd>
 +
 
 +
<dt>Social features:</dt>
 +
<dd>
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 4,198: Line 4,422:  
! effect
 
! effect
 
|-
 
|-
| <samp>Id</samp>
+
| <samp>CanSocialize</samp>
| A key which uniquely identifies this entry within the current list. The ID should only contain alphanumeric/underscore/dot characters. For custom entries, this should be prefixed with your mod ID like <samp>Example.ModId_DrawLayerId</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.
 
|-
 
|-
| <samp>SourceRect</samp>
+
| <samp>CanBeRomanced</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.
+
| ''(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.
 
|-
 
|-
| <samp>DrawPosition</samp>
+
| <samp>CanReceiveGifts</samp>
| The tile position at which to draw the top-left corner of the texture, relative to the building's top-left corner tile.
+
| ''(Optional)'' Whether players can give gifts to this NPC. Default true.
 +
 
 +
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.
 
|-
 
|-
| <samp>Texture</samp>
+
| <samp>CanCommentOnPurchasedShopItems</samp>
| ''(Optional)'' The asset name of the texture to draw. Defaults to the building's default <samp>Texture</samp> field.
+
| ''(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>.
 +
 
 +
The NPC must also be social per <samp>CanSocialize</samp> to allow it, regardless of this value.
 
|-
 
|-
| <samp>DrawInBackground</samp>
+
| <samp>CanGreetNearbyCharacters</samp>
| ''(Optional)'' Whether to draw the texture behind the building sprite (i.e. underlay) instead of over it.
+
| ''(Optional)'' Whether this NPC can show a speech bubble greeting nearby players or NPCs, and or be greeted by other NPCs. Default true.
 
|-
 
|-
| <samp>SortTileOffset</samp>
+
| <samp>CanVisitIsland</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.
+
| ''(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.
 +
 
 +
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"
 
|-
 
|-
| <samp>OnlyDrawIfChestHasContents</samp>
+
! value
| ''(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.
+
! effect
 
|-
 
|-
| <samp>FrameCount</samp><br /><samp>FramesPerRow</samp><br /><samp>FrameDuration</samp>
+
| <samp>HiddenAlways</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.
+
| They never appear in the calendar.
 
  −
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>
+
| <samp>HiddenUntilMet</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).
+
| Until the player meets them, they don't appear in the calendar.
|}
   
|-
 
|-
| <samp>DrawShadow</samp>
+
| <samp>AlwaysShown</samp>
| ''(Optional)'' Whether to draw an automatic shadow along the bottom edge of the building's sprite. Default true.
+
| They always appear in the calendar.
 
|}
 
|}
   −
====Interior====
+
Defaults to <samp>AlwaysShown</samp>.
 +
|-
 +
| <samp>SocialTab</samp>
 +
| ''(Optional)'' Determines how the NPC is shown on the [[friendship|social tab]] when unlocked. Possible values:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! value
 
! effect
 
! effect
 
|-
 
|-
| <samp>IndoorMap</samp>
+
| <samp>HiddenAlways</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.
+
| They never appear in the social tab.
 +
|-
 +
| <samp>HiddenUntilMet</samp>
 +
| Until the player meets them, they don't appear on the social tab.
 +
|-
 +
| <samp>UnknownUntilMet</samp>
 +
| Until the player meets them, their name on the social tab is replaced with "???".
 
|-
 
|-
| <samp>IndoorMapType</samp>
+
| <samp>AlwaysShown</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...
+
| They always appear in the social tab (including their name).
* <samp>StardewValley.AnimalHouse</samp>;
+
|}
* <samp>StardewValley.Locations.Cabin</samp>;
+
 
* <samp>StardewValley.Locations.Cellar</samp>;
+
Defaults to <samp>UnknownUntilMet</samp>.
* <samp>StardewValley.Locations.DecoratableLocation</samp>;
+
|-
* <samp>StardewValley.Locations.FarmCave</samp>;
+
| <samp>SpouseAdopts</samp>
* <samp>StardewValley.Locations.FarmHouse</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.
* <samp>StardewValley.Shed</samp>;
+
 
* and <samp>StardewValley.SlimeHutch</samp>.
+
The <samp>Target</samp> player is the one they're married to.
Defaults to the generic <samp>StardewValley.GameLocation</samp> class.
   
|-
 
|-
| <samp>NonInstancedIndoorLocation</samp>
+
| <samp>SpouseWantsChildren</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.
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether the spouse will ask to have children. Defaults to true.
   −
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.
+
The <samp>Target</samp> player is the one they're married to.
 
|-
 
|-
| <samp>MaxOccupants</samp>
+
| <samp>SpouseGiftJealousy</samp>
| ''(Optional)'' The maximum number of animals who can live in this building.
+
| ''(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.
 +
 
 +
The <samp>Target</samp> player is the one they're married to, and the <samp>Target</samp> item is the one that was gifted.
 
|-
 
|-
| <samp>AllowAnimalPregnancy</samp>
+
| <samp>SpouseGiftJealousyFriendshipChange</samp>
| ''(Optional)'' Whether animals can get pregnant and produce offspring in this building. Default false.
+
| ''(Optional)'' The [[Friendship|friendship point]] effect when the <samp>SpouseGiftJealously</samp> is triggered. Default -30.
 
|-
 
|-
| <samp>ValidOccupantTypes</samp>
+
| <samp>SpouseRoom</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.
+
| ''(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.
|}
     −
====Item processing====
+
This consists of a model with these fields:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 4,281: Line 4,517:  
! effect
 
! effect
 
|-
 
|-
| <samp>HayCapacity</samp>
+
| <samp>MapAsset</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.
+
| ''(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>MapSourceRect</samp>
 +
| ''(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>ItemConversions</samp>
+
| <samp>SpousePatio</samp>
| ''(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:
+
| ''(Optional)'' The [[Marriage#Spouse Outside Area|NPC's patio area]] on the farm when the player marries them, if any. Default none.
 +
 
 +
This consists of a model with these fields:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 4,291: Line 4,533:  
! effect
 
! effect
 
|-
 
|-
| <samp>Id</samp>
+
| <samp>MapAsset</samp>
| A key which uniquely identifies this rule within the current list. The ID should only contain alphanumeric/underscore/dot characters. For custom entries, this should be prefixed with your mod ID like <samp>Example.ModId_RuleId</samp>.
+
| ''(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>RequiredTags</samp>
+
| <samp>MapSourceRect</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)'' 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>SourceChest</samp>
+
| <samp>SpriteAnimationFrames</samp>
| The ID of the inventory defined in <samp>Chests</samp> from which to take input items.
+
| ''(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.
|-
+
 
| <samp>DestinationChest</samp>
+
For example, here is Abigail playing the flute:
| The ID of the inventory defined in <samp>Chests</samp> in which to store output items.
+
<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>SpriteAnimationPixelOffset</samp>
 +
| ''(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>SpouseFloors</samp><br /><samp>SpouseWallpapers</samp>
 +
| ''(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>IntroductionsQuest</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>ItemDeliveryQuests</samp>
 +
| ''(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>.
 +
 
 +
The NPC must also be social per <samp>CanSocialize</samp> to allow it, regardless of this value.
 +
|-
 +
| <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.
 +
 
 +
The NPC must also be social per <samp>CanSocialize</samp> to be counted, regardless of this value.
 
|-
 
|-
| <samp>ProducedItems</samp>
+
| <samp>EndSlideShow</samp>
| The output items produced when an input item is converted. This consists of a list of models with these fields:
+
| ''(Optional)'' How the NPC appears in the end-game perfection slide show. Possible values:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! value
 
! effect
 
! effect
 
|-
 
|-
| ''common fields''
+
| <samp>Hidden</samp>
| See [[#Item spawn fields|item spawn fields]] for the generic item fields supported by machine output.
+
| The NPC doesn't appear in the slide show.
 
+
|-
If set to an [[#Item queries|item query]] which returns multiple items, one of them will be selected at random.
+
| <samp>MainGroup</samp>
 +
| The NPC is added to the main group of NPCs which walk across the screen.
 
|-
 
|-
| <samp>Chance</samp>
+
| <samp>TrailingGroup</samp>
| ''(Optional)'' The probability that the item will be produced, as a value between 0 (never drops) and 1 (always drops). Default 1 (100% chance).
+
| The NPC is added to the trailing group of NPCs which follow the main group.
 
|}
 
|}
 +
 +
Defaults to <samp>MainGroup</samp>.
 
|-
 
|-
| <samp>RequiredCount</samp>
+
| <samp>FriendsAndFamily</samp>
| ''(Optional)'' The number of the input item to consume. Default 1.
+
| ''(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.
|-
+
 
| <samp>MaxDailyConversions</samp>
+
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.
| ''(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.
   
|}
 
|}
|-
+
</dd>
| <samp>Chests</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:
+
<dt>Dumpster diving:</dt>
 +
<dd>
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 4,333: Line 4,605:  
! effect
 
! effect
 
|-
 
|-
| <samp>Id</samp>
+
| <samp>DumpsterDiveEmote</samp>
| A key which uniquely identifies this chest within the current list. The ID should only contain alphanumeric/underscore/dot characters. For custom entries, this should be prefixed with your mod ID like <samp>Example.ModId_ActionId</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>
   −
This is referenced from the <samp>ItemConversions</samp> field.
+
<dt>Festivals:</dt>
 +
<dd>
 +
{| class="wikitable"
 
|-
 
|-
| <samp>Type</samp>
+
! field
| The inventory type. This must be one of:
+
! effect
* <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>FlowerDanceCanDance</samp>
| ''(Optional)'' The sound to play once when the player clicks the chest.
+
| ''(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>.
 +
 
 +
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>InvalidItemMessage</samp><br /><samp>InvalidCountMessage</samp><br /><samp>ChestFullMessage</samp>
+
| <samp>WinterStarParticipant</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 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>.
* 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.
   
|-
 
|-
| <samp>InvalidItemMessageCondition</samp>
+
| <samp>WinterStarGifts</samp>
| ''(Optional)'' A [[#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.
+
| 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:
 +
{| class="wikitable"
 
|-
 
|-
| <samp>DisplayTile</samp>
+
! field
| ''(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.
+
! effect
 
|-
 
|-
| <samp>DisplayHeight</samp>
+
| ''common fields''
| ''(Optional)'' If <samp>DisplayTile</samp> is set, the chest's tile height like <samp>1.5</samp>.
+
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields.
 +
 
 +
If set to an [[Modding:Item queries|item query]] which returns multiple items, one of them will be selected at random.
 
|}
 
|}
 
|}
 
|}
   −
====Tile interactions====
+
<dt>Spawn rules:</dt>
 +
<dd>
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 4,371: Line 4,650:  
! effect
 
! effect
 
|-
 
|-
| <samp>ActionTiles</samp>
+
| <samp>UnlockConditions</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:
+
| ''(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.
 +
|-
 +
| <samp>SpawnIfMissing</samp>
 +
| ''(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.
 +
|-
 +
| <samp>Home</samp>
 +
| ''(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:  
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 4,378: Line 4,665:  
! effect
 
! effect
 
|-
 
|-
| <samp>Id</samp>
+
| <samp>ID</samp>
| A key which uniquely identifies this entry within the current list. The ID should only contain alphanumeric/underscore/dot characters. For custom entries, this should be prefixed with your mod ID like <samp>Example.ModId_ActionId</samp>.
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the current list.
 +
|-
 +
| <samp>Location</samp>
 +
| ''(Optional)'' The internal name for the home location where this NPC spawns and returns each day. Default none.
 
|-
 
|-
 
| <samp>Tile</samp>
 
| <samp>Tile</samp>
| The tile position, relative to the building's top-left corner tile.
+
| ''(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>.
 
|-
 
|-
| <samp>Action</samp>
+
| <samp>Direction</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.
+
| ''(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>.
|}
   
|-
 
|-
| <samp>DefaultAction</samp>
+
| <samp>Condition</samp>
| ''(Optional)'' The default tile action if the clicked tile isn't in <samp>ActionTiles</samp>. Default none.
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this entry can be selected. Default true.
 +
|}
 +
|}
 +
</dd>
 +
 
 +
<dt>Appearance & sprite:</dt>
 +
<dd>
 +
{| class="wikitable"
 +
|-
 +
! field
 +
! effect
 +
|-
 +
| <samp>TextureName</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.
 
|-
 
|-
| <samp>TileProperties</samp>
+
| <samp>Appearance</samp>
| ''(Optional)'' The [[Modding:Maps|map tile properties]] to set. This consists of a list of models with these fields:
+
| ''(Optional)'' The portrait/sprite textures to use.
 +
 
 +
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"
 
{| class="wikitable"
 
|-
 
|-
Line 4,399: Line 4,707:  
|-
 
|-
 
| <samp>Id</samp>
 
| <samp>Id</samp>
| A key which uniquely identifies this entry within the current list. The ID should only contain alphanumeric/underscore/dot characters. For custom entries, this should be prefixed with your mod ID like <samp>Example.ModId_EntryId</samp>.
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the current list.
 
|-
 
|-
| <samp>Name</samp>
+
| <samp>Season</samp>
| The tile property name to set.
+
| ''(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.
 
|-
 
|-
| <samp>Value</samp>
+
| <samp>Indoors</samp><br /><samp>Outdoors</samp>
| ''(Optional)'' The tile property value to set, or omit to set a null value.
+
| ''(Optional)'' Whether this appearance should be used when indoors and/or outdoors. Both default to true.
 
|-
 
|-
| <samp>Layer</samp>
+
| <samp>Condition</samp>
| The name of the map layer whose tiles to change.
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this entry can be selected. Default true.
 
|-
 
|-
| <samp>TileArea</samp>
+
| <samp>Portrait</samp><br /><samp>Sprite</samp>
| 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.
+
| ''(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.
|}
   
|-
 
|-
| <samp>AdditionalTilePropertyRadius</samp>
+
| <samp>IsIslandAttire</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)'' Whether this is island beach attire worn at the resort. Default false.
|}
     −
====Advanced====
+
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.
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>Precedence</samp>
! effect
+
| ''(Optional)'' The order in which this entry should be checked, where lower values are checked first. This can be a negative value. Default 0.
 
|-
 
|-
| <samp>Metadata</samp>
+
| <samp>Weight</samp>
| ''(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.
+
| ''(Optional)'' If multiple entries with the same <samp>Precedence</samp> 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.
 +
|}
   −
The base game recognizes these properties:
+
'''Note:''' the default textures based on <samp>TextureName</samp> must still exist, even if you use this field to override them.
{| class="wikitable"
   
|-
 
|-
! property
+
| <samp>MugShotSourceRect</samp>
! description
+
| ''(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.
 
|-
 
|-
| <samp>ChimneyPosition: {{t|x}} {{t|y}}</samp>
+
| <samp>Size</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).
+
| ''(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>.
 +
 
 +
'''Note:''' sizes bigger than 16×32 will cause issues like broken spawning, pathfinding, misalignment in the [[perfection]] end-game slide show, etc.
 
|-
 
|-
| <samp>ChimneyPosition{{o|upgrade level}}: {{t|x}} {{t|y}}</samp>
+
| <samp>Breather</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>).
+
| ''(Optional)'' Whether the chest on the NPC's overworld sprite puffs in and out as they breathe. Default true</samp>.
|}
  −
 
  −
This can also contain arbitrary custom properties, which C# mods can read using <samp>building.GetMetadata(key)</samp>.
   
|-
 
|-
| <samp>BuildingType</samp>
+
| <samp>BreathChestRect</samp>
| ''(Optional)'' The full name of the C# type to instantiate for the building instance. Defaults to a generic <samp>Building</samp> instance.
+
| ''(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.
 
  −
'''⚠ 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>
+
| <samp>BreathChestPosition</samp>
| ''(Optional)'' A string → string lookup of arbitrary <samp>modData</samp> values to attach to the building when it's constructed.
+
| ''(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>CustomFields</samp>
+
| <samp>Shadow</samp>
| The [[#Custom data fields|custom fields]] for this entry.
+
| ''(Optional)'' The options for the shadow to draw under the NPC, or omit to apply the default shadow behavior.
|}
     −
===Build anywhere===
+
This consists of a model with these fields:
Buildings and animals are no longer hardcoded to the [[The Farm|farm]] location (except [[cabin]]s and the [[farmhouse]] which still are). 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).
     −
===Other building changes===
  −
: ''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"
 
{| class="wikitable"
 
|-
 
|-
! type
+
! field
! method
   
! effect
 
! effect
 
|-
 
|-
|rowspan="7"| <samp>Building</samp>
+
| <samp>Visible</samp>
| <samp>CreateInstanceFromId</samp>
+
| ''(Optional)'' Whether the shadow should be drawn. Default true.
| Create a building instance from its type ID in <samp>Data/Buildings</samp>. For example:
  −
<syntaxhighlight lang="c#">
  −
Building shippingBin = Building.CreateInstanceFromId("Shipping Bin", Vector2.Zero); // creates an instance of StardewValley.Buildings.ShippingBin
  −
</syntaxhighlight>
   
|-
 
|-
| <samp>GetData</samp>
+
| <samp>Offset</samp>
| Get the data for this building's type from <samp>Data/Building</samp>.
+
| ''(Optional)'' A [[Modding:Common data field types#Point|point]] pixel offset applied to the shadow position. Default zero.
 
|-
 
|-
| <samp>GetMetadata</samp>
+
| <samp>Scale</samp>
| Get a value from [[#Custom buildings|the <samp>Metadata</samp> field in <samp>Data/Buildings</samp>]] for this building.
+
| ''(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, <samp>0.5</samp> means half the size it'd be drawn if you didn't specify a scale.
 +
|}
 
|-
 
|-
| <samp>GetPaintDataKey</samp>
+
| <samp>EmoteOffset</samp>
| Get the key in <samp>Data/PaintData</samp> for this building, if it has any.
+
| ''(Optional)'' A [[Modding:Common data field types#Point|point]] pixel offset applied to emote drawn over the NPC. Default zero.
 
|-
 
|-
| <samp>ReloadBuildingData</samp>
+
| <samp>ShakePortraits</samp>
| Apply the latest data in <samp>Data/Buildings</samp> to this building.
+
| ''(Optional)'' The portrait indexes which should shake when displayed. Default none.
 
|-
 
|-
| <samp>FinishConstruction</samp>
+
| <samp>KissSpriteIndex</samp>
| If the building is being constructed or upgrade, instantly finish doing so.
+
| ''(Optional)'' If the NPC can be married, the sprite index within their <samp>Texture</samp> to use when kissing a player. Default 28.
 
|-
 
|-
| <samp>UpdateTransparency</samp>
+
| <samp>KissSpriteFacingDirection</samp>
| Update the building transparency on tick for the local player's position.
+
| ''(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>
   −
This method mainly exists to let mods override/patch the transparency logic.
+
<dt>[[Secrets#Gift Log|Hidden gift log emote]]:</dt>
 +
<dd>
 +
{| class="wikitable"
 +
|-
 +
! field
 +
! effect
 +
|-
 +
| <samp>HiddenProfileEmoteSound</samp>
 +
| ''(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>.
 +
|-
 +
| <samp>HiddenProfileEmoteDuration</samp>
 +
| ''(Optional)'' For the [[Secrets#Gift Log|hidden gift log emote]], how long the animation plays measured in milliseconds. Defaults to 4000 (4 seconds).
 +
|-
 +
| <samp>HiddenProfileEmoteStartFrame</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.
 
|-
 
|-
| <samp>Farm</samp>
+
| <samp>HiddenProfileEmoteFrameCount</samp>
| <samp>GetMainFarmHouse</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.
| Get the main [[farmhouse]] building.
+
 
 +
This has no effect if <samp>HiddenProfileEmoteStartFrame</samp> isn't set.
 
|-
 
|-
| <samp>GameLocation</samp>
+
| <samp>HiddenProfileEmoteFrameDuration</samp>
| <samp>OnParentBuildingUpgraded</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.
| Called when the building containing this location is upgraded, if applicable.
+
 
 +
This has no effect if <samp>HiddenProfileEmoteStartFrame</samp> isn't set.
 
|}
 
|}
</li>
+
</dd>
</ul>
  −
* Added building <samp>id</samp> field, which uniquely identifies each building in the world.
     −
; [[Junimo Hut|Junimo hut]] changes
+
<dt>Advanced:</dt>
* The <samp>JunimoHut.cropHarvestRange</samp> field is now per-building and editable.
+
<dd>
 
  −
; [[Fish Pond|Fish pond]] changes
  −
<ul>
  −
<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"
 
|-
 
|-
! precedence
+
! field
! used for
+
! effect
 
|-
 
|-
| 0<br /><small>(default value)</small>
+
| <samp>CustomFields</samp>
| specific fish
+
| The [[#Custom data fields|custom fields]] for this entry.
 
|-
 
|-
| 100
+
| <samp>FormerCharacterNames</samp>
| custom groups (e.g. desert fish)
+
| ''(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).
|-
  −
| 500
  −
| broad fish type (e.g. ocean fish)
  −
|-
  −
| 1000
  −
| fallback (e.g. fish category)
  −
|}
  −
</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>
  −
</ul>
     −
==What's new for NPCs==
+
A former name is only applied if:
===Custom NPCs===
+
# it doesn't match a current ID in <samp>Data/Characters</samp>;
[[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.
+
# the save has an NPC with the former name;
 +
# the save doesn't already have an NPC with the new name.
   −
====Format====
+
For example:
This consists of a string → model lookup, where...
+
<syntaxhighlight lang="js">
* The key is the unique internal NPC name.
+
"FormerCharacterNames": [ "SomeOldName" ]
* The value is a model with the following fields.
+
</syntaxhighlight>
   −
<dl style="margin-left: 2em;">
+
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).
<dt>Basic info:</dt>
  −
<dd>
  −
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>FestivalVanillaActorIndex</samp>
! effect
+
| ''(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.
|-
  −
| <samp>DisplayName</samp>
  −
| A [[#Tokenizable string format|tokenizable string]] for the NPC's display name.
  −
|-
  −
| <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>.
  −
|-
  −
| <samp>Gender</samp>
  −
| ''(Optional)'' The NPC's gender identity. One of <samp>Female</samp>, <samp>Male</samp>, or <samp>Undefined</samp>. Default <samp>Undefined</samp>.
  −
|-
  −
| <samp>Age</samp>
  −
| ''(Optional)'' The general age of the NPC. One of <samp>Child</samp>, <samp>Teen</samp>, or <samp>Adult</samp>. Default <samp>Adult</samp>.
  −
 
  −
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>.
  −
|-
  −
| <samp>SocialAnxiety</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>.
  −
|-
  −
| <samp>Optimism</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>.
  −
|-
  −
| <samp>BirthSeason</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.
  −
|-
  −
| <samp>BirthDay</samp>
  −
| ''(Optional if non-social)'' The day number for the NPC's birthday. Default 0.
  −
|-
  −
| <samp>HomeRegion</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>.
   
|}
 
|}
 
</dd>
 
</dd>
 +
</dl>
   −
<dt>Social features:</dt>
+
====Examples====
<dd>
+
For example, this content pack adds a new ''Amabel'' NPC with full social features:
{| class="wikitable"
  −
|-
  −
! field
  −
! effect
  −
|-
  −
| <samp>CanBeRomanced</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.
  −
|-
  −
| <samp>LoveInterest</samp>
  −
| ''(Optional)'' Unused.
  −
|-
  −
| <samp>Calendar</samp>
  −
| ''(Optional)'' Determines when the NPC's birthday is shown in the [[calendar]]. Possible values:
  −
{| class="wikitable"
  −
|-
  −
! value
  −
! 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>AlwaysShown</samp>
  −
| They always appear in the calendar.
  −
|}
     −
Defaults to <samp>AlwaysShown</samp>.
+
{{#tag:syntaxhighlight|<nowiki>
|-
+
{
| <samp>SocialTab</samp>
+
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
| ''(Optional)'' Determines how the NPC is shown on the [[friendship|social tab]] when unlocked. Possible values:
+
    "Changes": [
{| class="wikitable"
+
        {
|-
+
            "Action": "EditData",
! value
+
            "Target": "Data/Characters",
! effect
+
            "Entries": {
|-
+
                "{{ModId}}_Amabel": {
| <samp>HiddenAlways</samp>
+
                    "DisplayName": "Amabel", // this would normally use {{i18n:}} to support translations
| They never appear in the social tab.
+
                    "BirthSeason": "Fall",
|-
+
                    "BirthDay": 14,
| <samp>HiddenUntilMet</samp>
+
                    "HomeRegion": "Town",
| Until the player meets them, they don't appear on the social tab.
+
                    "Gender": "Female",
|-
+
                    "Age": "Teen",
| <samp>UnknownUntilMet</samp>
+
                    "Manner": "Rude",
| Until the player meets them, their name on the social tab is replaced with "???".
+
                    "SocialAnxiety": "Outgoing",
|-
+
                    "Optimism": "Neutral",
| <samp>AlwaysShown</samp>
  −
| They always appear in the social tab (including their name).
  −
|}
     −
Defaults to <samp>UnknownUntilMet</samp>.
+
                    "CanBeRomanced": true,
|-
+
                    "LoveInterest": "Abigail",
| <samp>SocialTabIconSourceRect</samp>
  −
| ''(Optional)'' The pixel area in the character's sprite texture to show as their icon in the social menu. This should be approximately 24x24 pixels or smaller. Defaults to part of their first sprite.
  −
|-
  −
| <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.
     −
This consists of a model with these fields:
+
                    "Home": [
{| class="wikitable"
+
                        {
|-
+
                            "Id": "Default",
! field
+
                            "Location": "SeedShop",
! effect
+
                            "Tile": { "X": 1, "Y": 9 },
|-
+
                            "Direction": "Left"
| <samp>MapAsset</samp>
+
                        }
| ''(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>MapSourceRect</samp>
+
            }
| ''(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>.
+
        }
|}
+
    ]
|-
+
}</nowiki>|lang=javascript}}
| <samp>SpousePatio</samp>
  −
| ''(Optional)'' The [[Marriage#Spouse Outside Area|NPC's patio area]] on the farm when the player marries them, if any. Default none.
     −
This consists of a model with these fields:
+
You can also add non-social NPCs which don't have birthdays or friendship points, accept gifts, give quests, etc:
{| class="wikitable"
+
{{#tag:syntaxhighlight|<nowiki>
|-
+
{
! field
+
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
! effect
+
    "Changes": [
|-
+
        {
| <samp>MapAsset</samp>
+
            "Action": "EditData",
| ''(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>.
+
            "Target": "Data/Characters",
|-
+
            "Entries": {
| <samp>MapSourceRect</samp>
+
                "{{ModId}}_Belwick": {
| ''(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>.
+
                    "DisplayName": "Belwick", // this would normally use {{i18n:}} to support translations
|-
+
 
| <samp>SpriteAnimationFrames</samp>
+
                    "SocialTab": "HiddenAlways",
| ''(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.
+
                    "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, here is Abigail playing the flute:
+
For example, you can load indoor/outdoor outfits for a custom NPC to swap between automatically:
 
<syntaxhighlight lang="js">
 
<syntaxhighlight lang="js">
"SpriteAnimationFrames": [
+
// add base indoor/outdoor sprites
     [16, 500], // show index 16 for 500ms
+
{
     [17, 500],
+
    "Action": "Load",
     [18, 500],
+
    "Target": "Characters/Johnny_Indoor, Characters/Johnny_Outdoor, Portraits/Johnny_Indoor, Portraits/Johnny_Outdoor",
     [19]      // if duration is omitted, defaults to 100ms
+
     "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>
 
</syntaxhighlight>
|-
+
 
| <samp>SpriteAnimationPixelOffset</samp>
+
See the <samp>Appearance</samp> field in [[#Custom NPCs|custom NPC data]] for more info.
| ''(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.
+
 
|}
+
===Custom farm animals===
|-
+
{{/doc status|[[Modding:Animal data]]|done=true}}
| <samp>SocializeConditions</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). Default 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).
|-
+
 
| <samp>CanVisitIslandCondition</samp>
+
===Custom pets===
| ''(Optional)'' A [[#Game state queries|game state query]] which indicates whether the NPC can visit the [[Ginger Island]] resort once it's unlocked. The NPC must be social (per <samp>SocializeConditions</samp>) to visit the island, regardless of this value. Default true.
+
{{/doc status|a new doc page|done=false}}
|-
+
 
| <samp>ExcludeFromIntroductionsQuest</samp>
+
====Format====
| ''(Optional)'' Whether this NPC will be ignored for the [[Quests#List of Story Quests|''introductions'' quest]]. Default false.
+
You can now create and customize [[Animals#Cat or Dog|pet]]s & pet breeds by editing the new <samp>Data/Pets</samp> asset.
|-
+
 
| <samp>ExcludeFromPerfectionScore</samp>
+
This consists of a string → model lookup, where...
| ''(Optional)'' Whether to exclude this NPC when checking whether the player has max friendships with every NPC for the perfection score. Default false.
+
* 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.
| <samp>EndSlideShow</samp>
+
 
| ''(Optional)'' How the NPC appears in the end-game perfection slide show. Possible values:
+
=====Basic info=====
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! value
+
! field
 
! effect
 
! effect
 
|-
 
|-
| <samp>Hidden</samp>
+
| <samp>DisplayName</samp>
| The NPC doesn't appear in the slide show.
+
| 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.
|-
  −
| <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.
   
|}
 
|}
   −
Defaults to <samp>MainGroup</samp>.
+
=====Audio & sprites=====
|-
  −
| <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.
  −
 
  −
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.
  −
|}
  −
</dd>
  −
 
  −
<dt>Spawn rules:</dt>
  −
<dd>
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 4,738: Line 4,993:  
! effect
 
! effect
 
|-
 
|-
| <samp>UnlockConditions</samp>
+
| <samp>BarkSound</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.
+
| The [[#Custom audio|cue ID]] for the pet's occasional 'bark' sound.
 +
|-
 +
| <samp>ContentSound</samp>
 +
| The [[#Custom audio|cue ID]] for the sound which the pet makes when you pet it.
 
|-
 
|-
| <samp>SpawnIfMissing</samp>
+
| <samp>RepeatContentSoundAfter</samp>
| ''(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.
+
| ''(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).
 
|-
 
|-
| <samp>Home</samp>
+
| <samp>EmoteOffset</samp>
| ''(Optional)'' The default place where this NPC spawns and returns each day. If there are multiple entries, the first matching one is used.
+
| ''(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.
 +
|}
   −
This consists of a list of models with these fields:
+
=====Events=====
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 4,753: Line 5,012:  
! effect
 
! effect
 
|-
 
|-
| <samp>ID</samp>
+
| <samp>EventOffset</samp>
| A key which uniquely identifies this entry. The ID should only contain alphanumeric/underscore/dot characters. When adding a custom home to an existing NPC, this should be prefixed with your mod ID like <samp>Example.ModId_HomeName</samp>; when adding a single home for your own NPC, you can just set the ID to <samp>Default</samp>.
+
| ''(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.
 
|-
 
|-
| <samp>Location</samp>
+
| <samp>AdoptionEventLocation</samp><br /><samp>AdoptionEventId</samp>
| ''(Optional)'' The internal name for the home location where this NPC spawns and returns each day. Default none.
+
| ''(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>Tile</samp>
+
| <samp>SummitPerfectionEvent</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 <samp>(0, 0)</samp>.
+
| ''(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.
|-
+
 
| <samp>Direction</samp>
+
This consists of a model with these fields:
| ''(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>.
  −
|-
  −
| <samp>Condition</samp>
  −
| ''(Optional)'' A [[#Game state queries|game state query]] which indicates whether this entry can be selected. Default true.
  −
|}
  −
|}
  −
</dd>
     −
<dt>Appearance & sprite:</dt>
  −
<dd>
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 4,778: Line 5,028:  
! effect
 
! effect
 
|-
 
|-
| <samp>TextureName</samp>
+
| <samp>SourceRect</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.
+
| The source rectangle within the pet's texture to draw.
 
|-
 
|-
| <samp>Size</samp>
+
| <samp>AnimationLength</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>.
+
| The number of frames to show starting from the <samp>SourceRect</samp>.
 
  −
'''Note:''' sizes bigger than 16×32 will cause issues like broken spawning, pathfinding, misalignment in the [[perfection]] end-game slide show, etc.
   
|-
 
|-
| <samp>Breather</samp>
+
| <samp>Motion</samp>
| ''(Optional)'' Whether the chest on the NPC's overworld sprite puffs in and out as they breathe. Default true</samp>.
+
| The motion to apply to the pet sprite.
 
|-
 
|-
| <samp>KissSpriteIndex</samp>
+
| <samp>Flipped</samp>
| ''(Optional)'' If the NPC can be married, the sprite index within their <samp>Texture</samp> to use when kissing a player. Default 28.
+
| ''(Optional)'' Whether to flip the pet sprite left-to-right. Default false.
 
|-
 
|-
| <samp>KissSpriteFacingDirection</samp>
+
| <samp>PingPong</samp>
| ''(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.
+
| ''(Optional)'' Whether to apply the 'ping pong' effect to the pet sprite animation. Default false.
 +
|}
 
|}
 
|}
</dd>
     −
<dt>[[Secrets#Gift Log|Hidden gift log emote]]:</dt>
+
=====Gifts=====
<dd>
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 4,804: Line 5,051:  
! effect
 
! effect
 
|-
 
|-
| <samp>HiddenProfileEmoteSound</samp>
+
| <samp>GiftChance</samp>
| ''(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>.
+
| ''(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>HiddenProfileEmoteDuration</samp>
+
| <samp>Gifts</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)'' 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"
 
|-
 
|-
| <samp>HiddenProfileEmoteStartFrame</samp>
+
! field
| ''(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.
+
! 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>HiddenProfileEmoteFrameCount</samp>
+
| <samp>Weight</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)'' 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.
 +
|}
 +
|}
   −
This has no effect if <samp>HiddenProfileEmoteStartFrame</samp> isn't set.
+
=====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>HiddenProfileEmoteFrameDuration</samp>
+
| <samp>Behaviors</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 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 has no effect if <samp>HiddenProfileEmoteStartFrame</samp> isn't set.
+
This consists of a list of models with these fields:
|}
  −
</dd>
     −
<dt>Advanced:</dt>
+
<dl>
 +
<dt>Required fields:</dt>
 
<dd>
 
<dd>
 
{| class="wikitable"
 
{| class="wikitable"
Line 4,832: Line 5,109:  
! effect
 
! effect
 
|-
 
|-
| <samp>FestivalVanillaActorIndex</samp>
+
| <samp>Id</samp>
| ''(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.
+
| 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).
|-
  −
| <samp>CustomFields</samp>
  −
| The [[#Custom data fields|custom fields]] for this entry.
   
|}
 
|}
 
</dd>
 
</dd>
</dl>
     −
====Examples====
+
<dt>Direction:</dt>
For example, this content pack adds a new ''Amabel'' NPC with full social features:
+
<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>
   −
{{#tag:syntaxhighlight|<nowiki>
+
<dt>Movement:</dt>
{
+
<dd>
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
+
{| class="wikitable"
    "Changes": [
+
|-
        {
+
! field
            "Action": "EditData",
+
! effect
            "Target": "Data/Characters",
+
|-
            "Entries": {
+
| <samp>WalkInDirection</samp>
                "Example.ModId_Amabel": {
+
| ''(Optional)'' Whether to walk in the pet's facing direction. Default false.
                    "DisplayName": "Amabel", // this would normally use {{i18n:}} to support translations
+
|-
                    "BirthSeason": "Fall",
+
| <samp>MoveSpeed</samp>
                    "BirthDay": 14,
+
| ''(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).
                    "HomeRegion": "Town",
+
|}
                    "Gender": "Female",
+
</dd>
                    "Age": "Teen",
  −
                    "Manner": "Rude",
  −
                    "SocialAnxiety": "Outgoing",
  −
                    "Optimism": "Neutral",
     −
                    "CanBeRomanced": true,
+
<dt>Audio:</dt>
                    "LoveInterest": "Abigail",
+
<dd>
 
+
{| class="wikitable"
                    "Home": [
+
|-
                        {
+
! field
                            "Id": "Default",
+
! effect
                            "Location": "SeedShop",
+
|-
                            "Tile": { "X": 1, "Y": 9 },
+
| <samp>SoundOnStart</samp>
                            "Direction": "Left"
+
| ''(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.
}</nowiki>|lang=javascript}}
+
|}
 +
</dd>
   −
You can also add non-social NPCs which don't have birthdays or friendship points, accept gifts, give quests, etc:
+
<dt>Behavior transitions:</dt>
{{#tag:syntaxhighlight|<nowiki>
+
<dd>
{
+
{| class="wikitable"
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
+
|-
    "Changes": [
+
! field
        {
+
! effect
            "Action": "EditData",
+
|-
            "Target": "Data/Characters",
+
| <samp>AnimationEndBehaviorChanges</samp><br /><samp>TimeoutBehaviorChanges</samp><br /><samp>PlayerNearbyBehaviorChanges</samp><br /><samp>RandomBehaviorChanges</samp><br /><samp>JumpLandBehaviorChanges</samp>
            "Entries": {
+
| ''(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.
                "Example.ModId_Belwick": {
  −
                    "DisplayName": "Belwick", // this would normally use {{i18n:}} to support translations
     −
                    "SocialTab": "HiddenAlways",
+
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>).
                    "SocializeConditions": "FALSE",
  −
                    "ExcludeFromIntroductionsQuest": true,
  −
                    "ExcludeFromPerfectionScore": true,
  −
                    "EndSlideShow": true
  −
                }
  −
            }
  −
        }
  −
    ]
  −
}</nowiki>|lang=javascript}}
     −
Most item data assets work just like <samp>Data/ObjectInformation</samp>. See also specific info for [[#Custom fruit trees|custom fruit trees]], [[#Custom tools|custom tools]], and [[#Custom melee weapon data|melee weapons]].
+
These consist of a list of models with these fields:
 
  −
===Custom farm animals===
  −
You can now create and customize [[Animals|farm animals]] by editing the revamped <samp>Data/FarmAnimals</samp> asset.
  −
 
  −
This consists of a string → model lookup, where...
  −
* The key is a unique farm animal ID. This should only contain alphanumeric/underscore/dot characters, and custom entries should be prefixed with your mod ID like <samp>Example.ModId_AnimalId</samp>.
  −
* The value is a model with the fields listed below.
  −
 
  −
====Main info====
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 4,918: Line 5,183:  
! effect
 
! effect
 
|-
 
|-
| <samp>DisplayName</samp>
+
| <samp>Behavior</samp><br /><samp>LeftBehavior</samp><br /><samp>RightBehavior</samp><br /><samp>UpBehavior</samp><br /><samp>DownBehavior</samp>
| A [[#Tokenizable string format|tokenizable string]] for the animal type's display name.
+
| 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>House</samp>
+
| <samp>OutsideOnly</samp>
| 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.
+
| ''(Optional)'' Whether the transition can only happen if the pet is outside. Default false.
 
|-
 
|-
| <samp>Gender</samp>
+
| <samp>Weight</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>.
+
| ''(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 possible values are:
  −
{| class="wikitable"
   
|-
 
|-
! value
+
| <samp>Duration</samp><br /><samp>MinimumDuration</samp><br /><samp>MaximumDuration</samp>
! effect
+
| ''(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>Male</samp><br /><samp>Female</samp>
+
| <samp>RandomBehaviorChangeChance</samp>
| Farm animals of this type are always male or always female.
+
| ''(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.
|-
  −
| <samp>MaleOrFemale</samp>
  −
| The gender of each animal is randomized based on its internal unique ID.
  −
|}
   
|}
 
|}
 +
</dd>
   −
====Animal shop====
+
<dt>Animation and per-frame sounds:</dt>
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.
+
<dd>
 
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 4,949: Line 5,208:  
! effect
 
! effect
 
|-
 
|-
| <samp>PurchasePrice</samp>
+
| <samp>Animation</samp>
| ''(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.
+
| ''(Optional)'' The animation frames to play while this state is active. This consists of a list of models with these fields:
 +
{| class="wikitable"
 
|-
 
|-
| <samp>ShopTexture</samp>
+
! field
| ''(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).
+
! effect
 
|-
 
|-
| <samp>ShopSourceRect</samp>
+
| <samp>Frame</samp>
| ''(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.
+
| The frame index in the animation. This should be an incremental number starting at 0.
 
|-
 
|-
| <samp>RequiredBuilding</samp>
+
| <samp>Duration</samp>
| ''(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.
+
| The millisecond duration for which the frame should be kept on-screen before continuing to the next frame.
 
|-
 
|-
| <samp>UnlockCondition</samp>
+
| <samp>HitGround</samp>
| ''(Optional)'' A [[#Game state queries|game state query]] which indicates whether the farm animal is available in the shop menu. Default always unlocked.
+
| ''(Optional)'' Whether to play the footstep sound for the tile under the pet when the frame starts. Default false.
 
|-
 
|-
| <samp>ShopDisplayName</samp>
+
| <samp>Jump</samp>
| ''(Optional)'' A [[#Tokenizable string format|tokenizable string]] for the display name shown in the shop menu. Defaults to the <samp>DisplayName</samp> field.
+
| ''(Optional)'' Whether the pet should perform a small hop when the frame starts, including a 'dwop' sound. Default false.
 
|-
 
|-
| <samp>ShopDescription</samp>
+
| <samp>Sound</samp>
| ''(Optional)'' A [[#Tokenizable string format|tokenizable string]] for the tooltip description shown in the shop menu. Defaults to none.
+
| ''(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>ShopMissingBuildingDescription</samp>
+
| <samp>SoundRange</samp><br /><samp>SoundRangeFromBorder</samp><br /><samp>SoundIsVoice</samp>
| ''(Optional)'' A [[#Tokenizable string format|tokenizable string]] which overrides <samp>ShopDescription</samp> if the <samp>RequiredBuilding</samp> isn't built. Defaults to none.
+
| See description for the equivalent behavior fields, but applies to the frame's <samp>Sound</samp> field instead.
 +
|}
 
|-
 
|-
| <samp>AlternatePurchaseTypes</samp>
+
| <samp>Shake</samp>
| ''(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:
+
| ''(Optional)'' The millisecond duration for which to shake the pet when the state starts. Default 0.
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>LoopMode</samp>
! effect
+
| ''(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>AnimalIDs</samp>
+
| <samp>AnimationMinimumLoops</samp><br /><samp>AnimationMaximumLoops</samp>
| 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.
+
| ''(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).
|-
  −
| <samp>Condition</samp>
  −
| ''(Optional)'' A [[#Game state queries|game state query]] which indicates whether this variant entry is available. Default always enabled.
   
|}
 
|}
 
+
</dd>
If multiple are listed, the first available variant is returned. Default none.
+
</dl>
 
|}
 
|}
   −
====Hatching====
+
=====Breeds=====
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 4,996: Line 5,253:  
! effect
 
! effect
 
|-
 
|-
| <samp>EggItemIds</samp>
+
| <samp>Breeds</samp>
| ''(Optional)'' A list of the [[#Custom items|object IDs]] that can be placed in the [[incubator]] or [[Ostrich Incubator|ostrich incubator]] to hatch this animal. If the animal's <samp>House</samp> field doesn't match the current building, the entry will be ignored. Default none.
+
| 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"
 
|-
 
|-
| <samp>IncubationTime</samp>
+
! field
| ''(Optional)'' How long eggs incubate before they hatch. Default 9000 minutes.
+
! effect
 
|-
 
|-
| <samp>IncubatorParentSheetOffset</samp>
+
| <samp>ID</samp>
| ''(Optional)'' An offset applied to the incubator's sprite index when it's holding an egg. Default 1.
+
| The unique ID for the breed within the pet type.
 
+
|-
The vanilla values are:
+
| <samp>Texture</samp>
{| class="wikitable"
+
| 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.
 
|-
 
|-
! offset
+
| <samp>IconTexture</samp>
! [[incubator]]
+
| 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.
! [[Ostrich Incubator|ostrich incubator]]
   
|-
 
|-
| 0
+
| <samp>IconSourceRect</samp>
| empty incubator
+
| 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.
| empty incubator
   
|-
 
|-
| 1
+
| <samp>BarkOverride</samp>
| small white egg
+
| ''(Optional)'' Override the pet's <samp>BarkSound</samp> field for this breed, if set.
| large brown egg
   
|-
 
|-
| 2
+
| <samp>VoicePitch</samp>
| small brown egg
+
| ''(Optional)'' The [[wikipedia:Pitch (music)|pitch]] applied to the pet's bark sound, measured as a decimal value relative to 1. Defaults to 1.
| ''invalid'' (will show [[Junimo Chest|Junimo chest]] sprite)
   
|}
 
|}
|-
  −
| <samp>BirthText</samp>
  −
| ''(Optional)'' A [[#Tokenizable string format|tokenizable string]] for the message shown when entering the building after the egg hatched. Defaults to the text "<samp>???</samp>".
   
|}
 
|}
   −
====Growth====
+
=====Advanced=====
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 5,035: Line 5,286:  
! effect
 
! effect
 
|-
 
|-
| <samp>DaysToMature</samp>
+
| <samp>CustomFields</samp>
| ''(Optional)'' The number of days until a freshly purchased/born animal becomes an adult and begins producing items. Default 1.
+
| The [[#Custom data fields|custom fields]] for this entry.
|-
  −
| <samp>CanGetPregnant</samp>
  −
| ''(Optional)'' Whether an animal can [[Animals#Animal Births|produce a child]] (regardless of gender). Default false.
   
|}
 
|}
   −
====Produce====
+
====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"
 
{| class="wikitable"
 
|-
 
|-
Line 5,048: Line 5,314:  
! effect
 
! effect
 
|-
 
|-
| <samp>ProduceItemIds</samp><br /><samp>DeluxeProduceItemIds</samp>
+
| <samp>DisplayName</samp>
| ''(Optional)'' The items produced by the animal when it's an adult. The <samp>DeluxeProduceItemIds</samp> field only applies if the <samp>Deluxe*</samp> fields match. Both default to none.
+
| A [[Modding:Tokenizable strings|tokenizable string]] for the goal's display name, shown on the board in the Adventurer's Guild.
 
  −
This consists of a list of models with these fields:
  −
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>Targets</samp>
! effect
+
| A list of [[Modding:Monster data#Monster IDs|monster IDs]] that are counted towards the <samp>Count</samp>.
 
|-
 
|-
| <samp>ItemId</samp>
+
| <samp>Count</samp>
| The [[#Custom items|''unqualified'' object ID]] of the item to produce.
+
| The total number of monsters (matching the <samp>Targets</samp>) which must be defeated to complete this goal.
 
|-
 
|-
| <samp>Condition</samp>
+
| <samp>RewardItemId</samp>
| ''(Optional)'' A [[#Game state queries|game state query]] which indicates whether this item can be produced now. Defaults to always true.
+
| ''(Optional)'' The [[#Custom items|qualified ID]] for the item that can be collected from [[Gil]] when this goal is completed. Default none.
 
|-
 
|-
| <samp>MinimumFriendship</samp>
+
| <samp>RewardItemPrice</samp>
| ''(Optional)'' The minimum friendship points with the animal needed to produce this item. Default 0.
+
| ''(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 multiple items can be produced, one is chosen at random (with deluxe items taking priority if applicable).
+
If there are reward items, they're shown after this dialogue.
|-
  −
| <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>FriendshipForFasterProduce</samp>
  −
| ''(Optional)'' The minimum friendship points needed to reduce the <samp>DaysToProduce</samp> by one. Defaults 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)'' [[#Quantity modifiers|Quantity 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)
+
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.
</pre>
     −
Specifically:
+
This doesn't send a letter; see <samp>RewardMail</samp> or <samp>RewardMailAll</samp> for that.
* <samp>DeluxeProduceCareDivisor</samp> reduces the bonus from friendship and happiness, so a lower value ''increases'' the probability of producing the deluxe item. Default 1200.
+
|-
* <samp>DeluxeProduceLuckMultiplier</samp> increases the effect of [[Luck|daily luck]]. Default 0.
+
| <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.
   −
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%.
+
Note that <samp>RewardFlag</samp> is usually not needed, since the game will also set a <samp>Gil_{{t|goal ID}}</samp> flag regardless.
   −
See [[Animals#Produce]] for more info on the calculation.
+
This doesn't send a letter; see <samp>RewardMail</samp> or <samp>RewardMailAll</samp> for that.
 
|-
 
|-
| <samp>HarvestType</samp>
+
| <samp>RewardMail</samp><br /><samp>RewardMailAll</samp>
| ''(Optional)'' How produced items are collected from the animal. The valid values are:
+
| ''(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.
{| class="wikitable"
   
|-
 
|-
! value
+
| <samp>CustomFields</samp>
! effect
+
| The [[#Custom data fields|custom fields]] for this entry.
|-
  −
| <samp>DropOvernight</samp>
  −
| The item is placed on the ground in the animal's home building overnight.
  −
|-
  −
| <samp>HarvestWithTool</samp>
  −
| The item is collected from the animal directly based on the <samp>HarvestTool</samp> field.
   
|}
 
|}
   −
Default <samp>DropOvernight</samp>.
+
===Custom phone calls===
|-
+
{{/doc status|a new doc page|done=false}}
| <samp>HarvestTool</samp>
+
 
| ''(Optional)'' The [[#Custom items|tool ID]] with which produced items 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.
+
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.
   −
====Audio & sprite====
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 5,129: Line 5,369:  
! effect
 
! effect
 
|-
 
|-
| <samp>Sound</samp>
+
| <samp>Dialogue</samp>
| ''(Optional)'' The [[#Custom audio|audio cue ID]] for the sound produced by the animal (e.g. when pet). Default none.
+
| 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>BabySound</samp>
+
| <samp>FromNpc</samp>
| ''(Optional)'' Overrides <samp>Sound</samp> field when the animal is a baby. Has no effect if <samp>Sound</samp> isn't specified. Default none.
+
| ''(Optional)'' The internal name of the NPC making the call. If specified, that NPC's name and portrait will be shown.
 
|-
 
|-
| <samp>Texture</samp>
+
| <samp>FromPortrait</samp>
| ''(Optional)'' The asset name for the animal's spritesheet. Defaults to <samp>Animals/{{t|ID}}</samp> (like <samp>Animals/Goat</samp> for a [[goat]]).
+
| ''(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>HarvestedTexture</samp>
+
| <samp>FromDisplayName</samp>
| ''(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.
+
| ''(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>BabyTexture</samp>
+
| <samp>MaxCalls</samp>
| ''(Optional)'' Overrides <samp>Texture</samp> and <samp>HarvestedTexture</samp> when the animal is a baby. Default none.
+
| ''(Optional)'' The maximum number of times a player can receive this phone call, or <samp>-1</samp> for no limit. Default 1.
 
|-
 
|-
| <samp>UseFlippedRightForLeft</samp>
+
| <samp>TriggerCondition</samp><br /><samp>RingCondition</samp>
| ''(Optional)'' When the animal is facing left, whether to use a flipped version of their right-facing sprite. Default false.
+
| ''(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>SpriteWidth</samp><br /><samp>SpriteHeight</samp>
+
| <samp>IgnoreBaseChance</samp>
| ''(Optional)'' The pixel height & width of the animal's sprite (before the in-game pixel zoom). Both default to 16.
+
| ''(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>EmoteOffset</samp>
+
| <samp>SimpleDialogueSplitBy</samp>
| ''(Optional)'' A pixel offset to apply to emotes from the farm animal, specified as an object with <samp>X</samp> and <samp>Y</samp>. Default zero.
+
| ''(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>Skins</samp>
+
| <samp>CustomFields</samp>
| ''(Optional)'' A list of alternate appearances. If specified, a skin is chosen at random when the animal is purchased or hatched. This consists of a list of models with these fields:
+
| 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"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! asset
! effect
+
! 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>ID</samp>
+
| <samp>AcceptGift_{{t|id}}</samp><br /><samp>AcceptGift_{{t|tag}}</samp>
| A key which uniquely identifies the skin for this animal type. The ID should only contain alphanumeric/underscore/dot characters. For custom skins, this should be prefixed with your mod ID like <samp>Example.ModId_SkinName</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>Weight</samp>
+
| <samp>DumpsterDiveComment</samp>
| ''(Optional)'' A multiplier for the probability to choose this skin when an animal is purchased. For example, <samp>2.0</samp> will double the chance this skin is selected relative to the other skins. Default <samp>1.0</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>Texture</samp><br /><samp>HarvestedTexture</samp><br /><samp>BabyTexture</samp>
+
| <samp>HitBySlingshot</samp>
| ''(Optional)'' Overrides the equivalent main field when this skin is selected. Defaults to the main field's value.
+
| Shown when the player shoots them with a [[slingshot]]. Defaults to a generic dialogue.
|}
   
|-
 
|-
| <samp>ShadowWhenBaby</samp><br /><samp>ShadowWhenBabySwims</samp><br /><samp>ShadowWhenAdult</samp><br /><samp>ShadowWhenAdultSwims</samp>
+
| <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>
| ''(Optional)'' The shadow to draw under the farm animal. The <samp>Baby</samp> fields only apply when the farm animal is a baby, and <samp>Adult</samp> fields only applies when it's an adult (e.g. a baby animal won't default to the adult fields). When the farm animal swims, it'll use the <samp>Swims</samp> variant if it's set, else default to the non-swim variant.
+
| Shown when the NPC rejects a [[bouquet]].
   −
These consist of a model with these fields:
+
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.
   −
{| class="wikitable"
+
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.
 
|-
 
|-
! field
+
| <samp>RejectGift_Divorced</samp>
! effect
+
| Shown when the NPC rejects a gift because you divorced them.
 
|-
 
|-
| <samp>Visible</samp>
+
| <samp>RejectItem_{{t|id}}</samp><br /><samp>RejectItem_{{t|tag}}</samp>
| ''(Optional)'' Whether the shadow should be drawn. Default true.
+
| 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>Offset</samp>
+
| <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>
| ''(Optional)'' A pixel offset applied to the shadow position, specified as an object with <samp>X</samp> and <samp>Y</samp> fields. Default zero.
+
| 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>Scale</samp>
+
| <samp>RejectMovieTicket_AlreadyInvitedBySomeoneElse</samp><br /><samp>RejectMovieTicket_AlreadyWatchedThisWeek</samp><br /><samp>RejectMovieTicket_Divorced</samp><br /><samp>RejectMovieTicket_DontWantToSeeThatMovie</samp><br /><samp>RejectMovieTicket</samp>
| ''(Optional)'' The scale at which to draw the shadow. Default 2.5 (swimming baby), 3 (baby), 3.5 (swimming adult), or 4 (adult).
+
| 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).
   −
====Player profession effects====
+
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.
{| class="wikitable"
+
|-
 +
| <samp>SpouseFarmhouseClutter</samp>
 +
| Shown by an NPC spouse when they couldn't pathfind to their kitchen standing spot in the farmhouse.
 
|-
 
|-
! field
+
| <samp>SpouseGiftJealous</samp>
! effect
+
| 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>ProfessionForFasterProduce</samp>
+
| <samp>Spouse_MonstersInHouse</samp>
| ''(Optional)'' The internal ID of a [[Skills|profession]] which reduces the <samp>DaysToProduce</samp> by one. Default none.
+
| Shown by an NPC spouse when they're in the farmhouse and there's a monster close to them.
 
|-
 
|-
| <samp>ProfessionForHappinessBoost</samp>
+
| <samp>SpouseStardrop</samp>
| ''(Optional)'' The internal ID of a [[Skills|profession]] which makes it easier to befriend this animal. Default none.
+
| Shown when receiving the [[stardrop]] from your spouse.
 
|-
 
|-
| <samp>ProfessionForQualityBoost</samp>
+
| <samp>Fair_Judging</samp>
| ''(Optional)'' The internal ID of a [[Skills|profession]] which increases the chance of higher-quality produce. Default none.
+
| 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.
   −
====Behavior====
+
''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).''
{| class="wikitable"
   
|-
 
|-
! field
+
| <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>
! effect
+
| 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>CanSwim</samp>
+
| <samp>FlowerDance_Accept_Roommate</samp><br /><samp>FlowerDance_Accept_Spouse</samp><br /><samp>FlowerDance_Accept</samp>
| ''(Optional)'' Whether animals on the farm can swim in water once they've been pet. Default false.
+
| 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>BabiesFollowAdults</samp>
+
| <samp>FlowerDance_Decline</samp>
| ''(Optional)'' Whether baby animals can follow nearby adults. Default false.
+
| 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>GrassEatAmount</samp>
+
| <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>
| ''(Optional)'' The amount of grass eaten by this animal each day. Default 2.
+
| 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>HappinessDrain</samp>
+
| <samp>WinterStar_ReceiveGift_{{t|id}}</samp><br /><samp>WinterStar_ReceiveGift_{{t|tag}}</samp><br /><samp>WinterStar_ReceiveGift</samp>
| ''(Optional)'' An amount which affects the daily reduction in happiness if the animal wasn't pet, or didn't have a heater in winter. Default none.
+
| 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>Price</samp>
+
| <samp>WipedMemory</samp>
| ''(Optional)'' The price when [[Animals#Selling Animals|the player sells the animal]], before the friendship boost. Default 0.
+
| Shown the first time you talk to the NPC after erasing their memory using the [[Dark Shrine of Memory]].
|-
  −
| <samp>CustomFields</samp>
  −
| The [[#Custom data fields|custom fields]] for this entry.
   
|}
 
|}
 
+
</li>
====Other====
+
<li>Added new [[Modding:Dialogue|dialogue]] commands:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! command
! effect
+
! 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>ShowInSummitCredits</samp>
+
| <samp>$action {{t|action}}</samp>
| ''(Optional)'' Whether to show the farm animal in the credit scene on [[The Summit|the summit]] after the player achieves [[perfection]]. Default false.
+
| Run a [[Modding:Trigger actions|trigger action string]], like <samp>$action AddMoney 500</samp> to add {{price|500}} to the current player.
 
|-
 
|-
| <samp>StatToIncrementOnProduce</samp>
+
| <samp>$query {{t|query}}#{{t|if true}}&#124;{{t|if false}}</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:
+
| Show different dialogue text depending on the [[Modding:Game state queries|game state query]] in {{t|query}}. For example:
{| class="wikitable"
+
<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>
 
|-
 
|-
! field
+
| <samp>$t {{t|topic ID}} {{o|day length}}</samp>
! effect
+
| Add a [[Modding:Dialogue#Conversation topics|conversation topic]] for the next {{o|day length}} days (default 4 days).
 
|-
 
|-
| <samp>StatName</samp>
+
| <samp>$v {{t|event id}} {{o|check preconditions}} {{o|skip if seen}}</samp>
| The name of the stat counter field on <samp>Game1.stats</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.
| <samp>RequiredTags</samp>
+
* {{o|skip if seen}}: whether to ignore the command if the player has already seen the given event. Default true.
| ''(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.
  −
|}
  −
|-
  −
| <samp>UpDownPetHitboxTileSize</samp><br /><samp>LeftRightPetHitboxTileSize</samp>
  −
| ''(Optional)'' The animal sprite's [[Modding:Modder Guide/Game Fundamentals#Tiles|tile]] size in the world when the player is clicking to pet them, specified in the form <samp>{{t|width}}, {{t|height}}</samp>. The <samp>UpDownPetHitboxTileSize</samp> applies when the animal is facing up or down, and <samp>LeftRightPetHitboxTileSize</samp> applies when facing left or right. The values can be fractional (''e.g.'' cows have a width of 1.75). Both default to a 1×1 tile.
  −
|-
  −
| <samp>BabyUpDownPetHitboxTileSize</samp><br /><samp>BabyLeftRightPetHitboxTileSize</samp>
  −
| ''(Optional)'' Overrides <samp>UpDownPetHitboxTileSize</samp> and <samp>LeftRightPetHitboxTileSize</samp> respectively before the animal is an adult. Both default to 1×1 tile.
  −
|}
     −
===Custom pets===
+
If the event is not played, the dialogue continues to the next line instead.
====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...
+
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.
* The key is a unique identifier for the pet (not the pet breed). The vanilla IDs are <samp>Cat</samp> and <samp>Dog</samp>. For custom pets, this should be prefixed with your mod ID like <samp>Example.ModId_PetName</samp>.
  −
* The value is a model with the fields listed below.
     −
=====Basic info=====
+
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"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! command
! effect
+
! changes
 
|-
 
|-
| <samp>DisplayName</samp>
+
| <samp>$p</samp>
| A [[#Tokenizable string format|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.
+
| 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>
   −
=====Audio & sprites=====
+
For C# mods that create <samp>Dialogue</samp> instances directly, there's a few ways to do it now:
{| class="wikitable"
+
<syntaxhighlight lang="c#">
|-
+
// from a translation key
! field
+
var dialogue = new Dialogue(npc, "Strings\\StringsFromCSFiles:Utility.cs.5360");
! effect
  −
|-
  −
| <samp>BarkSound</samp>
  −
| The [[#Custom audio|cue ID]] for the pet's occasional 'bark' sound.
  −
|-
  −
| <samp>ContentSound</samp>
  −
| The [[#Custom audio|cue ID]] for the sound which the pet makes when you pet it.
  −
|-
  −
| <samp>RepeatContentSoundAfter</samp>
  −
| ''(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).
  −
|-
  −
| <samp>EmoteOffset</samp>
  −
| ''(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.
  −
|}
     −
=====Events=====
+
// from custom text (with or without a translation key)
{| class="wikitable"
+
var dialogue = new Dialogue(npc, null, "Some arbitrary text to show as-is");
|-
  −
! field
  −
! effect
  −
|-
  −
| <samp>EventOffset</samp>
  −
| ''(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.
  −
|-
  −
| <samp>AdoptionEventLocation</samp><br /><samp>AdoptionEventId</samp>
  −
| ''(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>SummitPerfectionEvent</samp>
  −
| ''(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:
+
// 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"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! type
 +
! field/method
 
! effect
 
! effect
 
|-
 
|-
| <samp>SourceRect</samp>
+
|rowspan="2"| <samp>AdventureGuild</samp>
| The source rectangle within the pet's texture to draw.
+
| <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>AnimationLength</samp>
+
| <samp>AnimalHouse</samp>
| The number of frames to show starting from the <samp>SourceRect</samp>.
+
| <samp>adoptAnimal</samp>
 +
| Add an animal to this location and set the location as the animal's home.
 
|-
 
|-
| <samp>Motion</samp>
+
| <samp>AnimatedSprite</samp>
| The motion to apply to the pet sprite.
+
| <samp>Owner</samp>
 +
| The NPC which owns the sprite.
 
|-
 
|-
| <samp>Flipped</samp>
+
|rowspan="3"| <samp>Character</samp>
| ''(Optional)'' Whether to flip the pet sprite left-to-right. Default false.
+
| <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>PingPong</samp>
+
| <samp>StandingPixel</samp>
| ''(Optional)'' Whether to apply the 'ping pong' effect to the pet sprite animation. Default false.
+
| The character's cached pixel position within the current location, based on the center pixel of their bounding box.
|}
  −
|}
  −
 
  −
=====Behavior=====
  −
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>Tile</samp><br /><samp>TilePoint</samp>
! effect
+
| 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.
 
|-
 
|-
| <samp>MoveSpeed</samp>
+
|rowspan="7"| <samp>FarmAnimal</samp>
| ''(Optional)'' How quickly the pet can move. Default 2.
+
| <samp>isAdult</samp>
 +
| Get whether the farm animal is fully grown (opposite of <samp>isBaby()</samp>).
 
|-
 
|-
| <samp>SleepOnBedChance</samp><br /><samp>SleepNearBedChance</samp><br /><samp>SleepOnRugChance</samp>
+
| <samp>CanGetProduceWithTool</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.
+
| Get whether the farm animal's produce can be collected with a given tool (e.g. milk pail for a cow).
 
|-
 
|-
| <samp>Behaviors</samp>
+
| <samp>CanLiveIn</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>.
+
| Get whether the animal can be added to a building.
 
  −
This consists of a list of models with these fields:
  −
 
  −
<dl>
  −
<dt>Required fields:</dt>
  −
<dd>
  −
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>GetDisplayName</samp><br /><samp>GetShopDescription</samp>
! effect
+
| Get the translated display name or shop description for this animal.
 
|-
 
|-
| <samp>Name</samp>
+
| <samp>GetHarvestType</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).
+
| Get whether the animal's produce is dropped or collected with a tool.
|}
  −
</dd>
  −
 
  −
<dt>Direction:</dt>
  −
<dd>
  −
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>growFully</samp>
! effect
+
| Instantly age the animal to adulthood if it's still a baby.
 
|-
 
|-
| <samp>Direction</samp>
+
| <samp>ReloadTextureIfNeeded</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>.  
+
| Update the animal sprite based on the current state + data.
 
|-
 
|-
| <samp>RandomizeDirection</samp>
+
| rowspan="2"| <samp>Farmer</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>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.
| <samp>IsSideBehavior</samp>
+
 
| ''(Optional)'' Whether to constrain the pet's facing direction to left and right while the state is active. Default false.
+
For example:
|}
+
<syntaxhighlight lang="c#">
</dd>
+
Game1.player.GetDisplayShirt(out Texture2D texture, out int spriteIndex);
 
+
</syntaxhighlight>
<dt>Movement:</dt>
+
|-
<dd>
+
| <samp>CanDyePants</samp><br /><samp>CanDyeShirt</samp>
{| class="wikitable"
+
| Get whether the currently equipped pants or shirt can be [[Dyeing|dyed]].
 
|-
 
|-
! field
+
| <samp>Monster</samp>
! effect
+
| <samp>GetDisplayName(name)</samp>
 +
| Get the translated display name for a monster type.
 
|-
 
|-
| <samp>WalkInDirection</samp>
+
|rowspan="4"| <samp>NPC</samp>
| ''(Optional)'' Whether to walk in the pet's facing direction. Default false.
+
| <samp>CanReceiveGifts</samp>
 +
| Get whether this NPC can receive gifts from the player (regardless of whether they've already received one today).
 
|-
 
|-
| <samp>MoveSpeed</samp>
+
| <samp>GetData</samp><br /><samp>NPC.TryGetData</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).
+
| Get the underlying data from <samp>Data/Characters</samp> for this NPC, if any.
|}
  −
</dd>
  −
 
  −
<dt>Audio:</dt>
  −
<dd>
  −
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>NPC.GetDisplayName(name)</samp>
! effect
+
| Get the translated display name in the current language for an NPC by their internal name.
 
|-
 
|-
| <samp>SoundOnStart</samp>
+
| <samp>hasDarkSkin</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.
+
| Whether this character has dark skin for the purposes of child genetics.
 
|-
 
|-
| <samp>SoundRange</samp><br /><samp>SoundRangeFromBorder</samp>
+
| <samp>Pet</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>GetPetData</samp><br /><samp>TryGetData</samp>
 +
| Get the underlying data from <samp>Data/Pets</samp> for this pet, if any.
 
|-
 
|-
| <samp>SoundIsVoice</samp>
+
| <samp>ShopMenu</samp>
| ''(Optional)'' Whether to mute the <samp>SoundOnStart</samp> when the 'mute animal sounds' option is set. Default false.
+
| <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.
</dd>
     −
<dt>Behavior transitions:</dt>
+
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.
<dd>
  −
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>Utility</samp>
! effect
+
| <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.
| <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.
+
</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]].''
   −
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>).
+
1.6 rewrites buffs to work more consistently and be more extensible:
   −
These consist of a list of models with these fields:
+
* 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.
{| class="wikitable"
+
* 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.
! field
+
 
! effect
+
'''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).
| <samp>Behavior</samp><br /><samp>LeftBehavior</samp><br /><samp>RightBehavior</samp><br /><samp>UpBehavior</samp><br /><samp>DownBehavior</samp>
+
* 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.
| 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.
+
* 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>.
| <samp>OutsideOnly</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.
| ''(Optional)'' Whether the transition can only happen if the pet is outside. Default false.
+
* 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>.
| <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.
+
For example, here's how to add a custom buff which adds +3 speed:
|}
+
 
|-
+
<syntaxhighlight lang="c#">
| <samp>Duration</samp><br /><samp>MinimumDuration</samp><br /><samp>MaximumDuration</samp>
+
Buff buff = new Buff(
| ''(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.
+
    id: "Example.ModId_ZoomZoom",
|-
+
    displayName: "Zoom Zoom", // can optionally specify description text too
| <samp>RandomBehaviorChangeChance</samp>
+
    iconTexture: this.Helper.ModContent.Load<Texture2D>("assets/zoom.png"),
| ''(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.
+
    iconSheetIndex: 0,
|}
+
    duration: 30_000, // 30 seconds
</dd>
+
    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.
   −
<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"
 
{| class="wikitable"
 
|-
 
|-
 
! field
 
! field
! effect
+
! purpose
 
|-
 
|-
| <samp>Frame</samp>
+
| <samp>DisplayName</samp>
| The frame index in the animation. This should be an incremental number starting at 0.
+
| A [[Modding:Tokenizable strings|tokenizable string]] for the buff name.
 
|-
 
|-
| <samp>Duration</samp>
+
| <samp>Description</samp>
| The millisecond duration for which the frame should be kept on-screen before continuing to the next frame.
+
| ''(Optional)'' A [[Modding:Tokenizable strings|tokenizable string]] for the buff name. Default none.
 
|-
 
|-
| <samp>HitGround</samp>
+
| <samp>IsDebuff</samp>
| ''(Optional)'' Whether to play the footstep sound for the tile under the pet when the frame starts. Default false.
+
| ''(Optional)'' >Whether this buff counts as a debuff, so its duration should be halved when wearing a [[Sturdy Ring|sturdy ring]]. Default false.
 
|-
 
|-
| <samp>Jump</samp>
+
| <samp>GlowColor</samp>
| ''(Optional)'' Whether the pet should perform a small hop when the frame starts, including a 'dwop' sound. Default false.
+
| ''(Optional)'' The glow color to apply to the player. See [[#Color fields|color format]]. Default none.
 
|-
 
|-
| <samp>Sound</samp>
+
| <samp>Duration</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.
+
| 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>SoundRange</samp><br /><samp>SoundRangeFromBorder</samp><br /><samp>SoundIsVoice</samp>
+
| <samp>MaxDuration</samp>
| See description for the equivalent behavior fields, but applies to the frame's <samp>Sound</samp> field instead.
+
| ''(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>Shake</samp>
+
| <samp>IconTexture</samp>
| ''(Optional)'' The millisecond duration for which to shake the pet when the state starts. Default 0.
+
| The asset name for the texture containing the buff's sprite.
 
|-
 
|-
| <samp>LoopMode</samp>
+
| <samp>IconSpriteIndex</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>.
+
| ''(Optional)'' The sprite index for the buff icon within the <samp>IconTexture</samp>. Default 0.
 
|-
 
|-
| <samp>AnimationMinimumLoops</samp><br /><samp>AnimationMaximumLoops</samp>
+
| <samp>Effects</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).
+
| ''(Optional)'' The buff attributes to apply. Default none.
|}
+
 
</dd>
+
This consists of a model with any combination of these fields:
</dl>
  −
|}
  −
 
  −
=====Breeds=====
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
 
! field
 
! field
! effect
+
! purpose
|-
  −
| <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>
+
| <samp>FarmingLevel</samp><br /><samp>FishingLevel</samp><br /><samp>ForagingLevel</samp><br /><samp>LuckLevel</samp><br /><samp>MiningLevel</samp>
| ''(Optional)'' Override the pet's <samp>BarkSound</samp> field for this breed, if set.
+
| ''(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>VoicePitch</samp>
+
| <samp>Attack</samp><br /><samp>Defense</samp><br /><samp>MagneticRadius</samp><br /><samp>MaxStamina</samp><br /><samp>Speed</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.
+
| ''(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.
 
|}
 
|}
|}
  −
  −
=====Advanced=====
  −
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>ActionsOnApply</samp>
! effect
+
| ''(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>
 
| <samp>CustomFields</samp>
| The [[#Custom data fields|custom fields]] for this entry.
+
| ''(Optional)'' The [[#Custom data fields|custom fields]] for this entry.  
 
|}
 
|}
   −
====Other changes====
+
===Custom data fields===
* 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).
+
{{/doc status|[[Modding:Common data field types#Custom fields]]|done=true}}
* 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===
+
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).
: ''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.
+
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...
 
This consists of a string → model lookup, where...
* The key is a unique ID for the monster eradication goal. This 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>.
+
* 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.
 
* The value is a model with the fields listed below.
   Line 5,566: Line 5,964:  
! effect
 
! effect
 
|-
 
|-
| <samp>DisplayName</samp>
+
| <samp>FromItemId</samp>
| A [[#Tokenizable string format|tokenizable string]] for the goal's display name, shown on the board in the Adventurer's Guild.
+
| 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>Targets</samp>
+
| <samp>HarvestItems</samp>
| A list of [[Modding:Monster data#Monster IDs|monster IDs]] that are counted towards the <samp>Count</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"
 
|-
 
|-
| <samp>Count</samp>
+
! field
| The total number of monsters (matching the <samp>Targets</samp>) which must be defeated to complete this goal.
+
! effect
 
|-
 
|-
| <samp>RewardItemId</samp>
+
| ''common fields''
| ''(Optional)'' The [[#Custom items|qualified ID]] for the item that can be collected from [[Gil]] when this goal is completed. Default none.
+
| 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>RewardItemPrice</samp>
+
| <samp>ForShavingEnchantment</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.
+
| ''(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>RewardDialogue</samp><br /><samp>RewardDialogueFlag</samp>
+
| <samp>ScaledMinStackWhenShaving</samp><br /><samp>ScaledMaxStackWhenShaving</samp>
| ''(Optional)'' A [[#Tokenizable string format|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.
+
| ''(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.
   −
If there are reward items, they're shown after this dialogue.
+
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 <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.
+
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.
 
+
|}
This doesn't send a letter; see <samp>RewardMail</samp> or <samp>RewardMailAll</samp> for that.
+
|-
 +
| <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>RewardFlag</samp><br /><samp>RewardFlagAll</samp>
+
| <samp>Chance</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.
+
| ''(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 <samp>RewardFlag</samp> is usually not needed, since the game will also set a <samp>Gil_{{t|goal ID}}</samp> flag regardless.
+
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.
 
  −
This doesn't send a letter; see <samp>RewardMail</samp> or <samp>RewardMailAll</samp> for that.
   
|-
 
|-
| <samp>RewardMail</samp><br /><samp>RewardMailAll</samp>
+
| <samp>Condition</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.
+
| ''(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>
 
| <samp>CustomFields</samp>
Line 5,604: Line 6,021:  
|}
 
|}
   −
===Custom phone calls===
+
===Custom jukebox tracks===
Mods can now extend the [[telephone]] with custom calls (both incoming calls, and phone numbers which the player can call).
+
{{/doc status|a new doc page|done=false}}
   −
====Incoming calls====
+
You can now change [[jukebox]] audio tracks by editing the new <samp>Data/JukeboxTracks</samp> data asset.
You can add or customize incoming calls by editing the <samp>Data/IncomingPhoneCalls</samp> asset.
      
This consists of a string → model lookup, where...
 
This consists of a string → model lookup, where...
* The key is a unique call ID. This should only contain alphanumeric/underscore/dot characters, and custom entries should be prefixed with your mod ID like <samp>Example.ModId_CallId</samp>.
+
* The key is the [[#Custom audio|audio cue ID]] to play (case-sensitive).
 
* The value is a model with the fields listed below.
 
* 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"
 
{| class="wikitable"
Line 5,619: Line 6,037:  
! effect
 
! effect
 
|-
 
|-
| <samp>Dialogue</samp>
+
| <samp>Name</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).
+
| ''(Optional)'' A [[Modding:Tokenizable strings|tokenizable string]] for the music track's in-game title. Defaults to the ID.
 
|-
 
|-
| <samp>FromNpc</samp>
+
| <samp>Available</samp>
| ''(Optional)'' The internal name of the NPC making the call. If specified, that NPC's name and portrait will be shown.
+
| ''(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>FromPortrait</samp>
+
| <samp>AlternativeTrackIds</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 "???".
+
| ''(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.
|-
+
 
| <samp>FromDisplayName</samp>
+
For example, this can be used when renaming a track to keep it unlocked for existing players:
| ''(Optional)'' A [[#Tokenizable string format|tokenizable string]] for the calling NPC's display name. If <samp>FromNpc</samp> is specified too, this overrides the display name from that NPC.
+
<syntaxhighlight lang="js">
|-
+
"{{ModId}}_TrackName": {
| <samp>MaxCalls</samp>
+
    "Name": "{{i18n: track-name}}",
| ''(Optional)'' The maximum number of times a player can receive this phone call, or <c>-1</samp> for no limit. Default 1.
+
    "AlternativeTrackIds": [ "OldTrackName" ]
|-
+
}
| <samp>TriggerCondition</samp><br /><samp>RingCondition</samp>
+
</syntaxhighlight>
| ''(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.
+
===Custom movies===
|-
+
{{/doc status|[[Modding:Movie theater data]]|done=false}}
| <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.
+
: ''See also: [[#Custom movie concessions|custom movie concessions]].''
|-
  −
| <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#">
+
[[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.
/// <summary>The mod entry point.</summary>
  −
internal class ModEntry : Mod
  −
{
  −
    /// <inheritdoc />
  −
    public override void Entry(IModHelper helper)
  −
    {
  −
        Phone.PhoneHandlers.Add(new CustomPhoneHandler());
  −
    }
  −
}
     −
/// <summary>A custom phone handler.</summary>
+
Stardew Valley 1.6 revamps how movies work to address those limitations.
internal 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.
+
<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>
   −
===Custom shops===
+
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>
====Format====
  −
You can now create and edit shops via the new <samp>Data/Shops</samp> asset. This consists of a string → model lookup, where the key is a unique ID for the shop (using a globally unique ID which includes your mod ID like <samp>ExampleMod.Id_ShopName</samp> for custom shops), and the value is a model with these fields:
      +
<dt>New data fields</dd>
 +
<dd>
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 5,683: Line 6,079:  
! effect
 
! effect
 
|-
 
|-
| <samp>Items</samp>
+
| <samp>Seasons</samp>
| The items to add to the shop inventory. This consists of a list of values with these fields:
+
| ''(Optional)'' The seasons when the movie should play, or omit for any season. For example:
{| class="wikitable"
+
<syntaxhighlight lang="js">"Seasons": [ "Spring", "Summer" ]</syntaxhighlight>
 
|-
 
|-
! field
+
| <samp>YearModulus</samp><br /><samp>YearRemainder</samp>
! effect
+
| ''(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.
|-
  −
| ''common fields''
  −
| See [[#Item spawn fields|item spawn fields]] for the generic item fields supported by shop items.
     −
Notes:
+
For example:
* If set to an [[#Item queries|item query]] which returns multiple items, all of them will be added to the shop.
  −
* The <samp>MinStack</samp> and <samp>MaxStack</samp> fields apply to the item after it's purchased, and have no effect on the price or <samp>Stock</samp> limit.
  −
* If the player found [[Pierre's Missing Stocklist]], season conditions in the <samp>Condition</samp> field are ignored in [[Pierre's General Store]].
  −
|-
  −
| <samp>Price</samp>
  −
| ''(Optional)'' The gold price to purchase the item from the shop. Defaults to the item's normal price, or zero if <samp>TradeItemId</samp> is specified.
  −
|-
  −
| <samp>TradeItemId</samp><br /><samp>TradeItemAmount</samp>
  −
| ''(Optional)'' The [[#Custom items|qualified or unqualified item ID]] and amount which must be traded to purchase this item. Defaults to no item and 1 respectively.
     −
If both <samp>Price</samp> and <samp>TradeItemId</samp> are specified, the player will have to provide both to get the item.
+
<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>ApplyDifficultyModifier</samp>
+
| <samp>Texture</samp>
| ''(Optional)'' Whether to multiply the price by the difficulty modifier, which reduces the price for higher [[options|profit margins]]. This can be <samp>true</samp> (always apply it), <samp>false</samp> (never apply it), or <samp>null</samp> (apply for certain items like saplings). This is applied before any quantity modifiers. Default <samp>null</samp>.
+
| ''(Optional)'' The asset name for the movie poster and screen images, or omit to use <samp>LooseSprites\Movies</samp>.
|-
  −
| <samp>IgnoreShopPriceModifiers</samp>
  −
| ''(Optional)'' Whether to ignore the shop's <samp>PriceModifiers</samp> field for this item. This has no effect on the item's equivalent field. Default false.
  −
|-
  −
| <samp>AvailableStockModifiers</samp><br /><samp>PriceModifiers</samp>
  −
| ''(Optional)'' [[#Quantity modifiers|Quantity modifiers]] applied to the <samp>AvailableStock</samp> or <samp>Price</samp> values.
     −
Notes:
+
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.)
* The price modifiers stack with the <samp>PriceModifiers</samp> field on the shop (unless <samp>IgnoreStorePriceModifiers</samp> is true).
  −
|-
  −
| <samp>AvailableStockModifierMode</samp><br /><samp>PriceModifierMode</samp>
  −
| ''(Optional)'' [[#Quantity modifiers|quantity modifier modes]] which indicate what to do if multiple modifiers in the <samp>AvailableStockModifiers</samp> or <samp>PriceModifiers</samp> field apply at the same time. Default <samp>Stack</samp>.
  −
|-
  −
| <samp>AvoidRepeat</samp>
  −
| ''(Optional)'' Whether to avoid adding this item to the shop if it would duplicate one that was already added. If the item ID is randomized, this will choose a value that hasn't already been added to the shop if possible. Default false.
   
|-
 
|-
| <samp>AvailableStock</samp>
+
| <samp>CranePrizes</samp>
| ''(Optional)'' The maximum number of the item which can be purchased in one day. Default unlimited.
+
| ''(Optional)'' The items to add to the [[Movie Theater#Crane Game|crane game]] prize pool on days when this movie is playing, if any.
|-
  −
| <samp>AvailableStockLimit</samp>
  −
| ''(Optional)'' If <samp>Stock</samp> is set, how the limit is applied in multiplayer. This has no effect on recipes.
     −
The possible values are:
+
This consists of a list of models with these fields:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! value
+
! field
 
! effect
 
! effect
 
|-
 
|-
| <samp>Global</samp>
+
| ''common fields''
| The limit is shared by 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.
+
| 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>Player</samp>
+
| <samp>Rarity</samp>
| The limit applies to each player separately. For example, if the <samp>Stock</samp> was <samp>1</samp>, each player could buy one.
+
| ''(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>None</samp>
+
| <samp>ClearDefaultCranePrizeGroups</samp>
| The limit applies to the current instance of the shop menu. If you exit and reopen the menu, the item will reappear with the same stock. This is mainly used for items that are added conditionally.
+
| ''(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>
   −
Default <samp>Global</samp>.
+
<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>SalableItemTags</samp>
+
* <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.
| ''(Optional)'' A list of [[Modding:Items#Context tags|context tags]] for items which the player can sell to to this shop. Default none.
+
* 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>.
| <samp>Owners</samp>
+
</dd>
| ''(Optional)'' The portrait and dialogue to show in the shop menu UI.
+
</dl>
   −
When the [[#Map/tile property changes|<samp>Action OpenShop</samp> tile property]] specifies {{o|owner tile area}}, the first NPC within the tile area which matches an owner entry is used; if no NPCs match, the shop isn't opened. If <samp>Owners</samp> is omitted, the shop is opened regardless of whether an NPC is present, and no portrait or dialogue is shown.
+
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
   −
This consists of a list of models with these fields:
+
                    "Seasons": [ "winter" ],
{| class="wikitable"
+
                    "YearModulus": 3,
|-
+
                    "YearRemainder": 0,
! field
+
 
! effect
+
                    "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?",
| <samp>Name</samp>
+
                    "Tags": [ "family", "adventure" ],
| One of...
+
 
* the internal name for the NPC who must be in range to use this entry;
+
                    "Texture": "{{InternalAssetKey: assets/movie.png}}", // an image in your content pack
* <samp>AnyOrNone</samp> to use this entry regardless of whether any NPC is within the shop area;
+
                    "SheetIndex": 0,
* <samp>Any</samp> to use this entry if ''any'' NPC is within the shop area;
+
 
* <samp>None</samp> to use this entry if ''no'' NPC is within the shop area.
+
                    "Scenes": [ ... ]
|-
+
                }
| <samp>Id</samp>
+
            }
| ''(Optional)'' An ID for this entry within the shop. This only needs to be unique within the current shop's owner list. Defaults to the <samp>Name</samp> value.
+
        }
|-
+
    ]
| <samp>Condition</samp>
+
}</nowiki>|lang=javascript}}
| ''(Optional)'' A [[#Game state queries|game state query]] which indicates whether this owner entry is available. If omitted, it's always available.
+
 
|-
+
===Custom wedding event===
| <samp>Portrait</samp>
+
{{/doc status|a new doc page|done=false}}
| ''(Optional)'' One of...
+
 
* the internal name of the NPC whose portrait to show;
+
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).
* the asset name of the portrait spritesheet to display.
     −
If omitted, defaults to the portrait for the NPC matching the <samp>Name</samp> field (if any). If set to a value which doesn't match an NPC or texture asset name, the portrait is disabled.
  −
|-
  −
| <samp>Dialogues</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:
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 5,790: Line 6,179:  
! effect
 
! effect
 
|-
 
|-
| <samp>Id</samp>
+
| <samp>EventScript</samp>
| An ID for this dialogue. This only needs to be unique within the current dialogue list. For a custom entry, you should use a unique ID which includes your mod ID like <samo>ExampleMod.Id_DialogueName</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.
|-
  −
| <samp>Dialogue</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>RandomDialogue</samp>
  −
| ''(Optional)'' A list of dialogue texts to randomly choose from, using the same format as <samp>Dialogue</samp>. If set, <samp>Dialogue</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">
  −
"RandomDialogue": [
  −
    "[LocalizedText Strings\StringsFromCSFiles:ShopMenu.cs.11469]",
  −
    "[LocalizedText Strings\StringsFromCSFiles:ShopMenu.cs.11470]",
  −
    "[LocalizedText Strings\StringsFromCSFiles:ShopMenu.cs.11471]"
  −
]
  −
</syntaxhighlight>
  −
|-
  −
| <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.
  −
|}
     −
This can be set to an empty list (<code>"Dialogues": []</code>) to disable the dialogue text entirely. If omitted, defaults to a generic "''Have a look at my wares''" text.
+
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);
| <samp>RandomizeDialogueOnOpen</samp>
+
* The value is a [[Modding:Tokenizable strings|tokenizable strings]] for the event script to play.
| ''(Optional)'' If <samp>Dialogues</samp> has multiple matching entries, whether to re-randomize which one is selected each time the shop is opened (<samp>true</samp>) or once per day (<samp>false</samp>).
  −
|}
  −
|-
  −
| <samp>Currency</samp>
  −
| ''(Optional)'' The currency in which all items in the shop should be priced. The valid values are 0 (money), 1 (star tokens), 2 (Qi coins), and 4 (Qi gems). Default 0. For item trading, see <samp>TradeItemId</samp> for each item.
  −
|-
  −
| <samp>StackSizeVisibility</samp>
  −
| ''(Optional)'' How to draw stack size numbers in the shop list by default. If omitted, the default shop logic is applied (usually equivalent to <samp>Show</samp>).
     −
The possible values are:
+
The event scripts also have access to three extra tokens:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! value
+
! token
 
! effect
 
! effect
 
|-
 
|-
| <samp>Hide</samp>
+
| <samp>[SetupContextualWeddingAttendees]</samp>
| Always hide the stack size.
+
| The concatenated <samp>Setup</samp> values for each of the <samp>Attendees</samp> present in the wedding.
 
|-
 
|-
| <samp>Show</samp>
+
| <samp>[ContextualWeddingCelebrations]</samp>
| Always draw the stack size.
+
| The concatenated <samp>Celebration</samp> values for each of the <samp>Attendees</samp> present in the wedding.
 
|-
 
|-
| <samp>ShowIfMultiple</samp>
+
| <samp>[SpouseActor]</samp>
| Draw the stack size if it's more than one.
+
| 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.)
 
|}
 
|}
  −
This is ignored in some special cases (e.g. recipes can't have a stack size).
   
|-
 
|-
| <samp>OpenSound</samp>
+
| <samp>Attendees</samp>
| ''(Optional)'' The [[#Custom audio|audio cue ID]] to play when the shop menu is opened. Defaults to <samp>dwop</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"
 
|-
 
|-
| <samp>PurchaseSound</samp>
+
! field
| ''(Optional)'' The [[#Custom audio|audio cue ID]] to play when an item is purchased normally. Defaults to <samp>purchaseClick</samp>.
+
! effect
 
|-
 
|-
| <samp>purchaseRepeatSound</samp>
+
| <samp>ID</samp>
| ''(Optional)'' The [[#Custom audio|audio cue ID]] to play when accumulating a stack to purchase (e.g. by holding right-click on PC). Defaults to <samp>purchaseRepeat</samp>.
+
| The internal NPC name.
 
|-
 
|-
| <samp>PriceModifiers</samp>
+
| <samp>Setup</samp>
| ''(Optional)'' [[#Quantity modifiers|Quantity modifiers]] applied to the sell price for items in this shop. See also <samp>PriceModifiers</samp> under <samp>Items</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>PriceModifierMode</samp>
+
| <samp>Celebration</samp>
| ''(Optional)'' A [[#Quantity modifiers|quantity modifier mode]] which indicates what to do if multiple modifiers in the <samp>PriceModifiers</samp> field apply at the same time. This only affects that specific field, it won't affect price modifiers under <samp>Items</samp>. Default <samp>Stack</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>VisualTheme</samp>
  −
| ''(Optional)'' The visual theme to apply to the shop UI, or omit to use the default theme. The first matching theme is applied. All fields are optional and will fallback to the default theme.
  −
 
  −
This consists of a list of models with these fields:
  −
{| class="wikitable"
  −
|-
  −
! field
  −
! effect
   
|-
 
|-
 
| <samp>Condition</samp>
 
| <samp>Condition</samp>
| ''(Optional)'' A [[#Game state queries|game state query]] which indicates whether this theme should be applied. Defaults to always true.
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether the NPC should attend. Defaults to true.
|-
  −
| <samp>WindowBorderTexture</samp><br /><samp>WindowBorderSourceRect</samp>
  −
| ''(Optional)'' The texture asset name, and the pixel area within it, for the shop window border. Defaults to <samp>LooseSprites\Cursors</samp> at (384, 373) with size 18×18.
  −
|-
  −
| <samp>PortraitBackgroundTexture</samp><br /><samp>PortraitBackgroundSourceRect</samp>
  −
| ''(Optional)'' The texture asset name, and the pixel area within it, for the NPC portrait background. Defaults to <samp>LooseSprites\Cursors</samp> at (603, 414) with size 74×74.
  −
|-
  −
| <samp>DialogueBackgroundTexture</samp><br /><samp>DialogueBackgroundSourceRect</samp>
  −
| ''(Optional)'' The texture asset name, and the pixel area within it, for the NPC dialogue background. Defaults to <samp>Maps\MenuTiles</samp> at (0, 256) with size 60×60.
  −
|-
  −
| <samp>DialogueColor</samp><br /><samp>DialogueShadowColor</samp>
  −
| ''(Optional)'' The sprite text color for the dialogue text. See [[#Color fields|color format]]. Defaults to the game's standard text color.
  −
|-
  −
| <samp>ItemRowBackgroundTexture</samp><br /><samp>ItemRowBackgroundSourceRect</samp>
  −
| ''(Optional)'' The texture asset name, and the pixel area within it, for the item row background in the shop inventory. Defaults to <samp>LooseSprites\Cursors</samp> at (384, 396) with size 15×15.
  −
|-
  −
| <samp>ItemRowBackgroundHoverColor</samp>
  −
| ''(Optional)'' The color tint to apply to the item row background in the shop inventory when the cursor is hovering over it, or <samp>White</samp> for no tint. See [[#Color fields|color format]]. Defaults to <samp>Wheat</samp>.
  −
|-
  −
| <samp>ItemRowTextColor</samp>
  −
| ''(Optional)'' The sprite text color for the item text. See [[#Color fields|color format]]. Defaults to the game's standard text color.
  −
|-
  −
| <samp>ItemIconBackgroundTexture</samp><br /><samp>ItemIconBackgroundSourceRect</samp>
  −
| ''(Optional)'' The texture asset name, and the pixel area within it, for the background behind the item icons. Defaults to <samp>LooseSprites\Cursors</samp> at (296, 363) with size 18×18.
  −
|-
  −
| <samp>ScrollUpTexture</samp><br /><samp>ScrollUpSourceRect</samp>
  −
| ''(Optional)'' The texture asset name, and the pixel area within it, for the up arrow icon above the scrollbar. Defaults to <samp>LooseSprites\Cursors</samp> at (421, 459) with size 11×12.
  −
|-
  −
| <samp>ScrollDownTexture</samp><br /><samp>ScrollDownSourceRect</samp>
  −
| ''(Optional)'' The texture asset name, and the pixel area within it, for the down arrow icon beneath the scrollbar. Defaults to <samp>LooseSprites\Cursors</samp> at (421, 472) with size 11×12.
  −
|-
  −
| <samp>ScrollBarFrontTexture</samp><br /><samp>ScrollBarFrontSourceRect</samp>
  −
| ''(Optional)'' The texture asset name, and the pixel area within it, for the sliding scrollbar foreground. Defaults to <samp>LooseSprites\Cursors</samp> at (435, 463) with size 6×10.
   
|-
 
|-
| <samp>ScrollBarBackTexture</samp><br /><samp>ScrollBarBackSourceRect</samp>
+
| <samp>IgnoreUnlockConditions</samp>
| ''(Optional)'' The texture asset name, and the pixel area within it, for the scrollbar background. Defaults to <samp>LooseSprites\Cursors</samp> at (403, 383) with size 6×6.
+
| ''(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.
 
|}
 
|}
|-
  −
| <samp>CustomFields</samp>
  −
| The [[#Custom data fields|custom fields]] for this entry.
   
|}
 
|}
   −
====Open a custom shop====
+
===Game state queries===
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.
+
{{/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.
   −
In C# code, you can get the inventory for a custom shop using <code>Utility.GetShopStock("shop id here")</code>, open a shop menu using <code>Utility.OpenShopMenu("shop id", …)</code>, and add temporary items to an open menu using <code>shopMenu.AddForSale(…)</code>. The ID of the opened shop is stored in the shop menu's <samp>storeContext</samp> field.
+
===Item queries===
 +
{{/doc status|[[Modding:Item queries]]|done=true}}
   −
====Examples====
+
''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]].
You can add or replace entire shops. For example, this content pack adds a shop that sells ice cream in summer, and pufferfish all year:
     −
{{#tag:syntaxhighlight|<nowiki>
+
For example, a shop can sell a random [[House Plant|house plant]] using the <samp>RANDOM_ITEMS</samp> query:
 +
<syntaxhighlight lang="js">
 
{
 
{
     "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
+
     "ItemId": "RANDOM_ITEMS (F) 1376 1390",
     "Changes": [
+
     "MaxItems": 1
        {
+
}
            "Action": "EditData",
+
</syntaxhighlight>
            "Target": "Data/Shops",
+
 
            "Entries": {
+
===Item spawn fields===
                "Example.ModId_CustomShop": {
+
{{/doc status|[[Modding:Item queries#Item spawn fields]]|done=true}}
                    "Owners": [
  −
                        {
  −
                            "Name": "Any",
  −
                            "Dialogues": [
  −
                                // dialogue on sunny summer days
  −
                                {
  −
                                    "Id": "Example.ModId_SunnySummer",
  −
                                    "Condition": "SEASON Summer, WEATHER Here Sun",
  −
                                    "Dialogue": "Ice-cream is perfect for a day like this."
  −
                                },
     −
                                // dialogue any other time
+
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.
                                {
  −
                                    "Id": "Example.ModId_Default",
  −
                                    "Dialogue": "Welcome to the only place in town for pufferfish!"
  −
                                }
  −
                            ]
  −
                        }
  −
                    ],
     −
                    "Items": [
+
===Color fields===
                        // ice-cream in summer, default price
+
{{/doc status|[[Modding:Common data field types#Color]]|done=true}}
                        {
  −
                            "Id": "Example.ModId_IceCream",
  −
                            "Condition": "SEASON Summer",
  −
                            "ItemId": "(O)233"
  −
                        },
     −
                        // pufferfish for 1000g, limited to one per day per player
+
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.
                        {
  −
                            "Id": "Example.ModId_PufferFish",
  −
                            "ItemId": "(O)128",
  −
                            "Price": 1000,
  −
                            "AvailableStock": 1,
  −
                            "AvailableStockLimit": "Player"
  −
                        }
  −
                    ]
  −
                }
  −
            }
  −
        }
  −
    ]
  −
}</nowiki>|lang=javascript}}
     −
You can also add, replace, edit, or reorder items in a specific shop by targeting the shop's <samp>Items</samp> field. For example, this removes Trout Soup (item #219) and adds Pufferfish above bait (item #685):
+
For example, you can set debris color in [[#Custom wild trees|<samp>Data/WildTrees</samp>]]:
{{#tag:syntaxhighlight|<nowiki>
+
<syntaxhighlight lang="js">
{
+
"DebrisColor": "White"
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
+
</syntaxhighlight>
    "Changes": [
+
 
        {
+
===<samp>modData</samp> field changes===
            "Action": "EditData",
+
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.
            "Target": "Data/Shops",
+
 
            "TargetField": [ "FishShop", "Items" ],
+
Stardew Valley 1.6...
            "Entries": {
+
* Adds <samp>modData</samp> fields to the <samp>Crop</samp>, <samp>Projectile</samp>, and <samp>Quest</samp> types too.
                "(O)219": null,
+
* Moves <samp>ModDataDictionary</samp> into the <samp>StardewValley.Mods</samp> namespace.
                "Example.ModId_Pufferfish": {
+
* Fixes <samp>Item.modData</samp> not copied when performing special equipment replacement (e.g. for the [[Pans|copper pan]] work as a hat).
                    "Id": "Example.ModId_Pufferfish",
+
 
                    "ItemId": "(O)128",
+
===Quantity modifiers===
                    "Price": 2000
+
{{/doc status|[[Modding:Common data field types]]|done=false}}
                }
  −
            },
  −
            "MoveEntries": [
  −
                { "Id": "Example.ModId_Pufferfish", "BeforeId": "(O)685" }
  −
            ]
  −
        }
  −
    ]
  −
}</nowiki>|lang=javascript}}
     −
====Vanilla shop IDs====
+
''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.
Vanilla shops are now defined in <samp>Data/Shops</samp> too (except a few special cases like [[:Category:Dressers|dressers]] and home renovations), using these shop IDs:
     −
{| class="wikitable sortable"
+
====Modifier format====
 +
These consist of a list of models with these fields:
 +
{| class="wikitable"
 
|-
 
|-
! shop
+
! field
! ID
+
! effect
 
|-
 
|-
| [[Abandoned House|Abandoned house shop]]
+
| <samp>Id</samp>
| <samp>HatMouse</samp>
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this modifier within the current list.
 
|-
 
|-
| [[Adventurer's Guild]]
+
| <samp>Modification</samp>
| <samp>AdventureShop</samp> (regular shop)<br /><samp>AdventureGuildRecovery</samp> (item recovery service)
+
| 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>.
 
|-
 
|-
| [[Casino]]
+
| <samp>Amount</samp>
| <samp>Casino</samp>
+
| ''(Optional if <samp>RandomAmount</samp> specified)'' The operand applied to the target value (e.g. the multiplier if used with <samp>Multiply</samp>).
 
|-
 
|-
| [[Blacksmith|Clint's blacksmith shop]]
+
| <samp>RandomAmount</samp>
| <samp>Blacksmith</samp> (regular shop)<br /><samp>ClintUpgrade</samp> (tool upgrades)
+
| ''(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>
 
|-
 
|-
| [[Desert Trader|Desert trader]]
+
| <samp>Condition</samp>
| <samp>DesertTrade</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"
 
|-
 
|-
| [[Dwarf#Shop|Dwarf's shop]]
+
! value
| <samp>Dwarf</samp>
+
! effect
 
|-
 
|-
| [[Harvey's Clinic|Harvey's clinic]]
+
| <samp>Stack</samp>
| <samp>Hospital</samp>
+
| Apply each modifier to the result of the previous one. For example, two modifiers which double a value will quadruple it.
 
|-
 
|-
| [[Ice Cream Stand|Ice-cream stand]]
+
| <samp>Minimum</samp>
| <samp>IceCreamStand</samp>
+
| Apply the modifier which results in the lowest value.
 
|-
 
|-
| [[Island Trader|Island trader]]
+
| <samp>Maximum</samp>
| <samp>IslandTrade</samp>
+
| Apply the modifier which results in the highest value.
|-
+
|}
| [[Joja Mart]]
+
 
| <samp>Joja</samp>
+
====Examples====
|-
+
For example, this will double the price of a shop item in <samp>Data/Shops</samp>:
| [[Krobus|Krobus' shop]]
+
<syntaxhighlight lang="js">
| <samp>ShadowShop</samp>
+
"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"
 
|-
 
|-
| [[Marnie's Ranch|Marnie's ranch]]
+
! precondition
| <samp>AnimalShop</samp>
+
! description
 
|-
 
|-
| [[Pierre's General Store|Pierre's general store]]
+
| <samp>!</samp>
| <samp>SeedShop</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.
 
|-
 
|-
| [[Carpenter's Shop|Robin's carpenter shop]]
+
| <samp>ActiveDialogueEvent {{t|id}}</samp>
| <samp>Carpenter</samp>
+
| The special dialogue event with the given ID (including [[Modding:Dialogue#Conversation_topics|Conversation Topics]]) is in progress.
 
|-
 
|-
| [[Saloon|Stardrop Saloon]]
+
| <samp>DayOfWeek {{t|day}}+</samp>
| <samp>Saloon</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>).
 
|-
 
|-
| [[Oasis|Sandy's Oasis shop]]
+
| <samp>FestivalDay</samp>
| <samp>Sandy</samp>
+
| Today is a [[Festivals|festival]] day.
 
|-
 
|-
| [[Traveling Cart|Traveling cart]]
+
| <samp>GameStateQuery {{t|query}}</samp>
| <samp>Traveler</samp>
+
| A [[Modding:Game state queries|game state query]] matches, like <code>G !WEATHER Here Sun</code> for 'not sunny in this location'.
 
|-
 
|-
| [[Fish Shop|Willy's fish shop]]
+
| <samp>Season {{t|season}}+</samp>
| <samp>FishShop</samp>
+
| The current season is one of the given values (may specify multiple seasons).
|}
  −
 
  −
Festival shops are also defined in <samp>Data/Shops</samp> now, though they can still be defined in the pre-1.6 way for backwards compatibility.
  −
{| class="wikitable sortable"
   
|-
 
|-
! festival shop
+
| <samp>Skill {{t|skill name}} {{t|min level}}</samp>
! ID
+
| 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>).
 
|-
 
|-
| [[Dance of the Moonlight Jellies]]
+
| <samp>UpcomingFestival {{t|day offset}}</samp>
| <samp>Festival_DanceOfTheMoonlightJellies_Pierre</samp>
+
| A [[Festivals|festival]] day will occur within the given number of days.
 +
|}</li>
 +
<li>Changed specific preconditions:
 +
{| class="wikitable"
 
|-
 
|-
| [[Egg Festival]]
+
! name
| <samp>Festival_EggFestival_Pierre</samp>
+
! changes
 
|-
 
|-
| [[Festival of Ice]]
+
| <samp>ChoseDialogueAnswers</samp> (<samp>q</samp>)
| <samp>Festival_FestivalOfIce_TravelingMerchant</samp>
+
| &#32;
 +
* Fixed precondition ignoring every second answer ID.
 
|-
 
|-
| [[Feast of the Winter Star]]
+
| <samp>InUpgradedHouse</samp> (<samp>L</samp>)
| <samp>Festival_FeastOfTheWinterStar_Pierre</samp>
+
| &#32;
 +
* Added optional argument for the min upgrade level.
 
|-
 
|-
| [[Flower Dance]]
+
| <samp>MissingPet</samp> (<samp>h</samp>)
| <samp>Festival_FlowerDance_Pierre</samp>
+
| &#32;
 +
* You can now specify any pet type ID.
 +
* You can now omit the argument to check for a pet of any type.
 
|-
 
|-
| [[Luau]]
+
| <samp>NotDayOfWeek</samp> (<samp>d</samp>)
| <samp>Festival_Luau_Pierre</samp>
+
| &#32;
 +
* You can now specify a full name like <samp>Monday</samp>.
 +
* The day of week is now case-insensitive.
 
|-
 
|-
| [[Night Market]] (decoration boat)
+
| <samp>NotSeason</samp> (<samp>z</samp>)
| <samp>Festival_NightMarket_DecorationBoat</samp>
+
| &#32;
 +
* You can now list values (like <code>notSeason spring summer fall</code> instead of <code>notSeason fall/notSeason winter/notSeason fall</code>).
 
|-
 
|-
| [[Night Market]] (magic boat)
+
| <samp>ReachedMineBottom</samp> (<samp>b</samp>)
| <samp>Festival_NightMarket_MagicBoat_Day1</samp><br /><samp>Festival_NightMarket_MagicBoat_Day2</samp><br /><samp>Festival_NightMarket_MagicBoat_Day3</samp>
+
| &#32;
 +
* Argument is now optional (default 1).
 
|-
 
|-
| [[Spirit's Eve]]
+
| <samp>SendMail</samp> (<samp>x</samp>)
| <samp>Festival_SpiritsEve_Pierre</samp>
+
| &#32;
 +
* Deprecated; see [[#Send-mail (x) precondition deprecated|''Send-mail (x) precondition deprecated'']] for more info.
 
|-
 
|-
| [[Stardew Valley Fair]]
+
| <samp>Tile</samp> (<samp>a</samp>)
| <samp>Festival_StardewValleyFair_StarTokens</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>
   −
And two special 'shops':
+
====Command changes====
{| class="wikitable sortable"
+
<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
 
|-
 
|-
! item
+
| <samp>action {{t|action}}</samp>
! ID
+
| 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]].
 
|-
 
|-
| [[Catalogue]]
+
| <samp>addSpecialOrder {{t|order ID}}</samp><br /><samp>removeSpecialOrder {{t|order ID}}</samp>
| <samp>Catalogue</samp>
+
| Add or remove a special order to the player team. This affects all players, since special orders are shared.
 
|-
 
|-
| [[Furniture Catalogue]]
+
| <samp>eventSeen {{t|event ID}} {{o|seen}}</samp>
| <samp>Furniture Catalogue</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).
|}
     −
===Dialogue changes===
+
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.
<ul>
  −
<li>Added new [[Modding:Dialogue|dialogue]] commands:
  −
{| class="wikitable"
   
|-
 
|-
! command
+
| <samp>mailToday {{t|mail key}}</samp>
! description
+
| Adds a letter to the mailbox immediately, given the {{t|mail key}} in <samp>Data/Mail</samp>.
 
|-
 
|-
| <samp>$f {{t|response IDs}}</samp>
+
| <samp>questionAnswered {{t|answer ID}} {{o|answered}}</samp>
| Forget any number of space-delimited [[Modding:Dialogue#Response IDs|dialogue response IDs]] previously answered by the player.
+
| 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>$v {{t|event id}} {{o|check preconditions}} {{o|skip if seen}}</samp>
+
| <samp>replaceWithClone {{t|NPC name}}</samp>
| Immediately start an [[Modding:Event data|event]] and end the current dialogue, subject to the conditions:
+
| Replace an NPC already in the event with a temporary copy. This allows changing the NPC for the event without affecting the real NPC.
* {{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 skipped, the dialogue continues to the next line instead.
+
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, <code>$v 60367 false false</code> will replay the bus arrival event from the start of the game.
+
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>
</li>
+
/setSkipActions AddCraftingRecipe Current "Garden Pot"#AddItem (BC)62
<li>[[Modding:Dialogue#Response IDs|Dialogue response IDs]] are now strings, so mods can use a unique key like <samp>Example.ModId_ResponseName</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.</li>
+
/skippable
<li>[[Secrets#Item Spawn Cheat|Item spawn codes]] can now spawn any item type by using the [[#Custom items|qualified item ID]], like <code>[(F)1664]</code> for a [[Mystic Rug]].</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}}):
+
/addItem (BC)62
<syntaxhighlight lang="c#">
+
/setSkipActions AddCraftingRecipe Current "Garden Pot"
private void OnMenuChanged(object sender, MenuChangedEventArgs e)
+
</pre>
{
  −
    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:
+
Skip actions aren't applied if the event completes normally without being skipped.
<syntaxhighlight lang="c#">
+
|-
// from a translation key
+
| <samp>stopSound {{t|sound ID}} {{o|immediate}}</samp>
var dialogue = new Dialogue(npc, "Strings\\StringsFromCSFiles:Utility.cs.5360");
+
| 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>).
 
  −
// 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>The <samp>reject_{{t|item id}}</samp> dialogue key now also works with [[Movie Ticket|movie tickets]], [[Void Ghost Pendant|void ghost pendants]], [[bouquet]]s, [[Wilted Bouquet|wilted bouquets]], and [[Mermaid's Pendant|mermaids' pendants]].</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>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===
  −
* Schedule keys are now case-insensitive.
  −
* Added a new <samp>{{t|day of week}}_{{t|min hearts}}</samp> schedule key.
  −
* Added an <samp>NPC.ScheduleKey</samp> field which always matches their loaded schedule.
  −
* Removed an unintended schedule fallback to a <samp>{season}_spring_{hearts}</samp> key. It'll skip to the <samp>spring</samp> 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 <samp>marriageJob</samp> or Pam's <samp>bus</samp>).
  −
* For C# mods, removed the <samp>dayOfMonth</samp> parameter in <samp>NPC.getSchedule()</samp>. This was misleading since it used <samp>Game1.dayOfMonth</samp> in all but one line regardless.
  −
 
  −
===Other NPC changes===
  −
<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:
      +
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"
 
{| class="wikitable"
 
|-
 
|-
! type
+
! index
! field/method
+
! field
 
! effect
 
! effect
 
|-
 
|-
|rowspan="2"| <samp>AdventureGuild</samp>
+
| 0
| <samp>IsComplete(data)</samp>
+
| <samp>texture</samp>
| Get whether an [[Adventurer's Guild]] monster eradication goal has been completed, regardless of whether the player collected its rewards yet.
+
| The asset name for texture to draw.
 
|-
 
|-
| <samp>HasCollectedReward(player, id)</samp>
+
| 1&ndash;4
| Get whether a given player has completed an [[Adventurer's Guild]] monster eradication goal and collected its rewards. For example:
+
| <samp>rectangle</samp>
<syntaxhighlight lang="c#">
+
| The pixel area within the <samp>texture</samp> to draw, in the form <samp>{{t|x}} {{t|y}} {{t|width}} {{t|height}}</samp>.
bool isPhoneUnlocked = AdventureGuild.HasCollectedReward(Game1.player, "Gil_FlameSpirits");
  −
</syntaxhighlight>
   
|-
 
|-
| <samp>AnimalHouse</samp>
+
| 5
| <samp>adoptAnimal</samp>
+
| <samp>interval</samp>
| Add an animal to this location and set the location as the animal's home.
+
| The millisecond duration for each frame in the animation.
 
|-
 
|-
| <samp>Character</samp>
+
| 6
| <samp>GetGender</samp>
+
| <samp>frames</samp>
| Get the character's gender as one of the numeric constants (<samp>NPC.female</samp>, <samp>NPC.male</samp>, or <samp>NPC.undefined</samp>). This returns the specific gender for players, villager NPCs, and children; other NPCs (like monsters) return <samp>NPC.undefined</samp>.
+
| The number of frames in the animation.
 
|-
 
|-
|rowspan="7"| <samp>FarmAnimal</samp>
+
| 7
| <samp>isAdult</samp>
+
| <samp>loops</samp>
| Get whether the farm animal is fully grown (opposite of <samp>isBaby()</samp>).
+
| The number of times to repeat the animation.
 
|-
 
|-
| <samp>CanGetProduceWithTool</samp>
+
| 8&ndash;9
| Get whether the farm animal's produce can be collected with a given tool (e.g. milk pail for a cow).
+
| <samp>tile</samp>
 +
| The tile position at which to draw the sprite, in the form <samp>{{t|x}} {{t|y}}</samp>.
 
|-
 
|-
| <samp>CanLiveIn</samp>
+
| 10
| Get whether the animal can be added to a building.
+
| <samp>flicker</samp>
 +
| Causes the sprite to flicker in and out of view repeatedly. (one of <samp>true</samp> or <samp>false</samp>).
 
|-
 
|-
| <samp>GetDisplayName</samp><br /><samp>GetShopDescription</samp>
+
| 11
| Get the translated display name or shop description for this animal.
+
| <samp>flip</samp>
 +
| Whether to flip the sprite horizontally when it's drawn (one of <samp>true</samp> or <samp>false</samp>).
 
|-
 
|-
| <samp>GetHarvestType</samp>
+
| 12
| Get whether the animal's produce is dropped or collected with a tool.
+
| <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.
 
|-
 
|-
| <samp>growFully</samp>
+
| 13
| Instantly age the animal to adulthood if it's still a baby.
+
| <samp>alpha fade</samp>
 +
| Fades out the sprite based on alpha set. The larger the number, the faster the fade out. 1 is instant.  
 
|-
 
|-
| <samp>ReloadTextureIfNeeded</samp>
+
| 14
| Update the animal sprite based on the current state + data.
+
| <samp>scale</samp>
 +
| A multiplier applied to the sprite size (in addition to the normal 4× pixel zoom).
 
|-
 
|-
| rowspan="3"| <samp>Farmer</samp>
+
| 15
| <samp>GetDisplayPants</samp><br /><samp>GetDisplayShirt</samp>
+
| <samp>scale change</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.
+
| Changes the scale based on the multiplier applied on top of the normal zoom. Continues endlessly.
 
  −
For example:
  −
<syntaxhighlight lang="c#">
  −
Game1.player.GetDisplayShirt(out Texture2D texture, out int spriteIndex);
  −
</syntaxhighlight>
   
|-
 
|-
| <samp>CanDyePants</samp><br /><samp>CanDyeShirt</samp>
+
| 16
| Get whether the currently equipped pants or shirt can be [[Dyeing|dyed]].
+
| <samp>rotation</samp>
 +
| The rotation to apply to the sprite, measured in [[wikipedia:radians|radians]].
 
|-
 
|-
| <samp>WearTemporaryWeddingAttire</samp><br /><samp>RemoveTemporaryWeddingAttire</samp>
+
| 17
| Temporarily change the player into or out of their wedding attire. The default logic changes male farmers into the tuxedo, and has no effect on female farmers.
+
| <samp>rotation change</samp>
 +
| Continuously rotates the sprite, causing it to spin. The speed is determined by input value.  
 
|-
 
|-
|rowspan="4"| <samp>NPC</samp>
+
| 18+
| <samp>CanReceiveGifts</samp>
+
| ''flags''
| Get whether this NPC can receive gifts from the player (regardless of whether they've already received one today).
+
| 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>GetData</samp><br /><samp>NPC.TryGetData</samp>
+
| <samp>translateName {{t|actor}} {{t|translation key}}</samp>
| Get the underlying data from <samp>Data/Characters</samp> for this NPC, if any.
+
| Set the display name for an NPC in the event to match the given translation key.
 
|-
 
|-
| <samp>NPC.GetDisplayName(name)</samp>
+
| <samp>warpFarmers [{{t|x}} {{t|y}} {{t|direction}}]+ {{t|default offset}} {{t|default x}} {{t|default}} {{t|direction}}</samp>
| Get the translated display name in the current language for an NPC by their internal name.
+
| 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"
 
|-
 
|-
| <samp>hasDarkSkin</samp>
+
! command
| Whether this character has dark skin for the purposes of child genetics.
+
! changes
 
|-
 
|-
| <samp>Pet</samp>
+
| <samp>addCookingRecipe</samp>
| <samp>GetPetData</samp><br /><samp>TryGetData</samp>
+
| Fixed error if player already knows the recipe.
| Get the underlying data from <samp>Data/Pets</samp> for this pet, if any.
   
|-
 
|-
| <samp>ShopMenu</samp>
+
| <samp>addMailReceived</samp>
| <samp>ShopId</samp>
+
| &#32;
| 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.
+
* 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>.
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>addTemporaryActor</samp>
| <samp>getAllVillagers</samp>
+
| &#32;
| Get all villager NPCs (excluding horses, pets, monsters, player children, etc). This works just like <samp>getAllCharacters</samp> with an added filter.
+
* 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.
</li>
+
* Argument 9 ({{o|animal name}}) is now {{o|override name}}, and can be used to set the name for non-animals too.
<li>NPCs now update on save loaded when their home data changes.</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>
+
| <samp>animate</samp>
<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>
+
| 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>.
<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>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===
  −
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 or edit [[Modding:Audio|music tracks or sound effects]] (called ''cues'') by editing the <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]]).
  −
 
  −
====Format====
  −
The <samp>Data/AudioChanges</samp> asset consists of a string → model lookup, where the key matches the <samp>ID</samp>, and the value is a model with the fields below.
  −
 
  −
Entries in this asset describe an '''override''' applied to the soundbank. The override is applied permanently for the current game session, even if the asset is edited to remove it. Overriding a cue will reset all values to the ones specified.
  −
 
  −
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>ambientLight</samp>
! effect
+
| 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>ID</samp>
+
| <samp>makeInvisible</samp>
| A unique cue ID, used when playing the sound in-game. The ID should only contain alphanumeric/underscore/dot characters. For custom audio cues, this should be prefixed with your mod ID like <samp>Example.ModId_AudioName</samp>.
+
| Fixed terrain features not hidden when using the default area size.
 
|-
 
|-
| <samp>FilePaths</samp>
+
| <samp>playSound</samp>
| A list of file paths (not asset names) from which to load the audio. These can be absolute paths or 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.
+
| Sounds started via <samp>playSound</samp> now stop automatically when the event ends.
 
|-
 
|-
| <samp>Category</samp>
+
| <samp>removeItem</samp>
| 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]]). Defaults to <samp>Default</samp>.
+
| Added argument for an optional count, like <code>removeItem (O)128 10</code> to remove 10 pufferfish.
 
|-
 
|-
| <samp>StreamedVorbis</samp>
+
| <samp>speak</samp>
| 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.
+
| Fixed friendship & socialize quest not updated when calling it with a translation key.
 
+
|}</li>
This is a tradeoff between memory usage and performance, so you should consider which value is best for each audio cue:
+
<li>Removed some commands:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! value
+
! command
! effect
+
! changes
 
|-
 
|-
| <samp>true</samp>
+
| <samp>addToTable</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).
+
| Removed (it was unused and worked in counterintuitive ways).
 
|-
 
|-
| <samp>false</samp>
+
| <samp>addTool</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.
+
| Removed (it was unused and only supported the [[Return Scepter|return scepter]]). Use <samp>addItem</samp> instead, which supports adding tools.
|}
   
|-
 
|-
| <samp>Looped</samp>
+
| <samp>grabObject</samp>
| Whether the audio cue loops continuously until stopped. Default false.
+
| Removed (it was unused and broken).
 
|-
 
|-
| <samp>UseReverb</samp>
+
| <samp>showRivalFrame</samp><br /><samp>taxVote</samp>
| Whether to apply a [[wikipedia:Reverberation|reverb]] effect to the audio. Default false.
+
| Removed (they were part of unimplemented features).
 
|-
 
|-
| <samp>CustomFields</samp>
+
| <samp>weddingSprite</samp>
| The [[#Custom data fields|custom fields]] for this entry.
+
| Removed (it was broken and unused).
 
|}
 
|}
 +
</ul>
   −
====Example====
+
====Festival changes====
This content pack adds a new music cue to the game, and plays it when the player enters the bus stop:
+
* 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.
   −
{{#tag:syntaxhighlight|<nowiki>
+
====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.
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
  −
    "Changes": [
  −
        // add music cue
  −
        {
  −
            "Action": "EditData",
  −
            "Target": "Data/AudioChanges",
  −
            "Entries": {
  −
                "Example.ModId_Music": {
  −
                    "ID": "Example.ModId_Music",
  −
                    "Category": "Music",
  −
                    "FilePaths": [ "{{AbsoluteFilePath: assets/music.ogg}}" ],
  −
                    "StreamedVorbis": true,
  −
                    "Looped": true
  −
                }
  −
            }
  −
        },
     −
        // add to bus stop
+
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"
            "Action": "EditMap",
+
|-
            "Target": "Maps/BusStop",
+
! old event ID
            "MapProperties": {
+
! new action ID
                "Music": "Example.ModId_Music"
+
! mail flag
            }
+
|-
        }
+
| <samp>68</samp>
    ]
+
| <samp>Mail_Mom_5K</samp>
}</nowiki>|lang=javascript}}
+
| <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}}
   −
====Other changes====
+
<ul>
* 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.)
+
<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>
   −
===Custom data fields===
+
===Stat changes for C# mods===
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).
+
The tracked stats API (e.g. <code>Game1.stats</code> and <code>Game1.player.stats</code>) has been overhauled.
   −
For example, a content pack can [[#Custom crops|add a crop]] with custom fields:
+
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.
{{#tag:syntaxhighlight|<nowiki>
+
 
{
+
The <samp>stats</samp> API has also been redesigned:
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
+
{| class="wikitable"
    "Changes": [
+
|-
        {
+
! member
            "Action": "EditData",
+
! comments
            "Target": "Data/Crops",
+
|-
            "Entries": {
+
| <samp>Values</samp>
                "Example.Id_CucumberSeeds": {
+
| The numeric metrics tracked by the game. This replaces <samp>stats_dictionary</samp>.
                    "Seasons": [ "summer" ],
+
|-
                    "DaysInPhase": [ 1, 2, 2, 2 ],
+
| <samp>Get(key)</samp>
                    "HarvestItemId": "Example.Id_Cucumber",
+
| Get the value of a tracked stat. This replaces <samp>getStat</samp>.
                    "Texture": "{{InternalAssetKey: assets/crops.png}}",
  −
                    "SpriteIndex": 0,
     −
                    "CustomFields": {
+
For example:
                        "Example.FrameworkMod/WetTexture": "{{InternalAssetKey: assets/crops-wet.png}}"
+
<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.
}</nowiki>|lang=javascript}}
     −
And then a C# mod could handle the custom field if it's set:
+
For example:
 
<syntaxhighlight lang="c#">
 
<syntaxhighlight lang="c#">
if (Game1.currentLocation.IsRainingHere())
+
Game1.stats.Set(StatKeys.ChildrenTurnedToDoves, 5);
{
  −
    CropData data = crop.GetData();
  −
    if (data != null && data.CustomFields.TryGet("Example.FrameworkMod/WetTexture", out string textureName))
  −
    {
  −
        // do magic
  −
    }
  −
}
   
</syntaxhighlight>
 
</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>.
   −
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/Movies</samp>, and <samp>Data/SpecialOrders</samp>.
+
For example:
 +
<syntaxhighlight lang="c#">
 +
uint stepsTaken = Game1.stats.Increment(StatKeys.StepsTaken);
 +
</syntaxhighlight>
 +
|}
   −
===Custom giant crops===
+
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:
You can now add/edit [[Crops#Giant Crops|giant crops]] by editing the <samp>Data/GiantCrops</samp> data asset.
+
<syntaxhighlight lang="c#">
 +
Game1.stats.Set("Your.ModId_CustomStat", 5);
 +
</syntaxhighlight>
   −
This consists of a string → model lookup, where...
+
And finally, setting a stat to 0 now removes it from the stats dictionary (since that's the default for missing stats).
* The key is a unique identifier for the giant crop. The ID should only contain alphanumeric/underscore/dot characters. For custom giant crops, this should be prefixed with your mod ID like <samp>Example.ModId_GiantCropName</samp>.
  −
* The value is a model with the fields listed below.
     −
{| class="wikitable"
+
===New C# utility methods===
|-
+
Stardew Valley 1.6 adds several new methods to simplify common logic.
! 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.
+
====Argument handling====
|-
+
The new <samp>ArgUtility</samp> class handles splitting, reading, and validating <samp>string[]</samp> argument lists. The main methods are:
| <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:
+
; Splitting arrays&#58;
{| class="wikitable"
+
: {| class="wikitable"
 
|-
 
|-
! field
+
! <samp>ArgUtility</samp> method
 
! effect
 
! effect
 
|-
 
|-
| ''common fields''
+
| <samp>SplitBySpace</samp>
| See [[#Item spawn fields|item spawn fields]] for the generic item fields supported for harvest items.
+
| 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>
   −
If set to an [[#Item queries|item query]] which returns multiple items, one of them will be selected at random.
+
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>Chance</samp>
+
| <samp>SplitBySpaceQuoteAware</samp>
| ''(Optional)'' The probability that this entry is selected, as a value between 0 (never drops) and 1 (always drops). Default 1 (100% chance).
+
| 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>ForShavingEnchantment</samp>
+
| <samp>SplitQuoteAware</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.
+
| Split delimited arguments in a string, with support for using quotes to protect delimiters within an argument.
|-
  −
| <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.
+
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.)
   −
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.
+
For example:
|}
+
<syntaxhighlight lang="c#">
|-
+
ArgUtility.SplitQuoteAware("A,B,C", ',');        // [ "A", "B", "C" ]
| <samp>Texture</samp>
+
ArgUtility.SplitQuoteAware("A,\"B,C\",D", ','); // [ "A", "B,C", "D" ]
| The asset name for the texture containing the giant crop's sprite.
+
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>TexturePosition</samp>
+
| <samp>EscapeQuotes</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).
+
| Escape quotes in a string so they're ignored by methods like <samp>SplitQuoteAware</samp>.
|-
  −
| <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.
+
This isn't idempotent (e.g. calling it twice will result in double-escaped quotes).
|-
  −
| <samp>Condition</samp>
  −
| ''(Optional)'' A [[#Game state queries|game state query]] which indicates whether this giant crop is available to spawn. Defaults to always true.
   
|-
 
|-
| <samp>CustomFields</samp>
+
| <samp>UnsplitQuoteAware</samp>
| The [[#Custom data fields|custom fields]] for this entry.
+
| 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.
|}
     −
===Custom movies===
+
For example:
: ''See also: [[#Custom movie concessions|custom movie concessions]].''
+
<syntaxhighlight lang="c#">
 +
string args = ArgUtility.UnsplitQuoteAware(new[] { "A", "B C", "D" }, ' '); // A "B C" D
 +
</syntaxhighlight>
   −
You could already [[Modding:Movie theater data#Movie data|add/edit movies]] shown in the [[Movie Theater|movie theater]], but conflicts were likely since the poster & screen sprites for each movie had to be in the vanilla <samp>LooseSprites/Movies</samp> spritesheet.
+
This isn't idempotent (e.g. calling it twice will result in double-escaped quotes).
 +
|}
   −
Stardew Valley 1.6 adds a new movie field in <samp>Data/Movies</samp> to fix that:
+
; Reading arrays&#58;
{| class="wikitable"
+
: {| class="wikitable"
 
|-
 
|-
! field
+
! <samp>ArgUtility</samp> method
 
! effect
 
! effect
 
|-
 
|-
| <samp>Texture</samp>
+
| <samp>HasIndex</samp>
| ''(Optional)'' The asset name for the movie poster and screen images, or omit to use <samp>LooseSprites\Movies</samp>.
+
| Get whether an index is within the bounds of the array. For example:
 
+
<syntaxhighlight lang="c#">
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.)
+
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.
   −
The existing <samp>SpriteIndex</samp> field is now an index within that texture.
+
For example, code like this:
 +
<syntaxhighlight lang="c#">
 +
int value = fields.Length > 4 && int.TryParse(fields[4], out int parsed)
 +
    ? parsed
 +
    : -1;
 +
</syntaxhighlight>
   −
For example, this content pack adds a new 'Pufferchick II' movie:
+
Can now be rewritten like this:
{{#tag:syntaxhighlight|<nowiki>
+
<syntaxhighlight lang="c#">
{
+
int value = ArgUtility.GetInt(fields, 4, -1);
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
+
</syntaxhighlight>
    "Changes": [
  −
        {
  −
            "Action": "EditData",
  −
            "Target": "Data/Movies",
  −
            "Entries": {
  −
                "Example.ModId_PufferchickII": {
  −
                    "Id": "Example.ModId_PufferchickII", // must specify ID again when creating a new entry
  −
 
  −
                    "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===
  −
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
+
| <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>
! effect
+
| 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.
|-
  −
| <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...
+
For example, this parses a numeric value from a space-delimited string:
* 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);
+
<syntaxhighlight lang="c#">
* The value is a [[#Tokenizable string format|tokenizable strings]] for the event script to play.
+
string[] fields = ArgUtility.SplitByString("10 35");
 
+
if (ArgUtility.TryGetInt(fields, 1, out int value, out string error))
The event scripts also have access to three extra tokens:
+
    this.Helper.Monitor.Log($"Parsed value: {value}"); // "Parsed value: 35"
{| class="wikitable"
+
else
 +
    this.Helper.Monitor.Log($"Failed parsing value: {error}", LogLevel.Warn);
 +
</syntaxhighlight>
 
|-
 
|-
! token
+
| <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>
! effect
+
| 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>[SetupContextualWeddingAttendees]</samp>
+
| <samp>GetRemainder</samp><br /><samp>TryGetRemainder</samp><br /><samp>TryGetOptionalRemainder</samp>
| The concatenated <samp>Setup</samp> values for each of the <samp>Attendees</samp> present in the wedding.
+
| 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>[ContextualWeddingCelebrations]</samp>
+
| <samp>GetSubsetOf</samp>
| The concatenated <samp>Celebration</samp> values for each of the <samp>Attendees</samp> present in the wedding.
+
| Get a slice of the input array. For example:
|-
+
<syntaxhighlight lang="c#">
| <samp>[SpouseActor]</samp>
+
string[] subset1 = ArgUtility.GetSubsetOf(new[] { "A", "B", "C", "D" }, startAt: 1); // B, C, D
| 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>.
+
string[] subset2 = ArgUtility.GetSubsetOf(new[] { "A", "B", "C", "D" }, startAt: 1, length: 2); // B, C
 +
</syntaxhighlight>
   −
(You can also use <samp>spouse</samp> as an actor ID, but that will only work when marrying an NPC.)
+
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>
 
|}
 
|}
|-
+
 
| <samp>Attendees</samp>
+
====Content assets====
| 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"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! method
 
! effect
 
! effect
 
|-
 
|-
| <samp>ID</samp>
+
| <samp>LocalizedContentManager.DoesAssetExist</samp>
| The internal NPC name.
+
| 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>Setup</samp>
+
| <samp>LocalizedContentManager.IsValidTranslationKey</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]].
+
| 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#">
| <samp>Celebration</samp>
+
bool exists = Game1.content.IsValidTranslationKey("Strings\\NPCNames:Abigail");
| ''(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.
+
</syntaxhighlight>
|-
  −
| <samp>Condition</samp>
  −
| ''(Optional)'' A [[#Game state queries|game state query]] which indicates whether the NPC should attend. Defaults to true.
  −
|}
   
|}
 
|}
   −
===Game state queries===
+
====Filtering====
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}}. 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 Sun</code> is true on sunny non-[[spring]] days.
+
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.
   −
'''⚠''' Game state queries are partly case-sensitive. While some values are case-insensitive (e.g. both <code>SEASON Spring</code> and <code>SEASON spring</code> will work), this isn't consistent. Using the exact capitalization is recommended to avoid issues.
+
For example:
 +
<syntaxhighlight lang="c#">
 +
int dirtTilesRemoved = Game1.currentLocation.terrainFeatures.RemoveWhere(pair => pair.Value is HoeDirt);
 +
</syntaxhighlight>
   −
====Argument format====
+
====Game paths====
Game state queries take space-delimited arguments. For example, <code>BUILDINGS_CONSTRUCTED Here Cabins</code> has two arguments: <code>Here</code> and <code>Cabins</code>.
+
The game folder paths were previously hardcoded throughout the code. These are now centralized with a few methods:
 
  −
You can add quotes to keep spaces within an argument. For example, <code>BUILDINGS_CONSTRUCTED Here "Junimo Hut"</code> passes <code>Junimo Hut</code> as one argument. You can escape inner quotes with backslashes like <code>ANY "BUILDINGS_CONSTRUCTED Here \"Junimo Hut\""</code>. Remember that quotes and backslashes inside JSON strings need to be escaped too, like <code>"Condition": "BUILDINGS_CONSTRUCTED Here \"Junimo Hut\""</code>.
     −
====Conditions====
  −
<dl>
  −
<dt>Meta</dt>
  −
<dd>
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! Condition
+
! method
 
! effect
 
! effect
 
|-
 
|-
| <samp>ANY {{t|query}}+</samp>
+
| <samp>Program.GetLocalAppDataFolder</samp><br /><samp>Program.GetAppDataFolder</samp>
| Get whether at least one of the listed game state queries match, where each argument is a query. For example, <code>ANY "SEASON Winter" "SEASON Spring, DAY_OF_WEEK Friday"</code> is true if (a) it's winter or (b) it's a spring Friday. You can list any number of queries to check.
+
| 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.
 
|}
 
|}
</dd>
     −
<dt>Date & time</dt>
+
====Hash sets====
<dd>
+
Since the [[#Hash set fields|game now uses hash sets]], it has a few extensions for working with them:
 +
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! Condition
+
! method
 
! effect
 
! effect
 
|-
 
|-
| <samp>DAY_OF_MONTH {{t|day}}+</samp>
+
| <samp>AddRange</samp>
| The day of month. This can be an integer between 1 and 28, or <samp>even</samp>/<samp>odd</samp> to match on any even/odd day. You can specify multiple values to match any of them.
+
| Add all the values from a list or enumerable to the set.
 
|-
 
|-
| <samp>DAY_OF_WEEK {{t|day}}+</samp>
+
| <samp>RemoveWhere</samp>
| The day of week. This can be an integer between 0 (Sunday) and 6 (Saturday), three-letter English name (like <samp>Fri</samp>), or full English name (like <samp>Friday</samp>). You can specify multiple values to match any of them (like <samp>DAY_OF_WEEK Monday Tuesday</samp> for Monday ''or'' Tuesday).
+
| Remove all values matching a condition.
 
|-
 
|-
| <samp>DAYS_PLAYED {{t|min}} {{o|max}}</samp>
+
| <samp>Toggle</samp>
| Whether {{t|min}} to {{o|max}} (default unlimited) 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.
+
| 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"
 
|-
 
|-
| <samp>IS_FESTIVAL_DAY {{o|day offset}}</samp>
+
! method
| 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>Utility.ForEachBuilding</samp>
| Whether a [[#Custom passive festivals|passive festival]] with the given ID is active today, and the current time is within its opening hours.
+
| Perform an action for each building in the game world.
 
|-
 
|-
| <samp>IS_PASSIVE_FESTIVAL_TODAY {{t|id}}</samp>
+
| <samp>Utility.ForEachCharacter</samp><br /><samp>Utility.ForEachVillager</samp>
| Whether a [[#Custom passive festivals|passive festival]] with the given ID is active today.
+
| 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>SEASON {{t|season}}+</samp>
+
| <samp>Utility.ForEachCrop</samp>
| The season (one of <samp>spring</samp>, <samp>summer</samp>, <samp>fall</samp>, or <samp>winter</samp>). You can specify multiple values to match any of them (like <samp>SEASON spring summer</samp> for spring ''or'' summer).
+
| Perform an action for each crop in the game world planted in the ground or in a [[Garden Pot|garden pot]].
 
|-
 
|-
| <samp>SEASON_DAY [{{t|season}} {{t|day}}]+</samp>
+
| <samp>Utility.ForEachItem</samp>
| The season (in the same format as <samp>SEASON</samp>) and day (an integer between 1 and 28). You can specify multiple values to match any of them (like <samp>SEASON_DAY fall 15 winter 20</samp> for fall 15 ''or'' winter 20).
+
| 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>TIME {{t|min}} {{o|max}}</samp>
+
| <samp>Utility.ForEachItemIn</samp>
| Whether the current time is between {{t|min}} and {{o|max}} (default unlimited) inclusively, specified in [[Modding:Modder Guide/Game Fundamentals#Time format|26-hour time]].
+
| Perform an action for each item within a given location, including items within items (e.g. in a chest or on a table).
 
|-
 
|-
| <samp>YEAR {{t|min}} {{o|max}}</samp>
+
| <samp>Utility.ForEachLocation</samp>
| Whether the current year is between {{t|min}} and {{o|max}} (default unlimited) inclusively.
+
| Perform an action for each location in the game world, optionally including building interiors and generated [[The Mines|mine]] or [[Volcano Dungeon|volcano]] levels.
 
|}
 
|}
</dd>
     −
<dt>World</dt>
+
For example, this code counts how many parsnips are planted everywhere in the world:
<dd>
+
<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"
 
{| class="wikitable"
 
|-
 
|-
! Condition
+
! method
 
! effect
 
! effect
 
|-
 
|-
| <samp>BUILDINGS_CONSTRUCTED {{t|locations}} {{o|building type}} {{o|min}} {{o|max}} {{o|count unbuilt}}</samp>
+
| <samp>Utility.CreateDaySaveRandom</samp>
| Whether the number of matching buildings is within a range.
+
| Creates a <samp>Random</samp> instance using the most common seed (based on the save ID and total days played).
 
  −
For example:
  −
* <code>BUILDINGS_CONSTRUCTED Here</code> checks if any buildings were constructed in the player's current location.
  −
* <code>BUILDINGS_CONSTRUCTED Target Cabin</code> checks if there's at least one cabin in the [[#Target location|target location]].
  −
* <code>BUILDINGS_CONSTRUCTED All "Junimo Hut" 3 5</code> checks if there's between 3 and 5 Junimo huts (inclusively) anywhere in the world.
  −
 
  −
Arguments:
  −
* {{t|locations}}: a [[#Target location|target location]], or <samp>All</samp> to count buildings in all locations.
  −
* {{o|building type}}: the building ID in <samp>Data/Buildings</samp> to count, or <samp>All</samp> to count all building types. Note that <samp>All</samp> includes default buildings like the farmhouse.
  −
* {{o|min}}/{{o|max}}: the minimum (default 1) and maximum (default unlimited) count to require.
  −
* {{o|count unbuilt}}: whether to count buildings that haven't been fully constructed yet.
   
|-
 
|-
| <samp>CAN_BUILD_CABIN</samp>
+
| <samp>Utility.CreateRandom</samp><br /><samp>Utility.CreateRandomSeed</samp>
| Whether players can build more [[cabin]]s (i.e. they haven't reached the maximum number of player slots yet).
+
| 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>CAN_BUILD_FOR_CABINS {{t|building ID}}</samp>
+
| <samp>Utility.TryCreateIntervalRandom</samp>
| Whether there are fewer of the given building constructed than there are cabins.
+
| 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>FARM_CAVE {{t|type}}</samp>
+
| <samp>Utility.TryGetRandom</samp>
| The current [[The Farm#The Cave|farm cave]] (one of <samp>Bats</samp>, <samp>Mushrooms</samp>, or <samp>None</samp>).
+
| Get a random entry from a dictionary.
 
|-
 
|-
| <samp>FARM_NAME {{t|name}}</samp>
+
| <samp>random.Choose</samp>
| The name of the farm.
+
| Choose a random option from the values provided:
 +
<syntaxhighlight lang="c#">
 +
string npcName = Game1.random.Choose("Abigail", "Penny", "Sam");
 +
</syntaxhighlight>
 
|-
 
|-
| <samp>FARM_TYPE {{t|type}}</samp>
+
| <samp>random.ChooseFrom</samp>
| The [[Farm Maps|farm type]]. The {{t|type}} can be one of...
+
| Choose a random option from a list or array:
* a numeric ID for a vanilla farm type: <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), or <samp>6</samp> (beach);
+
<syntaxhighlight lang="c#">
* a readable key for a vanilla farm type: <samp>Standard</samp>, <samp>Beach</samp>, <samp>Forest</samp>, <samp>FourCorners</samp>, <samp>Hilltop</samp>, <samp>Riverland</samp>, or <samp>Wilderness</samp>;
+
string[] names = new[] { "Abigail", "Penny", "Sam" };
* or the ID for a custom farm type.
+
string npcName = Game1.random.ChooseFrom(names);
|-
+
</syntaxhighlight>
| <samp>FOUND_ALL_LOST_BOOKS</samp>
  −
| Whether all the [[Lost Books]] for the [[museum]] have been found.
  −
|-
  −
| <samp>IS_COMMUNITY_CENTER_COMPLETE</samp>
  −
| Whether the [[Community Center|community center]] has been repaired.
  −
|-
  −
| <samp>IS_CUSTOM_FARM_TYPE</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.)
  −
|-
  −
| <samp>IS_HOST</samp>
  −
| Whether the current player is the main/host player.
   
|-
 
|-
| <samp>IS_ISLAND_NORTH_BRIDGE_FIXED</samp>
+
| <samp>random.NextBool</samp>
| Whether the [[Ginger Island#Island North|North Ginger Island]] bridge to the dig site has been repaired.
+
| Randomly choose <samp>true</samp> or <samp>false</samp>. For example:
|-
+
<syntaxhighlight lang="c#">
| <samp>IS_JOJA_MART_COMPLETE</samp>
+
bool flipSprite = Game1.random.NextBool();
| Whether the [[Joja Warehouse|Joja warehouse]] has been built.
+
</syntaxhighlight>
|-
+
 
| <samp>IS_MULTIPLAYER</samp>
+
You can optionally set the probability of <samp>true</samp>:
| Whether the game is currently in multiplayer mode (regardless of whether there's multiple players connected).
+
<syntaxhighlight lang="c#">
|-
+
bool flipSprite = Game1.random.NextBool(0.8);
| <samp>IS_VISITING_ISLAND {{t|name}}</samp>
+
</syntaxhighlight>
| Whether the named NPC is visiting [[Ginger Island]] today.
+
|}
|-
  −
| <samp>LOCATION_ACCESSIBLE {{t|name}}</samp>
  −
| Whether the [[#Target location|given location]] is accessible. For vanilla locations, this is relevant to <samp>CommunityCenter</samp>, <samp>JojaMart</samp>, or <samp>Railroad</samp>; any other location will return true unless a mod customizes the query.
  −
|-
  −
| <samp>LOCATION_CONTEXT {{t|location}}</samp>
  −
| The location context name for the [[#Target location|given location]].
  −
|-
  −
| <samp>LOCATION_IS_INDOORS {{t|location}}</samp><br /><samp>LOCATION_IS_OUTDOORS {{t|location}}</samp><br /><samp>LOCATION_IS_MINES {{t|location}}</samp><br /><samp>LOCATION_IS_SKULL_CAVE {{t|location}}</samp>
  −
| Whether the [[#Target location|given location]] is indoors, outdoors, in [[The Mines|the mines]], or in the [[Skull Cavern]].
  −
|-
  −
| <samp>LOCATION_SEASON {{t|location}} [{{t|season}}]+</samp>
  −
| Whether the [[#Target location|given location]] is in one of the given seasons (which can be <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]].
     −
For example, this is valid in spring ''or'' summer: <code>LOCATION_SEASON Here spring summer</code>.
+
====Other====
|-
+
Here are some of the other new methods:
| <samp>MUSEUM_DONATIONS {{t|min count}} {{o|max count}} {{o|object type}}+</samp>
  −
| Whether all players have donated a total of {{t|min count}} to {{o|max count}} (default unlimited) inclusively to the [[museum]]. This can optionally be filtered by the object type field, like <samp>MUSEUM_DONATIONS 40 Arch Minerals</samp> to require at least 40 artifacts and minerals combined. You can omit the max count and still specify a filter.
  −
|-
  −
| <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_FIELD {{t|name}} {{t|value}}</samp>
  −
| Whether a property on <samp>Game1.netWorldState</samp> has the given value. If the property is numeric, this is the ''minimum'' value. Some useful values not covered by their own query:
      
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! name
+
! method
 
! effect
 
! effect
 
|-
 
|-
| <samp>GoldenCoconutCracked</samp>
+
| <samp>Game1.getOfflineFarmhands()</samp>
| Whether the player has cracked open any [[Golden Coconut]]s (<samp>true</samp> or <samp>false</samp>).
+
| Get all farmhands who aren't connected to the game.
 
|-
 
|-
| <samp>GoldenWalnutsFound</samp><br /><samp>GoldenWalnuts</samp>
+
| <samp>Game1.PerformActionWhenPlayerFree</samp>
| The total number of [[Golden Walnut]]s found or held by any player. To check how many one player currently holds, see the <samp>PLAYER_HAS_ITEM</samp> query.
+
| 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>IsGoblinRemoved</samp>
+
| <samp>Game1.createRadialDebris_MoreNatural</samp>
| Whether the [[Henchman]] has been removed, so the player can access [[Witch's Hut]] (<samp>true</samp> or <samp>false</samp>).
+
| Scatter item debris around a position with a more randomized distribution than <samp>createRadialDebris</samp>.
 
|-
 
|-
| <samp>IsSubmarineLocked</samp>
+
| <samp>Object.GetCategoryColor</samp><br /><samp>Object.GetCategoryDisplayName</samp>
| Whether the [[Night Market]] submarine is currently in use by a player (<samp>true</samp> or <samp>false</samp>).
+
| Get the color and display name for the given category number when it's shown in a tooltip.
 
|-
 
|-
| <samp>LostBooksFound</samp>
+
| <samp>Utility.distanceFromScreen</samp>
| The total number of [[Lost Book]]s found or held by any player.
+
| Get the pixel distance between a position in the world and the player's screen viewport, where 0 is within the viewport.
 
|-
 
|-
| <samp>MinesDifficulty</samp><br /><samp>SkullCavesDifficulty</samp>
+
| <samp>Utility.DrawErrorTexture</samp>
| The current [[The Mines#Shrine of Challenge|Shrine of Challenge]] difficulty level for the [[The Mines|mine]] or [[Skull Cavern]] (a numeric value, where <samp>0</samp> is the default level when the shrine is deactivated).
+
| Draw the game's missing-texture image (🚫) to the screen, stretched to fit a given pixel area.
 
|-
 
|-
| <samp>MiniShippingBinsObtained</samp>
+
| <samp>Utility.DrawSquare</samp>
| The number of times the player has obtained a [[Mini-Shipping Bin]].
+
| Draw a square to the screen with a background color and/or borders.
 
|-
 
|-
| <samp>ParrotPlatformsUnlocked</samp>
+
| <samp>Utility.GetEnumOrDefault</samp>
| Whether the player has unlocked [[Ginger Island]] parrot platforms, regardless of whether they've completed them (<samp>true</samp> or <samp>false</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>ServerPrivacy</samp>
+
| <samp>Utility.getRandomNpcFromHomeRegion</samp>
| The [[multiplayer]] connection privacy mode (<samp>InviteOnly</samp> or <samp>FriendsOnly</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>ShuffleMineChests</samp>
+
| <samp>Utility.isFestivalDay</samp>
| The value of the 'mine rewards' [[Options|game option]] (<samp>Default</samp> or <samp>Remixed</samp>).
+
| This method existed before 1.6, but you can now omit arguments to check today instead of a specific date:
|-
+
<syntaxhighlight lang="c#">
| <samp>WeatherForTomorrow</samp>
+
bool festivalToday = Utility.isFestivalToday();
| The weather ID for tomorrow in the main valley area.
+
</syntaxhighlight>
|-
  −
| <samp>VisitsUntilY1Guarantee</samp>
  −
| The number of times the [[Traveling Cart]] will visit before [[Red Cabbage]] is guaranteed to drop.
  −
|}
     −
For example, the [[Traveling Cart]] shop uses a <code>WORLD_STATE_FIELD VisitsUntilY1Guarantee 0</code> condition to check if it should guarantee a [[Red Cabbage]] item.
+
Or check for a festival in specific location context:
 +
<syntaxhighlight lang="c#">
 +
bool desertFestivalToday = Utility.isFestivalToday(LocationContexts.DesertId);
 +
</syntaxhighlight>
 
|-
 
|-
| <samp>WORLD_STATE_FIELD {{t|name}} {{t|min}} {{t|max}}</samp>
+
| <samp>Utility.IsPassiveFestivalDay</samp>
| For numeric properties only, whether a property on <samp>Game1.netWorldState</samp> has a value between {{t|min}} and {{t|max}}. If {{t|max}} is omitted or the properties isn't numeric, the previous form is used. See the previous entry for a list of useful properties.
+
| This method existed before 1.6, but now can now omit arguments to check today instead of a specific date:
|-
+
<syntaxhighlight lang="c#">
| <samp>WORLD_STATE_ID {{t|id}}</samp>
+
bool passiveFestivalToday = Utility.IsPassiveFestivalDay();
| Whether any world state flag with the given {{t|id}} is set.
+
</syntaxhighlight>
|}
  −
</dd>
     −
<dt>Player info & progress</dt>
+
Or check for a specific passive festival:
<dd>
+
<syntaxhighlight lang="c#">
{| class="wikitable"
+
bool nightMarketToday = Utility.IsPassiveFestivalDay("NightMarket");
 +
</syntaxhighlight>
 
|-
 
|-
! Condition
+
| <samp>Utility.TryGetPassiveFestivalData</samp><br /><samp>Utility.TryGetPassiveFestivalDataForDay</samp>
! effect
+
| Get the [[#Custom passive festivals|passive festival data]] for the given ID or date.
 
|-
 
|-
| <samp>MINE_LOWEST_LEVEL_REACHED {{t|min}} {{o|max}}</samp>
+
| <samp>Utility.TryParseDirection</samp>
| Whether any player has reached a level between {{t|min}} and {{t|max}} (default unlimited) inclusively in [[The Mines|the mines]].
+
| 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>PLAYER_COMBAT_LEVEL {{t|player}} {{t|min}} {{o|max}}</samp><br /><samp>PLAYER_FARMING_LEVEL {{t|player}} {{t|min}} {{o|max}}</samp><br /><samp>PLAYER_FISHING_LEVEL {{t|player}} {{t|min}} {{o|max}}</samp><br /><samp>PLAYER_FORAGING_LEVEL {{t|player}} {{t|min}} {{o|max}}</samp><br /><samp>PLAYER_LUCK_LEVEL {{t|player}} {{t|min}} {{o|max}}</samp><br /><samp>PLAYER_MINING_LEVEL {{t|player}} {{t|min}} {{o|max}}</samp>
+
| <samp>Utility.TryParseEnum</samp>
| Whether the [[#Target player|specified player(s)]] have a [[skills|skill level]] between {{t|min}} and {{t|max}} (default unlimited) inclusively, including the effects of buffs which raise them.
+
| 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>PLAYER_CURRENT_MONEY {{t|player}} {{t|min}} {{o|max}}</samp>
+
| <samp>Utility.fuzzyCompare</samp>
| Whether the [[#Target player|specified player(s)]] have between {{t|min}} and {{o|max}} (default unlimited) gold inclusively.
+
| 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>PLAYER_FARMHOUSE_UPGRADE {{t|player}} {{t|min}} {{o|max}}</samp>
+
| <samp>rectangle.GetPoints</samp><br /><samp>rectangle.GetVectors</samp>
| Whether the [[#Target player|specified player(s)]] have upgraded their [[farmhouse]] or [[cabin]] to a level between {{t|min}} and {{o|max}} (default unlimited) inclusively. See [https://github.com/Pathoschild/StardewMods/blob/develop/ContentPatcher/docs/author-guide/tokens.md#FarmhouseUpgrade possible levels].
+
| 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>PLAYER_GENDER {{t|player}} {{t|gender}}</samp>
+
| <samp>Utility.GetDeterministicHashCode</samp>
| Whether the [[#Target player|specified player(s)]] are <samp>Male</samp> or <samp>Female</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>PLAYER_HAS_ACHIEVEMENT {{t|player}} {{t|achievement id}}</samp>
+
| <samp>Utility.WrapIndex</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.
+
| 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).
|-
  −
| <samp>PLAYER_HAS_ALL_ACHIEVEMENTS {{t|player}}</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.
  −
|-
  −
| <samp>PLAYER_HAS_CAUGHT_FISH {{t|player}} {{t|id}}</samp>
  −
| Whether the [[#Target player|specified player(s)]] have caught at least one fish with the given ID.
  −
|-
  −
| <samp>PLAYER_HAS_CONVERSATION_TOPIC {{t|player}} {{t|id}}</samp>
  −
| Whether the [[#Target player|specified player(s)]] have a [[Modding:Dialogue#Conversation topics|conversation topic]] with the ID {{t|id}} active.
  −
|-
  −
| <samp>PLAYER_HAS_CRAFTING_RECIPE {{t|player}} {{t|recipe name}}</samp><br /><samp>PLAYER_HAS_COOKING_RECIPE {{t|player}} {{t|recipe name}}</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>.
  −
|-
  −
| <samp>PLAYER_HAS_DIALOGUE_ANSWER {{t|player}} {{t|id}}</samp>
  −
| Whether the [[#Target player|specified player(s)]] have chosen the given dialogue answer in a previous dialogue.
  −
|-
  −
| <samp>PLAYER_HAS_FLAG {{t|player}} {{t|id}}</samp>
  −
| Whether the [[#Target player|specified player(s)]] have the given [[Modding:Mail data|mail flag]] set (with spaces allowed in the {{t|id}}).
  −
|-
  −
| <samp>PLAYER_HAS_ITEM {{t|player}} {{t|item}} {{o|min}} {{o|max}}</samp>
  −
| Whether the [[#Target player|specified player(s)]] have between {{o|min}} and {{o|max}} (default unlimited) matching items in their inventory, inclusively. The {{t|item}} can be <samp>858</samp> or <samp>(O)858</samp> (Qi Gems), <samp>73</samp> or <samp>(O)73</samp> (Walnuts), or the [[#Custom items|qualified or unqualified item ID]].
  −
|-
  −
| <samp>PLAYER_HAS_PROFESSION {{t|player}} {{t|profession id}}</samp>
  −
| Whether the [[#Target player|specified player(s)]] have the given [[Skills|profession]] ID.
  −
|-
  −
| <samp>PLAYER_HAS_READ_LETTER {{t|player}} {{t|id}}</samp>
  −
| 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>.
  −
|-
  −
| <samp>PLAYER_HAS_SECRET_NOTE {{t|player}} {{t|id}}</samp>
  −
| Whether the [[#Target player|specified player(s)]] have read a secret note, where {{t|id}} is the secret note's integer ID.
  −
|-
  −
| <samp>PLAYER_HAS_SEEN_EVENT {{t|player}} {{t|id}}</samp>
  −
| Whether the [[#Target player|specified player(s)]] have seen the event with given {{t|id}}.
  −
|-
  −
| <samp>PLAYER_HAS_TOWN_KEY {{t|player}}</samp>
  −
| Whether the [[#Target player|specified player(s)]] have the [[Key To The Town|town key]].
  −
|-
  −
| <samp>PLAYER_HAS_TRASH_CAN_LEVEL {{t|player}} {{t|min}} {{o|max}}</samp>
  −
| Whether the [[#Target player|specified player(s)]] have a [[Trash Cans|trash can upgrade level]] between {{t|min}} and {{o|max}} (default unlimited) inclusively. The {{t|level}} can be <samp>0</samp> (base), <samp>1</samp> (copper), <samp>2</samp> (steel), <samp>3</samp> (gold), or <samp>4</samp> (iridium).
  −
|-
  −
| <samp>PLAYER_LOCATION_CONTEXT {{t|player}} {{t|location context}}</samp>
  −
| Whether the [[#Target player|specified player(s)]] are in the given [[#Custom location contexts|location context]].
  −
|-
  −
| <samp>PLAYER_LOCATION_NAME {{t|player}} {{t|location name}}</samp><br /><samp>PLAYER_LOCATION_UNIQUE_NAME {{t|player}} {{t|location name}}</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>.
  −
|-
  −
| <samp>PLAYER_MOD_DATA {{t|player}} {{t|key}} {{t|value}}</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}}.
  −
|-
  −
| <samp>PLAYER_MONEY_EARNED {{t|player}} {{t|min}} {{o|max}}</samp>
  −
| Whether the [[#Target player|specified player(s)]] have earned between {{t|min}} and {{o|max}} (default unlimited) gold inclusively.
  −
|-
  −
| <samp>PLAYER_SHIPPED_BASIC_ITEM {{t|player}} {{t|item ID}} {{o|min count}} {{t|max count}}</samp>
  −
| Whether the [[#Target player|specified player(s)]] have shipped the given item between {{o|min count}} (default 1) and {{o|max count}} (default unlimited) times inclusively. This only works for the items tracked by the game for shipping stats (shown in the [[Shipping#Collection|shipping collections menu]]).
  −
|-
  −
| <samp>PLAYER_SPECIAL_ORDER_ACTIVE {{t|player}} {{t|order id}}</samp>
  −
| Whether the [[#Target player|specified player(s)]] have the given [[Special Orders|special order]] active.
  −
|-
  −
| <samp>PLAYER_SPECIAL_ORDER_RULE_ACTIVE {{t|player}} {{t|rule id}}</samp>
  −
| Whether the [[#Target player|specified player(s)]] have a special rule active for a [[Special Orders|special order]]. Some vanilla rules are...
     −
{| class="wikitable"
+
For example:
|-
+
<syntaxhighlight lang="c#">
! rule ID
+
string[] values = new[] { "0", "1", "2" };
! effect
+
int index = Utility.WrapIndex(-1, values.Length); // 2
|-
+
</syntaxhighlight>
| <samp>DROP_QI_BEANS</samp>
  −
| The player can find [[Qi Beans]] for the ''Qi's Crop'' order.
  −
|-
  −
| <samp>LEGENDARY_FAMILY</samp>
  −
| The player catch the new legendary fish for the ''Extended Family'' order.
  −
|-
  −
| <samp>MINE_HARD</samp><br /><samp>SC_HARD</samp>
  −
| Raises the difficulty level of the mines or [[Skull Cavern]].
  −
|-
  −
| <samp>SC_NO_FOOD</samp>
  −
| The player can't eat food in the [[Skull Cavern]].
  −
|}
  −
|-
  −
| <samp>PLAYER_STAT {{t|player}} {{t|stat name}} {{t|min value}} {{o|max value}}</samp>
  −
| Whether a stat counter for the [[#Target player|specified player(s)]] has a value between {{t|min value}} and {{o|max value}} (default unlimited) inclusively. The available stat names are...
  −
* <samp>averageBedtime</samp>;
  −
* <samp>beachFarmSpawns</samp>;
  −
* <samp>beveragesMade</samp>;
  −
* <samp>boatRidesToIsland</samp>;
  −
* <samp>bouldersCracked</samp>;
  −
* <samp>caveCarrotsFound</samp>;
  −
* <samp>cheeseMade</samp>;
  −
* <samp>chickenEggsLayed</samp>;
  −
* <samp>childrenTurnedToDoves</samp>;
  −
* <samp>coalFound</samp>;
  −
* <samp>coinsFound</samp>;
  −
* <samp>copperFound</samp>;
  −
* <samp>cowMilkProduced</samp>;
  −
* <samp>cropsShipped</samp>;
  −
* <samp>daysPlayed</samp>;
  −
* <samp>diamondsFound</samp>;
  −
* <samp>dirtHoed</samp>;
  −
* <samp>duckEggsLayed</samp>;
  −
* <samp>exMemoriesWiped</samp>;
  −
* <samp>fishCaught</samp>;
  −
* <samp>geodesCracked</samp>;
  −
* <samp>giftsGiven</samp>;
  −
* <samp>goatCheeseMade</samp>;
  −
* <samp>goatMilkProduced</samp>;
  −
* <samp>goldFound</samp>;
  −
* <samp>goodFriends</samp>;
  −
* <samp>hardModeMonstersKilled</samp>;
  −
* <samp>individualMoneyEarned</samp>;
  −
* <samp>iridiumFound</samp>;
  −
* <samp>ironFound</samp>;
  −
* <samp>itemsCooked</samp>;
  −
* <samp>itemsCrafted</samp>;
  −
* <samp>itemsForaged</samp>;
  −
* <samp>itemsShipped</samp>;
  −
* <samp>monstersKilled</samp>;
  −
* <samp>mysticStonesCrushed</samp>;
  −
* <samp>notesFound</samp>;
  −
* <samp>otherPreciousGemsFound</samp>;
  −
* <samp>piecesOfTrashRecycled</samp>;
  −
* <samp>preservesMade</samp>;
  −
* <samp>prismaticShardsFound</samp>;
  −
* <samp>questsCompleted</samp>;
  −
* <samp>rabbitWoolProduced</samp>;
  −
* <samp>rocksCrushed</samp>;
  −
* <samp>seedsSown</samp>;
  −
* <samp>sheepWoolProduced</samp>;
  −
* <samp>slimesKilled</samp>;
  −
* <samp>starLevelCropsShipped</samp>;
  −
* <samp>stepsTaken</samp>;
  −
* <samp>sticksChopped</samp>;
  −
* <samp>stoneGathered</samp>;
  −
* <samp>stumpsChopped</samp>;
  −
* <samp>timesEnchanted</samp>;
  −
* <samp>timesFished</samp>;
  −
* <samp>timesUnconscious</samp>;
  −
* <samp>totalMoneyGifted</samp>;
  −
* <samp>trashCansChecked</samp>;
  −
* <samp>trufflesFound</samp>;
  −
* <samp>walnutsFound</samp>;
  −
* <samp>weedsEliminated</samp>.
   
|}
 
|}
</dd>
     −
<dt>Player relationships</dt>
+
===Static delegate builder===
<dd>
+
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>]].
{| class="wikitable"
  −
|-
  −
! Condition
  −
! effect
  −
|-
  −
| <samp>PLAYER_HAS_CHILDREN {{t|player}} {{o|min}} {{o|max}}</samp>
  −
| Whether the [[#Target player|specified player(s)]] have a number of children between {{t|min}} (default 1) and {{o|max}} (default unlimited) inclusively.
  −
|-
  −
| <samp>PLAYER_HAS_PET {{t|player}}</samp>
  −
| Whether the [[#Target player|specified player(s)]] have a [[Animals#Cat or Dog|pet]].
  −
|-
  −
| <samp>PLAYER_HEARTS {{t|player}} {{t|npc}} {{t|min hearts}} {{o|max hearts}}</samp>
  −
| Whether the [[#Target player|specified player(s)]] have a friend with a [[friendship]] level between {{t|min hearts}} and {{o|max hearts}} (default unlimited) inclusively. 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>
  −
| Whether the [[#Target player|specified player(s)]] have 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>, <samp>Dog</samp>, or a specified custom pet type.
  −
|}
  −
</dd>
     −
<dt>Randomization</dt>
+
For example, given a static method like this:
<dd>
+
<syntaxhighlight lang="c#">
{| class="wikitable"
+
public static bool OutputDeconstructor(Object machine, Item inputItem, bool probe, MachineItemOutput outputData, out int? overrideMinutesUntilReady) { ... }
|-
+
</syntaxhighlight>
! Condition
  −
! effect
  −
|-
  −
| <samp>RANDOM {{t|chance}} {{o|@addDailyLuck}}</samp>
  −
| A random probability check which is re-rolled each time it's called. For example, <code>RANDOM 0.4</code> is true 40% of the time.
     −
If the exact text <samp>@addDailyLuck</samp> is specified, the current player's [[Daily Luck|daily luck]] is added to the probability.
+
And a delegate which matches it:
|-
+
<syntaxhighlight lang="c#">
| <samp>SYNCED_CHOICE {{t|interval}} {{t|key}} {{t|min}} {{t|max}} {{t|choices}}+</samp>
+
public delegate bool MachineOutputDelegate(Object machine, Item inputItem, bool probe, MachineItemOutput outputData, out int? overrideMinutesUntilReady);
| Choose a random integer between {{t|min}} and {{t|max}} inclusively, and check whether it matches one of the {{t|choices}}. The result will be identical for all queries with the same {{t|key}} value during the given {{t|interval}} (one of <samp>tick</samp>, <samp>day</samp>, <samp>season</samp>, or <samp>year</samp>), including between players in multiplayer mode.
+
</syntaxhighlight>
   −
For example, <samp>SYNCED_CHOICE day example_key 1 5 1 2</samp> chooses a random value between 1 and 5, and checks if it's either 1 or 2.
+
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>
   −
This is mainly useful in cases where you need to pick between a number of discrete cases. For regular probability checks, see <samp>SYNCED_RANDOM</samp> instead.
+
The <samp>TryCreateDelegate</samp> method will cache created delegates, so calling it again will just return the same delegate instance.
|-
  −
| <samp>SYNCED_RANDOM {{t|interval}} {{t|key}} {{t|chance}} {{o|@addDailyLuck}}</samp>
  −
| A random probability check. The result will be identical for all queries with the same {{t|key}} value during the given {{t|interval}} (one of <samp>tick</samp>, <samp>day</samp>, <samp>season</samp>, or <samp>year</samp>), including between players in multiplayer mode.
     −
For example, <samp>SYNCED_RANDOM day cart_rare_seed 0.4</samp> has a 40% chance to be true the first time it's called that day, and will always be the same value if called again with the same key on the same day.
+
===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);
   −
If the exact text <samp>@addDailyLuck</samp> is specified, the current player's [[Daily Luck|daily luck]] is added to the probability.
+
// new code
|-
+
Game1.log.Error("Error playing sound.", ex);
| <samp>SYNCED_SUMMER_RAIN_RANDOM {{t|base chance}} {{t|day multiplier}}</samp>
+
</syntaxhighlight>
| A specialized variant of <samp>SYNCED_DAY_RANDOM</samp> used to calculate the chance of rain in summer, which increases with the day number.
  −
|}
  −
</dd>
     −
<dt>For items only</dt>
+
This has a few benefits:
<dd>
+
* For vanilla players, the game no longer uses time & resources writing to a console that's not visible anyway.
These queries apply in cases where there's an item (e.g. machine recipes, shops, etc); they'll return false if not applicable. They take a {{t|type}} argument which can be <samp>Input</samp> (the machine input item) or <samp>Target</samp> (the machine output, tree fruit, shop item, etc).
+
* 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"
 
{| class="wikitable"
 
|-
 
|-
! Condition
+
! old methods
! effect
+
! new method
 
|-
 
|-
| <samp>ITEM_HAS_TAG {{t|target}} {{t|tags}}</samp>
+
| <samp>Game1.playSound</samp><br /><samp>Game1.playSoundAt</samp><br /><samp>Game1.playSoundPitched</samp>
| Whether the item has all of the given space-delimited tags. For example, <code>ITEM_HAS_TAG Target bone_item marine_item</code> will only match items with both tags.
+
| <samp>Game1.playSound</samp>
 
|-
 
|-
| <samp>ITEM_ID {{t|target}} {{t|item ID}}</samp>
+
| <samp>GameLocation.playSound</samp><br /><samp>GameLocation.playSoundAt</samp><br /><samp>GameLocation.playSoundPitched</samp>
| Whether the item has the given [[#Custom items|qualified or unqualified item ID]]. The item ID is qualified before checking, so <samp>128</samp> will match pufferfish (<samp>(O)128</samp>) but not mushroom boxes (<samp>(BC)128</samp>).
+
| <samp>GameLocation.playSound</samp>
 
|-
 
|-
| <samp>ITEM_QUALITY {{t|target}} {{t|min}} {{t|max}}</samp>
+
| <samp>GameLocation.localSound</samp><br /><samp>GameLocation.localSoundAt</samp>
| Whether the item's quality is between {{t|min}} and {{t|max}} (default unlimited) inclusively. The possible values are <samp>0</samp> (normal), <samp>1</samp> (silver), <samp>2</samp> (gold), or <samp>4</samp> (iridium).
+
| <samp>GameLocation.localSound</samp>
 
|-
 
|-
| <samp>ITEM_STACK {{t|target}} {{t|min}} {{t|max}}</samp>
+
| <samp>NetAudio.Play</samp><br /><samp>NetAudio.PlayAt</samp><br /><samp>NetAudio.PlayPitched</samp>
| Whether the item stack size is between {{t|min}} and {{t|max}} (default unlimited) inclusively. Note that this only applies to the target item, it doesn't include other stacks in the inventory.
+
| <samp>NetAudio.Play</samp>
 
|-
 
|-
| <samp>ITEM_TYPE {{t|target}} {{t|type}}</samp>
+
| <samp>NetAudio.PlayLocal</samp><br /><samp>NetAudio.PlayLocalAt</samp>
| Whether the [[#Custom items|item's type definition ID]] matches the given value. For example, <samp>ITEM_TYPE Target (BC)</samp> matches bigcraftables.
+
| <samp>NetAudio.PlayLocal</samp>
|}
+
|}</li>
</dd>
+
</ul>
 +
 
 +
====Debug commands====
 +
{{/doc status|[[Modding:Console commands]]|done=false}}
   −
<dt>Immutable</dt>
+
<ul>
<dd>
+
<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"
 
{| class="wikitable"
 
|-
 
|-
! Condition
+
! command
! effect
+
! 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>TRUE</samp>
+
| <samp>artifactSpots</samp>
| A condition which always matches.
+
| Spawn an [[Artifact Spot|artifact spot]] in each empty tile around the player.
 
|-
 
|-
| <samp>FALSE</samp>
+
| <samp>endEvent</samp> / <samp>ee</samp>
| A condition which never matches.
+
| 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.
|}
  −
</dd>
  −
</dl>
     −
====Target location====
+
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.
Some conditions have a {{t|location}} argument. This can be one of...
  −
{| class="wikitable"
   
|-
 
|-
! value
+
| <samp>exportShops</samp>
! result
+
| 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>Here</samp>
+
| <samp>forcebuild</samp>
| The location containing the current player (regardless of the [[#Target player|target player]]).
+
| 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>Target</samp>
+
| <samp>gamequery</samp> / <samp>gq</samp>
| The location containing the in-game entity being edited (e.g. the machine for <samp>Data/Machines</samp> or fruit tree for <samp>Data/FruitTrees</samp>).
+
| ''Syntax:'' <samp>gq {{t|query}}</samp>
   −
If the asset being edited isn't tied to a location, this is the location of the [[#Target player|target player]] (if set), else equivalent to <samp>Here</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>
 
|-
 
|-
| ''any other''
+
| <samp>itemquery</samp> / <samp>iq</samp>
| The [[#Custom locations|location ID]] (i.e. internal name) for the location to check.
+
| ''Syntax:'' <samp>iq {{t|query}}</samp>
|}
     −
====Target player====
+
Open a shop menu with all the items matching an [[Modding:Item queries|item query]] (all items free). For example:
Some conditions have a {{t|player}} argument. This can be one of...
+
* <samp>debug iq ALL_ITEMS</samp> shows all items;
{| class="wikitable"
+
* <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.
 
|-
 
|-
! value
+
| <samp>logFile</samp>
! result
+
| 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>Any</samp>
+
| <samp>logSounds</samp>
| At least one player must match the condition, regardless of whether they're online.
+
| Log info about each sound effect played to the SMAPI console window.
 
|-
 
|-
| <samp>All</samp>
+
| <samp>movieSchedule {{o|year}}</samp>
| Every player must match the condition, regardless of whether they're online.
+
| Lists the movies that will play in a given {{o|year}} (default this year), with the dates they'll play.
 
|-
 
|-
| <samp>Current</samp>
+
| <samp>qualifiedid</samp>
| The local player.
+
| Print the held item's display name and [[#Custom items|qualified item ID]].
 
|-
 
|-
| <samp>Host</samp>
+
| <samp>search</samp>
| The main player.
+
| ''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>Target</samp>
+
| <samp>setFarmEvent</samp> / <samp>sfe</samp>
| This value depends on the context:
+
| ''Syntax:'' <samp>setFarmEvent {{t|event id}}</samp>
{| class="wikitable"
+
 
 +
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).
 
|-
 
|-
! context
+
| <samp>shop</samp>
! effect
+
| ''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>Data/LocationContexts</samp>
+
| <samp>skinBuilding</samp> / <samp>bsm</samp>
| For the <samp>PassOutLocations</samp> field only, the player whose pass-out location to get.
+
| If the player is standing right under a building, open a menu to change the building appearance.
 
|-
 
|-
| <samp>Data/MiscGameData</samp>
+
| <samp>testwedding</samp>
| For the <samp>WeddingContextualAttendees</samp> field only, the attendee player (if the attendee is a player).
+
| 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>Data/WildTrees</samp>
+
| <samp>thishouseupgrade</samp> / <samp>thishouse</samp> / <samp>thu</samp>
| For the <samp>AdditionalChopDrops</samp> field only, the last player who chopped the tree.
+
| 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.
 
|-
 
|-
| ''custom queries''
+
| <samp>toggleCheats</samp>
| C# mods may specify a <samp>target_farmer</samp> parameter when calling <samp>GameStateQuery.CheckConditions</samp>.
+
| Enable or disable entering debug commands into the in-game chat (prefixed with <samp>/</samp>).
 
|-
 
|-
| ''any other''
+
| <samp>tokens</samp>
| Equivalent to <samp>Current</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>
 
|-
 
|-
| ''any other''
+
| <samp>worldMapLines</samp>
| The unique multiplayer ID for the player to check.
+
| Toggles the [[Modding:World map#Debug view|world map's debug view]].
|}
+
|}</li>
 
+
<li>Improved existing debug commands:
====Using queries elsewhere====
  −
C# code can use the <samp>GameStateQuery</samp> class to work with queries, like <code>GameStateQuery.CheckConditions(query)</code>.
  −
 
  −
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 Sun</code>.
  −
 
  −
====Extensibility====
  −
C# mods can check if a query exists using <code>GameStateQuery.Exists("Example.ModId_ConditionName")</code>, and define custom conditions using <code>GameStateQuery.Register("Example.ModId_ConditionName", handleQueryMethod)</code>. To avoid conflicts, prefixing custom condition names with your mod ID is strongly recommended.
  −
 
  −
===Item queries===
  −
''Item queries'' 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]].
  −
 
  −
====Available queries====
  −
The supported item queries are:
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! query
+
! command
! effect
+
! changes
 
|-
 
|-
| <samp>ALL_ITEMS {{o|type ID}}</samp>
+
| <samp>build</samp>
| Every item provided by the [[#Custom items|item data definitions]]. If {{o|type ID}} is set to an item type identifier (like <samp>(O)</samp> for object), only returns items from the matching item data definition.
+
| Removed custom space handling; quote arguments with spaces instead of replacing them with 9 (e.g. <code>Junimo9Hut</code> → <code>"Junimo Hut"</code>).
 
|-
 
|-
| <samp>DISH_OF_THE_DAY</samp>
+
| <samp>clearFurniture</samp>
| The [[The Stardrop Saloon#Rotating Stock|Saloon's dish of the day]].
+
| Now works outside the farmhouse too.
 
|-
 
|-
| <samp>FLAVORED_ITEM {{t|type}} {{t|ingredient ID}} {{o|ingredient flavor ID}}</samp>
+
| <samp>dialogue</samp>
| A flavored item like Apple Wine. The {{t|type}} can be one of [[Aged Roe|<samp>AgedRoe</samp>]], [[Honey|<samp>Honey</samp>]], [[Jellies and Pickles|<samp>Jelly</samp>]], [[Juice|<samp>Juice</samp>]], [[Jellies and Pickles|<samp>Pickle</samp>]], [[Roe|<samp>Roe</samp>]], or [[Wine|<samp>Wine</samp>]]. The {{t|ingredient ID}} is the qualified or unqualified item ID which provides the flavor (like Apple in Apple Wine). For <samp>Honey</samp>, you can set the {{t|flavor ID}} to <samp>-1</samp> for Wild Honey.
+
| 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>).
 
  −
For aged roe only, the {{o|ingredient flavor ID}} is the flavor of the {{t|ingredient ID}}. For example, <samp>FLAVORED_ITEM AgedRoe (O)812 128</samp> creates Aged Pufferfish Roe (812 is [[roe]] and 128 is [[pufferfish]]).
   
|-
 
|-
| <samp>ITEMS_SOLD_BY_PLAYER {{t|shop location}}</samp>
+
| <samp>ebi</samp>
| Random items the player has recently sold to the {{t|shop location}}, which can be one of <samp>SeedShop</samp> (Pierre's store) or <samp>FishShop</samp> (Willy's fish shop).
+
| Fixed event not played correctly if called from the same location as the event.
 
|-
 
|-
| <samp>LOCATION_FISH {{t|location}} {{t|bobber tile}} {{t|depth}}</samp>
+
| <samp>fish</samp>
| A random item that can be found by fishing in the given location. The {{t|location}} should be the internal name of the location, {{t|bobber tile}} is the position of the fishing rod's bobber in the water (in the form <samp>{{t|x}} {{t|y}}</samp>), and {{t|depth}} is the bobber's distance from the nearest shore measured in tiles (where 0 is directly adjacent to the shore).
+
| Fixed error if you're not holding a fishing rod. It now opens the fishing minigame with no tackle instead.
 
  −
'''Careful:''' since the target location might use <samp>LOCATION_FISH</samp> queries in its list, it's easy to cause a circular reference by mistake (e.g. location A gets fish from B, which gets fish from A). If this happens, the game will log an error and return no item.
   
|-
 
|-
| <samp>LOST_BOOK_OR_ITEM {{o|alternate query}}</samp>
+
| <samp>frameOffset</samp>
| Returns a [[Lost Books|lost book]] if the player hasn't found them all yet, else the result of the {{o|alternate query}} if specified, else nothing.
+
| &#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.
For example, <code>LOST_BOOK_OR_ITEM (O)770</code> returns [[Mixed Seeds|mixed seeds]] if the player found every book already.
+
* Fixed command only taking the last digit in each number.
 
|-
 
|-
| <samp>RANDOM_ARTIFACT_FOR_DIG_SPOT</samp>
+
| <samp>getStat</samp><br /><samp>setStat</samp>
| A random item which is defined in <samp>Data/ObjectInformation</samp> with the <samp>Arch</samp> (artifact) type, and whose spawn rules (field 6) match the current location and whose random probability passes. This is mainly used by [[Artifact Spot|artifact spots]].
+
| Added argument validation.
 
|-
 
|-
| <samp>RANDOM_BASE_SEASON_ITEM</samp>
+
| <samp>grass</samp>
| A random seasonal vanilla item which can be found by searching garbage cans, breaking containers in the mines, etc.
+
| Now applies to the current location, instead of the farm.
 
|-
 
|-
| <samp>RANDOM_ITEMS {{t|type definition ID}} {{o|options}}</samp>
+
| <samp>growAnimals</samp><br /><samp>growAnimalsFarm</samp>
| Random items from the given [[#Item types|type definition ID]], with any combination of the following criteria and options (in any order, all optional):
+
| Merged into one <samp>growAnimals</samp> command that supports any location and doesn't reset the age of animals which are already adults.
 
  −
{| class="wikitable"
   
|-
 
|-
! format
+
| <samp>growCrops</samp>
! item criteria
+
| Fixed error growing mixed seeds or giant crops.
 
|-
 
|-
!colspan="2"| search criteria
+
| <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>@has_category {{o|category}}</samp>
+
| <samp>junimoGoodbye</samp><br /><samp><samp>junimoStar</samp>
| Must have one of the given [[Modding:Items#Categories|object categories]] (space-delimited), or any valid category if none specified. Can be negated with <samp>@!has_category</samp>.
+
| Added validation to check that you're inside the community center.
 
|-
 
|-
| <samp>@has_id {{t|id}}+</samp>
+
| <samp>killAll</samp><br /><samp>killAllHorses</samp><br /><samp>killNpc</samp>
| Must have one of the given unqualified item IDs. Can be negated with <samp>@!has_id</samp>.
+
| These now remove matching NPCs inside constructed buildings too.
 
|-
 
|-
| <samp>@has_id_in_base_range {{t|min}} {{t|max}}</samp>
+
| <samp>killMonsterStat</samp>
| Must have a numeric ID between the {{t|min}} and {{t|max}} values (inclusive). Can be negated with <samp>@!has_id_in_base_range </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>@has_id_prefix {{t|prefix}}+</samp>
+
| <samp>mailForTomorrow</samp>
| Must have an unqualified item ID starting with one of the given prefixes. For example, <samp>@has_id_prefix ExampleAuthor_ExampleMod_</samp> for a mod's items. Can be negated with <samp>@!has_id_prefix</samp>.
+
| Fixed zeros in the mail ID getting replaced with underscores.
 
|-
 
|-
| <samp>@has_object_type {{o|type}}+</samp>
+
| <samp>monster</samp>
| Must have one of the given object ty pes (space-delimited), or any valid type if none specified. Can be negated with <samp>@!has_object_type</samp>.
+
| Added validation for the monster name.
 
|-
 
|-
!colspan="2"| options
+
| <samp>moveBuilding</samp>
 +
| Now applies to the current location, instead of the farm.
 
|-
 
|-
| <samp>@allow_missing_price</samp>
+
| <samp>movie</samp>
| Allow items with a base sell price of 0 or lower. If omitted, those items are skipped.
+
| 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.
|-
  −
| <samp>@count {{t|count}}</samp>
  −
| The number of random items to return. Default 1.
  −
|-
  −
| <samp>@require_explicit_category</samp>
  −
| Whether to ignore items which don't set a category directly in <samp>Data/ObjectInformation</samp>. These are often (but not always) special items like [[Secret Note]] or unimplemented items like Lumber.
  −
|}
     −
For example, you can sell a random [[wallpaper]] for {{price|200}} in <samp>Data/Shops</samp>:
+
New usage:
<syntaxhighlight lang="js">
+
: ''<samp>debug movie {{o|movie ID}} {{o|invite NPC name}}''
{
+
: ''<samp>debug movie current {{o|invite NPC name}}''
    "ItemId": "RANDOM_ITEMS (WP)",
  −
    "Price": 200
  −
}
  −
</syntaxhighlight>
     −
Or a random [[House Plant|house plant]]:
+
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.
<syntaxhighlight lang="js">
  −
{
  −
    "ItemId": "RANDOM_ITEMS (F) @has_id_in_base_range 1376 1390"
  −
}
  −
</syntaxhighlight>
  −
 
  −
Or a random [[#Custom items|custom item]] added by a mod by its item ID prefix:
  −
<syntaxhighlight lang="js">
  −
{
  −
    "ItemId": "RANDOM_ITEMS (O) @has_id_prefix AuthorName_ModName_"
  −
}
  −
</syntaxhighlight>
  −
 
  −
Or 10 random objects with any category except <samp>-13</samp> or <samp>-14</samp>:
  −
<syntaxhighlight lang="js">
  −
{
  −
    "ItemId": "RANDOM_ITEMS (O) @has_category @!has_category -13 -14 @count 10"
  −
}
  −
</syntaxhighlight>
   
|-
 
|-
| <samp>SECRET_NOTE_OR_ITEM {{o|alternate query}}</samp>
+
| <samp>panMode</samp>
| Returns a [[Secret Notes|secret note]] (or [[Journal Scraps|journal scrap]] on the island) if the player hasn't found them all yet, else the result of the {{o|alternate query}} if specified, else nothing.
+
| 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>.
 
  −
For example, <code>SECRET_NOTE_OR_ITEM (O)390</code> returns [[clay]] if the player found every secret note already.
   
|-
 
|-
| <samp>SHOP_TOWN_KEY</samp>
+
| <samp>paintBuilding</samp>
| The special [[Key To The Town|town key]] item. This is only valid in shops.
+
| &#32;
 +
* Now applies to the current location, instead of the farm.
 +
* Added validation for the target building.
 
|-
 
|-
| <samp>TOOL_UPGRADES {{o|tool ID}}</samp>
+
| <samp>playSound</samp>
| The tool upgrades listed in <samp>Data/Shops</samp> whose conditions match the player's inventory (i.e. the same rules as [[Blacksmith|Clint's tool upgrade shop]]). If {{o|tool ID}} is specified, only upgrades which consume that tool ID are shown.
+
| 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.
|}
  −
 
  −
====Item spawn fields====
  −
Several data assets (like [[#Custom machines|machines]] and [[#Custom shops|shops]]) let you configure items to create. For consistency, these all share a set of common fields (internally represented by <samp>ISpawnItemData</samp>, and <samp>GenericSpawnItemData</samp> or <samp>GenericSpawnItemDataWithCondition</samp>):
  −
 
  −
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>question</samp>
! effect
+
| 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>ID</samp>
+
| <samp>runTestEvent</samp>
| A unique identifier for this entry (not the item itself) within the current list. The ID should only contain alphanumeric/underscore/dot characters. For custom items, this should be prefixed with your mod ID like <samp>Example.ModId_Parsnips</samp>.
+
| Fixed support for Unix line endings.
 
  −
This is semi-optional — if omitted, it'll be auto-generated from the <samp>ItemId</samp>, <samp>RandomItemId</samp>, and <samp>IsRecipe</samp> fields. However multiple entries with the same ID may cause unintended behavior (e.g. shop items reducing each others' stock limits), so it's often a good idea to set a globally unique ID instead.
   
|-
 
|-
| <samp>ItemId</samp>
+
| <samp>seenEvent</samp>
| One of:
+
| You can now forget an event (instead of adding it) by setting the second argument to false, like <samp>seenEvent {{t|id}} false</samp>.
* the [[#Custom items|qualified or unqualified item ID]] (like <samp>(O)128</samp> for a [[pufferfish]]);
  −
* or an [[#Item queries|item query]] to dynamically choose one or more items.
   
|-
 
|-
| <samp>RandomItemId</samp>
+
| <samp>seenMail</samp>
| ''(Optional)'' A list of item IDs to randomly choose from, using the same format as <samp>ItemId</samp> (including item queries). If set, <samp>ItemId</samp> is optional and ignored. Each entry in the list has an equal probability of being chosen. For example:
+
| 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>.
<syntaxhighlight lang="js">
  −
// wood, stone, or pizza
  −
"RandomItemId": [ "(O)388", "(O)390", "(O)206" ]
  −
</syntaxhighlight>
   
|-
 
|-
| <samp>Condition</samp>
+
| <samp>skinBuilding</samp>
| ''(Optional)'' A [[#Game state queries|game state query]] which indicates whether this entry should be applied. Defaults to always true.
+
| &#32;
 
+
* Now applies to the current location, instead of the farm.
'''Note:''' not supported for weapon projectiles.
+
* Added validation for the target building.
 
|-
 
|-
| <samp>IsRecipe</samp>
+
| <samp>skullGear</samp>
| ''(Optional)'' Whether to get the crafting/cooking recipe for the item, instead of the item itself. Default false.
+
| &#32;
 +
* Fixed command setting 32 slots instead of 36.
 +
* Fixed command not adding empty inventory slots as expected by some game code.
 
|-
 
|-
| <samp>Quality</samp>
+
| <Samp>setupFishPondFarm</samp>
| ''(Optional)'' The quality of the item to find. One of <samp>0</samp> (normal), <samp>1</samp> (silver), <samp>2</samp> (gold), or <samp>4</samp> (iridium). Invalid values will snap to the closest valid one (e.g. <samp>7</samp> will become iridium). Default -1, which keeps the value set by the item query (usually 0).
+
| Fixed error if the farm already has non-fish-pond buildings constructed.
 
|-
 
|-
| <samp>MinStack</samp>
+
| <samp>speech</samp>
| ''(Optional)'' The item's minimum and default stack size. Default -1, which keeps the value set by the item query (usually 1).
+
| 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>MaxStack</samp>
+
| <samp>spreadDirt</samp>
| ''(Optional)'' If set to a value higher than <samp>MinStack</samp>, the stack is set to a random value between them (inclusively). Default -1.
+
| Now applies to the current location, instead of the farm.
 
|-
 
|-
| <samp>ObjectDisplayName</samp>
+
| <samp>spreadSeeds</samp>
| ''(Optional)'' For objects only, a [[#Tokenizable string format|tokenizable string]] for the item's display name. Defaults to the item's display name in <samp>Data/ObjectInformation</samp>. This can optionally contain <code>%DISPLAY_NAME</code> (the item's default display name) and <code>%PRESERVED_DISPLAY_NAME</code> (the preserved item's display name if applicable, ''e.g.'' if set via <samp>PreserveId</samp> in [[#Custom machines|machine data]]).
+
| Now applies to the current location, instead of the farm.
 
  −
'''Careful:''' text in this field will be saved permanently in the object's info and won't be updated when the player changes language or the content pack changes. That includes Content Patcher translations (like <code><nowiki>%DISPLAY_NAME {{i18n: wine}}</nowiki></code>), which will save the translated text for the current language. Instead, add the text to a strings asset like <samp>Strings/Objects</samp> and then use the [[#Tokenizable string format|<samp>[LocalizedText]</samp> token]].
  −
{{collapse|For example, here's how you'd create flavored oils with Content Patcher:|content=
  −
<ol>
  −
<li>Add the display name to [[Modding:Translations|your <samp>i18n/default.json</samp> file]] (with <samp>{0}</samp> where you want the flavor name):
  −
<syntaxhighlight lang="json">
  −
{
  −
    "flavored-oil": "{0} Oil"
  −
}
  −
</syntaxhighlight></li>
  −
<li>Add the text to a strings asset visible to the game:
  −
{{#tag:syntaxhighlight|<nowiki>
  −
{
  −
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
  −
    "Changes": [
  −
        {
  −
            "Action": "EditData",
  −
            "Target": "Strings/Objects",
  −
            "Entries": {
  −
                "Example.ModId_Oil": "{{i18n: flavored-oil}}"
  −
            }
  −
        }
  −
}</nowiki>|lang=javascript}}</li>
  −
<li>Use the [[#Tokenizable string format|<samp>[LocalizedText]</samp> token]] to get your translation, and pass in the flavor as an argument:
  −
<syntaxhighlight lang="json">
  −
"ObjectDisplayName": "[LocalizedText Strings/Objects:Example.ModId_Oil %PRESERVED_DISPLAY_NAME]",
  −
</syntaxhighlight>
  −
</ol>
  −
 
  −
Now when the player changes language, the object will automatically get the new translation from <samp>Strings/Object</samp>.
  −
}}
   
|-
 
|-
| <samp>ToolUpgradeLevel</samp>
+
| <samp>thisHouseUpgrade</samp>
| ''(Optional)'' For tools only, the initial upgrade level for the tool when created (like [[Axes|Copper vs Gold Axe]], or [[Training Rod]] vs [[Iridium Rod]]). Default -1, which keeps the value set by the item query (usually 0).
+
| Now applies to the current location, instead of the farm.
 
|-
 
|-
| <samp>QualityModifiers</samp><br /><samp>StackModifiers</samp>
+
| <samp>warpToPlayer</samp>
| ''(Optional)'' [[#Quantity modifiers|Quantity modifiers]] applied to the <samp>Quality</samp> or <samp>Stack</samp> value. Default none.
+
| Removed custom space handling; quote arguments with spaces instead of removing them (e.g. <code>JohnSmith</code> <code>"John Smith"</code>).
 
  −
The quality modifiers operate on the numeric quality values (''i.e.'' <samp>0</samp> = normal, <samp>1</samp> = silver, <samp>2</samp> = gold, and <samp>4</samp> = iridium). For example, silver × 2 is gold.
   
|-
 
|-
| <samp>QualityModifierMode</samp><br /><samp>StackModifierMode</samp>
+
| <samp>whereIs</samp>
| ''(Optional)'' [[#Quantity modifiers|quantity modifier modes]] which indicate what to do if multiple modifiers in the <samp>QualityModifiers</samp> or <samp>StackModifiers</samp> field apply at the same time. Default <samp>Stack</samp>.
+
| &#32;
|}
+
* Now lists all matching NPCs instead of the first one.
 +
* Now searches the current event or festival, if any.
 +
|}</li>
   −
===Color fields===
+
<li>Removed some debug commands:
1.6 adds a standardized color format for data fields in assets like [[#Custom wild trees|<samp>Data/WildTrees</samp>]]:
  −
<syntaxhighlight lang="js">
  −
"DebrisColor": "White"
  −
</syntaxhighlight>
  −
 
  −
This supports colors in any of these formats:
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! format
+
! command
! example
+
! notes
 
|-
 
|-
| A [https://docs.monogame.net/api/Microsoft.Xna.Framework.Color.html#properties <samp>Color</samp> property name].
+
| <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>
| <samp>ForestGreen</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]]).
 
|-
 
|-
| A [https://en.wikipedia.org/wiki/Web_colors#Hex_triplet hexadecimal color code]. The optional alpha is a value between <samp>00</samp> (transparent) and <samp>FF</samp> (opaque).
+
| <samp>addQuartz</samp><br /><samp>blueBook</samp><br /><samp>blueprint</samp><br /><samp>end</samp>
| <samp>#228B22</samp><br /><samp>#228B22FF</samp>
+
| These were part of unused features removed in 1.6.
 
|-
 
|-
| An [https://en.wikipedia.org/wiki/RGB_color_model#Numeric_representations 8-bit RGB color code]. The optional alpha is a value between <samp>0</samp> (transparent) and <samp>255</samp> (opaque).
+
| <samp>changeStat</samp>
| <samp>34 139 34</samp><br /><samp>34 139 34 255</samp>
+
| Removed; use <samp>setStat</samp> instead.
|}
  −
 
  −
C# mods can parse a color like <code>Utility.StringToColor("White")</code>.
  −
 
  −
===More <samp>modData</samp> fields===
  −
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 a <samp>modData</samp> field for the <samp>Quest</samp> type, to support custom quest mods.
  −
 
  −
===Quantity modifiers===
  −
''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
+
| <samp>ee</samp><br /><samp>endEvent</samp>/<samp>leaveEvent</samp><br /><samp>eventOver</samp>
! effect
+
| Replaced by the new <samp>endEvent</samp> command.
 
|-
 
|-
| <samp>Id</samp>
+
| <samp>everythingshop</samp>
| An ID for this modifier. This only needs to be unique within the current modifier list. For a custom entry, you should use a unique ID which includes your mod ID like <samp>ExampleMod.Id_ModifierName</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>Modification</samp>
+
| <samp>oldMineGame</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>.
+
| Removed along with the pre-1.4 [[Junimo Kart]] code.
 
|-
 
|-
| <samp>Amount</samp>
+
| <samp>pathSpouseToMe</samp>/<samp>pstm</samp>
| ''(Optional if <samp>RandomAmount</samp> specified)'' The operand applied to the target value (e.g. the multiplier if used with <samp>Multiply</samp>).
+
| Removed along with the unimplemented farm activities code.
|-
+
|}</li>
| <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 [[#Game state queries|game state query]] which indicates whether this change should be applied. Defaults to always true.
  −
|}
     −
====Modifier mode====
+
<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>
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:
+
<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>
   −
{| class="wikitable"
+
====Location logic====
|-
+
* The [[desert]] no longer assumes the player arrived by bus unless their previous location was the [[Bus Stop|bus stop]].
! value
+
* 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.
! 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====
+
====Menus & UI====
For example, this will double the price of a shop item in <samp>Data/Shops</samp>:
+
* 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.
<syntaxhighlight lang="js">
+
* Added <samp>Game1.textShadowDarkerColor</samp> field for the colors previously hardcoded in <samp>Utility.drawTextWithShadow</samp>.
"PriceModifiers": [
+
* 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>.
        "Modification": "Multiply",
+
* The <samp>SpriteText</samp> methods now accept arbitrary <samp>Color</samp> tints instead of a few predefined color IDs.
        "Amount": 2.0
+
* 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.
</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]]):
+
====[[Modding:Modder Guide/Game Fundamentals#Net fields|Net fields]]====
<syntaxhighlight lang="js">
+
* 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.
"PriceModifierMode": "Maximum",
+
* <samp>NetLocationRef</samp> now has a public <samp>LocationName</samp> and <samp>IsStructure</samp>, and its <samp>Update</samp> method allows forcing an update.
"PriceModifiers": [
  −
    {
  −
        "Modification": "Set",
  −
        "RandomAmount": [ 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000 ]
  −
    },
  −
    {
  −
        "Modification": "Multiply",
  −
        "RandomAmount": [ 3, 4, 5 ]
  −
    }
  −
]
  −
</syntaxhighlight>
     −
===Tokenizable string format===
+
====Quests====
Stardew Valley 1.6 adds support for literal strings that contain tokens. These are only usable in specific fields (their docs will say 'tokenizable string' with a link to this section).
+
{{/doc status|[[Modding:Quest data]]|done=false}}
   −
====Literal text====
+
* Quests now have string IDs, to simplify custom quest frameworks.
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):
+
* 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.
   −
<syntaxhighlight lang="js">
+
====Dates & seasons====
// before
+
* 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>).
"Dialogue": "Strings\\StringsFromCSFiles:ShopMenu.cs.11488",
+
* 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.
   −
// after: literal text supported
+
====Time====
"Dialogue": "Welcome to Pierre's!",
+
* 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.
   −
// after: literal text with Content Patcher tokens
+
====Other====
"Dialogue": "Welcome to Pierre's, {{PlayerName}}! {{i18n: translatable-text}}",
+
* Error stack traces on Linux/macOS now have line numbers.
</syntaxhighlight>
+
* 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.
   −
====Tokens====
+
==Breaking changes for C# mods==
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''". Token names are not case-sensitive.
+
'''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.'''
   −
Here are the supported tokens:
+
See also [[#Breaking changes for content packs|''Breaking changes for content packs'']], which affect C# mods too.
{| class="wikitable"
  −
|-
  −
! token format
  −
! output
  −
|-
  −
| <samp>[ArticleFor {{t|word}}]</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''.
  −
|-
  −
| <samp>[CharacterName {{t|name}}]</samp>
  −
| The translated display name for an NPC, given their internal name.
  −
|-
  −
| <samp>[DataString {{t|asset name}} {{t|key}} {{t|index}}]</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).
     −
For example, <samp>[DataString Data\Blueprints Silo 8]</samp> matches the word "Silo" from this entry in <samp>Data\Blueprints</samp>:
+
===.NET 6===
<syntaxhighlight lang="js">
+
: ''See also: [[#.NET 6|.NET 6]] under what's new.''
  "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"
+
 
 +
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>
 
</syntaxhighlight>
|-
+
</li>
| <samp>[DayOfMonth]</samp>
+
<li>Delete your solution's hidden <samp>.vs</samp> folder, and every project's <samp>bin</samp> and <samp>obj</samp> folders.</li>
| The numeric day of month, like <samp>5</samp> on spring 5.
+
<li>Reopen the solution in Visual Studio, click ''Build > Rebuild Solution'', and make sure it still loads into the game fine.</li>
|-
+
</ol>
| <samp>[EscapedText]</samp><br /><samp>[EscapedText {{t|text}}]</samp>
+
 
| Marks a snippet of text as a single argument, so it can be safely passed into another token's space-delimited arguments even if it's empty or contains spaces.
+
===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:
   −
For example, the <samp>SpouseFarmerText</samp> expects two arguments separated by spaces. This passes an empty string for the first one, and text containing spaces for the second:
+
{| class="wikitable"
<pre>[SpouseFarmerText [EscapedText] [EscapedText spouse 28 63 2]]</pre>
   
|-
 
|-
| <samp>[FarmerUniqueID]</samp>
+
! old code
| The target player's unique internal multiplayer ID
+
! new code
 
|-
 
|-
| <samp>[FarmName]</samp>
  −
| The farm name for the current save (without the injected "Farm" text).
   
|-
 
|-
| <samp>[GenderedText {{t|male text}} {{t|female text}}</samp>
+
| <samp>item.ParentSheetIndex == 848</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>.
+
| <samp>item.QualifiedItemId == "(O)848"</samp>
 
|-
 
|-
| <samp>[LocalizedText {{t|string key}}]</samp><br /><samp>[LocalizedText {{t|string key}} {{t|token values}}+]</samp>
+
| <samp>IsNormalObjectAtParentSheetIndex(item, 74)</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.
+
| <samp>item.QualifiedItemId == "(O)74"</samp>
 
|-
 
|-
| <samp>[LocationName {{t|location ID}}]</samp>
+
| <samp>!item.bigCraftable && item.ParentSheetIndex == 128</samp>
| The translated display name for a location given its ID [[#Custom locations|in <samp>Data/Locations</samp>]].
+
| <samp>item.QualifiedItemId == "(O)128"</samp>
 
|-
 
|-
| <samp>[PositiveAdjective]</samp>
+
| <samp>item is Boots && item.ParentSheetIndex == 505</samp>
| A random adjective from the <samp>Strings\Lexicon</samp> data asset's <samp>RandomPositiveAdjective_PlaceOrEvent</samp> entry.
+
| <samp>item.QualifiedItemId == "(B)505"</samp>
|-
+
|}</li>
| <samp>[Season]</samp>
+
<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>
| The current season name, like ''spring''.
+
<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:
|-
  −
| <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 {{o|interval}} {{o|sync key}}]</samp>
  −
| '''(For shops only.)''' The name of a random item currently available in the shop stock.
     −
The result will be identical for all queries with the same {{o|sync key}} during the given {{o|interval}} (one of <samp>tick</samp>, <samp>day</samp>, <samp>season</samp>, <samp>year</samp>), including between players in multiplayer mode. If omitted, they default to <samp>day</samp> and the shop ID respectively.
+
<syntaxhighlight lang="c#">
|}
+
new Object("634", 1);                      // vanilla item
 +
new Object("Example.ModId_Watermelon", 1); // custom item
 +
</syntaxhighlight>
   −
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''.
+
You can also use the new <samp>ItemRegistry</samp> API to construct items from their <samp>QualifiedItemId</samp>:
   −
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!''".
+
<syntaxhighlight lang="c#">
 
+
Item item = ItemRegistry.Create("(B)505"); // Rubber Boots
====Extensibility====
+
</syntaxhighlight></li>
C# mods can define custom tokens by calling <code>TokenParser.RegisterParser("tokenName", ...)</code>. To avoid conflicts, prefixing custom condition names with your mod ID (like <samp>Example.ModId_TokenName</samp>) is strongly recommended.
+
</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]].''
   −
===[[Modding:Event data|Event]] changes===
  −
'''Major changes:'''
   
<ul>
 
<ul>
<li><p>Event IDs are now strings, 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.</p>
+
<li>Several <samp>Game1.player</samp> / <samp>Farmer</samp> fields changed as part of the [[#Buff overhaul|buff overhaul]]:
 
  −
<p>Prefixing the event ID with your mod ID is recommended to simplify troubleshooting and avoid conflicts. For best compatibility, custom IDs should only contain alphanumeric/underscore/dot characters.</p></li>
  −
<li>Added validation for event preconditions & 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 & preconditions 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. For example:
  −
<syntaxhighlight lang="js">
  −
"SomeEventId/": "
  −
    none/-1000 -1000/farmer 5 7 0/
  −
    skippable/
  −
    viewport 5 7 10/
  −
    ...
  −
"
  −
</syntaxHighlight></li>
  −
<li>Event/festival commands with a direction argument now allow both case-insensitive names (like <samp>up</samp>) and numeric values.</li>
  −
<li>C# mods can now add custom event preconditions & commands using <samp>Event.RegisterCustomPrecondition</samp> and <samp>Event.RegisterCustomCommand</samp> respectively.</li>
  −
<li>Added new preconditions:
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! precondition
+
! old field
! description
+
! how to migrate
 
|-
 
|-
| <samp>!</samp>
+
| <samp>appliedBuffs</samp><br /><samp>appliedSpecialBuffs</samp>
| Prefixing <samp>!</samp> to any other precondition will now invert it. For example, <code>!O Abigail</code> will match if the player is ''not'' married to Abigail.
+
| Use <code>Game1.player.hasBuff(id)</code> instead.
 
|-
 
|-
| <samp>G</samp>
+
| <samp>attack</samp><br /><samp>immunity</samp>
| Check the result of a [[#Game state queries|game state query]], like <code>G !WEATHER Here Sun</code> for 'not sunny in this location'.
+
| Use <samp>Attack</samp> and <samp>Immunity</samp> instead.
|}
  −
</li>
  −
<li>Added new event commands:
  −
{| class="wikitable"
   
|-
 
|-
! command
+
| <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>
! description
+
| Use equivalent properties under <samp>Game1.player.buffs</samp> instead (e.g. <samp>Game1.player.buffs.CombatLevel</code>).
 
|-
 
|-
| <samp>addItem {{t|item ID}} {{o|count}} {{o|quality}}</samp>
+
| <samp>resilience</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]].
+
| Use <samp>buffs.Defense</samp> instead.
 
|-
 
|-
| <samp>mailToday {{t|mail key}}</samp>
+
| <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>
| Adds a letter to the mailbox immediately, given the {{t|mail key}} in <samp>Data/Mail</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>
| <samp>stopSound {{t|sound ID}} {{o|immediate}}</samp>
+
<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>
| 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>).
+
<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:
   −
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"
 
{| class="wikitable"
 
|-
 
|-
! index
+
! method
! field
   
! effect
 
! effect
 
|-
 
|-
| 0
+
| <samp>CanSpawnCharacterHere</samp>
| <samp>texture</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.
| The asset name for texture to draw.
   
|-
 
|-
| 1&ndash;4
+
| <samp>CanItemBePlacedHere</samp>
| <samp>rectangle</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.
| 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>isBuildable</samp>
| <samp>interval</samp>
+
| Get whether buildings can be placed on the given tile.
| The millisecond duration for each frame in the animation.
   
|-
 
|-
| 6
+
| <samp>IsTilePassable</samp>
| <samp>frames</samp>
+
| Get whether the tile can be walked on (ignoring collisions with in-game objects, NPCs, etc).
| The number of frames in the animation.
   
|-
 
|-
| 7
+
| <samp>IsTileOccupiedBy</samp>
| <samp>loops</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.
| The number of times to repeat the animation.
   
|-
 
|-
| 8&ndash;9
+
| <samp>IsTileBlockedBy</samp>
| <samp>tile</samp>
+
| Equivalent to calling both <samp>IsTilePassable</samp> and <samp>IsTileOccupiedBy</samp>.
| The tile position at which to draw the sprite, in the form <samp>{{t|x}} {{t|y}}</samp>.
   
|-
 
|-
| 10
+
| <samp>IsLocationSpecificOccupantOnTile</samp><br /><samp>IsLocationSpecificPlacementRestriction</samp>
| <samp>flicker</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]]).
| '''[TODO: document what this does]''' (one of <samp>true</samp> or <samp>false</samp>).
+
|}
 +
 
 +
===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"
 
|-
 
|-
| 11
+
! namespace
| <samp>flip</samp>
+
! class name
| Whether to flip the sprite horizontally when it's drawn (one of <samp>true</samp> or <samp>false</samp>).
   
|-
 
|-
| 12
+
| <samp>StardewValley</samp>
| <samp>sort tile Y</samp>
+
| &#32;
| The tile Y position to use in the layer depth calculation, which affects which sprite is drawn on top if two sprites overlap.
+
* <samp>BuildingUpgrade</samp>
 +
* <samp>DisposableList</samp>
 +
* <samp>FurniturePlacer</samp>
 +
* <samp>ListPool</samp>
 +
* <samp>OneTimeRandom</samp>
 
|-
 
|-
| 13
+
| <samp>StardewValley.Characters</samp>
| <samp>alpha fade</samp>
+
| &#32;
| '''[TODO: document what this does]'''
+
* <samp>BotchedNetBool</samp>
 +
* <samp>BotchedNetField</samp>
 +
* <samp>BotchedNetInt</samp>
 +
* <samp>BotchedNetLong</samp>
 
|-
 
|-
| 14
+
| <samp>StardewValley.Menus</samp>
| <samp>scale</samp>
+
| &#32;
| A multiplier applied to the sprite size (in addition to the normal 4× pixel zoom).
+
* <samp>FarmInfoPage</samp>
 +
* <samp>MiniatureTerrainFeature</samp><!-- not a typo, it really was in StardewValley.Menus -->
 
|-
 
|-
| 15
+
| <samp>StardewValley.Monsters</samp>
| <samp>scale change</samp>
+
| &#32;
| '''[TODO: document what this does]'''
+
* <samp>LavaCrab</samp>
 
|-
 
|-
| 16
+
| <samp>StardewValley.Objects</samp>
| <samp>rotation</samp>
+
| &#32;
| The rotation to apply to the sprite, measured in [[wikipedia:radians|radians]].
+
* <samp>ObjectFactory</samp> (replaced by [[#Custom items|<samp>ItemRegistry</samp>]])
 
|-
 
|-
| 17
+
| <samp>StardewValley.TerrainFeatures</samp>
| <samp>rotation change</samp>
+
| &#32;
| '''[TODO: document what this does]'''
+
* <samp>Quartz</samp>
 
|-
 
|-
| 18+
+
| <samp>StardewValley.Tools</samp>
| ''flags''
+
| &#32;
| Any combination of these space-delimited flags:
+
* <samp>Blueprints</samp>
* <samp>color {{t|color}}</samp>: apply a [[#Color fields|standard color]] to the sprite.
+
* <samp>ToolFactory</samp> (replaced by [[#Custom items|<samp>ItemRegistry</samp>]])
* <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>: '''[TODO: document what this does]'''
  −
* <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]'''
  −
|}
  −
|-
  −
| <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>
  −
</ul>
     −
'''Improved preconditions:'''
+
And these class members:
* The <samp>h</samp> precondition can now be used with any pet type. You can also omit the argument to check for a pet of any type.
  −
 
  −
'''Improved commands:'''
  −
<ul>
  −
<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>Changed specific commands:
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! command
+
! type
! changes
+
! members
 +
|-
 +
| <samp>Axe</samp>
 +
| &#32;
 +
* <samp>StumpStrength</samp>
 
|-
 
|-
| <samp>addTemporaryActor</samp>
+
| <samp>Bush</samp>
 
| &#32;
 
| &#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>.
+
* <samp>alpha</samp>
* Underscores in the display name are no longer replaced with spaces. You should quote arguments containing spaces instead.
+
* <samp>lastPlayerToHit</samp>
 
|-
 
|-
| <samp>animate</samp>
+
| <samp>Chest</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>.
+
| &#32;
 +
* <samp>chestType</samp>
 +
* <samp>coins</samp>
 +
|-
 +
| <samp>CosmeticPlant</samp>
 +
| &#32;
 +
* <samp>scale</samp>
 
|-
 
|-
| <samp>ambientLight</samp>
+
| <samp>CraftingRecipe</samp>
| Removed four-argument form (which was unused and had confusing behavior). The other versions of <samp>ambientLight</samp> still work like before.
+
| &#32;
 +
* <samp>itemType</samp>
 
|-
 
|-
| <samp>awardFestivalPrize</samp>
+
| <samp>Critter</samp>
| Added support for arbitrary item IDs, like <code>awardFestivalPrize (O)128</code> for a pufferfish.
+
| &#32;
 +
* <samp>InitShared()</samp>
 
|-
 
|-
| <samp>changeName</samp>
+
| <samp>Crop</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>.
+
| &#32;
 +
* <samp>daysOfUnclutteredGrowth</samp>
 
|-
 
|-
| <samp>changePortrait</samp><br /><samp>changeSprite</samp>
+
| <samp>Dialogue</samp>
| You can now omit the suffix argument to reset the NPC back to their normal portrait/sprite.
+
| &#32;
 +
* <samp>dialogueToBeKilled</samp>
 
|-
 
|-
| <samp>ignoreMovementAnimation</samp>
+
| <samp>Farm</samp>
 
| &#32;
 
| &#32;
* Fixed its ''ignore'' argument being ignored.
+
* <samp>GetSpouseOutdoorAreaSpritesheetIndex()</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>ignoreMovementAnimation "Mr Qi" …</code>.
   
|-
 
|-
| <samp>itemAboveHead</samp>
+
| <samp>FarmAnimal</samp>
| Added support for arbitrary item IDs, like <code>itemAboveHead (O)128</code> for a pufferfish.
+
| &#32;
 +
* <samp>homeLocation</samp>
 
|-
 
|-
| <samp>makeInvisible</samp>
+
| <samp>Farmer</samp>
| Fixed terrain features not hidden when using the default area size.
+
| &#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>removeItem</samp>
+
| <samp>Game1</samp>
| Added argument for an optional count, like <code>removeItem (O)128 10</code> to remove 10 pufferfish.
+
| &#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>speak</samp>
+
| <samp>GameLocation</samp>
| Fixed friendship & socialize quest not updated when calling it with a translation key.
+
| &#32;
 +
* <samp>boardBus(…)</samp>
 +
* <samp>checkForMapChanges()</samp>
 +
* <samp>getWallDecorItem(…)</samp>
 +
* <samp>removeBatch(…)</samp>
 +
* <samp>removeDirt(…)</samp>
 +
* <samp>removeStumpOrBoulder(…)</samp>
 +
* <samp>tryToBuyNewBackpack()</samp>
 
|-
 
|-
| <samp>weddingSprite</samp>
+
| <samp>GiantCrop</samp>
| Removed (it was broken and unused).
+
| &#32;
|}</li>
+
* <samp>forSale</samp>
</ul>
  −
 
  −
'''Other improvements:'''
  −
* Festivals now set the event ID to a value like <samp>festival_fall16</samp>, instead of <samp>-1</samp>.
  −
* For C# mods, the new <samp>Event.fromAssetName</samp> field indicates which data asset (if any) the event was loaded from.
  −
* Event script errors are now logged (in addition to being shown in the chatbox like before).
  −
 
  −
===[[Modding:Mail data|Mail]] changes===
  −
<ul>
  −
<li>Improved mail commands:
  −
{| class="wikitable"
   
|-
 
|-
! command
+
| <samp>IClickableMenu</samp>
! changes
+
| &#32;
 +
* <samp>currentRegion</samp>
 
|-
 
|-
| <samp>%item</samp>
+
| <samp>MeleeWeapon</samp>
 
| &#32;
 
| &#32;
* Added <samp>%item id {{t|item id}} {{o|count}}</samp> form which accepts a [[#Custom items|qualified or unqualified item ID]]. This deprecates the <samp>bigobject</samp>, <samp>furniture</samp>, <samp>object</samp>, and <samp>tools</samp> options.
+
* <samp>attackSwordCooldownTime</samp>
* 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.
+
* <samp>doStabbingSwordFunction()</samp>
* 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>
  −
</ul>
  −
 
  −
===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
+
| <samp>Monster</samp>
! effect
+
| &#32;
 +
* <samp>doHorizontalMovement(…)</samp>
 +
* <samp>durationOfRandomMovements</samp>
 +
* <samp>coinsToDrop</samp>
 
|-
 
|-
| <samp>SplitBySpace</samp>
+
| <samp>NPC</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:
+
| &#32;
<syntaxhighlight lang="c#">
+
* <samp>idForClones</samp>
string[] fields = ArgUtility.SplitBySpace("a b c");
  −
string secondField = fields[1]; // "b"
  −
</syntaxhighlight>
   
|-
 
|-
| <samp>SplitBySpaceAndGet</samp>
+
| <samp>Object</samp>
| Get the value at an index in a space-delimited string (if found), else return the default value. For example:
+
| &#32;
 
+
* <samp>attachToSprinklerAttachment()</samp>
<syntaxhighlight lang="c#">
+
* <samp>canBePlacedInWater()</samp>
string thirdField = ArgUtility.SplitBySpaceAndGet("a b c", 2); // "c"
+
* <samp>consumeRecipe()</samp>
string invalidFieldA = ArgUtility.SplitBySpaceAndGet("a b c", 5); // null
+
* <samp>copperBar</samp>
string invalidFieldB = ArgUtility.SplitBySpaceAndGet("a b c", 5, defaultValue: "boop"); // "boop"
+
* <samp>goldBar</samp>
</syntaxhighlight>
+
* <samp>iridiumBar</samp>
 
+
* <samp>ironBar</samp>
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>isHoeDirt</samp> and <samp>IsHoeDirt</samp>
 
|-
 
|-
| <samp>SplitBySpaceQuoteAware</samp>
+
| <samp>PathFindController</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.
+
| &#32;
 
+
* <samp>CheckClearance(…)</samp>
For example:
+
* <samp>limit</samp>
<syntaxhighlight lang="c#">
+
|-
string buildingName = ArgUtility.SplitBySpaceQuoteAware("BUILDINGS_CONSTRUCTED Here \"Junimo Hut\"")[1]; // Junimo Hut
+
| <samp>SaveGame</samp>
</syntaxhighlight>
+
| &#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>SplitQuoteAware</samp>
+
| <samp>Tool</samp>
| Split delimited arguments in a string, with support for using quotes to protect delimiters within an argument.
+
| &#32;
 
+
* <samp>batteredSwordSpriteIndex</samp>
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.)
+
* <samp>copperColor</samp>
 
+
* <samp>GetSecondaryEnchantmentCount()</samp>
For example:
+
* <samp>goldColor</samp>
<syntaxhighlight lang="c#">
+
* <samp>iridiumColor</samp>
ArgUtility.SplitQuoteAware("A,B,C", ',');        // [ "A", "B", "C" ]
+
* <samp>nonUpgradeable</samp>
ArgUtility.SplitQuoteAware("A,\"B,C\",D", ','); // [ "A", "B,C", "D" ]
+
* <samp>parsnipSpriteIndex</samp>
ArgUtility.SplitQuoteAware("A,\\\"B,C", ',');    // [ "A", "\"B", "C" ]
+
* <samp>Stackable</samp>
</syntaxhighlight>
+
* <samp>startOfNegativeWeaponIndex</samp>
 
+
* <samp>steelColor</samp>
You can also set the optional arguments for more advanced cases. For example, [[#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>
+
| <samp>Utility</samp>
| Escape quotes in a string so they're ignored by methods like <samp>SplitQuoteAware</samp>.
+
| &#32;
 
+
* <samp>buyFloor()</samp>
This isn't idempotent (e.g. calling it twice will result in double-escaped quotes).
+
* <samp>buyWallpaper()</samp>
 +
* <samp>cropsOfTheWeek()</samp>
 +
* <samp>facePlayerEndBehavior()</samp>
 +
* <samp>getRandomSlotCharacter()</samp>
 +
* <samp>plantCrops(…)</samp>
 +
* <samp>showLanternBar()</samp>
 
|}
 
|}
   −
; Reading arrays&#58;
+
====Renamed classes====
: {| class="wikitable"
+
These classes were renamed in 1.6:
 +
{| class="wikitable"
 
|-
 
|-
! <samp>ArgUtility</samp> method
+
! old name
! effect
+
! new name
 
|-
 
|-
| <samp>HasIndex</samp>
+
| <samp>Game1.MusicContext</samp>
| Get whether an index is within the bounds of the array. For example:
+
| <samp>MusicContext</samp> (in <samp>StardewValley.GameData</samp>)
<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>
+
| <samp>LocationContext</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.
+
| <samp>LocationContexts</samp>
 
  −
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>
+
| <samp>SpecialOrder.QuestStatus</samp>
| Similar to the previous methods, but gets arguments starting from an index as a concatenated string. For example:
+
| <samp>SpecialOrderStatus</samp> (in <samp>StardewValley.SpecialOrders</samp>)
<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>
   
|}
 
|}
   −
====Content assets====
+
And these were moved to a different namespace:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! method
+
! type
! effect
+
! old namespace
 +
! new namespace
 
|-
 
|-
| <samp>LocalizedContentManager.DoesAssetExist</samp>
+
| <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>
| 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:
+
| <samp>StardewValley</samp>
<syntaxhighlight lang="c#">
+
| <samp>StardewValley.Enchantments</samp>
bool exists = Game1.content.DoesAssetExist<Map>("Maps/Town");
  −
</syntaxhighlight>
   
|-
 
|-
| <samp>LocalizedContentManager.IsValidTranslationKey</samp>
+
| <samp>Extensions</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:
+
| <samp>StardewValley</samp>
<syntaxhighlight lang="c#">
+
| <samp>StardewValley.Extensions</samp>
bool exists = Game1.content.IsValidTranslationKey("Strings\\NPCNames:Abigail");
  −
</syntaxhighlight>
  −
|}
  −
 
  −
====Game paths====
  −
The game folder paths were previously hardcoded throughout the code. These are now centralized with a few methods:
  −
 
  −
{| class="wikitable"
   
|-
 
|-
! method
+
| <samp>ModDataDictionary</samp><br /><samp>ModHooks</samp>
! effect
+
| <samp>StardewValley</samp>
 +
| <samp>StardewValley.Mods</samp>
 
|-
 
|-
| <samp>Program.GetLocalAppDataFolder</samp><br /><samp>Program.GetAppDataFolder</samp>
+
| <samp>PathFindController</samp><br /><samp>PathNode</samp><br /><samp>PriorityQueue</samp><br /><samp>SchedulePathDescription</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>StardewValley</samp>
 +
| <samp>StardewValley.Pathfinding</samp>
 
|-
 
|-
| <samp>Program.GetSavesFolder</samp>
+
| <samp>SpecialOrder</samp>
| Get the absolute path to the game's [[saves|<samp>Saves</samp> folder]].
+
| <samp>StardewValley</samp>
 +
| <samp>StardewValley.SpecialOrders</samp>
 
|-
 
|-
| <samp>Game1.GetScreenshotFolder</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>
| Get the absolute path to the game's <samp>Screenshots</samp> folder.
+
| <samp>StardewValley</samp>
 +
| <samp>StardewValley.SpecialOrders.Objectives</samp>
 
|-
 
|-
| <samp>options.GetFilePathForDefaultOptions</samp>
+
| <samp>FriendshipReward</samp><br /><samp>GemsReward</samp><br /><samp>MailReward</samp><br /><samp>MoneyReward</samp><br /><samp>OrderReward</samp><br /><samp>ResetEventReward</samp>
| Get the absolute path to the game's <samp>default_options</samp> file.
+
| <samp>StardewValley</samp>
 +
| <samp>StardewValley.SpecialOrders.Rewards</samp>
 
|}
 
|}
   −
====Iteration====
+
====Other API changes====
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.
+
These class members changed in 1.6:
    
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! method
+
! type
! effect
+
! member
 +
! migration
 
|-
 
|-
| <samp>Utility.ForEachBuilding</samp>
+
| <samp>BigSlime</samp>
| Perform an action for each building in the game world.
+
| <samp>heldObject</samp>
 +
| Replaced by <samp>heldItem</samp>, which allows non-object items too.
 
|-
 
|-
| <samp>Utility.ForEachCharacter</samp><br /><samp>Utility.ForEachVillager</samp>
+
|rowspan="3"| <samp>Bush</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>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>Utility.ForEachCrop</samp>
+
| <samp>getTileLocation</samp><br /><samp>getTileX</samp><br /><samp>getTileY</samp><br />
| Perform an action for each crop in the game world planted in the ground or in a [[Garden Pot|garden pot]].
+
| Removed; use <samp>character.Tile</samp> instead.
 
|-
 
|-
| <samp>Utility.ForEachItem</samp>
+
| <samp>getTileLocationPoint</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.
+
| Removed; use <samp>character.TilePoint</samp> instead.
 
|-
 
|-
| <samp>Utility.ForEachItemIn</samp>
+
| <samp>Chest</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>MoveToSafePosition</samp>
 +
| Replaced by the simpler <samp>TryMoveToSafePosition</samp>
 
|-
 
|-
| <samp>Utility.ForEachLocation</samp>
+
|rowspan="2"| <samp>Dialogue</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.
+
| <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.
 
  −
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>
  −
 
  −
C# mods which add custom item types can override <samp>Item.ForEachItem</samp> to add support for nested items.
  −
 
  −
====Randomization====
  −
{| class="wikitable"
   
|-
 
|-
! method
+
| <samp>isOnFinalDialogue()</samp>
! effect
+
| 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.
 
|-
 
|-
| <samp>Utility.CreateDaySaveRandom</samp>
+
|rowspan="3"| <samp>Farmer</samp>
| Creates a <samp>Random</samp> instance using the most common seed (based on the save ID and total days played).
+
| <samp>changePants(…)</samp>
 +
| Renamed to <samp>changePantsColor()</samp> for consistency with <samp>change[Eye&#124;Hair&#124;Shoe]Color</samp>.
 
|-
 
|-
| <samp>Utility.CreateRandom</samp><br /><samp>Utility.CreateRandomSeed</samp>
+
| <samp>isMarried()</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.
+
| Renamed to <samp>isMarriedOrRoommates()</samp> for clarity.
 
|-
 
|-
| <samp>Utility.TryCreateIntervalRandom</samp>
+
| <samp>visibleQuestCount</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.
+
| Replaced by <samp>hasVisibleQuests</samp>.
 
+
|-
For example, this will return the same number each time it's called until the in-game day changes:
+
| <samp>Flooring</samp>
<syntaxhighlight lang="c#">
+
| <samp>GetFloorPathLookup</samp>
public int GetDailyRandomNumber()
+
| Use <samp>Game1.floorPathData</samp> instead.
{
  −
    Utility.TryCreateIntervalRandom("day", "example sync key", out Random random, out _);
  −
    return random.Next();
  −
}
  −
</syntaxhighlight>
   
|-
 
|-
| <samp>Utility.TryGetRandom</samp>
+
| <samp>Forest</samp>
| Get a random entry from a dictionary.
+
| <samp>log</samp>
 +
| Moved into <samp>Forest.resourceClumps</samp>.
 
|-
 
|-
| <samp>random.Choose</samp>
+
| <samp>FruitTree</samp>
| Choose a random option from the values provided:
+
| <samp>GreenHouseTree</samp>
<syntaxhighlight lang="c#">
+
| Replaced by <samp>IgnoresSeasonsHere()</samp>.
string npcName = Game1.random.Choose("Abigail", "Penny", "Sam");
  −
</syntaxhighlight>
   
|-
 
|-
| <samp>random.ChooseFrom</samp>
+
|rowspan="3"| <samp>Game1</samp>
| Choose a random option from a list or array:
+
| <samp>bigCraftableInformation</samp>
<syntaxhighlight lang="c#">
+
| Overhauled into [[#Custom big craftables|<samp>Game1.bigCraftableData</samp>]].
string[] names = new[] { "Abigail", "Penny", "Sam" };
  −
string npcName = Game1.random.ChooseFrom(names);
  −
</syntaxhighlight>
   
|-
 
|-
| <samp>random.NextBool</samp>
+
| <samp>clothingInformation</samp>
| Randomly choose <samp>true</samp> or <samp>false</samp>. For example:
+
| Overhauled into [[#Custom shirts|<samp>Game1.shirtData</samp>]] and [[#Custom pants|<samp>Game1.pantsData</samp>]].
<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
+
| <samp>objectInformation</samp>
! effect
+
| Overhauled into [[#Custom objects|<samp>Game1.objectData</samp>]].
 
|-
 
|-
| <samp>Utility.distanceFromScreen</samp>
+
|rowspan="3"| <samp>GameLocation</samp>
| Get the pixel distance between a position in the world and the player's screen viewport, where 0 is within the viewport.
+
| <samp>getCharacters</samp>
 +
| Removed; use the <samp>characters</samp> field instead.
 
|-
 
|-
| <samp>Utility.DrawErrorTexture</samp>
+
| <samp>GetMapPropertyPosition</samp>
| Draw the game's missing-texture image (🚫) to the screen, stretched to fit a given pixel area.
+
| Replaced by <samp>TryGetMapPropertyAs</samp>, which supports multiple data types (not just <samp>Point</samp>).
 
|-
 
|-
| <samp>Utility.GetEnumOrDefault</samp>
+
| <samp>isTileOccupied</samp><br /><samp>isTileOccupiedForPlacement</samp><br /><samp>isTileOccupiedIgnoreFloors</samp><br /><samp>isTileLocationOpenIgnoreFrontLayers</samp><br /><samp>isTileLocationTotallyClearAndPlaceable</samp><br /><samp>isTileLocationTotallyClearAndPlaceableIgnoreFloors</samp>
| Get an enum value if it's valid, else get a default value. This is mainly used to validate input from data files.
+
| 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.
   −
For example:
+
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.
<syntaxhighlight lang="c#">
+
{{collapse|expand for non-recommended code|content=<syntaxhighlight lang="c#">
NpcGender gender = (NPCGender)999999;
+
public static class GameLocationExtensions
gender = Utility.GetEnumOrDefault(gender, Gender.Male); // returns Gender.Male since there's no enum constant with value 999999
+
{
 +
    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>
 
</syntaxhighlight>
 +
}}
 
|-
 
|-
| <samp>Utility.getRandomNpcFromHomeRegion</samp>
+
| <samp>GiantCrop</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:
+
| <samp>which</samp>
<syntaxhighlight lang="c#">
+
| Replaced by <samp>itemId</samp>.
NPC npc = Utility.getRandomNpcFromHomeRegion(NPC.region_town);
+
|-
</syntaxhighlight>
+
| <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>Utility.isFestivalDay</samp><br /><samp>Utility.IsPassiveFestivalDay</samp>
+
| <samp>NetFields</samp>
| These methods existed before 1.6, but now have versions with no arguments to check today:
+
| <samp>AddFields</samp>
 +
| Removed; use <samp>AddField</samp> instead. For example:
 
<syntaxhighlight lang="c#">
 
<syntaxhighlight lang="c#">
bool festivalToday = Utility.isFestivalToday();
+
// old code
</syntaxhighlight>
+
NetFields.AddFields(textureName, spriteWidth, spriteHeight);
   −
<samp>IsPassiveFestivalDay</samp> also has a new form to check for a specific festival today:
+
// new code
<syntaxhighlight lang="c#">
+
NetFields
bool nightMarketToday = Utility.IsPassiveFestivalDay("NightMarket");
+
    .AddField(textureName)
 +
    .AddField(spriteWidth)
 +
    .AddField(spriteHeight);
 
</syntaxhighlight>
 
</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.
 
|-
 
|-
| <samp>Utility.TryGetPassiveFestivalData</samp><br /><samp>Utility.TryGetPassiveFestivalDataForDay</samp>
+
|rowspan="7"| <samp>NPC</samp>
| Get the [[#Custom passive festivals|passive festival data]] for the given ID or date.
+
| <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>Utility.TryParseDirection</samp>
+
| <samp>Gender</samp><br /><samp>female</samp><br /><samp>male</samp><br /><samp>undefined</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]].
+
| 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>Utility.TryParseEnum</samp>
+
| <samp>homeRegion</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:
+
| 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>.
<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>
+
| <samp>isBirthday</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.
+
| Remove the arguments, like <code>npc.isBirthday(Game1.currentSeason, Game1.dayOfMonth)</code> → <code>npc.isBirthday()</code>.
 
|-
 
|-
| <samp>rectangle.GetPoints</samp><br /><samp>rectangle.GetVectors</samp>
+
| <samp>isVillager()</samp>
| Get all the integer coordinates within a given <samp>Rectangle</samp>. For example:
+
| Deprecated; use the <samp>character.IsVillager</samp> property instead.
<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>
+
| <samp>populateRoutesFromLocationToLocationList</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.
+
| Replaced by <samp>WarpPathfindingCache.PopulateCache</samp>.
 
|-
 
|-
| <samp>Utility.WrapIndex</samp>
+
| <samp>Schedule</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).
+
| 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:
 
For example:
 
<syntaxhighlight lang="c#">
 
<syntaxhighlight lang="c#">
string[] values = new[] { "0", "1", "2" };
+
// old code
int index = Utility.WrapIndex(-1, values.Length); // 2
+
bool inUse = Utility.GetHorseWarpRestrictionsForFarmer(player).Any(p => p == 4);
</syntaxhighlight>
  −
|}
     −
===Static delegate builder===
+
// new code
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>]].
+
bool inUse = Utility.GetHorseWarpRestrictionsForFarmer(player).HasFlag(Utility.HorseWarpRestrictions.InUse);
 
  −
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>
 
</syntaxhighlight>
   −
And a delegate which matches it:
+
Or to check if no restrictions apply:
 
<syntaxhighlight lang="c#">
 
<syntaxhighlight lang="c#">
public delegate bool MachineOutputDelegate(Object machine, Item inputItem, bool probe, MachineItemOutput outputData, out int? overrideMinutesUntilReady);
+
bool canSummon = Utility.GetHorseWarpRestrictionsForFarmer(player) == Utility.HorseWarpRestrictions.None;
 
</syntaxhighlight>
 
</syntaxhighlight>
   −
You can create an optimized delegate and call it like this:
+
C# mods can patch <samp>Utility.GetHorseWarpErrorMessage</samp> if they need to add an error message for a custom restriction value.
<syntaxhighlight lang="c#">
+
|-
if (StaticDelegateBuilder.TryCreateDelegate("StardewValley.Object.OutputDeconstructor", out MachineOutputDelegate method, out string error))
+
| <samp>getRandomTownNPC(…)</samp>
    return method(this, inputItem, probe, outputData, out minutesUntilMorning);
+
| Replaced by either <code>Utility.GetRandomWinterStartParticipant(…)</code> or <code>Utility.getRandomNpcFromHomeRegion(NPC.region_town)</code>.
else
+
|-
    Game1.log.Warn($"Machine {ItemId} has invalid output method: {error}");
+
| <samp>getTodaysBirthdayNPC</samp>
</syntaxhighlight>
+
| Remove the arguments, like <code>Utility.getTodaysBirthdayNPC(Game1.currentSeason, Game1.dayOfMonth)</code> → <code>Utility.getTodaysBirthdayNPC()</code>.
 
+
|-
The <samp>TryCreateDelegate</samp> method will cache created delegates, so calling it again will just return the same delegate instance.
+
| <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.
===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:
+
| <samp>numObelisksOnFarm</samp>
<syntaxhighlight lang="c#">
+
| Renamed to <samp>GetObeliskTypesBuilt</samp>, which searches all locations.
// old code
+
|-
Console.WriteLine("Error playing sound: " + ex);
+
| <samp>numSilos</samp>
 +
| Removed.
   −
// new code
+
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.
Game1.log.Error("Error playing sound.", ex);
  −
</syntaxhighlight>
     −
This has a few benefits:
+
If you actually need the number of silos, use <samp>location.getNumberBuildingsConstructed("Silo")</samp> (one location) or <samp>Game1.GetNumberBuildingsConstructed("Silo")</samp> (all locations).
* 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
+
| <samp>removeThisCharacterFromAllLocations</samp>
! new method
+
| Removed; use <samp>Game1.removeCharacterFromItsLocation</samp> instead.
 
|-
 
|-
| <samp>Game1.playSound</samp><br /><samp>Game1.playSoundAt</samp><br /><samp>Game1.playSoundPitched</samp>
+
| <samp>ShopMenu</samp>
| <samp>Game1.playSound</samp>
+
| <samp>storeContext</samp>
 +
| Replaced by <samp>ShopId</samp>.
 
|-
 
|-
| <samp>GameLocation.playSound</samp><br /><samp>GameLocation.playSoundAt</samp><br /><samp>GameLocation.playSoundPitched</samp>
+
|rowspan="3"| <samp>Stats</samp>
| <samp>GameLocation.playSound</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>GameLocation.localSound</samp><br /><samp>GameLocation.localSoundAt</samp>
+
| <samp>getStat(…)</samp><br /><samp>incrementStat(…)</samp>
| <samp>GameLocation.localSound</samp>
+
| Replaced by <samp>Get(…)</samp> and <samp>Increment(…)</samp>. See [[#Stat changes for C# mods|stat changes for C# mods]].
 
|-
 
|-
| <samp>NetAudio.Play</samp><br /><samp>NetAudio.PlayAt</samp><br /><samp>NetAudio.PlayPitched</samp>
+
| <samp>stat_dictionary</samp>
| <samp>NetAudio.Play</samp>
+
| Renamed to <samp>Values</samp>. See [[#Stat changes for C# mods|stat changes for C# mods]].
 
|-
 
|-
| <samp>NetAudio.PlayLocal</samp><br /><samp>NetAudio.PlayLocalAt</samp>
+
| <samp>Woods</samp>
| <samp>NetAudio.PlayLocal</samp>
+
| <samp>stumps</samp>
|}</li>
+
| Moved into <samp>resourceClumps</samp>.
</ul>
+
|}
   −
====Debug commands====
+
===Check for obsolete code===
<ul>
+
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.
<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>bsm</samp>
  −
| If the player is standing right under a building, open a menu to change the building appearance.
  −
|-
  −
| <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.
+
==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.'''
| <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 [[#Game state queries|game state query]] matches in the current context. For example:
+
===Standardized ID fields===
<pre>
+
Stardew Valley 1.6 adds an <samp>Id</samp> field to these assets. For Content Patcher content packs, these replace the previous synthetic ID:
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 [[#Item queries|item query]] (all items free). For example:
+
{| class="wikitable"
* <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>legacyTimeouts</samp>
+
! asset
| Switches the multiplayer timeout behavior between legacy (timeouts are based on both ping time and last sync time like in 1.5.6) and non-legacy (timeouts are only based on ping time).
+
! old key
 +
! new key
 +
! migration steps
 
|-
 
|-
| <samp>logSounds</samp>
+
| <samp>Data/ConcessionTastes</samp><br /><samp>Data/MovieReactions</samp><br /><samp>Data/RandomBundles</samp> (area)<br /><samp>Data/RandomBundles</samp> (bundle)
| Log info about each sound effect played to the SMAPI console window.
+
| <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>qualifiedid</samp>
+
| <samp>Data/FishPondData</samp><br /><samp>Data/RandomBundles</samp> (bundle set)
| Print the held item's display name and [[#Custom items|qualified item ID]].
+
| <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>shop</samp>
+
| <samp>Data/TailoringRecipes</samp>
| ''Syntax:'' <samp>shop {{t|shop ID}} {{o|owner name}}</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}}
   −
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).
+
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.
| <samp>testwedding</samp>
+
* To add a custom entry, use a [[Modding:Common data field types#Unique string ID|unique string ID]].
| Immediately play the [[Marriage#The Wedding|wedding]] event.
  −
|-
  −
| <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>tokens</samp>
  −
| ''Syntax:'' <samp>tokens {{t|tokenized string}}</samp>
     −
Parses a [[#Tokenizable string|tokenizable string]] and prints its output. For example:
+
For example:
<pre>
+
{{#tag:syntaxhighlight|<nowiki>
tokens [LocalizedText Strings\StringsFromCSFiles:MapPage.cs.11064 [EscapedText [FarmName]]]
+
{
> Result: "Lon Lon Farm"
+
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
</pre>
+
    "Changes": [
|}</li>
+
        {
<li>Improved existing debug commands:
+
            "Action": "EditData",
{| class="wikitable"
+
            "Target": "Data/TailorRecipes",
|-
+
            "Entries": {
! command
+
                "ExampleAuthor.ModId_RainCoatFromPufferchick": {
! changes
+
                    "Id": "ExampleAuthor.ModId_RainCoatFromPufferchick", // need to specify ID again when creating it
|-
+
                    "FirstItemTags": [ "item_cloth" ],
| <samp>build</samp>
+
                    "SecondItemTags": [ "item_pufferchick" ],
| Removed custom space handling; quote arguments with spaces instead of replacing them with 9 (e.g. <code>Junimo9Hut</code> <code>"Junimo Hut"</code>).
+
                    "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"
 
|-
 
|-
| <samp>clearFurniture</samp>
+
! old flag
| Now works outside the farmhouse too.
+
! new flag
 
|-
 
|-
| <samp>dialogue</samp>
+
| <samp>Gil_Slime Charmer Ring</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>Gil_Slimes</samp>
 
|-
 
|-
| <samp>ebi</samp>
+
| <samp>Gil_Savage Ring</samp>
| Fixed event not played correctly if called from the same location as the event.
+
| <samp>Gil_Shadows</samp>
 
|-
 
|-
| <samp>fish</samp>
+
| <samp>Gil_Vampire Ring</samp>
| Fixed error if you're not holding a fishing rod. It now opens the fishing minigame with no tackle instead.
+
| <samp>Gil_Bats</samp>
 
|-
 
|-
| <samp>frameOffset</samp>
+
| <samp>Gil_Skeleton Mask</samp>
| &#32;
+
| <samp>Gil_Skeletons</samp>
* 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>
+
| <samp>Gil_Insect Head</samp>
| Added validation for the stat name.
+
| <samp>Gil_Insects</samp>
 
|-
 
|-
| <samp>grass</samp>
+
| <samp>Gil_Hard Hat</samp>
| Now applies to the current location, instead of the farm.
+
| <samp>Gil_Duggy</samp>
 
|-
 
|-
| <samp>growAnimals</samp><br /><samp>growAnimalsFarm</samp>
+
| <samp>Gil_Burglar's Ring</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>Gil_DustSpirits</samp>
 
|-
 
|-
| <samp>growCrops</samp>
+
| <samp>Gil_Crabshell Ring</samp>
| Fixed error growing mixed seeds or giant crops.
+
| <samp>Gil_Crabs</samp>
 
|-
 
|-
| <samp>itemNamed</samp>
+
| <samp>Gil_Arcane Hat</samp>
| Removed custom space handling; quote arguments with spaces instead of removing them (e.g. <code>EelRoe</code> → <code>"Eel Roe"</code>).
+
| <samp>Gil_Mummies</samp>
 
|-
 
|-
| <samp>junimoGoodbye</samp><br /><samp><samp>junimoStar</samp>
+
| <samp>Gil_Knight's Helmet</samp>
| Added validation to check that you're inside the community center.
+
| <samp>Gil_Dinos</samp>
 
|-
 
|-
| <samp>killAll</samp><br /><samp>killAllHorses</samp><br /><samp>killNpc</samp>
+
| <samp>Gil_Napalm Ring</samp>
| These now remove matching NPCs inside constructed buildings too.
+
| <samp>Gil_Serpents</samp>
 
|-
 
|-
| <samp>killMonsterStat</samp>
+
| <samp>Gil_Telephone</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>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"
 
|-
 
|-
| <samp>mailForTomorrow</samp>
+
!rowspan="2"| content asset
| Fixed zeros in the mail ID getting replaced with underscores.
+
!rowspan="2"| changes in 1.6
 +
!colspan="2"| compatibility for pre-1.6 mods
 
|-
 
|-
| <samp>monster</samp>
+
! XNB mods
| Added validation for the monster name.
+
! Content Patcher packs
 
|-
 
|-
| <samp>moveBuilding</samp>
+
| <samp>Buildings/houses</samp>
| Now applies to the current location, instead of the farm.
+
| &#32;
 +
* fixed missing pixels
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>movie</samp>
+
| <samp>Characters/Dialogue/Abigail</samp><br /><samp>Characters/Dialogue/Alex</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.
+
| &#32;
 
+
* added [[#Dialogue changes|flower dance dialogue]]
New usage:
+
* fixed typos
: ''<samp>debug movie {{o|movie ID}} {{o|invite NPC name}}''
+
| '''✘ broken'''
: ''<samp>debug movie current {{o|invite NPC name}}''
+
| ✓ mostly unaffected
 
  −
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>
+
| <samp>Characters/Dialogue/Caroline</samp><br /><samp>Characters/Dialogue/Demetrius</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>.
+
| &#32;
 +
* fixed typos
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>paintBuilding</samp>
+
| <samp>Characters/Dialogue/Elliott</samp>
 
| &#32;
 
| &#32;
* Now applies to the current location, instead of the farm.
+
* added [[#Dialogue changes|flower dance dialogue]]
* Added validation for the target building.
+
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>playSound</samp>
+
| <samp>Characters/Dialogue/Emily</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.
+
| &#32;
 +
* added [[#Dialogue changes|flower dance dialogue]]
 +
* fixed typos
 +
* updated <samp>%revealtaste</samp> format (backwards-compatible)
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>skinBuilding</samp>
+
| <samp>Characters/Dialogue/George</samp>
 
| &#32;
 
| &#32;
* Now applies to the current location, instead of the farm.
+
* added [[#Dialogue changes|Winter Star gift exchange dialogue]]
* Added validation for the target building.
+
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>skullGear</samp>
+
| <samp>Characters/Dialogue/Gus</samp>
 
| &#32;
 
| &#32;
* Fixed command setting 32 slots instead of 36.
+
* fixed typos
* Fixed command not adding empty inventory slots as expected by some game code.
+
| ✘ will remove changes
 +
| ✓ mostly unaffected
 
|-
 
|-
| <Samp>setupFishPondFarm</samp>
+
| <samp>Characters/Dialogue/Haley</samp>
| Fixed error if the farm already has non-fish-pond buildings constructed.
+
| &#32;
 +
* added [[#Dialogue changes|flower dance dialogue]]
 +
* fixed typos
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>speech</samp>
+
| <samp>Characters/Dialogue/Harvey</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>).
+
| &#32;
 +
* added [[#Dialogue changes|flower dance dialogue]]
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>spreadDirt</samp>
+
| <samp>Characters/Dialogue/Jas</samp><br /><samp>Characters/Dialogue/Jodi</samp>
| Now applies to the current location, instead of the farm.
+
| &#32;
 +
* fixed typos
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>spreadSeeds</samp>
+
| <samp>Characters/Dialogue/Krobus</samp>
| Now applies to the current location, instead of the farm.
+
| &#32;
 +
* added [[#Dialogue changes|roommate stardrop dialogue]]
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>thisHouseUpgrade</samp>
+
| <samp>Characters/Dialogue/Leah</samp>
| Now applies to the current location, instead of the farm.
+
| &#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>warpToPlayer</samp>
+
| <samp>Characters/Dialogue/Marnie</samp>
| Removed custom space handling; quote arguments with spaces instead of removing them (e.g. <code>JohnSmith</code> → <code>"John Smith"</code>).
+
| &#32;
 +
* added [[#Dialogue changes|Stardew Valley Fair dialogue]]
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>whereIs</samp>
+
| <samp>Characters/Dialogue/MarriageDialogue</samp><br /><samp>Characters/Dialogue/MarriageDialogueAbigail</samp><br /><samp>Characters/Dialogue/MarriageDialogueElliott</samp>
| Now lists all matching NPCs instead of the first one.
+
| &#32;
|}</li>
+
* fixed typos
 
+
| ✘ will remove changes
<li>Removed some debug commands:
+
| ✓ mostly unaffected
{| class="wikitable"
   
|-
 
|-
! command
+
| <samp>Characters/Dialogue/MarriageDialogueEmily</samp>
! notes
+
| &#32;
 +
* changed <samp>spring_Maru</samp> key to <samp>spring_Emily</samp>
 +
* fixed typos
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
| <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>
+
| <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>
| 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 [[#Item queries|item query]]).
+
| &#32;
 +
* fixed typos
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>addQuartz</samp><br /><samp>blueBook</samp><br /><samp>blueprint</samp>
+
| <samp>Characters/Dialogue/Maru</samp>
| These were part of unused features removed in 1.6.
+
| &#32;
 +
* added [[#Dialogue changes|flower dance dialogue]]
 +
* fixed typos
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>oldMineGame</samp>
+
| <samp>Characters/Dialogue/Penny</samp>
| Removed along with the pre-1.4 [[Junimo Kart]] code.
+
| &#32;
 +
* added [[#Dialogue changes|flower dance dialogue]]
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>pathSpouseToMe</samp>/<samp>pstm</samp>
+
| <samp>Characters/Dialogue/Pierre</samp>
| Removed along with the unimplemented farm activities code.
+
| &#32;
|}</li>
+
* added [[#Dialogue changes|Stardew Valley Fair dialogue]]
 
+
* fixed typos
<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>
+
| '''✘ broken'''
<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>
+
| ✓ mostly unaffected
</ul>
+
|-
 
+
| <samp>Characters/Dialogue/Robin</samp>
====Location logic====
+
| &#32;
* The [[desert]] no longer assumes the player arrived by bus unless their previous location was the [[Bus Stop|bus stop]].
+
* fixed typos
* 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.
+
| ✘ will remove changes
 
+
| ✓ mostly unaffected
====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.
+
| <samp>Characters/Dialogue/Sam</samp>
* The <samp>SpriteText</samp> methods now accept arbitrary <samp>Color</samp> tints instead of a few predefined color IDs.
+
| &#32;
* Added <samp>Game1.textShadowDarkerColor</samp> field for the colors previously hardcoded in <samp>Utility.drawTextWithShadow</samp>.
+
* added [[#Dialogue changes|flower dance dialogue]]
* Added <samp>MoneyDial.ShouldShakeMainMoneyBox</samp> field to simplify custom dials.
+
* fixed typos
* Fixed an edge case where a custom language's fonts wouldn't be loaded when switching language.
+
| '''✘ broken'''
 
+
| ✓ mostly unaffected
====[[Modding:Modder Guide/Game Fundamentals#Net fields|Net fields]]====
+
|-
* Removed implicit conversion operators for most types (except <samp>NetBool</samp>, <samp>NetInt</samp>, and <samp>NetString</samp>).
+
| <samp>Characters/Dialogue/Sandy</samp>
* <samp>NetLocationRef</samp> now has a public <samp>LocationName</samp> and <samp>IsStructure</samp>, and its <samp>Update</samp> method allows forcing an update.
+
| &#32;
 
+
* fixed typos
====Quests====
+
| ✘ will remove changes
* Quests now have string IDs, to simplify custom quest frameworks.
+
| ✓ mostly unaffected
* 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.
+
| <samp>Characters/Dialogue/Sebastian</samp>
* For C# mods, fixed <samp>DescriptionElement</samp> not allowing more than four translation token substitutions.
+
| &#32;
 
+
* added [[#Dialogue changes|flower dance dialogue]]
====Seasons====
+
* fixed typos
* 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>).
+
| '''✘ broken'''
* Added <samp>Game1.season</samp>, <samp>Game1.GetSeasonForLocation</samp>, <samp>Game1.WorldDate.Season</samp>, and <samp>location.GetSeason()</samp> to get the season enum.
+
| ✓ mostly unaffected
* Added <samp>Utility.getSeasonKey</samp> to get the key form from a season enum.
+
|-
* 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>).
+
| <samp>Characters/Dialogue/Willy</samp>
* Fixed <samp>location.GetSeasonKey()</samp> not applying the greenhouse logic.
+
| &#32;
 
+
* added [[#Dialogue changes|Stardew Valley Fair dialogue]]
====Time====
+
| '''✘ broken'''
* 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.
+
| ✓ mostly unaffected
 
+
|-
====Other====
+
| <samp>Characters/Dialogue/Shane</samp>
* Error stack traces on Linux/macOS now have line numbers.
+
| &#32;
* All space-delimited fields now ignore extra spaces instead of crashing. This affects map/tile properties, data assets, event commands, game state queries, etc.
+
* added [[#Dialogue changes|flower dance dialogue]]
* 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]].
+
| '''✘ broken'''
* 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.
+
| ✓ mostly unaffected
* 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).
+
|-
* Added C# code docs in many places.
+
| <samp>Characters/Farmer/hats</samp>
* Added <samp>Id</samp> fields to simplify content pack edits in fish pond, movie concession, random bundle, and tailoring recipe data.
+
| &#32;
* 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.)
+
* removed stray pixel on chicken mask
* Added <samp>Game1.versionBuildNumber</samp> with the build number (like <samp>26039</samp>).
+
| ✘ will remove changes
* Added field-changed events to <samp>NetPosition</samp>.
+
| ✓ mostly unaffected
* 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.
  −
* 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
+
| <samp>Characters/schedules/Elliott</samp>
! new code
+
| &#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>item.ParentSheetIndex == 848</samp>
+
| <samp>Data/AquariumFish</samp>
| <samp>item.QualifiedItemId == "(O)848"</samp>
+
| &#32;
 +
* [[#Custom items|changed key type]]
 +
* added hat position for [[Sea Urchin]]
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>IsNormalObjectAtParentSheetIndex(item, 74)</samp>
+
| <samp>Data/BigCraftablesInformation</samp>
| <samp>item.QualifiedItemId == "(O)74"</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>!item.bigCraftable && item.ParentSheetIndex == 128</samp>
+
| <samp>Data/Blueprints</samp>
| <samp>item.QualifiedItemId == "(O)128"</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>item is Boots && item.ParentSheetIndex == 505</samp>
+
| <samp>Data/Boots</samp>
| <samp>item.QualifiedItemId == "(B)505"</samp>
+
| &#32;
|}</li>
+
* [[#Custom items|changed key type]]
<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>
+
* added display name
<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:
+
| '''✘ broken'''
 
+
| ✓ mostly unaffected<br /><small>(covered by runtime migration)</small>
<syntaxhighlight lang="c#">
+
|-
new Object("634", 1);                     // vanilla item
+
| <samp>Data/Bundles</samp>
new Object("Example.ModId_Watermelon", 1); // custom item
+
| &#32;
</syntaxhighlight>
+
* can no longer omit empty fields before display name
 
+
* added display name field in English
You can also use the new <samp>ItemRegistry</samp> API to construct items from their <samp>QualifiedItemId</samp>:
+
* removed meat items in animal bundle
 
+
| '''✘ broken'''
<syntaxhighlight lang="c#">
+
| '''✘ likely broken'''
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.
  −
 
  −
===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
+
| <samp>Data/ClothingInformation</samp>
! how to migrate
+
| &#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>appliedBuffs</samp><br /><samp>appliedSpecialBuffs</samp>
+
| <samp>Data/Concessions</samp>
| Use <code>Game1.player.hasBuff(id)</code> instead.
+
| &#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>attack</samp><br /><samp>immunity</samp>
+
| <samp>Data/ConcessionTastes</samp>
| Use <samp>Attack</samp> and <samp>Immunity</samp> instead.
+
| &#32;
 +
* added automatic <samp>ID</samp> field
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
| <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>
+
| <samp>Data/CookingRecipes</samp>
| Use equivalent properties under <samp>Game1.player.buffs</samp> instead (e.g. <samp>Game1.player.buffs.CombatLevel</code>).
+
| &#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>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>Data/CraftingRecipes</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.
+
| &#32;
|}</li>
+
* replaced translations with [[Modding:Tokenizable strings|tokenizable strings]]
<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>
+
* display names can now be omitted to use item name
<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>
+
* added <samp>default</samp> unlock condition
</ul>
+
* fixed typo in Cookout Kit entry
 
+
| '''✘ broken'''
===Collision changes===
+
| ✓ mostly unaffected
The game's tile collision logic has been overhauled and merged into a simpler set of methods on <samp>GameLocation</samp> instances:
+
|-
 
+
| <samp>Data/Crops</samp>
{| class="wikitable"
+
| &#32;
 +
* [[#Custom crops|completely overhauled]]
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected<br /><small>(covered by runtime migration)</small>
 
|-
 
|-
! method
+
| <samp>Data/Events/AnimalShop</samp>
! effect
+
| &#32;
 +
* updated command syntax (backwards-compatible)
 +
|
 +
|
 
|-
 
|-
| <samp>CanSpawnCharacterHere</samp>
+
| <samp>Data/Events/Farm</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.
+
| &#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>CanItemBePlacedHere</samp>
+
| <samp>Data/Events/FishShop</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.
+
| &#32;
 +
* fixed typos
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>isBuildable</samp>
+
| <samp>Data/Events/Forest</samp>
| Get whether buildings can be placed on the given tile.
+
| &#32;
 +
* fixed typos
 +
* updated Jas <samp>faceDirection</samp> command for sewer event
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>IsTilePassable</samp>
+
| <samp>Data/Events/IslandHut</samp>
| Get whether the tile can be walked on (ignoring collisions with in-game objects, NPCs, etc).
+
| &#32;
 +
* updated how Leo's name is translated
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>IsTileOccupiedBy</samp>
+
| <samp>Data/Events/IslandNorth</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.
+
| &#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>IsTileBlockedBy</samp>
+
| <samp>Data/Events/IslandSouth</samp>
| Equivalent to calling both <samp>IsTilePassable</samp> and <samp>IsTileOccupiedBy</samp>.
+
| &#32;
 +
* fixed blank music field (backwards-compatible)
 +
* fixed typos
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>IsLocationSpecificOccupantOnTile</samp><br /><samp>IsLocationSpecificPlacementRestriction</samp>
+
| <samp>Data/Events/JoshHouse</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]]).
+
| &#32;
|}
+
* fixed typos
 
+
| ✘ will remove changes
===Map & tile property changes===
+
| ✓ mostly unaffected
When reading map or tile properties, the <samp>PropertyValue</samp> class no longer exists. You can replace it with <samp>string</samp> to get the value directly instead. For example:
  −
<syntaxhighlight lang="c#">
  −
// old code (broken)
  −
if (tile.Properties.TryGetValue("name", out PropertyValue propertyValue))
  −
{
  −
    string value = propertyValue.ToString();
  −
    // ...
  −
}
  −
 
  −
// updated
  −
if (tile.Properties.TryGetValue("name", out string value))
  −
{
  −
    // ...
  −
}
  −
</syntaxhighlight>
  −
 
  −
===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
+
| <samp>Data/Events/LeahHouse</samp>
! class name
+
| &#32;
 +
* fixed <samp>move</samp> command format in Leah's 2-heart event
 +
* fixed typos
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>StardewValley</samp>
+
| <samp>Data/Events/Mountain</samp>
| <samp>BuildingUpgrade</samp><br /><samp>DisposableList</samp><br /><samp>FurniturePlacer</samp><br /><samp>ListPool</samp><br /><samp>OneTimeRandom</samp>
+
| &#32;
 +
* fixed skipped dialogue in Maru's 14-heart event
 +
* fixed typos
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>StardewValley.Characters</samp>
+
| <samp>Data/Events/Saloon</samp><br /><samp>Data/Events/ScienceHouse</samp><br /><samp>Data/Events/SebastianRoom</samp>
| <samp>BotchedNetBool</samp><br /><samp>BotchedNetField</samp><br /><samp>BotchedNetInt</samp><br /><samp>BotchedNetLong</samp>
+
| &#32;
 +
* fixed typos
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>StardewValley.Menus</samp>
+
| <samp>Data/Events/Town</samp>
| <samp>FarmInfoPage</samp><br /><samp>MiniatureTerrainFeature</samp><!-- not a typo, it really was in StardewValley.Menus -->
+
| &#32;
 +
* fixed <samp>warp</samp> command format in community center completed event
 +
* fixed typos
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>StardewValley.Monsters</samp>
+
| <samp>Data/Events/WizardHouse</samp>
| <samp>LavaCrab</samp>
+
| &#32;
 +
* fixed typos
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>StardewValley.Objects</samp>
+
| <samp>Data/ExtraDialogue</samp>
| <samp>ObjectFactory</samp> (replaced by [[#Custom items|<samp>ItemRegistry</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>StardewValley.TerrainFeatures</samp>
+
| <samp>Data/FarmAnimals</samp>
| <samp>Quartz</samp>
+
| &#32;
 +
* [[#Custom farm animals|completely overhauled]]
 +
| '''✘ broken'''
 +
| '''✘ broken'''
 
|-
 
|-
| <samp>StardewValley.Tools</samp>
+
| <samp>Data/Festivals/fall16</samp>
| <samp>Blueprints</samp><br /><samp>ToolFactory</samp> (replaced by [[#Custom items|<samp>ItemRegistry</samp>]])
+
| &#32;
|}
+
* updated command syntax (backwards-compatible)
 
+
* fixed typos
And these class members:
+
| ✘ will remove changes
{| class="wikitable"
+
| ✓ mostly unaffected
 
|-
 
|-
! type
+
| <samp>Data/Festivals/fall27</samp>
! members
+
| &#32;
 +
* removed <samp>shop</samp> field (moved into [[#Custom shops|<samp>Data/Shops</samp>]])
 +
| ✓ mostly unaffected
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>Axe</samp>
+
| <samp>Data/Festivals/spring13</samp>
| <samp>StumpStrength</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>Bush</samp>
+
| <samp>Data/Festivals/spring24</samp><br /><samp>Data/Festivals/summer11</samp><br /><samp>Data/Festivals/summer28</samp>
| <samp>alpha</samp><br /><samp>lastPlayerToHit</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>
 
|-
 
|-
| <samp>Chest</samp>
+
| <br /><samp>Data/Festivals/winter8</samp>
| <samp>chestType</samp><br /><samp>coins</samp>
+
| &#32;
|-
+
* migrated to new <samp>warpFarmers</samp> command
| <samp>CosmeticPlant</samp>
+
* removed <samp>shop</samp> field (moved into [[#Custom shops|<samp>Data/Shops</samp>]])
| <samp>scale</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>CraftingRecipe</samp>
+
| <samp>Data/Festivals/winter25</samp>
| <samp>itemType</samp>
+
| &#32;
 +
* removed <samp>shop</samp> field (moved into [[#Custom shops|<samp>Data/Shops</samp>]])
 +
| ✓ mostly unaffected
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>Crop</samp>
+
| <samp>Data/Fish</samp>
| <samp>daysOfUnclutteredGrowth</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>Farm</samp>
+
| <samp>Data/FishPondData</samp>
| <samp>GetSpouseOutdoorAreaSpritesheetIndex</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>FarmAnimal</samp>
+
| <samp>Data/fruitTrees</samp>
| <samp>homeLocation</samp>
+
| &#32;
 +
* [[#Custom fruit trees|completely overhauled]]
 +
| '''✘ broken'''
 +
| '''✘ broken'''
 
|-
 
|-
| <samp>Farmer</samp>
+
| <samp>Data/Furniture</samp>
| <samp>blueprints</samp><br /><samp>eyeColor</samp><br /><samp>hasBusTicket</samp><br /><samp>furnitureOwned</samp><br /><samp>newSkillPointsToSpend</samp><br /><samp>overallsColor</samp><br /><samp>ownsFurniture</samp><br /><samp>shirtColor</samp><br /><samp>skinColor</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>Game1</samp>
+
| <samp>Data/hats</samp>
| <samp>boardingBus</samp><br /><samp>chanceToRainTomorrow</samp><br /><samp>checkForNewLevelPerks</samp><br /><samp>progressBar</samp><br /><samp>shiny</samp><br /><samp>shippingTax</samp><br /><samp>tinyFontBorder</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>GameLocation</samp>
+
| <samp>Data/Locations</samp>
| <samp>boardBus</samp><br /><samp>getWallDecorItem</samp><br /><samp>removeDirt</samp>
+
| &#32;
 +
* [[#Custom locations|completely overhauled]]
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected<br /><small>(covered by runtime migration)</small>
 
|-
 
|-
| <samp>GiantCrop</samp>
+
| <samp>Data/mail</samp>
| <samp>forSale</samp>
+
| &#32;
 +
* migrated to <samp>%item id</samp> (backwards-compatible)
 +
* removed unused entries
 +
* fixed typos
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>IClickableMenu</samp>
+
| <samp>Data/Monsters</samp>
| <samp>currentRegion</samp>
+
| &#32;
 +
* changed ''Dust Spirit'' display name to ''Dust Sprite''
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>MeleeWeapon</samp>
+
| <samp>Data/Movies</samp>
| <samp>attackSwordCooldownTime</samp><br /><samp>doStabbingSwordFunction</samp>
+
| &#32;
 +
* [[#Custom movies|significantly overhauled]]
 +
| '''✘ broken'''
 +
| '''✘ broken'''
 
|-
 
|-
| <samp>Monster</samp>
+
| <samp>Data/MoviesReactions</samp>
| <samp>doHorizontalMovement</samp><br /><samp>durationOfRandomMovements</samp><br /><samp>coinsToDrop</samp>
+
| &#32;
 +
* replaced translations with [[Modding:Tokenizable strings|tokenizable strings]]
 +
* standardized <samp>ID</samp><samp>Id</samp> naming
 +
* fixed typo
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>NPC</samp>
+
| <samp>Data/NPCDispositions</samp>
| <samp>canReceiveThisItemAsGift</samp><br /><samp>idForClones</samp>
+
| &#32;
 +
* asset replaced by [[#Custom NPCs|<samp>Data/Characters</samp>]]
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected<br /><small>(covered by runtime migration)</small>
 
|-
 
|-
| <samp>Object</samp>
+
| <samp>Data/NPCGiftTastes</samp>
| <samp>attachToSprinklerAttachment</samp><br /><samp>canBePlacedInWater</samp><br /><samp>consumeRecipe</samp><br /><samp>IsHoeDirt</samp><br /><samp>isHoeDirt</samp>
+
| &#32;
 +
* removed invalid item IDs
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>PathFindController</samp>
+
| <samp>Data/ObjectContextTags</samp>
| <samp>CheckClearance</samp><br /><samp>limit</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>PetBowl</samp>
+
| <samp>Data/ObjectInformation</samp>
| <samp>FindPet</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>SaveGame</samp>
+
| <samp>Data/PaintData</samp>
| <samp>shippingTax</samp>
+
| &#32;
 +
* fixed trailing slash in <samp>Deluxe Barn</samp> entry
 +
|
 +
|
 
|-
 
|-
| <samp>Spiker</samp>
+
| <samp>Data/Quests</samp>
| <samp>GetSpawnPosition</samp>
+
| &#32;
 +
* changed key type to string
 +
* migrated to use item IDs (backwards-compatible)
 +
* fixed typo
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>Tool</samp>
+
| <samp>Data/RandomBundles</samp>
| <samp>batteredSwordSpriteIndex</samp><br /><samp>GetSecondaryEnchantmentCount</samp><br /><samp>nonUpgradeable</samp><br /><samp>parsnipSpriteIndex</samp><br /><samp>Stackable</samp><br /><samp>startOfNegativeWeaponIndex</samp>
+
| &#32;
 +
* add optional <samp>Id</samp> field
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>Utility</samp>
+
| <samp>Data/SecretNotes</samp>
| <samp>plantCrops</samp><br /><samp>showLanternBar</samp>
+
| &#32;
|}
+
* updated <samp>%revealtaste</samp> format (backwards-compatible)
 
+
| ✘ will remove changes
====Renamed classes====
+
| ✓ mostly unaffected
These classes were renamed in 1.6:
  −
{| class="wikitable"
   
|-
 
|-
! old name
+
| <samp>Data/SpecialOrders</samp>
! new name
+
| &#32;
 +
* changed type of <samp>Repeatable</samp> and <samp>Duration</samp> fields
 +
* added optional <samp>CustomFields</samp> and <samp>Conditions</samp> fields
 +
| '''✘ broken'''
 +
|
 
|-
 
|-
| <samp>LocationContext</samp>
+
| <samp>Data/SpousePatios</samp><br /><samp>Data/SpouseRooms</samp>
| <samp>LocationContexts</samp>
+
| &#32;
|}
+
* removed asset (merged into [[#Custom NPCs|<samp>Data/Characters</samp>]])
 
+
| '''✘ broken'''
And these were moved to a different namespace:
+
| '''✘ broken'''
{| class="wikitable"
   
|-
 
|-
! type
+
| <samp>Data/TailoringRecipes</samp>
! old namespace
+
| &#32;
! new namespace
+
* 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>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>Data/TV/CookingChannel</samp><br /><samp>Data/TV/TipChannel</samp>
| <samp>StardewValley</samp>
+
| &#32;
| <samp>StardewValley.Enchantments</samp>
+
* fixed typos
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>Extensions</samp>
+
| <samp>Data/weapons</samp>
| <samp>StardewValley</samp>
+
| &#32;
| <samp>StardewValley.Extensions</samp>
+
* [[#Custom melee weapons|completely overhauled]]
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected<br /><small>(covered by runtime migration)</small>
 
|-
 
|-
| <samp>ModDataDictionary</samp><br /><samp>ModHooks</samp>
+
| <samp>LooseSprites/Cursors</samp>
| <samp>StardewValley</samp>
+
| &#32;
| <samp>StardewValley.Mods</samp>
+
* new sprites in empty area
 +
* moved mailbox to <samp>Buildings/Mailbox</samp>
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>PathFindController</samp><br /><samp>PathNode</samp><br /><samp>PriorityQueue</samp><br /><samp>SchedulePathDescription</samp>
+
| <samp>LooseSprites/Cursors2</samp>
| <samp>StardewValley</samp>
+
| &#32;
| <samp>StardewValley.Pathfinding</samp>
+
* new sprite in empty area
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>SpecialOrder</samp>
+
| <samp>LooseSprites/map</samp>
| <samp>StardewValley</samp>
+
| &#32;
| <samp>StardewValley.SpecialOrders</samp>
+
* redrawn to better match in-game locations
 +
* added more detail
 +
| '''✘ broken'''
 +
| ✘ likely broken
 
|-
 
|-
| <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>Maps/AbandonedJojaMart</samp><br /><samp>Maps/AdventureGuild</samp>
| <samp>StardewValley</samp>
+
| &#32;
| <samp>StardewValley.SpecialOrders.Objectives</samp>
+
* moved <samp>Music</samp> property into <samp>Data/Locations</samp>
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>FriendshipReward</samp><br /><samp>GemsReward</samp><br /><samp>MailReward</samp><br /><samp>MoneyReward</samp><br /><samp>OrderReward</samp><br /><samp>ResetEventReward</samp>
+
| <samp>Maps/AnimalShop</samp>
| <samp>StardewValley</samp>
+
| &#32;
| <samp>StardewValley.SpecialOrders.Rewards</samp>
+
* removed unused pathfinding tiles
|}
+
|
 
+
|
====Other API changes====
  −
These class members changed in 1.6:
  −
 
  −
{| class="wikitable"
   
|-
 
|-
! type
+
| <samp>Maps/ArchaeologyHouse</samp>
! member
+
| &#32;
! migration
+
* removed unused pathfinding tiles
 +
* moved <samp>Music</samp> property into <samp>Data/Locations</samp>
 +
|
 +
|
 
|-
 
|-
|rowspan="3"| <samp>Bush</samp>
+
| <samp>Maps/Backwoods</samp><br /><samp>Maps/Backwoods_GraveSite</samp><br /><samp>Maps/Backwoods_Staircase</samp>
| <samp>overrideSeason</samp>
+
| &#32;
| Removed; use <code>bush.currentLocation.GetSeason()</code> instead.
+
* removed unused tile properties
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
|
 +
|
 
|-
 
|-
| <samp>greenhouseBush</samp>
+
| <samp>Maps/Barn</samp><br /><samp>Maps/Barn2</samp>
| Removed; use <code>bush.IsSheltered()</code> or <code>bush.currentLocation.IsGreenhouse</code> instead.
+
| &#32;
 +
* removed unused map properties
 +
|
 +
|
 
|-
 
|-
| <samp>inBloom</samp>
+
| <samp>Maps/Barn3</samp>
| Remove the arguments, like <code>bush.inBloom(Game1.currentSeason, Game1.dayOfMonth)</code> → <code>bush.inBloom()</code>.
+
| &#32;
 +
* added <samp>AutoFeed</samp> map property
 +
* removed unused map properties
 +
| '''✘ broken'''
 +
|
 
|-
 
|-
|rowspan="3"| <samp>Character</samp>
+
| <samp>Maps/BathHouse_Entry</samp><br /><samp>Maps/BathHouse_MensLocker</samp>
| <samp>getStandingX</samp><br /><samp>getStandingY</samp><br /><samp>getStandingXY</samp>
+
| &#32;
| Removed; use <samp>character.StandingPixel</samp> instead.
+
* moved <samp>Music</samp> property into <samp>Data/Locations</samp>
 +
* removed unused pathfinding tiles
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>getTileLocation</samp><br /><samp>getTileX</samp><br /><samp>getTileY</samp><br />
+
| <samp>Maps/BathHouse_Pool</samp>
| Removed; use <samp>character.Tile</samp> instead.
+
| &#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>getTileLocationPoint</samp>
+
| <samp>Maps/Beach</samp>
| Removed; use <samp>character.TilePoint</samp> instead.
+
| &#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
 
|-
 
|-
|rowspan="2"| <samp>Farmer</samp>
+
| <samp>Maps/Blacksmith</samp>
| <samp>changePants</samp>
+
| &#32;
| Renamed to <samp>changePantsColor</samp> for consistency with <samp>change[Eye&#124;Hair&#124;Shoe]Color</samp>.
+
* removed unused pathfinding tiles
 +
|
 +
|
 
|-
 
|-
| <samp>visibleQuestCount</samp>
+
| <samp>Maps/BoatTunnel</samp>
| Replaced by <samp>hasVisibleQuests</samp>.
+
| &#32;
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
|
 +
|
 
|-
 
|-
| <samp>Flooring</samp>
+
| <samp>Maps/BugLand</samp>
| <samp>GetFloorPathLookup</samp>
+
| &#32;
| Use <samp>Game1.floorPathData</samp> instead.
+
* 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>Forest</samp>
+
| <samp>Maps/BusStop</samp>
| <samp>log</samp>
+
| &#32;
| Moved into <samp>Forest.resourceClumps</samp>.
+
* 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)
 +
|
 +
|
 
|-
 
|-
|rowspan="2"| <samp>GameLocation</samp>
+
| <samp>Maps/Caldera</samp>
| <samp>getCharacters</samp>
+
| &#32;
| Removed; use the <samp>characters</samp> field instead.
+
* removed unused map property
 +
|
 +
|
 
|-
 
|-
| <samp>isTileOccupied</samp><br /><samp>isTileOccupiedForPlacement</samp><br /><samp>isTileOccupiedIgnoreFloors</samp><br /><samp>isTileLocationOpenIgnoreFrontLayers</samp><br /><samp>isTileLocationTotallyClearAndPlaceable</samp><br /><samp>isTileLocationTotallyClearAndPlaceableIgnoreFloors</samp>
+
| <samp>Maps/Cellar</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.
+
| &#32;
 
+
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
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>Maps/Club</samp>
| <samp>which</samp>
+
| &#32;
| Replaced by <samp>itemId</samp>.
+
* added <samp>LocationContext</samp> map property
 +
* moved <samp>Music</samp> property into <samp>Data/Locations</samp>
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>Item</samp>
+
| <samp>Maps/Coop</samp><br /><samp>Maps/Coop2</samp>
| <samp>SanitizeContextTag</samp>
+
| &#32;
| Replaced by <samp>ItemContextTagManager.SanitizeContextTag</samp>.
+
* removed unused map properties
 +
|
 +
|
 
|-
 
|-
| <samp>LocalizedContentManager</samp>
+
| <samp>Maps/Coop3</samp>
| <samp>LanguageCodeString</samp>
+
| &#32;
| Now static.
+
* added <samp>AutoFeed</samp> map property
 +
* removed unused map properties
 +
| '''✘ broken'''
 +
|
 
|-
 
|-
| <samp>LocationContextData</samp>
+
| <samp>Maps/Desert</samp>
| <samp>Name</samp>
+
| &#32;
| Removed; use its dictionary key in <samp>Game1.locationContextData</samp> instead.
+
* 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>NetFields</samp>
+
| <samp>Maps/ElliottHouse</samp>
| <samp>AddFields</samp>
+
| &#32;
| Removed; use <samp>AddField</samp> instead. For example:
+
* removed unused pathfinding tiles
<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="4"| <samp>NPC</samp>
+
| <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>
| <samp>homeRegion</samp>
+
| &#32;
| 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>.
+
* 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>isBirthday</samp>
+
| <samp>Maps/Farm_Greenhouse_Dirt</samp><br /><samp>Maps/Farm_Greenhouse_Dirt_FourCorners</samp>
| Remove the arguments, like <code>npc.isBirthday(Game1.currentSeason, Game1.dayOfMonth)</code> <code>npc.isBirthday()</code>.
+
| &#32;
 +
* removed unused map properties
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
|
 +
|
 
|-
 
|-
| <samp>populateRoutesFromLocationToLocationList</samp>
+
| <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>
| Replaced by <samp>WarpPathfindingCache.PopulateCache</samp>.
+
| &#32;
 +
* removed unused map properties
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
|
 +
|
 
|-
 
|-
| <samp>Schedule</samp>
+
| <samp>Maps/FishingGame</samp>
| No longer assignable, use one of the <samp>TryLoadSchedule</samp> overloads instead.
+
| &#32;
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
|
 +
|
 
|-
 
|-
|rowspan="8"| <samp>Utility</samp>
+
| <samp>Maps/FishShop</samp>
| <samp>doesItemWithThisIndexExistAnywhere</samp>
+
| &#32;
| Replace with <samp>Utility.doesItemExistAnywhere</samp>, which takes a string item ID. For example:
+
* fixed broken <samp>DayTiles</samp> and <samp>NightTiles</samp> values
* <code>Utility.doesItemWithThisIndexExistAnywhere(128)</code> &rarr; <code>Utility.doesItemExistAnywhere("(O)128")</code>;
+
* removed unused pathfinding tiles
* <code>Utility.doesItemWithThisIndexExistAnywhere(128, true)</code> &rarr; <code>Utility.doesItemExistAnywhere("(BC)128")</code>.
+
| ✘ will remove changes
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>ForAllLocations</samp><br /><samp>iterateAllCrops</samp><br /><samp>iterateAllItems</samp>
+
| <samp>Maps/Forest</samp>
| Removed; use the equivalent <samp>Utility.ForEach*</samp> methods instead.
+
| &#32;
 +
* removed unused map/tile properties
 +
* removed unused pathfinding tiles
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
|
 +
|
 
|-
 
|-
| <samp>GetHorseWarpRestrictionsForFarmer</samp>
+
| <samp>Maps/Forest-FlowerFestival</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>.
+
| &#32;
 
+
* updated for festival shops now in <samp>Data/Shops</samp>
For example:
+
* removed unused map/tile properties
<syntaxhighlight lang="c#">
+
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
// old code
+
| '''✘ broken'''
bool inUse = Utility.GetHorseWarpRestrictionsForFarmer(player).Any(p => p == 4);
+
| ✓ mostly unaffected
 
  −
// 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>getTodaysBirthdayNPC</samp>
+
| <samp>Maps/Forest-IceFestival</samp>
| Remove the arguments, like <code>Utility.getTodaysBirthdayNPC(Game1.currentSeason, Game1.dayOfMonth)</code> <code>Utility.getTodaysBirthdayNPC()</code>.
+
| &#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>getPooledList</samp><br /><samp>returnPooledList</samp>
+
| <samp>Maps/Forest-SewerClean</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.
+
| &#32;
 +
* removed unused map/tile properties
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
|
 +
|
 
|-
 
|-
| <samp>numObelisksOnFarm</samp>
+
| <samp>Maps/HaleyHouse</samp><br /><samp>Maps/HarveyRoom</samp>
| Renamed to <samp>GetObeliskTypesBuilt</samp>, which searches all locations.
+
| &#32;
 +
* removed unused pathfinding tiles
 +
|
 +
|
 
|-
 
|-
| <samp>numSilos</samp>
+
| <samp>Maps/Hospital</samp>
| Removed.
+
| &#32;
 
+
* removed deprecated <samp>UniquePortrait</samp> & <samp>UniqueSprite</samp> map properties
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.
+
* removed unused pathfinding tiles
 
+
| ✘ will remove changes<br /><small>(This may cause mod conflicts)</samp>
If you actually need the number of silos, use <samp>location.getNumberBuildingsConstructed("Silo")</samp> (one location) or <samp>Game1.GetNumberBuildingsConstructed("Silo")</samp> (all locations).
+
| ✓ mostly unaffected
 
|-
 
|-
| <samp>removeThisCharacterFromAllLocations</samp>
+
| <samp>Maps/Island_Bridge_Broken</samp><br /><samp>Maps/Island_Bridge_Repaired</samp><br /><samp>Maps/Island_House_Cave</samp>
| Removed; use <samp>Game1.removeCharacterFromItsLocation</samp> instead.
+
| &#32;
 +
* removed unused map properties
 +
|
 +
|
 
|-
 
|-
| <samp>ShopMenu</samp>
+
| <samp>Maps/Island_N</samp>
| <samp>storeContext</samp>
+
| &#32;
| Replaced by <samp>ShopId</samp>.
+
* update walnut bush tile so it still works in 1.6
|}
+
* removed unused tile property
 
+
| '''✘ broken'''
===Check for obsolete code===
+
| ✓ mostly unaffected
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 data fields===
  −
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.'''
  −
 
  −
Three examples illustrate the standardization:
  −
 
  −
<ul>
  −
<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/BigCraftablesInformation</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):
  −
<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
  −
"151": "Marble Brazier/500/-300/Crafting -9/Provides a moderate amount of light./true/true/0//Marble Brazier" // 10 fields
  −
</syntaxhighlight></li>
  −
<li><samp>Data/ObjectInformation</samp> had several optional fields at the end. These are now required even if empty:
  −
<syntaxhighlight lang="json">
  −
// before
  −
"0": "Weeds/0/-1/Basic/Weeds/A bunch of obnoxious weeds."
  −
 
  −
// after
  −
"0": "Weeds/0/-1/Basic/Weeds/A bunch of obnoxious weeds.///"
  −
</syntaxhighlight></li>
  −
</ul>
  −
 
  −
Existing mods which add entries without the now-required fields may cause errors and crashes. XNB mods which change data are likely universally broken.
  −
 
  −
The exception is fields which only exist for modding, like the texture + index overrides for [[#Custom items|custom items]]. These can typically be omitted.
  −
 
  −
===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
+
| <samp>Maps/IslandNorthCave1</samp><br /><samp>Maps/IslandSouthEastCave</samp><br /><samp>Maps/IslandSouthEastCave_pirates</samp><br /><samp>Maps/IslandWestCave1</samp>
! old key
+
| &#32;
! new key
+
* moved <samp>Music</samp> property into <samp>Data/Locations</samp>
! migration steps
+
| ✘ will remove changes
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>Data/ConcessionTastes</samp><br /><samp>Data/MovieReactions</samp><br /><samp>Data/RandomBundles</samp> (area)<br /><samp>Data/RandomBundles</samp> (bundle)
+
| <samp>Maps/Island_Bridge_Broken</samp><br /><samp>Maps/Island_Bridge_Repaired</samp>
| <samp>Name</samp><br /><samp>NPCName</samp><br /><samp>AreaName</samp><br />''none''
+
| &#32;
|<samp>Id</samp>
+
* removed unused map property
| 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.
+
* 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>Data/FishPondData</samp><br /><samp>Data/RandomBundles</samp> (bundle set)
+
| <samp>Maps/Island_Shrine</samp>
| <samp>RequiredTags</samp><br />''none''
+
| &#32;
| <samp>Id</samp>
+
* moved <samp>Music</samp> property into <samp>Data/Locations</samp>
| Use the new <samp>Id</samp> field to target an entry, and add it when creating a new entry. Required.
+
| ✘ will remove changes
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>Data/TailoringRecipes</samp>
+
| <samp>Maps/Island_W</samp>
| <samp>FirstItemTags</samp> and <samp>SecondItemTags</samp>
+
| &#32;
| <samp>Id</samp>
+
* removed unused tile property
| 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.
+
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
|}
+
|
 
+
|
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 globally unique ID prefixed with your mod ID. This should only have alphanumeric, underscore, and dot characters so it's safe to use in delimited fields, file names, etc. The recommended format is <samp>ExampleAuthor.ModId_EntryName</samp>.
  −
 
  −
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===
  −
: ''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===
  −
: ''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
+
| <samp>Maps/IslandFarmHouse</samp>
! new flag
+
| &#32;
 +
* removed unused tile properties
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
|
 +
|
 
|-
 
|-
| <samp>Gil_Slime Charmer Ring</samp>
+
| <samp>Maps/JojaMart</samp><br /><samp>Maps/JoshHouse</samp><br /><samp>Maps/LeahHouse</samp><br /><samp>Maps/ManorHouse</samp>
| <samp>Gil_Slimes</samp>
+
| &#32;
 +
* removed unused pathfinding tiles
 +
|
 +
|
 
|-
 
|-
| <samp>Gil_Savage Ring</samp>
+
| <samp>Maps/MarnieBarn</samp>
| <samp>Gil_Shadows</samp>
+
| &#32;
 +
* removed unused map properties
 +
|
 +
|
 
|-
 
|-
| <samp>Gil_Vampire Ring</samp>
+
| <samp>Maps/Mine</samp>
| <samp>Gil_Bats</samp>
+
| &#32;
 +
* updated for [[#Custom minecarts|minecart changes]]
 +
* removed unused map properties
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>Gil_Skeleton Mask</samp>
+
| <samp>Maps/Mountain</samp>
| <samp>Gil_Skeletons</samp>
+
| &#32;
 +
* removed unused map/tile properties
 +
* removed unused pathfinding tiles
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
|
 +
|
 
|-
 
|-
| <samp>Gil_Insect Head</samp>
+
| <samp>Maps/Mountain-BridgeFixed</samp><br /><samp>Maps/Mountain_Shortcuts</samp>
| <samp>Gil_Insects</samp>
+
| &#32;
 +
* removed unused map/tile properties
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
|
 +
|
 
|-
 
|-
| <samp>Gil_Hard Hat</samp>
+
| <samp>Maps/MovieTheater</samp>
| <samp>Gil_Duggy</samp>
+
| &#32;
 +
* moved <samp>Music</samp> property into <samp>Data/Locations</samp>
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>Gil_Burglar's Ring</samp>
+
| <samp>Maps/MovieTheaterScreen</samp>
| <samp>Gil_DustSpirits</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>Gil_Crabshell Ring</samp>
+
| <samp>Maps/MovieTheaterScreen_TileSheet</samp>
| <samp>Gil_Crabs</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>Gil_Arcane Hat</samp>
+
| <samp>Maps/paths</samp>
| <samp>Gil_Mummies</samp>
+
| &#32;
 +
* added icon for [[#Custom wild trees|custom wild tree spawn]]
 +
* removed unused pathfinding tiles
 +
|
 +
|
 
|-
 
|-
| <samp>Gil_Knight's Helmet</samp>
+
| <samp>Maps/QiNutRoom</samp>
| <samp>Gil_Dinos</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>Gil_Napalm Ring</samp>
+
| <samp>Maps/Railroad</samp>
| <samp>Gil_Serpents</samp>
+
| &#32;
 +
* removed unused map property
 +
* removed unused pathfinding tiles
 +
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
|
 +
|
 
|-
 
|-
| <samp>Gil_Telephone</samp>
+
| <samp>Maps/Saloon</samp><br /><samp>Maps/SamHouse</samp>
| <samp>Gil_FlameSpirits</samp>
+
| &#32;
|}
+
* removed unused pathfinding tiles
 
+
|
===XNB impact===
+
|
Here's 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 changes in non-English files.
  −
 
  −
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.
  −
 
  −
{| class="wikitable"
   
|-
 
|-
! content file
+
| <samp>Maps/SandyHouse</samp>
! changes
+
| &#32;
! XNB
+
* added <samp>LocationContext</samp> map property
! Content Patcher
+
| '''✘ broken'''
 +
|
 
|-
 
|-
| <samp>Buildings/houses</samp>
+
| <samp>Maps/ScienceHouse</samp><br /><samp>Maps/SebastianRoom</samp>
| fixed missing pixels
+
| &#32;
| ✘ will remove changes
+
* removed unused pathfinding tiles
| ✓ mostly unaffected
+
|
 +
|
 
|-
 
|-
| <samp>Characters/Dialogue/Abigail</samp><br /><samp>Characters/Dialogue/Alex</samp><br /><samp>Characters/Dialogue/Caroline</samp><br /><samp>Characters/Dialogue/Demetrius</samp>
+
| <samp>Maps/SeedShop</samp>
| fixed typos
+
| &#32;
| ✘ will remove changes
+
* removed unused tile properties
| ✓ mostly unaffected
+
* removed unused pathfinding tiles
 +
|
 +
|
 
|-
 
|-
| <samp>Characters/Dialogue/Emily</samp>
+
| <samp>Maps/Sewer</samp>
| fixed typos, updated <samp>%revealtaste</samp> format (backwards-compatible)
+
| &#32;
 +
* moved <samp>Music</samp> property into <samp>Data/Locations</samp>
 
| ✘ will remove changes
 
| ✘ will remove changes
 
| ✓ mostly unaffected
 
| ✓ mostly unaffected
 
|-
 
|-
| <samp>Characters/Dialogue/Gus</samp><br /><samp>Characters/Dialogue/Haley</samp><br /><samp>Characters/Dialogue/Jodi</samp>
+
| <samp>Maps/Shed</samp><br /><samp>Maps/Shed2</samp>
| fixed typos
+
| &#32;
| will remove changes
+
* added <samp>FloorIDs</samp> and <samp>WallIDs</samp> map properties
| ✓ mostly unaffected
+
| '''broken'''
 +
|
 
|-
 
|-
| <samp>Characters/Dialogue/Lewis</samp>
+
| <samp>Maps/SkullCave</samp>
| updated <samp>%revealtaste</samp> format (backwards-compatible)
+
| &#32;
| ✘ will remove changes
+
* added <samp>LocationContext</samp> map property
 +
* moved <samp>Music</samp> property into <samp>Data/Locations</samp>
 +
| '''broken'''
 
| ✓ mostly unaffected
 
| ✓ mostly unaffected
 
|-
 
|-
| <samp>Characters/Dialogue/Linus</samp><br /><samp>Characters/Dialogue/MarriageDialogueAbigail</samp><br /><samp>Characters/Dialogue/MarriageDialogueElliott</samp>
+
| <samp>Maps/SlimeHutch</samp>
| fixed typos
+
| &#32;
| ✘ will remove changes
+
* removed unused tile property
| ✓ mostly unaffected
+
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
|
 +
|
 
|-
 
|-
| <samp>Characters/Dialogue/MarriageDialogueEmily</samp>
+
| <samp>Maps/spousePatios</samp>
| changed <samp>spring_Maru</samp> key to <samp>spring_Emily</samp>, fixed typos
+
| &#32;
| ✘ will remove changes
+
* 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>Characters/Dialogue/MarriageDialogueMaru</samp><br /><samp>Characters/Dialogue/MarriageDialoguePenny</samp><br /><samp>Characters/Dialogue/MarriageDialogueSam</samp><br /><samp>Characters/Dialogue/Maru</samp><br /><samp>Characters/Dialogue/Pierre</samp><br /><samp>Characters/Dialogue/Robin</samp><br /><samp>Characters/Dialogue/Sam</samp><br /><samp>Characters/Dialogue/Sebastian</samp>
  −
| fixed typos
  −
| ✘ will remove changes
   
| ✓ mostly unaffected
 
| ✓ mostly unaffected
 
|-
 
|-
| <samp>Characters/schedules/Elliott</samp>
+
| <samp>Maps/Submarine</samp>
| fixed order of <samp>Fri_6</samp> and <samp>Fri</samp> entries
+
| &#32;
| ✘ will remove changes
+
* removed unused tile property
 +
|
 
|
 
|
 
|-
 
|-
| <samp>Characters/schedules/Lewis</samp>
+
| <samp>Maps/Sunroom</samp>
| fixed <samp>winter_Sun</samp> schedule
+
| &#32;
| ✘ will remove changes
+
* added <samp>IsGreenhouse</samp map property
 +
| '''broken'''
 
|
 
|
 
|-
 
|-
| <samp>Characters/schedules/Maru</samp>
+
| <samp>Maps/Tent</samp>
| fixed <samp>summer_Mon</samp> and <samp>summer_Sun</samp> schedules
+
| &#32;
| ✘ will remove changes
+
* removed unused pathfinding tiles
 
|
 
|
|-
  −
| <samp>Characters/schedules/Penny</samp>
  −
| fixed <samp>summer_Sun</samp> schedule
  −
| ✘ will remove changes
   
|
 
|
 
|-
 
|-
| <samp>Characters/shirts</samp><br /><samp>Characters/WeddingOutfits</samp>
+
| <samp>Maps/Town</samp>
| asset removed (they were unused)
+
| &#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>Data/AquariumFish</samp>
+
| <samp>Maps/Town-Christmas</samp>
| [[#Custom items|changed key type]], [[#Standardized data fields|standardized fields]]
+
| &#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'''
 
| '''✘ broken'''
| '''✘ likely 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>Data/BigCraftablesInformation</samp>
+
| <samp>Maps/Town-EggFestival</samp>
| [[#Custom items|changed key type]], [[#Standardized data fields|standardized fields]]
+
| &#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'''
 
| '''✘ broken'''
| '''✘ likely broken'''
+
| ✓ mostly unaffected
 
|-
 
|-
| <samp>Data/Blueprints</samp>
+
| <samp>Maps/Town-Fair</samp>
| asset removed (replaced by [[#Custom buildings|<samp>Data/Buildings</samp>]])
+
| &#32;
| '''✘ broken'''
+
* removed unused map/tile properties
| '''✘ broken'''
+
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
|
 +
|
 
|-
 
|-
| <samp>Data/Boots</samp>
+
| <samp>Maps/Town-Halloween</samp>
| [[#Custom items|changed key type]], added display name
+
| &#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'''
 
| '''✘ broken'''
| '''✘ likely broken'''
+
| ✓ mostly unaffected
 
|-
 
|-
| <samp>Data/Bundles</samp>
+
| <samp>Maps/Town-Theater</samp><br /><samp>Maps/Town-TheaterCC</samp><br /><samp>Maps/Town-TrashGone</samp>
| [[#Standardized data fields|standardized fields]], added display name
+
| &#32;
| '''✘ broken'''
+
* removed unused tile properties
| '''✘ likely broken'''
+
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
 +
|
 +
|
 
|-
 
|-
| <samp>Data/ClothingInformation</samp>
+
| <samp>Maps/Trailer</samp>
| asset removed (replaced by [[#Custom pants|<samp>Data/Pants</samp>]] and [[#Custom shirts|<samp>Data/Shirts</samp>]])
+
| &#32;
| '''✘ broken'''
+
* removed unused tile property
| '''✘ likely broken'''
+
* removed unused pathfinding tiles
 +
|
 +
|
 
|-
 
|-
| <samp>Data/ConcessionTastes</samp>
+
| <samp>Maps/Trailer_big</samp>
| [[#Custom movie concessions|added new required fields (<samp>Texture</samp> and <samp>SpriteIndex</samp>)]], added automatic <samp>ID</samp> field
+
| &#32;
| '''✘ broken'''
+
* removed unused pathfinding tiles
| ✓ mostly unaffected<br /><small>(✘ broken if they add new concessions)</small>
+
|
 +
|
 
|-
 
|-
| <samp>Data/CookingRecipes</samp>
+
| <samp>Maps/Tunnel</samp>
| no longer has per-language versions, removed display names (now default to item name)
+
| &#32;
 +
* moved <samp>Music</samp> property into <samp>Data/Locations</samp>
 +
* removed unused map property
 
| ✘ will remove changes
 
| ✘ will remove changes
 
| ✓ mostly unaffected
 
| ✓ mostly unaffected
 
|-
 
|-
| <samp>Data/CraftingRecipes</samp>
+
| <samp>Maps/WitchHut</samp>
| no longer has per-language versions, added <samp>default</samp> unlock condition, removed display names (now default to item name), fixed typo in Cookout Kit entry
+
| &#32;
| '''broken'''
+
* moved <samp>Music</samp> property into <samp>Data/Locations</samp>
 +
| ✘ will remove changes
 
| ✓ mostly unaffected
 
| ✓ mostly unaffected
 
|-
 
|-
| <samp>Data/Crops</samp>
+
| <samp>Maps/WitchSwamp</samp>
| [[#Custom crops|completely overhauled]]
+
| &#32;
| '''✘ broken'''
+
* moved <samp>Music</samp> property into <samp>Data/Locations</samp>
| '''✘ broken'''
+
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
|-
+
| ✘ will remove changes
| <samp>Data/Events/Farm</samp>
  −
| updated pet event to support custom pet types
  −
| '''broken'''
   
| ✓ mostly unaffected
 
| ✓ mostly unaffected
 
|-
 
|-
| <samp>Data/Events/FishShop</samp>
+
| <samp>Maps/WitchWarpCave</samp>
| fixed typos
+
| &#32;
 +
* moved <samp>Music</samp> property into <samp>Data/Locations</samp>
 
| ✘ will remove changes
 
| ✘ will remove changes
 
| ✓ mostly unaffected
 
| ✓ mostly unaffected
 
|-
 
|-
| <samp>Data/Events/Forest</samp>
+
| <samp>Maps/WizardHouse</samp>
| fixed typos, updated Jas <samp>faceDirection</samp> command for sewer event
+
| &#32;
 +
* moved <samp>Music</samp> property into <samp>Data/Locations</samp>
 +
* removed unused pathfinding tiles
 
| ✘ will remove changes
 
| ✘ will remove changes
 
| ✓ mostly unaffected
 
| ✓ mostly unaffected
 
|-
 
|-
| <samp>Data/Events/IslandHut</samp>
+
| <samp>Maps/WizardHouseBasement</samp>
| updated how Leo's name is translated
+
| &#32;
 +
* moved <samp>Music</samp> property into <samp>Data/Locations</samp>
 +
* removed unused map property
 
| ✘ will remove changes
 
| ✘ will remove changes
 
| ✓ mostly unaffected
 
| ✓ mostly unaffected
 
|-
 
|-
| <samp>Data/Events/IslandNorth</samp>
+
| <samp>Maps/Woods</samp>
| updated quote format
+
| &#32;
| '''✘ broken'''
+
* removed unused tile property
| ✓ mostly unaffected<br /><small>(✘ likely broken if they edit the <samp>6497421</samp> event)</small>
+
* standardized <samp>T</samp> for boolean tile property values (backwards-compatible)
|-
  −
| <samp>Data/Events/IslandSouth</samp>
  −
| changed event music field from blank to <samp>none</samp> (backwards-compatible)
   
|
 
|
 
|
 
|
 
|-
 
|-
| <samp>Data/Events/LeahHouse</samp>
+
| <samp>Minigames/boatJourneyMap</samp>
| fixed <samp>move</samp> command format in Leah's 2-heart event
+
| &#32;
 +
* asset replaced by redrawn seasonal variants like <samp>fall_boatJourneyMap</samp>
 +
| '''✘ broken'''
 
| '''✘ broken'''
 
| '''✘ broken'''
|
   
|-
 
|-
| <samp>Data/Events/Mountain</samp>
+
| <samp>Strings/Characters</samp>
| fixed broken dialogue in Maru's 14-heart event, fixed typos
+
| &#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
 
| ✘ will remove changes
| ✓ mostly unaffected
   
|-
 
|-
| <samp>Data/Events/Saloon</samp><br /><samp>Data/Events/SebastianRoom</samp>
+
| <samp>Strings/Events</samp>
| fixed typos
+
| &#32;
| ✘ will remove changes
+
* moved [[#Dialogue changes|flower dance dialogue]] for Emily and Shane to their NPC dialogue files
 
| ✓ mostly unaffected
 
| ✓ mostly unaffected
|-
  −
| <samp>Data/Events/Town</samp>
  −
| fixed <samp>warp</samp> command format in community center completed event, fixed typos
  −
| '''✘ broken'''
   
| ✓ mostly unaffected
 
| ✓ mostly unaffected
 
|-
 
|-
| <samp>Data/FarmAnimals</samp>
+
| <samp>Strings/FarmAnimals</samp>
| [[#Custom farm animals|completely overhauled]]
+
| &#32;
 +
* added new entries
 
| '''✘ broken'''
 
| '''✘ broken'''
|  
+
|
 
|-
 
|-
| <samp>Data/Festivals/fall27</samp>
+
| <samp>Strings/Lexicon</samp>
| removed <samp>shop</samp> field (moved into [[#Custom shops|<samp>Data/Shops</samp>]])
+
| &#32;
 +
* removed unused entries
 
|
 
|
 
|
 
|
 
|-
 
|-
| <samp>Data/Festivals/spring13</samp>
+
| <samp>Strings/Locations</samp>
| migrated to new <samp>warpFarmers</samp> command, removed <samp>shop</samp> field (moved into [[#Custom shops|<samp>Data/Shops</samp>]]), fixed typos
+
| &#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'''
 
| '''✘ broken'''
| ✓ mostly unaffected<br /><small>(✘ broken if they edit event script fields)</small>
+
| ✓ mostly unaffected
 
|-
 
|-
| <samp>Data/Festivals/spring24</samp><br /><samp>Data/Festivals/summer11</samp><br /><samp>Data/Festivals/summer28</samp><br /><samp>Data/Festivals/winter8</samp>
+
| <samp>Strings/NPCNames</samp>
| migrated to new <samp>warpFarmers</samp> command, removed <samp>shop</samp> field (moved into [[#Custom shops|<samp>Data/Shops</samp>]])
+
| &#32;
 +
* added new entries
 +
* removed unused entry
 
| '''✘ broken'''
 
| '''✘ broken'''
| ✓ mostly unaffected<br /><small>(✘ broken if they edit event script fields)</small>
+
|
 
|-
 
|-
| <samp>Data/Festivals/winter25</samp>
+
| <samp>Strings/Notes</samp>
| removed <samp>shop</samp> field (moved into [[#Custom shops|<samp>Data/Shops</samp>]])
+
| &#32;
 +
* trimmed trailing whitespace
 
|
 
|
 
|
 
|
 
|-
 
|-
| <samp>Data/Fish</samp>
+
| <samp>Strings/Objects</samp>
| no longer has per-language versions, [[#Custom items|changed key type]], field 13 now refers to whether fish can be tutorial catch
+
| &#32;
 +
* added new entries
 +
* removed unused entries
 
| '''✘ broken'''
 
| '''✘ broken'''
| ✘ likely broken
+
|
 +
|-
 +
| <samp>Strings/schedules/Caroline</samp>
 +
| &#32;
 +
* fixed typo
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>Data/FishPondData</samp>
+
| <samp>Strings/SpecialOrderStrings</samp>
| added required <samp>Id</samp> field, added optional <samp>Precedence</samp> field, [[#Custom items|changed <samp>ItemId</samp> field type]], moved fallback entries to bottom
+
| &#32;
| '''✘ broken'''
+
* renamed ''Dust Spirits'' to ''Dust Sprites''
| ✘ likely broken
+
* fixed typos
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>Data/fruitTrees</samp>
+
| <samp>Strings/StringsFromCSFiles</samp>
| [[#Custom fruit trees|completely overhauled]]
+
| &#32;
| '''✘ broken'''
+
* 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'''
 
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>Data/Furniture</samp>
+
| <samp>Strings/StringsFromMaps</samp>
| [[#Custom items|changed key type]], [[#Standardized data fields|standardized fields]], added display name
+
| &#32;
| '''✘ broken'''
+
* fixed typos
| '''✘ likely broken'''
+
* removed unused entries
|-
  −
| <samp>Data/hats</samp>
  −
| [[#Custom items|changed key type]], [[#Standardized data fields|standardized fields]], added display name
  −
| '''✘ broken'''
  −
| '''✘ likely broken'''
  −
|-
  −
| <samp>Data/Locations</samp>
  −
| [[#Custom locations|completely overhauled]]
  −
| '''✘ broken'''
  −
|
  −
|-
  −
| <samp>Data/mail</samp>
  −
| migrated to <samp>%item id</samp> (backwards-compatible), removed unused tax entries, fixed typos
   
| ✘ will remove changes
 
| ✘ will remove changes
| ✓ mostly unaffected
  −
|-
  −
| <samp>Data/Monsters</samp>
  −
| renamed ''Dust Spirit'' to ''Dust Sprite''
  −
| ✘ will remove changes
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Data/Movies</samp>
  −
| added optional <samp>CustomFields</samp> and <samp>Textures</samp> fields
  −
| '''✘ broken'''
  −
|
  −
|-
  −
| <samp>Data/MoviesReactions</samp>
  −
| added automatic <samp>ID</samp> field, fixed typo
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Data/NPCDispositions</samp>
  −
| asset removed (replaced by [[#Custom NPCs|<samp>Data/Characters</samp>]])
  −
| '''✘ broken'''
  −
| '''✘ broken'''
  −
|-
  −
| <samp>Data/ObjectContextTags</samp>
  −
| added new entries & tags
  −
| '''✘ 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>
  −
| added new entries, added texture & index fields, adjusted [[#Other item changes|litter items]], [[#Custom items|changed key type]], [[#Standardized data fields|standardized fields]], fixed typos
  −
| '''✘ broken'''
  −
| '''✘ likely broken'''
  −
|-
  −
| <samp>Data/PainData</samp>
  −
| fixed trailing slash in <samp>Deluxe Barn</samp> entry
  −
|
   
|  
 
|  
 
|-
 
|-
| <samp>Data/Quests</samp>
+
| <samp>Strings/UI</samp>
| changed item fields to use item IDs (backwards-compatible), changed key type to string, fixed typo
+
| &#32;
 +
* added new entries
 +
* added placeholder for cabin count in <samp>Character_CoopHelpString</samp>
 +
* fixed typos
 +
* removed unused entries
 
| '''✘ broken'''
 
| '''✘ broken'''
 
| ✓ mostly unaffected
 
| ✓ mostly unaffected
|-
+
|}
| <samp>Data/RandomBundles</samp>
+
 
| add optional <samp>ID</samp> field
+
====Removed unused assets====
| '''✘ broken'''
+
Stardew Valley 1.6 deletes assets which weren't used by the game. Mods usually aren't affected by this.
| ✓ mostly unaffected
+
 
|-
+
Removed assets:
| <samp>Data/SecretNotes</samp>
+
* <samp>Characters/Dana</samp>
| updated <samp>%revealtaste</samp> format (backwards-compatible)
+
* <samp>Characters/Dick</samp>
| ✘ will remove changes
+
* <samp>Characters/femaleRival</samp>
| ✓ mostly unaffected
+
* <samp>Characters/maleRival</samp>
|-
+
* <samp>Characters/shirts</samp>
| <samp>Data/SpecialOrders</samp>
+
* <samp>Characters/WeddingOutfits</samp>
| changed type of <samp>Repeatable</samp> and <samp>Duration</samp> fields, added optional <samp>CustomFields</samp> and <samp>Conditions</samp> fields
+
* <samp>Data/TV/InterviewShow</samp>
| '''✘ broken'''
+
* <samp>Effects/BrightWhite</samp>
|
+
* <samp>Fonts/tinyFontBorder</samp>
|-
+
* <samp>Maps/Cabin</samp>
| <samp>Data/TailoringRecipes</samp>
+
* <samp>Maps/Cabin1</samp>
| changed to [[#Custom items|string item IDs]] (backwards-compatible), added optional <samp>ID</samp> and <samp>CraftedItemIdFeminine</samp> fields,<br />adjusted recipes for gender-variant shirts, renamed <samp>*ID</samp> to <samp>*Id</samp>
+
* <samp>Maps/Cabin1_marriage</samp>
| '''✘ broken'''
+
* <samp>Maps/Cabin2</samp>
| ✓ mostly unaffected<br /><small>(<samp>MoveEntries</samp> may break, but fallback entries are now<br />checked last automatically)</small>
+
* <samp>Maps/Cabin2_marriage</samp>
|-
+
* <samp>Maps/Island_Boulder_Removed</samp>
| <samp>Data/TV/CookingChannel</samp><br /><samp>Data/TV/TipChannel</samp>
+
* <samp>Maps/qiNutRoom_tilesheet_0</samp>
| fixed typos
+
* <samp>Maps/spring_outrdoorsTileSheet_lightergrass</samp>
| ✘ will remove changes
+
* <samp>Portraits/Dobson</samp>
| ✓ mostly unaffected
+
* <samp>TerrainFeatures/DiggableWall_basic</samp>
|-
+
* <samp>TerrainFeatures/DiggableWall_basic_dark</samp>
| <samp>Data/weapons</samp>
+
* <samp>TerrainFeatures/DiggableWall_frost</samp>
| [[#Custom melee weapons|completely overhauled]]
+
* <samp>TerrainFeatures/DiggableWall_frost_dark</samp>
| '''✘ broken'''
+
* <samp>TerrainFeatures/DiggableWall_lava</samp>
| '''✘ likely broken'''
+
* <samp>TerrainFeatures/DiggableWall_lava_dark</samp>
|-
+
* <samp>TerrainFeatures/Quartz</samp>
| <samp>Effects/BrightWhite</samp>
  −
| asset removed
  −
|
  −
|
  −
|-
  −
| <samp>LooseSprites/Cursors</samp>
  −
| new sprites in empty area, moved mailbox to <samp>Buildings/Mailbox</samp>
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>LooseSprites/Cursors2</samp>
  −
| new sprite in empty area
  −
| '''✘ broken'''
  −
|
  −
|-
  −
| <samp>Maps/AbandonedJojaMart</samp>
  −
| [[#Other changes|changed map & tile properties to string]]
  −
|
  −
|
  −
|-
  −
| <samp>Maps/AnimalShop</samp>
  −
| added <samp>Music</samp> map property, removed unused pathfinding tiles
  −
| '''✘ broken'''
  −
|
  −
|-
  −
| <samp>Maps/ArchaeologyHouse</samp>
  −
| removed unused pathfinding tiles
  −
|
  −
|
  −
|-
  −
| <samp>Maps/Backwoods</samp><br /><samp>Maps/Backwoods_GraveSite</samp><br /><samp>Maps/Backwoods_Staircase</samp>
  −
| [[#Other changes|changed map & tile properties to string]]
  −
|
  −
|
  −
|-
  −
| <samp>Maps/Barn</samp><br /><samp>Maps/Barn2</samp>
  −
| [[#Other changes|changed map & tile properties to string]], removed unused map properties
  −
|
  −
|
  −
|-
  −
| <samp>Maps/Barn3</samp>
  −
| added <samp>AutoFeed</samp> map property, [[#Other changes|changed map & tile properties to string]], removed unused map properties
  −
| '''✘ broken'''
  −
|
  −
|-
  −
| <samp>Maps/BathHouse_Entry</samp><br /><samp>Maps/BathHouse_MensLocker</samp>
  −
| removed unused pathfinding tiles
  −
|
  −
|
  −
|-
  −
| <samp>Maps/BathHouse_Pool</samp>
  −
| added <samp>Music</samp> map property, removed unused map & tile properties, removed unused pathfinding tiles
  −
| '''✘ broken'''
  −
|
  −
|-
  −
| <samp>Maps/BathHouse_WomensLocker</samp>
  −
| removed unused pathfinding tiles
  −
|
  −
|
  −
|-
  −
| <samp>Maps/Beach</samp>
  −
| added <samp>Music</samp> + <samp>MusicIgnoreInRain</samp> map properties, removed unused map properties, removed unused pathfinding tiles
  −
| '''✘ broken'''
  −
|
  −
|-
  −
| <samp>Maps/Beach-Jellies</samp><br /><samp>Maps/Beach-Luau</samp><br /><samp>Maps/Beach-NightMarket</samp>
  −
| updated for festival shops now in <samp>Data/Shops</samp>, removed unused map/tile properties, removed unused pathfinding tiles
  −
| '''✘ broken'''
  −
|
  −
|-
  −
| <samp>Maps/Blacksmith</samp>
  −
| removed unused pathfinding tiles
  −
|
  −
|
  −
|-
  −
| <samp>Maps/BoatTunnel</samp>
  −
| [[#Other changes|changed map & tile properties to string]]
  −
|
  −
|
  −
|-
  −
| <samp>Maps/BusStop</samp>
  −
| removed unused map/tile properties, removed unused pathfinding tiles
  −
|
  −
|
  −
|-
  −
| <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>
  −
| removed assets (they were unused)
  −
|
  −
|
  −
|-
  −
| <samp>Maps/Caldera</samp>
  −
| added <samp>Music</samp> map property, removed unused map property
  −
| '''✘ broken'''
  −
|
  −
|-
  −
| <samp>Maps/Club</samp>
  −
| added <samp>LocationContext</samp> map property
  −
| '''✘ broken'''
  −
|
  −
|-
  −
| <samp>Maps/Coop</samp><br /><samp>Maps/Coop2</samp>
  −
| [[#Other changes|changed map & tile properties to string]], removed unused map properties
  −
|
  −
|
  −
|-
  −
| <samp>Maps/Coop3</samp>
  −
| [[#Other changes|changed map & tile properties to string]], removed unused map properties, added <samp>AutoFeed</samp> map property
  −
| '''✘ broken'''
  −
|
  −
|-
  −
| <samp>Maps/Desert</samp>
  −
| added <samp>LocationContext</samp> map property, removed unused map/tile properties, removed unused pathfinding tiles
  −
| '''✘ broken'''
  −
|
  −
|-
  −
| <samp>Maps/ElliottHouse</samp>
  −
| added <samp>Music</samp> map property, removed unused pathfinding tiles
  −
| '''✘ broken'''
  −
|
  −
|-
  −
| <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 <samp>PetBowlLocation</samp> map property (for <samp>Maps/Four_Corners</samp> and <samp>Farm/Island</samp> only);
  −
* significant tile & tile property changes;
  −
* removed farmhouse + pet bowl areas (now moveable);
  −
* removed unused map/tile properties;
  −
* [[#Other changes|changed map & tile properties to string]]
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Maps/Farm_Greenhouse_Dirt</samp><br /><samp>Maps/Farm_Greenhouse_Dirt_FourCorners</samp>
  −
| [[#Other changes|changed map & tile properties to string]], removed unused map properties
  −
|
  −
|
  −
|-
  −
| <samp>Maps/FarmHouse</samp>
  −
| removed unused map properties
  −
|
  −
|
  −
|-
  −
| <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>
  −
| [[#Other changes|changed map & tile properties to string]], removed unused map properties
  −
|
  −
|
  −
|-
  −
| <samp>Maps/FishShop</samp>
  −
| fixed broken <samp>DayTiles</samp> and <samp>NightTiles</samp> values, removed unused pathfinding tiles
  −
| ✘ will remove changes
  −
|
  −
|-
  −
| <samp>Maps/Forest</samp>
  −
| removed unused map/tile properties, removed unused pathfinding tiles
  −
|
  −
|
  −
|-
  −
| <samp>Maps/Forest-FlowerFestival</samp>
  −
| updated for festival shops now in <samp>Data/Shops</samp>, removed unused map properties
  −
| '''✘ broken'''
  −
|
  −
|-
  −
| <samp>Maps/Forest-IceFestival</samp>
  −
| updated for festival shops now in <samp>Data/Shops</samp>, fixed warp positions, removed unused map/tile properties, removed unused pathfinding tiles
  −
| '''✘ broken'''
  −
|
  −
|-
  −
| <samp>Maps/Forest-SewerClean</samp>
  −
| removed unused map/tile properties
  −
|
  −
|
  −
|-
  −
| <samp>Maps/Greenhouse</samp>
  −
| [[#Other changes|changed map & tile properties to string]]
  −
|
  −
|
  −
|-
  −
| <samp>Maps/HaleyHouse</samp><br /><samp>Maps/HarveyRoom</samp>
  −
| removed unused pathfinding tiles
  −
|
  −
|
  −
|-
  −
| <samp>Maps/Hospital</samp>
  −
| added <samp>Music</samp> and <samp>MusicIgnoreInRain</samp> map properties, removed unused pathfinding tiles
  −
| '''✘ broken'''
  −
|
  −
|-
  −
| <samp>Maps/Island_Bridge_Broken</samp><br /><samp>Maps/Island_Bridge_Repaired</samp><br /><samp>Maps/Island_House_Cave</samp>
  −
| removed unused map properties
  −
|
  −
|
  −
|-
  −
| <samp>Maps/Island_N</samp>
  −
| update walnut bush tile so it still works in 1.6, removed unused tile property
  −
| '''✘ broken'''
  −
|
  −
|-
  −
| <samp>Maps/Island_N_Trader</samp><br /><samp>Maps/Island_Secret</samp><br /><samp>Maps/Island_W</samp>
  −
| removed unused tile property
  −
|
  −
|
  −
|-
  −
| <samp>Maps/IslandFarmHouse</samp>
  −
| [[#Other changes|changed map & tile properties to string]], removed unused tile properties
  −
|
  −
|
  −
|-
  −
| <samp>Maps/JojaMart</samp>
  −
| added <samp>Music</samp> and <samp>MusicContext</samp> map properties, removed unused pathfinding tiles
  −
| '''✘ broken'''
  −
|
  −
|-
  −
| <samp>Maps/JoshHouse</samp>
  −
| removed unused pathfinding tiles
  −
|
  −
|
  −
|-
  −
| <samp>Maps/LeahHouse</samp>
  −
| added <samp>Music</samp> map property, removed unused pathfinding tiles
  −
| '''✘ broken'''
  −
|
  −
|-
  −
| <samp>Maps/LeoTreeHouse</samp>
  −
| added <samp>Music</samp> map property
  −
| '''✘ broken'''
  −
|
  −
|-
  −
| <samp>Maps/ManorHouse</samp>
  −
| removed unused pathfinding tiles
  −
|
  −
|
  −
|-
  −
| <samp>Maps/MarnieBarn</samp><br /><samp>Maps/Mine</samp>
  −
| [[#Other changes|changed map & tile properties to string]], removed unused map properties
  −
|
  −
|
  −
|-
  −
| <samp>Maps/Mines/Volcano_SetPieces_32</samp>
  −
| [[#Other changes|changed map & tile properties to string]]
  −
|
  −
|
  −
|-
  −
| <samp>Maps/Mountain</samp>
  −
| [[#Other changes|changed map & tile properties to string]], removed unused map properties, removed unused pathfinding tiles
  −
|
  −
|
  −
|-
  −
| <samp>Maps/Mountain-BridgeFixed</samp><br /><samp>Maps/Mountain_Shortcuts</samp>
  −
| removed unused map properties
  −
|
  −
|
  −
|-
  −
| <samp>Maps/MovieTheater</samp>
  −
| [[#Other changes|changed map & tile properties to string]]
  −
|
  −
|
  −
|-
  −
| <samp>Maps/MovieTheaterScreen</samp>
  −
| [[#Other changes|changed map & tile properties to string]], 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>
  −
| 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>
  −
| added icon for [[#Custom wild trees|custom wild tree spawn]], removed unused pathfinding tiles
  −
|
  −
|
  −
|-
  −
| <samp>Maps/qiNutRoom_tilesheet_0</samp>
  −
| removed asset (unused)
  −
|
  −
|
  −
|-
  −
| <samp>Maps/Railroad</samp>
  −
| removed unused map property, removed unused pathfinding tiles
  −
|
  −
|
  −
|-
  −
| <samp>Maps/Saloon</samp>
  −
| added <samp>Music</samp> map property, removed unused pathfinding tiles
  −
| '''✘ broken'''
  −
|
  −
|-
  −
| <samp>Maps/SamHouse</samp>
  −
| removed unused pathfinding tiles
  −
|
  −
|
  −
|-
  −
| <samp>Maps/SandyHouse</samp>
  −
| added <samp>LocationContext</samp> and <samp>Music</samp> map properties
  −
| '''✘ broken'''
  −
|
  −
|-
  −
| <samp>Maps/ScienceHouse</samp>
  −
| added <samp>Music</samp> map property, removed unused pathfinding tiles
  −
| '''✘ broken'''
  −
|
  −
|-
  −
| <samp>Maps/SebastianRoom</samp>
  −
| removed unused pathfinding tiles
  −
|
  −
|
  −
|-
  −
| <samp>Maps/SeedShop</samp>
  −
| removed unused tile properties, removed unused pathfinding tiles
  −
|
  −
|
  −
|-
  −
| <samp>Maps/Shed</samp>
  −
| added <samp>FloorIDs</samp> and <samp>WallIDs</samp> map properties
  −
| '''✘ broken'''
  −
|
  −
|-
  −
| <samp>Maps/SkullCave</samp>
  −
| added <samp>LocationContext</samp> map property
  −
| '''✘ broken'''
  −
|
  −
|-
  −
| <samp>Maps/SlimeHutch</samp>
  −
| removed unused tile property
  −
|
  −
|
  −
|-
  −
| <samp>Maps/spousePatios</samp>
  −
| removed unused map properties, [[#Other changes|changed map & tile properties to string]]
  −
|
  −
|
  −
|-
  −
| <samp>Maps/spring_outdoorsTileSheet</samp><br /><samp>Maps/summer_outdoorsTileSheet</samp><br /><samp>Maps/fall_outdoorsTileSheet</samp><br /><samp>Maps/winter_outdoorsTileSheet</samp>
  −
| Pet bowl moved to <samp>Buildings/Pet Bowl</samp>.
  −
| ✓ mostly unaffected
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Maps/Submarine</samp>
  −
| removed unused tile property
  −
|
  −
|
  −
|-
  −
| <samp>Maps/Sunroom</samp>
  −
| added <samp>Music</samp> and <samp>MusicIgnoreInRain</samp> properties, [[#Other changes|changed map & tile properties to string]]
  −
| '''✘ broken'''
  −
|
  −
|-
  −
| <samp>Maps/Tent</samp>
  −
| removed unused pathfinding tiles
  −
|
  −
|
  −
|-
  −
| <samp>Maps/Town</samp>
  −
| added multiple <samp>Music*</samp> map properties, removed unused map properties, changed to [[#Custom garbage cans|new garbage can IDs]] (backwards-compatible), removed unused pathfinding tiles
  −
| '''✘ broken'''
  −
|
  −
|-
  −
| <samp>Maps/Town-Christmas</samp>
  −
| updated for festival shops now in <samp>Data/Shops</samp>, removed unused map properties, removed unused pathfinding tiles
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Maps/Town-DogHouse</samp>
  −
| removed unused map properties
  −
|
  −
|
  −
|-
  −
| <samp>Maps/Town-EggFestival</samp>
  −
| fixed Elliott appearing twice during egg hunt, updated for festival shops now in <samp>Data/Shops</samp>, removed unused map properties
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Maps/Town-Fair</samp>
  −
| removed unused map properties
  −
|
  −
|
  −
|-
  −
| <samp>Maps/Town-Halloween</samp>
  −
| updated for festival shops now in <samp>Data/Shops</samp>, removed unused map properties, removed unused pathfinding tiles
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Maps/Town-Theater</samp><br /><samp>Maps/Town-TheaterCC</samp><br /><samp>Maps/Town-TrashGone</samp>
  −
| removed unused map properties
  −
|
  −
|
  −
|-
  −
| <samp>Maps/Trailer</samp>
  −
| removed unused tile property, removed unused pathfinding tiles
  −
|
  −
|
  −
|-
  −
| <samp>Maps/Trailer_big</samp>
  −
| removed unused pathfinding tiles
  −
|
  −
|
  −
|-
  −
| <samp>Maps/Tunnel</samp>
  −
| removed unused map property
  −
|
  −
|
  −
|-
  −
| <samp>Maps/WizardHouse</samp>
  −
| removed unused pathfinding tiles
  −
|
  −
|
  −
|-
  −
| <samp>Maps/WizardHouseBasement</samp>
  −
| removed unused map property
  −
|
  −
|
  −
|-
  −
| <samp>Maps/Woods</samp>
  −
| added <samp>Music</samp> and <samp>MusicIgnoreInRain</samp> map properties, removed unused tile property
  −
| '''✘ broken'''
  −
|
  −
|-
  −
| <samp>Strings/Buildings</samp><br /><samp>Strings/Characters</samp>
  −
| added new entries
  −
| '''✘ broken'''
  −
|
  −
|-
  −
| <samp>Strings/credits</samp>
  −
| updated credit line
  −
| ✘ will remove changes
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Strings/FarmAnimals</samp>
  −
| added new entries
  −
| '''✘ broken'''
  −
|
  −
|-
  −
| <samp>Strings/Locations</samp>
  −
| replaced bus price with placeholder, updated how Professor Snail's name is translated, removed unused entries, fixed typos
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Strings/NPCNames</samp>
  −
| added new entries
  −
| '''✘ broken'''
  −
|
  −
|-
  −
| <samp>Strings/Objects</samp><br /><samp>Strings/schedules/Caroline</samp>
  −
| fixed typos
  −
| ✘ will remove changes
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Strings/SpecialOrderStrings</samp>
  −
| renamed ''Dust Spirit'' to ''Dust Sprite''
  −
| ✘ will remove changes
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Strings/StringsFromCSFiles</samp>
  −
| added new entries, removed unused entries, fixed typos
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Strings/StringsFromMaps</samp>
  −
| fixed typos
  −
| ✘ will remove changes
  −
|
  −
|-
  −
| <samp>Strings/UI</samp>
  −
| added new entries, fixed typos
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected
  −
|}
      
==Vanilla release notes==
 
==Vanilla release notes==
{{note box|'''These are unofficial release notes for the 1.6 mod author alpha.'''<br />The [https://twitter.com/ConcernedApe new content announced by ConcernedApe] hasn't been revealed yet and isn't listed below.|type=warning}}
+
''Moved to [[Version History#1.6]].''
 
  −
This is a draft for the [[Version History]] section when 1.6 is released. Feel free to edit or suggest anything that was missed.
  −
 
  −
<blockquote>
  −
<big>'''1.6.0'''</big><br />
  −
Stardew Valley 1.6.0 was released to the Steam beta branch on XX XX 20XX, and released on XX XXXX 20XX.
  −
 
  −
; New features
  −
:* The world map now shows your actual position within the world in real-time (instead of showing you at a fixed point for each location). In multiplayer, you'll see other players' position in real-time too. This currently doesn't apply in [[Cindersap Forest]] or on the farm, since their drawn map is too different from the real location.
  −
:* The farmhouse and pet bowl can now be moved through Robin's menu.
  −
:* The [[Farm Computer|farm computer]] can now be used anywhere to see a summary of that location, instead of only the farm.
  −
:* The [[Mini-Jukebox|mini-jukebox]] can now be used on the [[Ginger Island]] farm.
  −
 
  −
; Balance changes
  −
:* You can no longer lose the Golden Scythe, Infinity weapons, or tools when dying.
  −
:* Added [[wikipedia:Coyote time|grace jumps]] in Junimo Kart: when you run off the track, you can still jump for a short time to recover.
  −
:* Increased the [[Forge#Enchantments|shaving enchantment]]'s effect on [[Crops#Giant Crops|giant crops]].<br /><small>Each giant crop now has a 60% chance of dropping an extra six crops while the shaving enchantment is equipped, spread across the number of hits needed to break it. For example, a base axe which breaks the giant crop in three hits gets three 20% chances of dropping 2 crops.</small>
  −
:* The [[The Cave|mushroom cave]] now provides mushrooms every second day. It was unintentionally changed to daily in Stardew Valley 1.5.
  −
:* Randomization no longer produces simple repeating patterns in many cases (e.g. clay farming, mushroom level prediction, crab pot fish offset, etc).<br /><small>You can enable "Use Legacy Randomization" in the [[Options|advanced save options]] to use the old randomization, though some specific patterns may still change due to the underlying changes. That option is mainly intended for speedrunners; most players should keep it disabled for the intended experience.</small>
  −
 
  −
; Quality of life changes
  −
:* Shops now have a slight delay before you can buy/sell items, to help avoid double-clicks doing it accidentally.
  −
:* [[Marnie's Ranch|Marnie's animal menu]] now shows prices in the tooltip, in case the tooltip covers the price display.
  −
:* Holding a [[Tea Sapling|tea sapling]] or [[Crops|seed]] over a [[Garden Pot|garden pot]] now shows the green/red placement tile.
  −
:* The museum reward menu now prevents picking up a reward that won't fit in your inventory.
  −
:* The museum reward menu now lets you exit while holding a reward. It'll be added to your inventory if possible, otherwise it'll drop at your feet.
  −
:* If an item menu exits while you're holding an item, the item is now always retrieved. (Previously only some item menus like chests would do it.)
  −
:* If a default farm building (like the greenhouse) is somehow removed, it'll now be rebuilt next time you load the save.
  −
:* You can no longer pick up rugs if there's something on it.
  −
:* Positional sounds now fade with distance when off-screen, instead of cutting off abruptly.
  −
:* Made more sounds positional (mainly player and tool sounds).
  −
:* Deleting a save on PC is now much faster.
  −
:* Significantly reduced save loading time when there are many custom locations.
  −
:* Performance improvements.
  −
 
  −
; Other changes
  −
:* Gender-specific clothing variants can now be worn by any gender.
  −
:* After reaching six hearts with some NPCs, they won't visit their rival love interest anymore. This affects [[Alex]] visiting [[Haley]], [[Elliott]] visiting [[Leah]], and Haley visiting Alex.
  −
:* The about page now shows the build number.
  −
:* The about page no longer hides the version if a tip message is shown.
  −
:* The [[Ginger Island#Gem Birds|Ginger Island shrine]] item pedestals are now normal items. Modded players can spawn them to display items decoratively (though they're not obtainable in vanilla currently).
  −
:* Fixed some NPC schedules not being applied:
  −
:** [[Lewis]] visiting the library on winter Sundays;
  −
:** [[Maru]] and [[Penny]] hanging out on summer Sundays;
  −
:** and [[Maru]] tinkering on summer Mondays.
  −
 
  −
; Fixes for gameplay
  −
:* Fixed issues with buffs:
  −
:** Fixed a range of bugs like attribute drift and double-debuff.
  −
:** Fixed food/drink buffs discarded if they have a balanced total of effects (e.g. +2 attack and -2 speed).
  −
:** Fixed negative custom buffs shown with a double-negative (e.g. "--2 speed").
  −
:** Fixed Squid Ink Ravioli buff not remaining active if another food buff is added later (although the buff icon was still shown).
  −
:** Fixed Squid Ink Ravioli not resetting the buff duration when you eat another one, unlike other food buffs.
  −
:** Fixed Squid Ink Ravioli description having an extra blank line.
  −
:** Fixed Burnt not showing the -3 Attack effect.
  −
:* Fixed unable to leave the [[Festival of Ice]] until it ends.
  −
:* Fixed player stuck in swimsuit if they collapse from damage while wearing it.
  −
:* Fixed gates popping off when closing them while the player overlaps the tile.
  −
:* Fixed broken event if the player is defeated in the mines and their name contains a slash.
  −
:* Fixed fishing crash if a treasure chest appears while the player has a large number of stacked fishing buffs.
  −
:* Fixed issue where breaking a [[Bee House|bee house]] containing honey would drop a generic "Honey" item, instead of the flavored honey it would produce when harvested.
  −
:* Fixed issue where using the [[Rain Totem|rain totem]] during a storm would make the next day stormy too, instead of rainy.
  −
:* Fixed issue where you could clear a forest-themed [[The Mines|mine level]] without finding a ladder.
  −
:* Fixed [[Magic Bait|magic bait]] disabling some fish area checks (e.g. so you could catch river fish in the forest pond).
  −
:* Fixed random seeds on [[Ginger Island]] being based on the valley's season.
  −
:* Fixed dropped tools not recovered if they're inside a constructed building.
  −
:* Fixed potted [[Tea Bush|tea bushes]] planted in town not being harvestable.
  −
:* Fixed [[Wedding Ring|wedding rings]] being giftable to NPCs.
  −
:* Fixed exploit where you could keep temporary items like Qi Fruit by selling them to Pierre and buying them back later.
  −
 
  −
; Fixes for NPC dialogue
  −
:* Many NPCs have their own dialogue for accepting a movie invitation, but only in English. This now works in other languages too.
  −
:* Fixed some dialogues that were never shown in-game.<br /><small>Specifically a line in Maru's 14-heart event, three dialogues from Sam related to Kent<!--Thu6_1, Thu6_2, summer_Thu6_1-->, two randomized dialogues when an NPC buys an item you sold to a shop, and two speech bubbles from Marnie/Robin when you enter their shop building.</small>
  −
:* Fixed Lewis not congratulating female farmers after their wedding.
  −
:* Fixed Lewis skipping his final dialogue at the [[Festival of Ice]] on subsequent player wins.
  −
:* Fixed the [[Stardew Valley Fair|fortune teller]] nearly always showing the text for your combat skill, instead of your highest skill.
  −
:* Fixed issue where an NPC who bought an iridium-quality item you sold to a shop could show a low-item-quality dialogue for it.
  −
:* Fixed [[Abigail#Fourteen Hearts|monster grave text]] only shown in English.
  −
 
  −
; Fixes for visual or cosmetic issues
  −
:* The submerged [[fishing]] bobber is now recolored automatically to match the water.
  −
:* Fixed cursor over NPCs sometimes showing a gift icon when they won't accept or react to the held item.
  −
:* Fixed [[Quality Fertilizer|quality fertilizer]] showing a green tile on sprouted crops, even though it can't be placed there.
  −
:* Fixed the <code>!</code> fish bite icon not shown when fishing in the [[Stardew Valley Fair]] and [[Festival of Ice]].
  −
:* Fixed some in-game error messages not having an error icon.
  −
:* Fixed inventory & crafting menus misaligned if you resize the window while they're open.
  −
:* Fixed fruit tree leaves not rustling in winter even if they're in a non-seasonal location like the [[greenhouse]].
  −
:* Fixed weeds being less varied than intended in summer.
  −
:* Fixed intro cutscene position not adjusted when the farmhouse is moved by a mod.
  −
:* Fixed cosmetic issues with the title & shipping screens for higher-resolution displays.
  −
:* Fixed calendar tooltip when a modded festival and birthday occur on the same day.
  −
:* Fixed beds or chests that were hidden for an event not reappearing afterwards.
  −
:* Fixed pre-built cabins sometimes placed on top of a bush or log.
  −
:* Fixed furniture drawn over sitting players if it has no front texture.
  −
:* Fixed the [[forge]] preview always showing soul level one for a [[Galaxy Soul|galaxy soul]] forge.
  −
:* Fixed many things on [[Ginger Island]] applying the valley's season or weather (including [[Fiber Seeds|fiber seeds]], [[Seasonal Decor|seasonal decor]], [[Seasonal Plant|seasonal plants]], [[Tea Bush|tea bushes]], and [[Tub o' Flowers|tubs o' flowers]]).
  −
:* Fixed [[Options|advanced save option]] tooltips being able to extend off-screen, and not shown for some field labels.
  −
:* Fixed Elliott appearing twice during the [[Egg Festival|egg hunt]].
  −
:* Fixed bombs being invisible when placed on [[The Summit|the summit]].
  −
 
  −
; Fixes for display text and localization
  −
:* Spanish prices are now formatted like ''15o'' instead of ''15g'' to match the translated term (''oro'' instead of ''gold'').
  −
:* Fixed ''many'' issues in dialogue, events, and other display text (including typos, broken tokens, translations that don't match the original, etc).
  −
:* Fixed NPC name translations applied to horses/pets that share a name with that NPC.
  −
:* Fixed unlocalized text shown for...
  −
:** the building paint menu's region names (like "Roof" or "Trim");
  −
:** NPC names in some movie theater dialogue;
  −
:** Professor Snail's name after his first event;
  −
:** Leo's name in his introductory event for some languages;
  −
:** fish names for some languages in certain cases;
  −
:** the 'Miss' text when an attack misses.
  −
:* Fixed [[Dust Sprite|dust sprites]] called ''dust spirits'' in Clint's special order and the summit cutscene.
  −
:* Fixed Lewis' letter for Feast of the Winter Star saying it starts at 10am instead of 9am.
  −
:* Fixed some recipe names not matching the items they produce.
  −
:* Fixed the hats added in 1.5 translating their internal name instead of setting the display name in some languages.
  −
:* Fixed French formatting times past midnight like "26h" instead of "02h" (e.g. on the fishing TV channel).
  −
:* Fixed French and Turkish showing broken dialogues about another NPC's gift tastes.
  −
:* Fixed German truncating Professor Snail's name in his intro event.
  −
:* Fixed Japanese and Korean formatting buff effects inconsistently.
  −
:* Fixed Korean credit line missing in other languages.
  −
:* Fixed Russian event for Professor Snail's intro freezing.
  −
 
  −
; Fixed for multiplayer
  −
:* Possibly fixed frequent disconnections for some players.
  −
:* Fixed [[Egg Festival|egg festival]] requiring 12 eggs to win if there are 5+ players. It now applies the four-player requirement to any player count beyond that.
  −
:* Fixed farmhands sometimes able to walk out of bounds at festivals.
  −
:* Fixed various cases where values weren't correctly synced between players.
  −
:* Fixed watered dirt edges not updated for farmhands when they change overnight.
  −
 
  −
; Fixes for modded players
  −
:* Monsters no longer [[Options#Advanced Game Options|spawn at night]] by default on custom farm types.
  −
:* Non-binary NPCs can now pathfind through any gendered route (e.g. men's or women's locker room), instead of defaulting to female routes.
  −
:* Fixed crashes when...
  −
:** loading a save with unknown locations, an invalid farm type, NPCs with no sprite texture, or null world objects.
  −
:** the farm map has no grass spawn tile and you walk through crops or grass.
  −
:** the data for an item, animal, tree, etc no longer exists.
  −
:** [[Carpenter's Shop#Painting|painting a building]] if its sprite changed to a smaller one since it was last painted.
  −
:** playing audio which doesn't exist (it now logs an error and plays a default 'quiet click' sound instead).
  −
:** a farmhand warps to a location which doesn't exist locally yet.
  −
:** an NPC can't parse its dialogue (it now logs the error and defaults to "..." instead).
  −
:** a [[Mini-Jukebox|mini-jukebox]] has an invalid track selected (it now turns off instead).
  −
:** a [[Mini-Shipping Bin|mini-shipping bin]] has null items.
  −
:** a [[Statue Of Endless Fortune|statue of endless fortune]] tries to produce a gift for an NPC whose first loved gift is a category or context tag (it now now chooses the first valid gift taste, and falls back to a non-birthday gift if none was found).
  −
:* Fixed calendar support for multiple events on the same day (including multiple weddings, multiple birthdays, birthdays on a festival day, etc).
  −
:* Fixed horses in indoor locations or [[The Mines|mine]]/[[Volcano Dungeon|volcano]] levels unable to return home.
  −
:* Fixed event setup not allowing more than 9 players.
  −
:* Fixed events not exiting correctly if they crash before the first script command.
  −
:* Fixed event errors not logged to the console.
  −
:* Fixed potential event crash if a custom NPC name contains 'farmer'.
  −
:* Fixed save loading very slowly if it has a broken outdoors location in some cases.
  −
 
  −
; Other bug fixes
  −
:* Fixed crashes when...
  −
:** taking a screenshot on macOS if the <samp>~/.local</samp> folder doesn't exist.
  −
:** a farmhand warps just as certain things happen (e.g. pet sounds).
  −
:* Fixed able to equip a [[staircase]] as pants to obtain [[Trimmed Lucky Purple Shorts|trimmed lucky purple shorts]].
  −
:* Fixed being able to place a [[Yellow Couch|yellow couch]] in a [[loom]].
  −
:* Fixed wilderness farm spawning a stone in water.
  −
:* Fixed hilltop farm spawning grass inside of stumps.
  −
:* Fixed [[Trash Bear]] treated as a villager (e.g. it could theoretically be picked for quests).
  −
:* Fixed save folder collision if you set the save's name & seed to the same value as an existing save.
  −
:* Fixed issue where viewing a letter with multiple pages and positioning the cursor directly above the skip button could cause the next viewed event to be skipped when the A button is pressed to progress text.
  −
:* Fixed the [[Secrets#Lonely Stone|lonely stone]] map tooltip not accessible with a gamepad.
  −
:* Fixed the build number not set on Linux/macOS.
  −
 
  −
; Other changes
  −
:* See [[Modding:Migrate to Stardew Valley 1.6|changes for mod authors]].
  −
</blockquote>
      
==See also==
 
==See also==
5

edits