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 49: Line 46:     
===Trigger actions===
 
===Trigger actions===
: ''Main article: [[Modding: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).
 
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).
Line 123: Line 120:     
===Unique string IDs===
 
===Unique string IDs===
: ''Main article: [[Modding:Common data field types#Unique string ID]].''
+
{{/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]].
 
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]].
Line 176: Line 173:  
==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 341: Line 340:  
                     "Texture": "Mods/{{ModId}}/Objects",
 
                     "Texture": "Mods/{{ModId}}/Objects",
 
                     "SpriteIndex": 0
 
                     "SpriteIndex": 0
 +
                }
 
             }
 
             }
 
         },
 
         },
Line 370: Line 370:  
                     "Texture": "Mods/{{ModId}}/Crops",
 
                     "Texture": "Mods/{{ModId}}/Crops",
 
                     "SpriteIndex": 0
 
                     "SpriteIndex": 0
 +
                }
 
             }
 
             }
 
         },
 
         },
Line 378: Line 379:  
             "Target": "Mods/{{ModId}}/Crops, Mods/{{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}}
Line 565: Line 566:     
===Custom big craftables:===
 
===Custom big craftables:===
''See also: [[Modding:Items#Big_craftables|Modding:Items]]''
+
{{/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>.
 
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>.
Line 777: Line 778:     
===Custom fences===
 
===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.
 
You can now add or customize [[Crafting#Fences|fences]] by editing the <samp>Data/Fences</samp> asset.
   Line 824: Line 827:     
===Custom floors (craftable) & paths===
 
===Custom floors (craftable) & paths===
 +
{{/doc status|a new doc page|done=false}}
 +
 
You can now add or customize [[Crafting#Decor|craftable floors & paths]] by editing the <samp>Data/FloorsAndPaths</samp> asset.
 
You can now add or customize [[Crafting#Decor|craftable floors & paths]] by editing the <samp>Data/FloorsAndPaths</samp> asset.
   Line 908: Line 913:     
===Custom machines===
 
===Custom machines===
You can now add/edit machine logic by editing the <samp>Data/Machines</samp> asset.
+
{{/doc status|[[Modding:Machines]]|done=true}}
 +
 
 +
You can now add/edit machine logic by editing the <samp>Data/Machines</samp> asset. This supports the full range of vanilla functionality, including calling custom code define in C# mods.
 +
 
 +
For C# mods, 1.6 also adds a new <samp>MachineDataUtility</samp> class and various <samp>Object</samp> to simplify working with machines in code. These are used by the game code itself to implement the base machine logic.
 +
 
 +
===Custom melee weapons===
 +
{{/doc status|[[Modding:Items#Weapons]]|done=false}}
 +
 
 +
[[Modding:Items#Weapons|Melee weapons]] are still stored in <samp>Data/Weapons</samp>, but that asset has been overhauled in Stardew Valley 1.6. The slash-delimited entries are now models to simplify edits and enable new features (like the new <samp>Projectiles</samp> feature).
    
This consists of a string → model lookup, where...
 
This consists of a string → model lookup, where...
* 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 key is the unqualified [[#Custom items|item ID]] for the weapon.
* The value is a model with the fields listed below.
+
* The value is model with the fields listed below.
   −
====Item processing rules====
+
====Basic weapon info====
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 920: Line 934:  
! effect
 
! effect
 
|-
 
|-
| <samp>OutputRules</samp>
+
| <samp>Name</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 internal weapon name.
 +
|-
 +
| <samp>DisplayName</samp><br /><samp>Description</samp>
 +
| A [[Modding:Tokenizable strings|tokenizable string]] for the translated display name & description.
 +
|-
 +
| <samp>Type</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).
 +
|}
 +
 
 +
====Appearance====
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 927: Line 950:  
! effect
 
! effect
 
|-
 
|-
| <samp>Id</samp>
+
| <samp>Texture</samp>
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this rule within the current machine (it doesn't need to be unique between machines).
+
| The asset name for the spritesheet containing the weapon's sprite.
 
|-
 
|-
| <samp>Triggers</samp>
+
| <samp>SpriteIndex</samp>
| When to apply this output rule. This can list any number of triggers; the output will apply if any of them match.
+
| The index within the <samp>Texture</samp> for the weapon sprite, where 0 is the top-left sprite.
 +
|}
   −
This consists of a list of models with these fields:
+
====Stats====
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 939: Line 963:  
! effect
 
! effect
 
|-
 
|-
| <samp>Id</samp>
+
| <samp>MinDamage</samp><br /><samp>MaxDamage</samp>
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this trigger within the current rule.
+
| The minimum and maximum based damage caused when hitting a monster with this weapon.
 
|-
 
|-
| <samp>Trigger</samp>
+
| <samp>Knockback</samp>
| ''(Optional)'' When this output rule applies. Defaults to <samp>ItemPlacedInMachine</samp>. The possible values are...
+
| ''(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>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]].
  −
 
  −
You can specify multiple values, like <code>"Trigger": "DayUpdate, MachinePutDown, OutputCollected"</code>.
   
|-
 
|-
| <samp>RequiredItemId</samp>
+
| <samp>Speed</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)'' 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>RequiredTags</samp>
+
| <samp>Precision</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)'' Reduces the chance that a strike will miss. Default 0.
 
|-
 
|-
| <samp>RequiredCount</samp>
+
| <samp>Defense</samp>
| ''(Optional)'' The required stack size for the input item, if the trigger is <samp>ItemPlacedInMachine</samp> or <samp>OutputCollected</samp>. Default 1.
+
| ''(Optional)'' Reduces damage received by the player. Default 0.
 
|-
 
|-
| <samp>Condition</samp>
+
| <samp>AreaOfEffect</samp>
| ''(Optional)'' A [[Modding: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.
+
| ''(Optional)'' Slightly increases the area of effect. Default 0.
|}
   
|-
 
|-
| <samp>OutputItem</samp>
+
| <samp>CritChance</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:
+
| ''(Optional)'' The chance of a critical hit, as a decimal value between 0 (never) and 1 (always). Default 0.02.
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>CritMultiplier</samp>
! effect
+
| ''(Optional)'' A multiplier applied to the base damage for a critical hit. This can be a decimal value. Default 3.
|-
+
|}
| ''common fields''
  −
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields supported by machine output.
     −
Notes:
+
====Game logic====
<ul>
  −
<li>If <samp>ItemId</samp> or <samp>RandomItemId</samp> is set to an [[Modding: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"
 
{| class="wikitable"
 
|-
 
|-
! token
+
! field
! replaced with
+
! effect
 
|-
 
|-
| <samp>DROP_IN_ID</samp>
+
| <samp>CanBeLostOnDeath</samp>
| The qualified item ID for the item placed in the machine.
+
| Whether the player can [[Adventurer's Guild#Item Recovery Service|lose this tool when they die]]. Default true.
 
|-
 
|-
| <samp>DROP_IN_PRESERVE</samp>
+
| <samp>MineBaseLevel</samp><br /><samp>MineMinLevel</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>.
+
| ''(Optional)'' The base and minimum mine level, which affect [[#Mine container drops|mine container drops]]. Both default to -1, which disables automatic mine drops.
|-
  −
| <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>
+
====Advanced====
<li>The <samp>Condition</samp> field will check the ''input'' (not output) item for item-related conditions.</li>
+
{| class="wikitable"
</ul>
   
|-
 
|-
| <samp>PreserveType</samp>
+
! field
| ''(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.
+
! effect
 
|-
 
|-
| <samp>PreserveId</samp>
+
| <samp>Projectiles</samp>
| ''(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.
+
| ''(Optional)'' The projectiles fired when the weapon is used, which continue along their path until they hit a monster and cause damage. A separate projectile is fired for each entry in this list.
 +
 
 +
This consists of a list of models with these fields (one projectile will fire for each entry in the list):
 +
{| class="wikitable"
 
|-
 
|-
| <samp>CopyColor</samp>
+
! field
| ''(Optional)'' Whether to inherit the color of the input item if it was a <samp>ColoredObject</samp>. This mainly affects [[roe]]. Default false.
+
! effect
 
|-
 
|-
| <samp>CopyPrice</samp>
+
| <samp>Id</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.
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for the projectile within the current weapon's data.
 
|-
 
|-
| <samp>CopyQuality</samp>
+
| <samp>Damage</samp>
| ''(Optional)'' Whether to inherit the quality of the input item (before <samp>QualityModifiers</samp> are applied).
+
| ''(Optional)'' The amount of damage caused when the projectile hits a monster. Default 10.
 
|-
 
|-
| <samp>PriceModifiers</samp><br /><samp>PriceModifiers</samp>
+
| <samp>Explodes</samp>
| ''(Optional)'' [[#Quantity modifiers|Quantity modifiers]] applied to the output item's price. Default none.
+
| ''(Optional)'' Whether the projectile explodes when it collides with something. Default false.
 
|-
 
|-
| <samp>IncrementMachineParentSheetIndex</samp>
+
| <samp>Bounces</samp>
| ''(Optional)'' An amount by which to increment the machine's spritesheet index while it's processing this output. This stacks with the <samp>ShowNextIndexWhenLoaded</samp> or <samp>ShowNextIndexWhileWorking</samp> field. Default 0.
+
| ''(Optional)'' The number of times the projectile can bounce off walls before being destroyed. Default 0.
 
|-
 
|-
| <samp>OutputMethod</samp>
+
| <samp>MaxDistance</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 maximum tile distance the projectile can travel. Default 4.
 
  −
This must be specified in the form <samp>{{t|full type name}}: {{t|method name}}</samp> (like <samp>StardewValley.Object, Stardew Valley: OutputSolarPanel</samp>). The method must be static and match the game's <samp>MachineOutputDelegate</samp> method signature:
  −
<syntaxhighlight lang="c#">
  −
/// <summary>Get the output item to produce.</summary>
  −
/// <param name="machine">The machine instance for which to produce output.</param>
  −
/// <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>
  −
/// <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>
  −
/// <returns>Returns the item to produce, or <c>null</c> if none should be produced.</returns>
  −
public static Item GetOutput(Object machine, Item inputItem, bool probe, MachineItemOutput outputData, out int? overrideMinutesUntilReady);
  −
</syntaxhighlight>
  −
 
  −
If this method returns null, the machine won't output anything.
   
|-
 
|-
| <samp>CustomData</samp>
+
| <samp>Velocity</samp>
| Machine-specific data provided to the machine logic, if applicable.
+
| ''(Optional)'' The speed at which the projectile moves. Default 10.
 
  −
For example, the cask uses this to set the aging rate for each item:
  −
<syntaxhighlight lang="js">
  −
"OutputItem": {
  −
    "OutputMethod": "StardewValley.Objects.Cask, Stardew Valley: OutputCask",
  −
    "CustomData": {
  −
        "AgingMultiplier": 4
  −
    }
  −
}
  −
</syntaxhighlight>
  −
|}
   
|-
 
|-
| <samp>UseFirstValidOutput</samp>
+
| <samp>RotationVelocity</samp>
| ''(Optional)'' If multiple <samp>OutputItem</samp> entries match, whether to use the first match instead of choosing one randomly. Default false.
+
| ''(Optional)'' The rotation velocity. Default 32.
 
|-
 
|-
| <samp>MinutesUntilReady</samp><br /><samp>DaysUntilReady</samp>
+
| <samp>TailLength</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.
+
| ''(Optional)'' The length of the tail which trails behind the main projectile. Default 1.
 
|-
 
|-
| <samp>InvalidCountMessage</samp>
+
| <samp>FireSound</samp><br /><samp>BounceSound</samp><br /><samp>CollisionSound</samp>
| ''(Optional)'' If set, overrides the machine's main <samp>InvalidCountMessage</samp> field.
+
| ''(Optional)'' The sound played when the projectile is fired, bounces off a wall, or collides with something. All three default to none.
 
|-
 
|-
| <samp>RecalculateOnCollect</samp>
+
| <samp>MinAngleOffset</samp><br /><samp>MaxAngleOffset</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.
+
| ''(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>AdditionalConsumedItems</samp>
+
| <samp>Item</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).
+
| ''(Optional)'' The item to shoot. If set, this overrides <samp>SpriteIndex</samp>.
    
This consists of a list of models with these fields:
 
This consists of a list of models with these fields:
Line 1,071: Line 1,058:  
! effect
 
! effect
 
|-
 
|-
| <samp>ItemId</samp>
+
| ''common fields''
| The [[#Custom items|qualified or unqualified item ID]] for the required item.
+
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields supported for ammo items.
|-
+
 
| <samp>RequiredCount</samp>
+
If set to an [[Modding:Item queries|item query]] which returns multiple items, one of them will be selected at random.
| ''(Optional)'' The required stack size for the item matching <samp>ItemId</samp>. Default 1.
+
|}
|-
  −
| <samp>InvalidCountMessage</samp>
  −
| ''(Optional)'' If set, overrides the machine's main <samp>InvalidCountMessage</samp> field.
   
|}
 
|}
 +
 +
Note that these are magic projectiles fired when the weapon is used, they're not aimed directly like [[slingshot]] projectiles.
 
|-
 
|-
| <samp>AllowFairyDust</samp>
+
| <samp>CustomFields</samp>
| ''(Optional)'' Whether the player can add [[Fairy Dust|fairy dust]] to speed up the machine. Default true.
+
| The [[#Custom data fields|custom fields]] for this entry.
|-
  −
| <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====
+
===Custom movie concessions===
 +
{{/doc status|[[Modding:Movie theater data]]|done=false}}
 +
: ''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 [[Modding:Common data field types#Unique string ID|unique string ID]].</li>
 +
<li>You can now use a different texture with two new required fields:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 1,097: Line 1,086:  
! effect
 
! effect
 
|-
 
|-
| <samp>PreventTimePass</samp>
+
| <samp>Texture</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 asset name for the texture containing the concession's sprite.
{| class="wikitable"
   
|-
 
|-
! value
+
| <samp>SpriteIndex</samp>
! effect
+
| The index within the <samp>Texture</samp> for the concession sprite, where 0 is the top-left sprite.
|-
  −
| <samp>Outside</samp><br /><samp>Inside</samp>
  −
| Pause when placed in an outside or inside location. For example, [[Bee House|bee houses]] don't work inside.
  −
|-
  −
| <samp>Spring</samp><br /><samp>Summer</samp><br /><samp>Fall</samp><br /><samp>Winter</samp>
  −
| Pause in the given season. For example, [[Bee House|bee houses]] don't work in winter.
  −
|-
  −
|-
  −
| <samp>Sun</samp><br /><samp>Rain</samp>
  −
| Pause on days with the given weather.
  −
|-
  −
| <samp>Always</samp>
  −
| Always pause the machine. This is used in specialized cases where the timer is handled by [[#Advanced logic|advanced machine logic]].
  −
|}
  −
|-
  −
| <samp>AllowLoadWhenFull</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.
  −
|-
  −
| <samp>ClearContentsOvernightCondition</samp>
  −
| ''(Optional)'' A [[Modding: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.
   
|}
 
|}
 +
</li>
 +
</ul>
   −
====Audio & visuals====
+
For example, this content pack adds a new 'Pufferchick Pop' concession with a custom image:
{| class="wikitable"
+
{{#tag:syntaxhighlight|<nowiki>
|-
+
{
! field
+
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
! effect
+
    "Changes": [
|-
+
        {
| <samp>LoadEffects</samp><br /><samp>WorkingEffects</samp>
+
            "Action": "EditData",
| ''(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:
+
            "Target": "Data/Concessions",
{| class="wikitable"
+
            "Entries": {
|-
+
                "{{ModId}}_PufferchickPop": {
! field
+
                    "Id": "{{ModId}}_PufferchickPop",  // must specify ID again when creating a new entry
! effect
+
                    "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.
 +
 
 +
{| class="wikitable"
 
|-
 
|-
| <samp>Condition</samp>
+
! field
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this effect should be played. For item queries, you can check the input item (<samp>Input</samp) or output item (<samp>Target</samp>). Defaults to always true.
+
! effect
 
|-
 
|-
| <samp>Sounds</samp>
+
| <samp>TargetContextTags</samp>
| ''(Optional)'' The audio to play. This consists of a list of models with these fields:
+
| The items that must be donated to complete this reward group. The player must fulfill every entry in the list to unlock the reward. This consists of a list of models with these fields:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 1,148: Line 1,140:  
! effect
 
! effect
 
|-
 
|-
| <samp>Id</samp>
+
| <samp>Tag</samp>
| The [[#Custom audio|audio cue ID]] to play.
+
| The [[Modding:Context tags|context tag]] for the items to require.
 
|-
 
|-
| <samp>Delay</samp>
+
| <samp>Count</samp>
| ''(Optional)'' The number of milliseconds until the sound should play. Default 0.
+
| The minimum number of items matching the context tags that must be donated.
 
|}
 
|}
   −
Defaults to no sound.
+
For example, an entry with the tag <samp>forage_item</samp> and count 2 will require donating any two forage items.
 +
 
 +
Special case: an entry with the exact values <code>Tag: "", Count: -1</code> passes if the museum is complete (i.e. the player has donated the max number of items).
 
|-
 
|-
| <samp>ShakeDuration</samp>
+
| <samp>FlagOnCompletion</samp>
| ''(Optional)'' A duration in milliseconds during which the machine sprite should shake. Default none.
+
| ''(Optional if <samp>RewardItemIsSpecial</samp> is true)'' Whether to add the <samp>ID</samp> value to the player's received mail. This is used to track whether the player has collected the reward, and should almost always be true. If this is omitted and <samp>RewardItemIsSpecial</samp> is false, the player will be able collect the reward infinite times. Default false.
 +
 
 +
After the reward is collected, you can check this value using the <samp><nowiki>HasFlag</nowiki></samp> condition in [[Modding:Content Patcher|Content Patcher]].
 
|-
 
|-
| <samp>Frames</samp>
+
| <samp>RewardActions</samp>
| ''(Optional)'' The animation to apply to the machine sprite, specified as a list of offsets relative to the base sprite index. Default none.
+
| 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>Interval</samp>
+
| <samp>RewardItemId</samp>
| ''(Optional)'' The number of milliseconds for which each frame in <samp>Frames</samp> is kept on-screen. Default 100.
+
| ''(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>TemporarySprites</samp>
+
| <samp>RewardItemCount</samp>
| ''(Optional)'' The temporary animated sprites to show. This consists of a list of models with these fields:
+
| ''(Optional)'' The stack size for the <samp>RewardItemId</samp> (if the item supports stacking). Default 1.
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>RewardItemIsSpecial</samp>
! effect
+
| ''(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>Id</samp>
+
| <samp>RewardItemIsRecipe</samp>
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this rule within the current machine (it doesn't need to be unique between machines).
+
| ''(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>Texture</samp>
+
| <samp>CustomFields</samp>
| The asset name for the texture (under the game's <samp>Content</samp> folder) for the animated sprite.
+
| The [[#Custom data fields|custom fields]] for this entry.
|-
  −
| <samp>SourceRect</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.
  −
|-
  −
| <samp>Condition</samp>
  −
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether to add this temporary sprite.
  −
|-
  −
| <samp>PositionOffset</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).
  −
|-
  −
| <samp>Color</samp>
  −
| ''(Optional)'' A tint color to apply to the sprite. See [[#Color fields|color format]]. Default <samp>White</samp> (no tint).
  −
|-
  −
| <samp>AlphaFade</samp><br /><samp>Loops</samp><br /><samp>Rotation</samp><br /><samp>RotationChange</samp><br /><samp>ScaleChange</samp><br /><samp>SortOffset</samp>
  −
| ''(Optional)'' See equivalent fields in the [[#Event changes|<samp>temporaryAnimatedSprite</samp> event command]]. Default 0.
  −
|-
  −
| <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:  
+
For example, this content pack adds two rewards (one mail and one item):
{| class="wikitable"
+
{{#tag:syntaxhighlight|<nowiki>
|-
+
{
! field
+
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
! effect
+
    "Changes": [
|-
+
        {
| <samp>Radius</samp>
+
            "Action": "EditData",
| ''(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.
+
            "Target": "Data/MuseumRewards",
|-
+
            "Entries": {
| <samp>Color</samp>
+
                // send a letter when a specific item is donated
| ''(Optional)'' A tint color to apply to the light. See [[#Color fields|color format]]. Default <samp>White</samp> (no tint).
+
                "{{ModId}}_ShinyArtifact": {
|}
+
                    "TargetContextTags": [
|-
+
                        {
| <samp>WobbleWhileWorking</samp>
+
                            "Tag": "id_{{ModId}}_ShinyArtifact", // unique context tag identifying the item by ID
| ''(Optional)'' Whether the machine sprite should bulge in & out while it's processing an item. Default false.
+
                            "Count": 1
|-
+
                        },
| <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.
+
                    "FlagOnCompletion": true,
|}
+
                    "RewardActions": [ "AddMail Current {{ModId}}_ShinyArtifact" ]
 +
                },
   −
====Player interaction messages====
+
                // give item when 18 minerals are donated
These only apply when the player interacts with a chest directly, instead of using a [[hopper]] or mod like {{nexus mod|1063|Automate}}.
+
                "{{ModId}}_18MineralItems": {
 
+
                    "TargetContextTags": [
{| class="wikitable"
+
                        {
|-
+
                            "Tag": "item_type_minerals",
! field
+
                            "Count": 18
! effect
+
                        },
|-
+
                    ],
| <samp>InvalidItemMessage</samp>
+
                    "RewardItemId": "(BC){{ModId}}_SuperMachine",
| ''(Optional)'' A [[Modding:Tokenizable strings|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.
+
                    "RewardItemCount": 1,
|-
+
                    "FlagOnCompletion": true
| <samp>InvalidItemMessageCondition</samp>
+
                }
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether <samp>InvalidItemMessage</samp> should be shown. This can use item-related queries like <samp>ITEM_TYPE</samp>. Defaults to always true.
+
            }
|-
+
        }
| <samp>InvalidCountMessage</samp>
+
    ]
| ''(Optional)'' A [[Modding:Tokenizable strings|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>.
+
}</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.
   −
This can use extra custom tokens:
+
====Achievements====
* <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>.
+
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).
|}
     −
====Advanced logic====
+
===Custom fruit trees===
{| class="wikitable"
+
{{/doc status|[[Modding:Fruit trees]]|done=false}}
|-
  −
! 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, Stardew Valley: SomeInteractMethod</samp>). The method must be static and match the game's <samp>MachineInteractDelegate</samp> method signature:
+
====Data format====
<syntaxhighlight lang="c#">
+
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...
/// <summary>The method signature for a custom <see cref="MachineData.InteractMethod"/> method.</summary>
+
* The key is the [[#Custom items|unqualified item ID]] for the sapling item in <samp>Data/Objects</samp>.
/// <param name="machine">The machine instance for which to produce output.</param>
+
* The value is a model with the fields listed below.
/// <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]].
  −
|-
  −
| <samp>StatsToIncrementWhenLoaded</samp><br /><samp>StatsToIncrementWhenHarvested</samp>
  −
| ''(Optional)'' The game stat counters to increment when an item is placed in the machine (<samp>StatsToIncrementWhenLoaded</samp>) or when the processed output is collected (<samp>StatsToIncrementWhenHarvested</samp>). Default none. This consists of a list of models with these fields:
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 1,286: Line 1,236:  
! effect
 
! effect
 
|-
 
|-
| <samp>StatName</samp>
+
| <samp>DisplayName</samp>
| The name of the stat counter field in <samp>Game1.stats</samp>. Stat names are case-insensitive.
+
| 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>RequiredItemId</samp>
+
| <samp>Seasons</samp>
| ''(Optional)'' If set, only increment the stat if the main input item has this qualified or unqualified item ID.
+
| 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>).
|-
  −
| <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).
  −
|}
     −
This can be used to increment both built-in stats (like <samp>GeodesCracked</samp> for the [[Geode Crusher|geode crusher]]) and custom stats. Using a [[Modding:Common data field types#Unique string ID|unique string ID]] is strongly recommended for custom stats to avoid conflicts.
+
'''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>CustomFields</samp>
+
| <samp>Fruit</samp>
| The [[#Custom data fields|custom fields]] for this entry.
+
| 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.
|}
     −
====Interacting with machines in C#====
+
This consists of a list of models with these fields:
Stardew Valley 1.6 adds two <samp>Object</samp> fields for reference:
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 1,309: Line 1,253:  
! effect
 
! effect
 
|-
 
|-
| <samp>lastOutputRuleId</samp>
+
| ''common fields''
| If this is a machine, the output rule ID for the rule being processed by the machine (if any).
+
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields supported for fruit items.
|-
  −
| <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:
+
Notes:
{| class="wikitable"
+
* 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]].
 
|-
 
|-
! field
+
| <samp>Season</samp>
! effect
+
| ''(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>IsMachineWorking()</samp>
+
| <samp>Chance</samp>
| Get whether the machine is currently processing an item.
+
| ''(Optional)'' The probability that this entry is selected, as a value between 0 (never drops) and 1 (always drops). Default 1 (100% chance).
 +
|}
 
|-
 
|-
| <samp>ShouldTimePassForMachine(location)</samp>
+
| <samp>Texture</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 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>GetMachineData()</samp>
+
| <samp>TextureSpriteRow</samp>
| Get the underlying machine data from <samp>Data/Machines</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).
 
|-
 
|-
| <samp>PlaceInMachine(…)</samp>
+
| <samp>PlantableLocationRules</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.
+
| ''(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>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.
+
This consists of a list of models with these fields:
 
  −
===Custom melee weapons===
  −
[[Modding:Items#Weapons|Melee weapons]] are still stored in <samp>Data/Weapons</samp>, but that asset has been overhauled in Stardew Valley 1.6. The slash-delimited entries are now models to simplify edits and enable new features (like the new <samp>Projectiles</samp> feature).
  −
 
  −
This consists of a string → model lookup, where...
  −
* The key is the unqualified [[#Custom items|item ID]] for the weapon.
  −
* The value is model with the fields listed below.
     −
====Basic weapon info====
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 1,353: Line 1,283:  
! effect
 
! effect
 
|-
 
|-
| <samp>Name</samp>
+
| <samp>Id</samp>
| The internal weapon name.
+
| 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>DisplayName</samp><br /><samp>Description</samp>
+
| <samp>Condition</samp>
| A [[Modding:Tokenizable strings|tokenizable string]] for the translated display name & description.
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this entry applies. Default true.
 
|-
 
|-
| <samp>Type</samp>
+
| <samp>PlantedIn</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).
+
| ''(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>.
|}
     −
====Appearance====
+
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>Texture</samp>
+
| <samp>CustomFields</samp>
| The asset name for the spritesheet containing the weapon's sprite.
+
| The [[#Custom data fields|custom fields]] for this entry.
|-
  −
| <samp>SpriteIndex</samp>
  −
| The index within the <samp>Texture</samp> for the weapon sprite, where 0 is the top-left sprite.
   
|}
 
|}
   −
====Stats====
+
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>MinDamage</samp><br /><samp>MaxDamage</samp>
  −
| The minimum and maximum based damage caused when hitting a monster with this weapon.
  −
|-
  −
| <samp>Knockback</samp>
  −
| ''(Optional)'' How far the target is pushed when hit, as a multiplier relative to a base weapon like the [[Rusty Sword]] (e.g. <samp>1.5</samp> for 150% of Rusty Sword's weight). Default 1.
  −
|-
  −
| <samp>Speed</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.
  −
|-
  −
| <samp>Precision</samp>
  −
| ''(Optional)'' Reduces the chance that a strike will miss. Default 0.
  −
|-
  −
| <samp>Defense</samp>
  −
| ''(Optional)'' Reduces damage received by the player. Default 0.
  −
|-
  −
| <samp>AreaOfEffect</samp>
  −
| ''(Optional)'' Slightly increases the area of effect. Default 0.
  −
|-
  −
| <samp>CritChance</samp>
  −
| ''(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====
+
{{#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
| <samp>CanBeLostOnDeath</samp>
+
        {
| Whether the player can [[Adventurer's Guild#Item Recovery Service|lose this tool when they die]]. Default true.
+
            "Action": "EditData",
|-
+
            "Target": "Data/Objects",
| <samp>MineBaseLevel</samp><br /><samp>MineMinLevel</samp>
+
            "Entries": {
| ''(Optional)'' The base and minimum mine level, which affect [[#Mine container drops|mine container drops]]. Both default to -1, which disables automatic mine drops.
+
                "{{ModId}}_Pufferfruit": {
|}
+
                    "Name": "{{ModId}}_Pufferfruit", // best practice to match the ID, since it's sometimes used as an alternate ID
 +
                    "DisplayName": "Pufferfruit",
 +
                    "Description": "An example fruit item.",
 +
                    "Type": "Basic",
 +
                    "Category": -6,
 +
                    "Price": 1200,
   −
====Advanced====
+
                    "Texture": "Mods/{{ModId}}/Objects",
{| class="wikitable"
+
                    "SpriteIndex": 0
|-
+
                },
! field
+
                "{{ModId}}_Puffersapling": {
! effect
+
                    "Name": "{{ModId}}_Puffersapling",
|-
+
                    "DisplayName": "Puffersapling",
| <samp>Projectiles</samp>
+
                    "Description": "An example tree sapling.",
| ''(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.
+
                    "Type": "Basic",
 +
                    "Category": -74,
 +
                    "Price": 1200,
 +
 
 +
                    "Texture": "Mods/{{ModId}}/Objects",
 +
                    "SpriteIndex": 1
 +
                }
 +
            }
 +
        },
   −
This consists of a list of models with these fields (one projectile will fire for each entry in the list):
+
        // add fruit tree
{| class="wikitable"
+
        {
|-
+
            "Action": "EditData",
! field
+
            "Target": "Data/FruitTrees",
! effect
+
            "Entries": {
|-
+
                "{{ModId}}_Puffersapling": {
| <samp>Id</samp>
+
                    "DisplayName": "Pufferfruit",
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for the projectile within the current weapon's data.
+
                    "Seasons": [ "spring" ],
|-
+
                    "Fruit": [
| <samp>Damage</samp>
+
                        {
| ''(Optional)'' The amount of damage caused when the projectile hits a monster. Default 10.
+
                            "Id": "E{{ModId}}_Pufferfruit",
|-
+
                            "ItemId": "{{ModId}}_Pufferfruit"
| <samp>Explodes</samp>
+
                        }
| ''(Optional)'' Whether the projectile explodes when it collides with something. Default false.
+
                    ],
|-
+
                    "Texture": "Mods/{{ModId}}/FruitTrees",
| <samp>Bounces</samp>
+
                    "TextureSpriteRow": 0
| ''(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.
+
 
|-
+
        // add images
| <samp>Velocity</samp>
+
        {
| ''(Optional)'' The speed at which the projectile moves. Default 10.
+
            "Action": "Load",
|-
+
            "Target": "Mods/{{ModId}}/FruitTrees, Mods/{{ModId}}/Objects",
| <samp>RotationVelocity</samp>
+
            "FromFile": "assets/{{TargetWithoutPath}}.png" // assets/FruitTrees.png, assets/Objects.png
| ''(Optional)'' The rotation velocity. Default 32.
+
        },
|-
+
    ]
| <samp>TailLength</samp>
+
}</nowiki>|lang=javascript}}
| ''(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:
+
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]]).
{| class="wikitable"
  −
|-
  −
! field
  −
! effect
  −
|-
  −
| ''common fields''
  −
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields supported for ammo items.
     −
If set to an [[Modding:Item queries|item query]] which returns multiple items, one of them will be selected at random.
+
====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).
|}
     −
Note that these are magic projectiles fired when the weapon is used, they're not aimed directly like [[slingshot]] projectiles.
+
====Spawning fruit trees====
|-
+
Custom trees can be added to the game in two ways:
| <samp>CustomFields</samp>
+
* 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.
| The [[#Custom data fields|custom fields]] for this entry.
+
* 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 movie concessions===
+
===Custom objects===
: ''See also: [[#Custom movies|custom movies]].''
+
{{/doc status|[[Modding:Items#Objects]]|done=false}}
   −
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.
+
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>.
   −
Stardew Valley 1.6 addresses that with two changes:
+
Besides the format change, this adds...
<ul>
+
* support for custom textures;
<li>The <samp>Id</samp> field is now a [[Modding:Common data field types#Unique string ID|unique string ID]].</li>
+
* revamped geode drops with support for conditions, probabilities, and item queries;
<li>You can now use a different texture with two new required fields:
+
* expanded food/drink buffs (e.g. set a custom buff ID, add a custom buff icon, etc);
 +
* context tags (moved from the former <samp>Data/ObjectContextTags</samp> asset);
 +
* [[#Custom data fields|custom fields]] to let framework mods support additional features.
 +
 
 +
This consists of a string → model lookup, where...
 +
* The key is the unqualified [[#Custom items|item ID]].
 +
* The value is a model with the fields listed below.
 +
 
 +
====Basic info====
 +
{| class="wikitable"
 +
|-
 +
! field
 +
! purpose
 +
|-
 +
| <samp>Name</samp>
 +
| The internal item name.
 +
|-
 +
| <samp>DisplayName</samp><br /><samp>Description</samp>
 +
| A [[Modding:Tokenizable strings|tokenizable string]] for the item's in-game display name and description.
 +
|-
 +
| <samp>Type</samp>
 +
| The item's general type, like <samp>Arch</samp> (artifact) or <samp>Minerals</samp>. See details at [[Modding:Items#Objects]].
 +
|-
 +
| <samp>Category</samp>
 +
| The [[Modding:Items#Categories|item category]].
 +
|-
 +
| <samp>Price</samp>
 +
| ''(Optional)'' The price when sold by the player. This is not the price when bought from a shop. Default 0.
 +
|}
 +
 
 +
====Appearance====
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
 
! field
 
! field
! effect
+
! purpose
 
|-
 
|-
 
| <samp>Texture</samp>
 
| <samp>Texture</samp>
| The asset name for the texture containing the concession's sprite.
+
| The asset name for the texture containing the item's sprite. Defaults to <samp>Maps/springobjects</samp>.
 
|-
 
|-
 
| <samp>SpriteIndex</samp>
 
| <samp>SpriteIndex</samp>
| The index within the <samp>Texture</samp> for the concession sprite, where 0 is the top-left sprite.
+
| The sprite's index within the <samp>Texture</samp>, where 0 is the top-left sprite.
 
|}
 
|}
</li>
  −
</ul>
     −
For example, this content pack adds a new 'Pufferchick Pop' concession with a custom image:
+
====Edibility====
{{#tag:syntaxhighlight|<nowiki>
+
{| class="wikitable"
{
+
|-
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
+
! field
    "Changes": [
+
! purpose
        {
+
|-
            "Action": "EditData",
+
| <samp>Edibility</samp>
            "Target": "Data/Concessions",
+
| ''(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.
            "Entries": {
+
|-
                "{{ModId}}_PufferchickPop": {
+
| <samp>IsDrink</samp>
                    "Id": "{{ModId}}_PufferchickPop",  // must specify ID again when creating a new entry
+
| ''(Optional)'' Whether to drink the item instead of eating it. Default false.
                    "Name": "{{ModId}}_PufferchickPop", // best practice to match the ID, since it's sometimes used as an alternate ID
+
|-
                    "DisplayName": "Pufferchick Pop",
+
| <samp>Buffs</samp>
                    "Description": "A cute cake pop shaped like a pufferchick.",
+
| ''(Optional)'' The buffs to apply to the player when this item is eaten, if any. Default none.
                    "Price": 25,
  −
                    "Texture": "{{InternalAssetKey: assets/pufferchick-pop.png}}" // an image in your content pack
  −
                    "SpriteIndex": 0
  −
                }
  −
            }
  −
        }
  −
    ]
  −
}</nowiki>|lang=javascript}}
  −
 
  −
===Custom museum donations & rewards===
  −
You can now add/edit the items which the [[museum]] accepts in donation and gives back in rewards through the new <samp>Data/MuseumRewards</samp> data asset.
  −
 
  −
====Format====
  −
The data asset consists of a string → model lookup, where...
  −
* The key 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.
      +
This consists of a list of models with these fields:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
 
! field
 
! field
! effect
+
! purpose
 +
|-
 +
| <samp>Id</samp>
 +
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the list.
 +
|-
 +
| <samp>Duration</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.
 
|-
 
|-
| <samp>TargetContextTags</samp>
+
| <samp>BuffId</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:
+
| ''(Optional)'' The unique ID of a buff from [[#Custom buffs|<samp>Data/Buffs</samp>]] to apply, or <samp>null</samp> to ignore <samp>Data/Buffs</samp> and set the ID to <samp>food</samp> or <samp>drink</samp> depending on the item's <samp>IsDrink</samp> field.
 +
 
 +
If a buff from <samp>Data/Buffs</samp> is applied and you also specify other fields, here's how the buff data is combined:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
 
! field
 
! field
! effect
+
! result
 +
|-
 +
| <samp>Duration</samp><br /><samp>IconTexture</samp><br /><samp>SpriteIndex</samp><br /><samp>GlowColor</samp>
 +
| 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>.
 
|-
 
|-
| <samp>Tag</samp>
+
| <samp>CustomAttributes</samp>
| The [[Modding:Context tags|context tag]] for the items to require.
+
| 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>Count</samp>
+
| <samp>IsDebuff</samp>
| The minimum number of items matching the context tags that must be donated.
+
| The value in <samp>Data/Objects</samp> is used.
 
|}
 
|}
  −
For example, an entry with the tag <samp>forage_item</samp> and count 2 will require donating any two forage items.
  −
  −
Special case: an entry with the exact values <code>Tag: "", Count: -1</code> passes if the museum is complete (i.e. the player has donated the max number of items).
   
|-
 
|-
| <samp>FlagOnCompletion</samp>
+
| <samp>IsDebuff</samp>
| ''(Optional if <samp>RewardItemIsSpecial</samp> is true)'' Whether to add the <samp>ID</samp> value to the player's received mail. This is used to track whether the player has collected the reward, and should almost always be true. If this is omitted and <samp>RewardItemIsSpecial</samp> is false, the player will be able collect the reward infinite times. Default false.
+
| ''(Optional)'' Whether this buff counts as a debuff, so its duration should be halved when wearing a Sturdy Ring. Default false.
 
+
|-
After the reward is collected, you can check this value using the <samp><nowiki>HasFlag</nowiki></samp> condition in [[Modding:Content Patcher|Content Patcher]].
+
| <samp>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>RewardActions</samp>
+
| <samp>GlowColor</samp>
| Run one or more [[Modding:Trigger actions|trigger action strings]]. For example, this adds {{price|500}} to the current player:
+
| ''(Optional)'' The glow color to apply to the player. See [[#Color fields|color format]]. Default none.
<syntaxhighlight lang="js">
  −
"RewardActions": [
  −
    "AddMoney 500"
  −
]
  −
</syntaxhighlight>
   
|-
 
|-
| <samp>RewardItemId</samp>
+
| <samp>CustomAttributes</samp>
| ''(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.
+
| The custom buff attributes to apply, if any.
 +
 
 +
This consists of a model with any combination of these fields:
 +
{| class="wikitable"
 
|-
 
|-
| <samp>RewardItemCount</samp>
+
! field
| ''(Optional)'' The stack size for the <samp>RewardItemId</samp> (if the item supports stacking). Default 1.
+
! purpose
 
|-
 
|-
| <samp>RewardItemIsSpecial</samp>
+
| <samp>FarmingLevel</samp><br /><samp>FishingLevel</samp><br /><samp>ForagingLevel</samp><br /><samp>LuckLevel</samp><br /><samp>MiningLevel</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.
+
| ''(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>RewardItemIsRecipe</samp>
+
| <samp>Attack</samp><br /><samp>Defense</samp><br /><samp>MagneticRadius</samp><br /><samp>MaxStamina</samp><br /><samp>Speed</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)'' 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 two rewards (one mail and one item):
+
====Geodes & artifact spots====
{{#tag:syntaxhighlight|<nowiki>
+
{| class="wikitable"
{
+
|-
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
+
! field
    "Changes": [
+
! purpose
        {
+
|-
            "Action": "EditData",
+
| <samp>GeodeDrops</samp><br /><samp><samp>GeodeDropsDefaultItems</samp>
            "Target": "Data/MuseumRewards",
+
| ''(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.
            "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===
  −
====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.
      +
You can specify one or both fields:
 +
<ul>
 +
<li><samp>GeodeDrops</samp> can be set to the specific items to drop. Default none. This consists of a list of models with these fields:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
 
! field
 
! field
! effect
+
! purpose
 
|-
 
|-
| <samp>DisplayName</samp>
  −
| 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>Seasons</samp>
+
| ''common fields''
| 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>).
+
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields supported by geode drops.
   −
'''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]]).
+
If set to an [[Modding:Item queries|item query]] which returns multiple items, one of them will be selected at random.
 
|-
 
|-
| <samp>Fruit</samp>
+
| <samp>Chance</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 probability that the item will be dropped if the other fields match, as a decimal value between 0 (never) and 1 (always). Default 1.
 
  −
This consists of a list of models with these fields:
  −
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>SetFlagOnPickup</samp>
! effect
+
| ''(Optional)'' The mail flag to set for the current player when this drop is picked up.
 
|-
 
|-
| ''common fields''
+
| <samp>Precedence</samp>
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields supported for fruit items.
+
| ''(Optional)'' The order in which this entry should be checked, where lower values are checked first. This can be a negative value. Geode drops with the same precedence are checked in the order listed. Default 0.
 +
 
 +
For consistency, vanilla drops mostly use these values:
 +
* <samp>-1000</samp>: special overrides like the [[Golden Helmet]];
 +
* <samp>0</samp>: normal items.
 +
|}</li>
 +
<li><samp>GeodeDropsDefaultItems</samp> chooses a predefined list of possible geode drops like [[clay]], [[coal]], [[Copper Ore|copper]], [[Iridium Ore|iridium]], etc. Default false.</li>
 +
</ul>
   −
Notes:
+
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.
* 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>Season</samp>
+
| <samp>ArtifactSpotChances</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]].
+
| ''(Optional)'' If this is an artifact (i.e. the <samp>Type</samp> field is <samp>Arch</samp>), the chance that it can be found by digging [[Artifact Spot|artifact spots]] in each location.
 +
 
 +
This consists of a string → model lookup, where:
 +
* the key is the internal location name;
 +
* the value is the probability the item will spawn if checked, as a decimal value between 0 (never) and 1 (always).
 +
|}
 +
 
 +
====Context tags & exclusions====
 +
{| class="wikitable"
 
|-
 
|-
| <samp>Chance</samp>
+
! field
| ''(Optional)'' The probability that this entry is selected, as a value between 0 (never drops) and 1 (always drops). Default 1 (100% chance).
+
! purpose
|}
   
|-
 
|-
| <samp>Texture</samp>
+
| <samp>ContextTags</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)'' 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>TextureSpriteRow</samp>
+
| <samp>ExcludeFromRandomSale</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)'' Whether to exclude this item from shops when selecting random items to sell. Default false.
 
|-
 
|-
| <samp>PlantableLocationRules</samp>
+
| <samp>ExcludeFromFishingCollection</samp><br /><samp>ExcludeFromShippingCollection</samp>
| ''(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.
+
| ''(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).
 
+
|}
This consists of a list of models with these fields:
      +
====Advanced====
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
 
! field
 
! field
! effect
+
! purpose
 
|-
 
|-
| <samp>Id</samp>
+
| <samp>CustomFields</samp>
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the list.
+
| ''(Optional)'' The [[#Custom data fields|custom fields]] for this entry.
 +
|}
 +
 
 +
===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...
 +
* The key is the unqualified [[#Custom items|item ID]].
 +
* The value is a model with the fields listed below.
 +
 
 +
====Basic pants data====
 +
{| class="wikitable"
 +
|-
 +
! field
 +
! purpose
 
|-
 
|-
| <samp>Result</samp>
+
| <samp>Name</samp>
| Indicates whether the sapling can be planted in a location if this entry is selected. The possible values are:
+
| ''(Optional)'' The internal name for the item. Default <samp>Pants</samp>.
* <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>
+
| <samp>DisplayName</samp><br /><samp>Description</samp>
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this entry applies. Default true.
+
| ''(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>PlantedIn</samp>
+
| <samp>Price</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>.
+
| ''(Optional)'' The default price when the item is sold to the player in a shop. Default 50.
 +
|}
   −
Note that saplings can't be planted in garden pots.
+
====Appearance====
 +
{| class="wikitable"
 +
|-
 +
! field
 +
! purpose
 +
|-
 +
| <samp>Texture</samp>
 +
| The asset name for the texture containing the pants' sprite. Defaults to <samp>Characters/Farmer/pants</samp>.
 +
|-
 +
| <samp>SpriteIndex</samp>
 +
| The pants' sprite index within the <samp>Texture</samp>, where 0 is the top-left set.
 +
|-
 +
| <samp>DefaultColor</samp>
 +
| ''(Optional)'' The dye color to apply to the sprite when the player hasn't [[dyeing|dyed]] it yet, if any. See [[#Color fields|color format]]. Default <samp>255 235 203</samp> (which matches the color of the cloth item).
 
|-
 
|-
| <samp>DeniedMessage</samp>
+
| <samp>CanBeDyed</samp>
| ''(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.
+
| ''(Optional)'' Whether the player can [[dyeing|dye]] these pants. Default false.
|}
   
|-
 
|-
| <samp>CustomFields</samp>
+
| <samp>IsPrismatic</samp>
| The [[#Custom data fields|custom fields]] for this entry.
+
| ''(Optional)'' Whether the pants continuously shift colors. This overrides <samp>DefaultColor</samp> and <samp>CanBeDyed</samp> if set. Default false.
 
|}
 
|}
   −
For example, this content pack adds a custom fruit tree, including [[#Custom items|custom items]] for the sapling and fruit:
+
====Other====
 
+
{| class="wikitable"
{{#tag:syntaxhighlight|<nowiki>
+
|-
{
+
! field
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
+
! purpose
    "Changes": [
+
|-
        // add fruit + sapling items
+
| <samp>CanChooseDuringCharacterCustomization</samp>
        // note: sapling must have an edibility under 0 (usually -300) to be plantable
+
| ''(Optional)'' Whether these pants can be selected on the character customization screen (e.g. when creating a character). Default false.
        {
+
|-
            "Action": "EditData",
+
| <samp>CustomFields</samp>
            "Target": "Data/Objects",
+
| The [[#Custom data fields|custom fields]] for this entry.
            "Entries": {
+
|}
                "{{ModId}}_Pufferfruit": {
  −
                    "Name": "{{ModId}}_Pufferfruit", // best practice to match the ID, since it's sometimes used as an alternate ID
  −
                    "DisplayName": "Pufferfruit",
  −
                    "Description": "An example fruit item.",
  −
                    "Type": "Basic",
  −
                    "Category": -6,
  −
                    "Price": 1200,
     −
                    "Texture": "Mods/{{ModId}}/Objects",
+
===Custom shirts===
                    "SpriteIndex": 0
+
{{/doc status|[[Modding:Items]]|done=false}}
                },
  −
                "{{ModId}}_Puffersapling": {
  −
                    "Name": "{{ModId}}_Puffersapling",
  −
                    "DisplayName": "Puffersapling",
  −
                    "Description": "An example tree sapling.",
  −
                    "Type": "Basic",
  −
                    "Category": -74,
  −
                    "Price": 1200,
     −
                    "Texture": "Mods/{{ModId}}/Objects",
+
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...
                    "SpriteIndex": 1
+
* The key is the unqualified [[#Custom items|item ID]].
                }
+
* The value is a model with the fields listed below.
            }
  −
        },
     −
        // add fruit tree
+
====Basic shirt data====
        {
+
{| class="wikitable"
            "Action": "EditData",
+
|-
            "Target": "Data/FruitTrees",
+
! field
            "Entries": {
+
! purpose
                "{{ModId}}_Puffersapling": {
+
|-
                    "DisplayName": "Pufferfruit",
+
| <samp>Name</samp>
                    "Seasons": [ "spring" ],
+
| ''(Optional)'' The internal name for the item. Default <samp>Shirt</samp>.
                    "Fruit": [
+
|-
                        {
+
| <samp>DisplayName</samp><br /><samp>Description</samp>
                            "Id": "E{{ModId}}_Pufferfruit",
+
| ''(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'').
                            "ItemId": "{{ModId}}_Pufferfruit"
+
|-
                        }
+
| <samp>Price</samp>
                    ],
+
| ''(Optional)'' The default price when the item is sold to the player in a shop. Default 50.
                    "Texture": "Mods/{{ModId}}/FruitTrees",
+
|}
                    "TextureSpriteRow": 0
  −
                }
  −
            }
  −
        },
     −
        // add images
+
====Appearance====
        {
  −
            "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===
  −
: ''See also: [[Modding:Items#Objects|Modding:Items]].''
  −
You can now create/edit objects (the main item type) by editing the new <samp>Data/Objects</samp> asset, which replaces the previous slash-delimited <samp>Data/objectInformation</samp>.
  −
 
  −
Besides the format change, this adds...
  −
* support for custom textures;
  −
* revamped geode drops with support for conditions, probabilities, and item queries;
  −
* expanded food/drink buffs (e.g. set a custom buff ID, add a custom buff icon, etc);
  −
* context tags (moved from the former <samp>Data/ObjectContextTags</samp> asset);
  −
* [[#Custom data fields|custom fields]] to let framework mods support additional features.
  −
 
  −
This consists of a string → model lookup, where...
  −
* The key is the unqualified [[#Custom items|item ID]].
  −
* The value is a model with the fields listed below.
  −
 
  −
====Basic info====
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 1,819: Line 1,679:  
! purpose
 
! purpose
 
|-
 
|-
| <samp>Name</samp>
+
| <samp>Texture</samp>
| The internal item name.
+
| The asset name for the texture containing the shirt's sprite. Defaults to <samp>Characters/Farmer/shirts</samp>.
 
|-
 
|-
| <samp>DisplayName</samp><br /><samp>Description</samp>
+
| <samp>SpriteIndex</samp>
| A [[Modding:Tokenizable strings|tokenizable string]] for the item's in-game display name and description.
+
| The shirt's sprite index within the <samp>Texture</samp>, where 0 is the top-left set.
 +
|-
 +
| <samp>DefaultColor</samp>
 +
| ''(Optional)'' The dye color to apply to the sprite when the player hasn't [[dyeing|dyed]] it yet, if any. See [[#Color fields|color format]]. Default none.
 
|-
 
|-
| <samp>Type</samp>
+
| <samp>CanBeDyed</samp>
| The item's general type, like <samp>Arch</samp> (artifact) or <samp>Minerals</samp>. See details at [[Modding:Items#Objects]].
+
| ''(Optional)'' Whether the player can [[dyeing|dye]] this shirt. Default false.
 
|-
 
|-
| <samp>Category</samp>
+
| <samp>IsPrismatic</samp>
| The [[Modding:Items#Categories|item category]].
+
| ''(Optional)'' Whether the shirt continuously shifts colors. This overrides <samp>DefaultColor</samp> and <samp>CanBeDyed</samp> if set. Default false.
 
|-
 
|-
| <samp>Price</samp>
+
| <samp>HasSleeves</samp>
| ''(Optional)'' The price when sold by the player. This is not the price when bought from a shop. Default 0.
+
| ''(Optional)'' Whether to draw shirt sleeves. Default true.
 
|}
 
|}
   −
====Appearance====
+
====Other====
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 1,841: Line 1,704:  
! purpose
 
! purpose
 
|-
 
|-
| <samp>Texture</samp>
+
| <samp>CanChooseDuringCharacterCustomization</samp>
| The asset name for the texture containing the item's sprite. Defaults to <samp>Maps/springobjects</samp>.
+
| ''(Optional)'' Whether this shirt can be selected on the character customization screen (e.g. when creating a character). Default false.
 
|-
 
|-
| <samp>SpriteIndex</samp>
+
| <samp>CustomFields</samp>
| The sprite's index within the <samp>Texture</samp>, where 0 is the top-left sprite.
+
| The [[#Custom data fields|custom fields]] for this entry.
 
|}
 
|}
   −
====Edibility====
+
===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...
 +
* The key is the unqualified [[#Custom items|item ID]].
 +
* The value is a model with the fields listed below.
 +
 
 +
====Basic tool data====
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 1,854: Line 1,724:  
! purpose
 
! purpose
 
|-
 
|-
| <samp>Edibility</samp>
+
| <samp>ClassName</samp>
| ''(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.
+
| The name of the C# class to construct within the <code>StardewValley.Tools</code> namespace. The class must be a subclass of <samp>StardewValley.Tool</samp>, and have a constructor with no arguments. For example, given a value of <samp>Axe</samp>, the game will create <code>StardewValley.Tools.Axe</code> instances.
 +
 
 +
The main values are:
 +
* main tools (<samp>Axe</samp>, <samp>FishingRod</samp>, <samp>Hoe</samp>, <samp>MeleeWeapon</samp>, <samp>MilkPail</samp>, <samp>Pan</samp>, <samp>Pickaxe</samp>, <samp>Shears</samp>, <samp>Wand</samp>, and <samp>WateringCan</samp>);
 +
* a special <samp>GenericTool</samp> type which applies the <samp>Data/Tools</samp> data and only has generic logic, so C# mods can patch in their own logic;
 +
* and two tools cut from the game which may not work correctly (<samp>Lantern</samp> and <samp>Raft</samp>).
 
|-
 
|-
| <samp>IsDrink</samp>
+
| <samp>Name</samp>
| ''(Optional)'' Whether to drink the item instead of eating it. Default false.
+
| The internal name to set for the tool item.
 
|-
 
|-
| <samp>Buffs</samp>
+
| <samp>DisplayName</samp><br /><samp>Description</samp>
| ''(Optional)'' The buffs to apply to the player when this item is eaten, if any. Default none.
+
| A [[Modding:Tokenizable strings|tokenizable string]] for the tool's in-game display name and description.
 
  −
This consists of a list of models with these fields:
  −
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>AttachmentSlots</samp>
! purpose
+
| ''(Optional)'' The number of attachment slots to enable on the tool. Note that only <samp>FishingRod</samp> tools have the code to render and use attachment slots. Default <samp>-1</samp>, which keeps the default value set by the tool class.
 
|-
 
|-
| <samp>Id</samp>
+
| <samp>SalePrice</samp>
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the list.
+
| ''(Optional)'' The default price when the item is sold to the player in a shop. Defaults to <samp>-1</samp>, in which case you should set the price manually in shops.
 
|-
 
|-
| <samp>Duration</samp>
+
| <samp>CustomFields</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.
+
| The [[#Custom data fields|custom fields]] for this entry.
|-
+
|}
| <samp>BuffId</samp>
+
 
| ''(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.
+
====Appearance====
 +
Note that drawing the tool correctly in the world (ie, while the player is trying to use it) probably still needs custom code.
   −
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
! result
+
! purpose
 
|-
 
|-
| <samp>Duration</samp><br /><samp>IconTexture</samp><br /><samp>SpriteIndex</samp><br /><samp>GlowColor</samp>
+
| <samp>Texture</samp>
| 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>.
+
| The asset name for the texture containing the tool's sprite.
 
|-
 
|-
| <samp>CustomAttributes</samp>
+
| <samp>SpriteIndex</samp>
| 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).
+
| The tool's sprite index within the <samp>Texture</samp>, where 0 is the top row.
 
|-
 
|-
| <samp>IsDebuff</samp>
+
| <samp>MenuSpriteIndex</samp>
| The value in <samp>Data/Objects</samp> is used.
+
| ''(Optional)'' The sprite index within the <samp>Texture</samp> for the item icon. Defaults to <samp>SpriteIndex</samp>.
 
|}
 
|}
|-
  −
| <samp>IsDebuff</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:
+
====Upgrades====
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 1,915: Line 1,772:  
! purpose
 
! purpose
 
|-
 
|-
| <samp>FarmingLevel</samp><br /><samp>FishingLevel</samp><br /><samp>ForagingLevel</samp><br /><samp>LuckLevel</samp><br /><samp>MiningLevel</samp>
+
| <samp>UpgradeLevel</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.
+
| ''(Optional)'' The tool upgrade level. Default <samp>-1</samp>, which keeps the default value set by the tool class.
 
|-
 
|-
| <samp>Attack</samp><br /><samp>Defense</samp><br /><samp>MagneticRadius</samp><br /><samp>MaxStamina</samp><br /><samp>Speed</samp>
+
| <samp>ApplyUpgradeLevelToDisplayName</samp>
| ''(Optional)'' An amount applied to the player's [[attack]], [[defense]], [[Magnetism|magnetic radius]], maximum [[Energy|stamina]], or [[speed]] while the buff is active. This can be negative for a debuff. Default 0.
+
| ''(Optional)'' Whether to adjust the <samp>DisplayName</samp> for the usual upgrade levels. For example, the display name for a level one Axe changes to 'Copper Axe'. Default false.
|}
+
 
 +
The display name format in English is:
 +
{| class="wikitable"
 
|-
 
|-
| <samp>CustomFields</samp>
+
! upgrade level
| ''(Optional)'' The [[#Custom data fields|custom fields]] for this entry.
+
! display name format
|}
+
|-
 +
| 1
 +
| Copper {{t|display name}}
 +
|-
 +
| 2
 +
| Steel {{t|display name}}
 +
|-
 +
| 3
 +
| Gold {{t|display name}}
 +
|-
 +
| 4
 +
| Iridium {{t|display name}}
 
|}
 
|}
 +
|-
 +
| <samp>ConventionalUpgradeFrom</samp>
 +
| ''(Optional)'' If set, prepends an upgrade for the given tool ID to the <samp>UpgradeFrom</samp> field. This applies these rules (based on the <samp>UpgradeLevel</samp> field, not the upgrade level of the specified tool ID):
   −
====Geodes & artifact spots====
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! upgrade level
! purpose
+
! price
 +
! items needed
 +
|-
 +
| 1
 +
| {{price|2000}}
 +
| {{name|Copper Bar|5}}
 +
|-
 +
| 2
 +
| {{price|5000}}
 +
| {{name|Iron Bar|5}}
 +
|-
 +
| 3
 +
| {{price|10000}}
 +
| {{name|Gold Bar|5}}
 +
|-
 +
| 4
 +
| {{price|25000}}
 +
| {{name|Iridium Bar|5}}
 +
|}
 +
 
 +
For example, Iridium Axe specifies this value:
 +
<syntaxhighlight lang="js">
 +
"ConventionalUpgradeFrom": "(T)GoldAxe"
 +
</syntaxhighlight>
 
|-
 
|-
| <samp>GeodeDrops</samp><br /><samp><samp>GeodeDropsDefaultItems</samp>
+
| <samp>UpgradeFrom</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.
+
| ''(Optional)'' The requirements to buy this tool from Clint's [[Blacksmith#Upgrade Tools|blacksmith tool upgrade shop]]. If you specify multiple entries, the first one which matches will be applied.
   −
You can specify one or both fields:
+
This consists of a list of models with these fields:
<ul>
  −
<li><samp>GeodeDrops</samp> can be set to the specific items to drop. Default none. This consists of a list of models with these fields:
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 1,944: Line 1,837:  
! purpose
 
! purpose
 
|-
 
|-
 +
| <samp>Price</samp>
 +
| ''(Optional)'' The gold price to buy the upgrade. Defaults to 0.
 
|-
 
|-
| ''common fields''
+
| <samp>RequireToolId</samp>
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields supported by geode drops.
+
| ''(Optional)'' If set, the [[#Custom items|qualified or unqualified item ID]] for the tool that must be in the player's inventory for the upgrade to appear. The tool will be destroyed when the upgrade is purchased.
 
+
|-
If set to an [[Modding:Item queries|item query]] which returns multiple items, one of them will be selected at random.
+
| <samp>TradeItemId</samp>
 +
| ''(Optional)'' If set, the [[#Custom items|qualified or unqualified item ID]] for an extra item that must be traded to upgrade the tool. (For example, many vanilla tools need metal bars.)
 
|-
 
|-
| <samp>Chance</samp>
+
| <samp>TradeItemAmount</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.
+
| ''(Optional)'' The number of <samp>TradeItemId</samp> required. Defaults to 1.
 
|-
 
|-
| <samp>SetFlagOnPickup</samp>
+
| <samp>Condition</samp>
| ''(Optional)'' The mail flag to set for the current player when this drop is picked up.
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this upgrade is available. Defaults to always true.
|-
+
|}
| <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.
     −
For consistency, vanilla drops mostly use these values:
+
For example, these are equivalent to the Steel Axe's upgrade settings:
* <samp>-1000</samp>: special overrides like the [[Golden Helmet]];
+
<syntaxhighlight lang="js">
* <samp>0</samp>: normal items.
+
"UpgradeFrom": [
|}</li>
+
    {
<li><samp>GeodeDropsDefaultItems</samp> chooses a predefined list of possible geode drops like [[clay]], [[coal]], [[Copper Ore|copper]], [[Iridium Ore|iridium]], etc. Default false.</li>
+
        "RequireToolId": "(T)CopperAxe",
</ul>
+
        "Price": 5000,
 +
        "TradeItemId": "(O)335", // Iron Bar
 +
        "TradeItemAmount": 5
 +
    }
 +
]
 +
</syntaxhighlight>
   −
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.
+
If you want the tool to always be available, you can just omit the conditions. For example:
|-
+
<syntaxhighlight lang="js">
| <samp>ArtifactSpotChances</samp>
+
"UpgradeFrom": [
| ''(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.
+
    {
 +
        "Price": 5000
 +
    }
 +
]
 +
</syntaxhighlight>
   −
This consists of a string → model lookup, where:
+
Note that Clint needs a few days to smith the new tool. If you want to sell the tool directly, [[#Custom shops|add it to a regular shop]] instead.
* the key is the internal location name;
  −
* the value is the probability the item will spawn if checked, as a decimal value between 0 (never) and 1 (always).
   
|}
 
|}
   −
====Context tags & exclusions====
+
====Game logic====
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 1,982: Line 1,883:  
! purpose
 
! purpose
 
|-
 
|-
| <samp>ContextTags</samp>
+
| <samp>CanBeLostOnDeath</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:
+
| Whether the player can [[Adventurer's Guild#Item Recovery Service|lose this tool when they die]]. Default false.
<syntaxhighlight lang="json">
+
|}
"ContextTags": [ "color_yellow", "fish_ocean", "fish_upright", "season_summer" ]
+
 
</syntaxhighlight>
+
====Extensibility====
|-
  −
| <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).
  −
|}
  −
 
  −
====Advanced====
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 2,001: Line 1,893:  
! purpose
 
! purpose
 
|-
 
|-
| <samp>CustomFields</samp>
+
| <samp>ModData</samp>
| ''(Optional)'' The [[#Custom data fields|custom fields]] for this entry.
+
| ''(Optional)'' The mod data values to set when the tool is created, accessible in C# code via the <samp>tool.modData</samp> dictionary. For example:
 +
<syntaxhighlight lang="js">
 +
"ModData": {
 +
    "PowerLevel": 9000
 +
}
 +
</syntaxhighlight>
 +
|-
 +
| <samp>SetProperties</samp>
 +
| ''(Optional)'' Set the value of arbitrary properties on the tool class. For example, this would disable the tool animation and require no stamina:
 +
<syntaxhighlight lang="js">
 +
"SetProperties": {
 +
    "InstantUse": true,
 +
    "IsEfficient": true
 +
}
 +
</syntaxhighlight>
 
|}
 
|}
   −
===Custom pants===
+
===Custom wild trees===
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...
+
{{/doc status|a new doc page|done=false}}
* The key is the unqualified [[#Custom items|item ID]].
+
 
* The value is a model with the fields listed below.
+
====Data format====
 +
You can now create/edit [[Trees|wild trees]] by editing the <samp>Data/WildTrees</samp> asset.
 +
 
 +
This consists of a string → model lookup, where...
 +
* The asset key is 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.
   −
====Basic pants data====
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
 
! field
 
! field
! purpose
+
! effect
 
|-
 
|-
| <samp>Name</samp>
+
| <samp>Textures</samp>
| ''(Optional)'' The internal name for the item. Default <samp>Pants</samp>.
+
| The texture to use as the tree's spritesheet in-game. If multiple textures are listed, the first matching one is used.
|-
  −
| <samp>DisplayName</samp><br /><samp>Description</samp>
  −
| ''(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>
  −
| ''(Optional)'' The default price when the item is sold to the player in a shop. Default 50.
  −
|}
     −
====Appearance====
+
This consists of a list of models with these fields:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
 
! field
 
! field
! purpose
+
! effect
 
|-
 
|-
 
| <samp>Texture</samp>
 
| <samp>Texture</samp>
| The asset name for the texture containing the pants' sprite. Defaults to <samp>Characters/Farmer/pants</samp>.
+
| The asset name for the tree's spritesheet.
 
|-
 
|-
| <samp>SpriteIndex</samp>
+
| <samp>Season</samp>
| The pants' sprite index within the <samp>Texture</samp>, where 0 is the top-left set.
+
| ''(Optional)'' If set, the specific season when this texture should apply. For more complex conditions, see <samp>Condition</samp>.
 
|-
 
|-
| <samp>DefaultColor</samp>
+
| <samp>Condition</samp>
| ''(Optional)'' The dye color to apply to the sprite when the player hasn't [[dyeing|dyed]] it yet, if any. See [[#Color fields|color format]]. Default <samp>255 235 203</samp> (which matches the color of the cloth item).
+
| ''(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.
 +
|}
 
|-
 
|-
| <samp>CanBeDyed</samp>
+
| <samp>SeedItemId</samp>
| ''(Optional)'' Whether the player can [[dyeing|dye]] these pants. Default false.
+
| ''(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>IsPrismatic</samp>
+
| <samp>SeedPlantable</samp>
| ''(Optional)'' Whether the pants continuously shift colors. This overrides <samp>DefaultColor</samp> and <samp>CanBeDyed</samp> if set. Default false.
+
| ''(Optional)'' Whether the seed can be planted by the player. If this is false, it can only be spawned automatically via map properties. Default true.
|}
  −
 
  −
====Other====
  −
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>GrowthChance</samp>
! purpose
+
| ''(Optional)'' The probability each day that the tree will grow to the next stage without [[Tree Fertilizer|tree fertilizer]], as a value from 0 (will never grow) to 1 (will grow every day). Defaults to 0.2 (20% chance).
 
|-
 
|-
| <samp>CanChooseDuringCharacterCustomization</samp>
+
| <samp>FertilizedGrowthChance</samp>
| ''(Optional)'' Whether these pants can be selected on the character customization screen (e.g. when creating a character). Default false.
+
| ''(Optional)'' Equivalent to <samp>GrowthChance</samp>, but with [[Tree Fertilizer|tree fertilizer]]. Defaults to 1 (100% chance).
 
|-
 
|-
| <samp>CustomFields</samp>
+
| <samp>SeedSpreadChance</samp>
| The [[#Custom data fields|custom fields]] for this entry.
+
| ''(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).
|}
  −
 
  −
===Custom shirts===
  −
You can now create/edit [[Tailoring#Shirts|shirts]] by editing the new <samp>Data/Shirts</samp> asset, which replaces <samp>Data/clothingInformation</samp>. This consists of a string → model lookup, where...
  −
* The key is the unqualified [[#Custom items|item ID]].
  −
* The value is a model with the fields listed below.
  −
 
  −
====Basic shirt data====
  −
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>SeedOnShakeChance</samp>
! purpose
+
| ''(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).
 
|-
 
|-
| <samp>Name</samp>
+
| <samp>SeedOnChopChance</samp>
| ''(Optional)'' The internal name for the item. Default <samp>Shirt</samp>.
+
| ''(Optional)'' The probability that a seed will drop when the player chops down the tree, as a value from 0 (never) to 1 (always). Default 0.75 (75% chance).
 
|-
 
|-
| <samp>DisplayName</samp><br /><samp>Description</samp>
+
| <samp>DropWoodOnChop</samp>
| ''(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'').
+
| ''(Optional)'' Whether to drop [[wood]] when the player chops down the tree. Default true.
 
|-
 
|-
| <samp>Price</samp>
+
| <samp>DropHardwoodOnLumberChop</samp>
| ''(Optional)'' The default price when the item is sold to the player in a shop. Default 50.
+
| ''(Optional)'' Whether to drop [[hardwood]] when the player chops down the tree, if they have the [[Skills#Foraging|Lumberjack profession]]. Default true.
|}
  −
 
  −
====Appearance====
  −
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>IsLeafy</samp>
! purpose
+
| ''(Optional)'' Whether shaking or chopping the tree causes cosmetic leaves to drop from tree and produces a leaf rustle sound. When a leaf drops, the game will use one of the four leaf sprites in the tree's spritesheet in the slot left of the stump sprite. Default true.
 
|-
 
|-
| <samp>Texture</samp>
+
| <samp>IsLeafyInWinter</samp>
| The asset name for the texture containing the shirt's sprite. Defaults to <samp>Characters/Farmer/shirts</samp>.
+
| ''(Optional)'' Whether <samp>IsLeafy</samp> also applies in winter. Default false.
 
|-
 
|-
| <samp>SpriteIndex</samp>
+
| <samp>GrowsInWinter</samp>
| The shirt's sprite index within the <samp>Texture</samp>, where 0 is the top-left set.
+
| ''(Optional)'' Whether the tree can grow in winter (subject to <samp>GrowthChance</samp> or <samp>FertilizedGrowthChance</samp>). Default false.
 
|-
 
|-
| <samp>DefaultColor</samp>
+
| <samp>IsStumpDuringWinter</samp>
| ''(Optional)'' The dye color to apply to the sprite when the player hasn't [[dyeing|dyed]] it yet, if any. See [[#Color fields|color format]]. Default none.
+
| ''(Optional)'' Whether the tree is reduced to a stump in winter and regrows in spring, like the vanilla [[Trees#Mushroom Tree|mushroom tree]]. Default false.
 
|-
 
|-
| <samp>CanBeDyed</samp>
+
| <samp>AllowWoodpeckers</samp>
| ''(Optional)'' Whether the player can [[dyeing|dye]] this shirt. Default false.
+
| ''(Optional)'' Whether woodpeckers can spawn on the tree. Default true.
 
|-
 
|-
| <samp>IsPrismatic</samp>
+
| <samp>UseAlternateSpriteWhenNotShaken</samp><br /><samp>UseAlternateSpriteWhenSeedReady</samp>
| ''(Optional)'' Whether the shirt continuously shifts colors. This overrides <samp>DefaultColor</samp> and <samp>CanBeDyed</samp> if set. Default false.
+
| ''(Optional)'' Whether to render a different tree sprite when the player hasn't shaken it on that day (<samp>UseAlternateSpriteWhenNotShaken</samp>) or it has a seed ready (<samp>UseAlternateSpriteWhenSeedReady</samp>). If either field is true, the tree spritesheet must be double-width with the alternate textures on the right. If both are true, the same alternate sprites are used for both. Default false.
 
|-
 
|-
| <samp>HasSleeves</samp>
+
| <samp>DebrisColor</samp>
| ''(Optional)'' Whether to draw shirt sleeves. Default true.
+
| ''(Optional)'' The color of the cosmetic wood chips when chopping the tree. This can be...
|}
+
* a [[#Color fields|standard color format]];
 +
* or one of <samp>12</samp> (brown/woody), <samp>100001</samp> (white), <samp>100001</samp> (light green),  <samp>100002</samp> (light blue), <samp>100003</samp> (red), <samp>100004</samp> (yellow), <samp>100005</samp> (black), <samp>100006</samp> (gray), or <samp>100007</samp> (charcoal / dim gray).
   −
====Other====
+
Defaults to <samp>12</samp> (brown/woody).
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>SeedDropItems</samp>
! purpose
+
| ''(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.
|-
  −
| <samp>CanChooseDuringCharacterCustomization</samp>
  −
| ''(Optional)'' Whether this shirt can be selected on the character customization screen (e.g. when creating a character). Default false.
  −
|-
  −
| <samp>CustomFields</samp>
  −
| The [[#Custom data fields|custom fields]] for this entry.
  −
|}
     −
===Custom tools===
+
This consists of a list of models with these fields:
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 value is a model with the fields listed below.
  −
 
  −
====Basic tool data====
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
 
! field
 
! field
! purpose
+
! effect
 
|-
 
|-
| <samp>ClassName</samp>
+
| ''common fields''
| The name of the C# class to construct within the <code>StardewValley.Tools</code> namespace. The class must be a subclass of <samp>StardewValley.Tool</samp>, and have a constructor with no arguments. For example, given a value of <samp>Axe</samp>, the game will create <code>StardewValley.Tools.Axe</code> instances.
+
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields supported for chop drops.
   −
The main values are:
+
If set to an [[Modding:Item queries|item query]] which returns multiple items, one of them will be selected at random.
* main tools (<samp>Axe</samp>, <samp>FishingRod</samp>, <samp>Hoe</samp>, <samp>MeleeWeapon</samp>, <samp>MilkPail</samp>, <samp>Pan</samp>, <samp>Pickaxe</samp>, <samp>Shears</samp>, <samp>Wand</samp>, and <samp>WateringCan</samp>);
  −
* a special <samp>GenericTool</samp> type which applies the <samp>Data/Tools</samp> data and only has generic logic, so C# mods can patch in their own logic;
  −
* and two tools cut from the game which may not work correctly (<samp>Lantern</samp> and <samp>Raft</samp>).
   
|-
 
|-
| <samp>Name</samp>
+
| <samp>Season</samp>
| The internal name to set for the tool item.
+
| ''(Optional)'' If set, the item only applies if the tree's location is in this season.
 
|-
 
|-
| <samp>DisplayName</samp><br /><samp>Description</samp>
+
| <samp>Chance</samp>
| A [[Modding:Tokenizable strings|tokenizable string]] for the tool's in-game display name and description.
+
| ''(Optional)'' The probability that the item will drop, as a value between 0 (never drops) and 1 (always drops). Default 1 (100% chance).
 
|-
 
|-
| <samp>AttachmentSlots</samp>
+
| <samp>ContinueOnDrop</samp>
| ''(Optional)'' The number of attachment slots to enable on the tool. Note that only <samp>FishingRod</samp> tools have the code to render and use attachment slots. Default <samp>-1</samp>, which keeps the default value set by the tool class.
+
| ''(Optional)'' If this item is dropped, whether to continue as if it hadn't been dropped for the remaining drop candidates. Default false.
 +
|}
 
|-
 
|-
| <samp>SalePrice</samp>
+
| <samp>ChopItems</samp>
| ''(Optional)'' The default price when the item is sold to the player in a shop. Defaults to <samp>-1</samp>, in which case you should set the price manually in shops.
+
| ''(Optional)'' The additional items to drop when the tree is chopped down. All matching items are dropped.
|-
  −
| <samp>CustomFields</samp>
  −
| The [[#Custom data fields|custom fields]] for this entry.
  −
|}
  −
 
  −
====Appearance====
  −
Note that drawing the tool correctly in the world (ie, while the player is trying to use it) probably still needs custom code.
      +
This consists of a list of models with these fields:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
 
! field
 
! field
! purpose
+
! effect
 +
|-
 +
| ''common fields''
 +
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields supported for chop drops.
 +
 
 +
If set to an [[Modding:Item queries|item query]] which returns multiple items, one of them will be selected at random.
 +
|-
 +
| <samp>Season</samp>
 +
| ''(Optional)'' If set, the item only applies if the tree's location is in this season.
 
|-
 
|-
| <samp>Texture</samp>
+
| <samp>Chance</samp>
| The asset name for the texture containing the tool's sprite.
+
| ''(Optional)'' The probability that the item will drop, as a value between 0 (never drops) and 1 (always drops). Default 1 (100% chance).
 
|-
 
|-
| <samp>SpriteIndex</samp>
+
| <samp>MinSize</samp><br /><samp>MaxSize</samp>
| The tool's sprite index within the <samp>Texture</samp>, where 0 is the top row.
+
| ''(Optional)'' The minimum and/or maximum growth stage for the tree at which this item is produced. The possible values are <samp>Seed</samp>, <samp>Sprout</samp>, <samp>Sapling</samp>, <samp>Bush</samp>, and <samp>Tree</samp>. Both default to no limit.
 
|-
 
|-
| <samp>MenuSpriteIndex</samp>
+
| <samp>ForStump</samp>
| ''(Optional)'' The sprite index within the <samp>Texture</samp> for the item icon. Defaults to <samp>SpriteIndex</samp>.
+
| ''(Optional)'' Whether the item is only produced if the tree is a stump (<samp>true</samp>), not a stump (<samp>false</samp>), or both (<samp>null</samp>). Defaults to <samp>false</samp> (non-stumps only).
 
|}
 
|}
 +
|-
 +
| <samp>ShakeItems</samp>
 +
| The items produced by shaking the tree when it's fully grown. This only applies the first time the tree is shaken each day. All matching items are dropped.
   −
====Upgrades====
+
This consists of a list of models with these fields:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
 
! field
 
! field
! purpose
+
! effect
 +
|-
 +
| ''common fields''
 +
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields supported for shake items.
 +
 
 +
If set to an [[Modding:Item queries|item query]] which returns multiple items, one of them will be selected at random.
 +
|-
 +
| <samp>Season</samp>
 +
| ''(Optional)'' If set, the item only applies if the tree's location is in this season.
 
|-
 
|-
| <samp>UpgradeLevel</samp>
+
| <samp>Chance</samp>
| ''(Optional)'' The tool upgrade level. Default <samp>-1</samp>, which keeps the default value set by the tool class.
+
| ''(Optional)'' The probability that this entry is selected, as a value between 0 (never drops) and 1 (always drops). Default 1 (100% chance).
 +
|}
 
|-
 
|-
| <samp>ApplyUpgradeLevelToDisplayName</samp>
+
| <samp>TapItems</samp>
| ''(Optional)'' Whether to adjust the <samp>DisplayName</samp> for the usual upgrade levels. For example, the display name for a level one Axe changes to 'Copper Axe'. Default false.
+
| The items produced by [[Tapper|tapping]] the tree. If multiple items can be produced, the first available one is selected.
   −
The display name format in English is:
+
This consists of a list of models with these fields:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! upgrade level
+
! field
! display name format
+
! effect
 +
|-
 +
| ''common fields''
 +
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields supported for tapper items.
 +
 
 +
If set to an [[Modding:Item queries|item query]] which returns multiple items, one of them will be selected at random.
 +
|-
 +
| <samp>Season</samp>
 +
| ''(Optional)'' If set, the item only applies if the tree's location is in this season.
 +
|-
 +
| <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).
 
|-
 
|-
| 1
+
| <samp>DaysUntilReady</samp>
| Copper {{t|display name}}
+
| The number of days before the tapper is ready to empty.
 
|-
 
|-
| 2
+
| <samp>PreviousItemId</samp>
| Steel {{t|display name}}
+
| ''(Optional)'' If set, the item only applies if the previous item produced by the tapper matches one of the given [[#Custom items|qualified item IDs]]. If an entry is null or an empty string, it matches when there's no previous item.
 +
 
 +
For example: <code>"PreviousItemId": [ null ]</code> only applies when a tapper is first added to the tree, and <code>"PreviousItemsId": [ "(O)420" ]</code> applies if the player just collected a [[Red Mushroom|red mushroom]] (object #420) from it.
 
|-
 
|-
| 3
+
| <samp>DaysUntilReadyModifiers</samp>
| Gold {{t|display name}}
+
| ''(Optional)'' [[#Quantity modifiers|Quantity modifiers]] applied to the <samp>DaysUntilReady</samp> value. Default none.
 
|-
 
|-
| 4
+
| <samp>DaysUntilReadyModifiersMode</samp>
| Iridium {{t|display name}}
+
| ''(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>ConventionalUpgradeFrom</samp>
+
| <samp>PlantableLocationRules</samp>
| ''(Optional)'' If set, prepends an upgrade for the given tool ID to the <samp>UpgradeFrom</samp> field. This applies these rules (based on the <samp>UpgradeLevel</samp> field, not the upgrade level of the specified tool ID):
+
| ''(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"
 
{| class="wikitable"
 
|-
 
|-
! upgrade level
+
! field
! price
+
! effect
! items needed
+
|-
 +
| <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.
 
|-
 
|-
| 1
+
| <samp>Condition</samp>
| {{price|2000}}
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this entry applies. Default true.
| {{name|Copper Bar|5}}
   
|-
 
|-
| 2
+
| <samp>PlantedIn</samp>
| {{price|5000}}
+
| ''(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>.
| {{name|Iron Bar|5}}
+
 
 +
Note that trees can't be planted in garden pots.
 
|-
 
|-
| 3
+
| <samp>DeniedMessage</samp>
| {{price|10000}}
+
| ''(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.
| {{name|Gold Bar|5}}
+
|}
 
|-
 
|-
| 4
+
| <samp>CustomFields</samp>
| {{price|25000}}
+
| The [[#Custom data fields|custom fields]] for this entry.
| {{name|Iridium Bar|5}}
   
|}
 
|}
   −
For example, Iridium Axe specifies this value:
+
====Spawning wild 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: wild {{t|tree ID}} {{o|growth stage on location created}} {{o|growth stage on day-update regrowth}}</samp> tile property. This must be added on the <samp>Paths</samp> layer, which must also have tile index 34 from the <samp>paths</samp> tilesheet.
 +
* Or give the player a seed item in the usual ways (e.g. from [[#Custom shops|a shop]], [[Modding:Mail data|mail letter]], etc).
 +
 
 +
===Default recipes===
 +
{{/doc status|[[Modding:Recipe data]]|done=false}}
 +
 
 +
You can now have [[Modding:Recipe data|crafting and cooking recipes]] that are learned automatically by setting the condition field to <samp>default</samp>. Any missing default recipes will be learned on day start.
 +
 
 +
For example, here's the chest entry from <samp>Data/CraftingRecipes</samp>:
 
<syntaxhighlight lang="js">
 
<syntaxhighlight lang="js">
"ConventionalUpgradeFrom": "(T)GoldAxe"
+
"Chest": "388 50/Home/130/true/default/"
 
</syntaxhighlight>
 
</syntaxhighlight>
|-
  −
| <samp>UpgradeFrom</samp>
  −
| ''(Optional)'' The requirements to buy this tool from Clint's [[Blacksmith#Upgrade Tools|blacksmith tool upgrade shop]]. If you specify multiple entries, the first one which matches will be applied.
     −
This consists of a list of models with these fields:
+
===Global inventories===
{| class="wikitable"
+
C# mods can now set a <samp>chest.GlobalInventoryId</samp> field to make it share a global inventory with every other chest having the same ID. This replaces the equivalent hardcoded logic for [[Junimo Chest|Junimo chests]], which now just default to a <samp>"JunimoChests"</samp> global inventory ID. For example, this can be used to have multiple Junimo chest networks or make other containers share inventory.
|-
+
 
! field
+
C# mods can also use this to store items for other mod purposes, by using <samp>Game1.player.team.globalInventories</samp> or <samp>Game1.player.team.GetOrCreateGlobalInventory(id)</samp> directly.
! purpose
  −
|-
  −
| <samp>Price</samp>
  −
| ''(Optional)'' The gold price to buy the upgrade. Defaults to 0.
  −
|-
  −
| <samp>RequireToolId</samp>
  −
| ''(Optional)'' If set, the [[#Custom items|qualified or unqualified item ID]] for the tool that must be in the player's inventory for the upgrade to appear. The tool will be destroyed when the upgrade is purchased.
  −
|-
  −
| <samp>TradeItemId</samp>
  −
| ''(Optional)'' If set, the [[#Custom items|qualified or unqualified item ID]] for an extra item that must be traded to upgrade the tool. (For example, many vanilla tools need metal bars.)
  −
|-
  −
| <samp>TradeItemAmount</samp>
  −
| ''(Optional)'' The number of <samp>TradeItemId</samp> required. Defaults to 1.
  −
|-
  −
| <samp>Condition</samp>
  −
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this upgrade is available. Defaults to always true.
  −
|}
     −
For example, these are equivalent to the Steel Axe's upgrade settings:
+
===Hats on aquarium fish===
<syntaxhighlight lang="js">
+
{{/doc status|[[Modding:Fish data]]|done=false}}
"UpgradeFrom": [
  −
    {
  −
        "RequireToolId": "(T)CopperAxe",
  −
        "Price": 5000,
  −
        "TradeItemId": "(O)335", // Iron Bar
  −
        "TradeItemAmount": 5
  −
    }
  −
]
  −
</syntaxhighlight>
     −
If you want the tool to always be available, you can just omit the conditions. For example:
+
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>:
<syntaxhighlight lang="js">
  −
"UpgradeFrom": [
  −
    {
  −
        "Price": 5000
  −
    }
  −
]
  −
</syntaxhighlight>
     −
Note that Clint needs a few days to smith the new tool. If you want to sell the tool directly, [[#Custom shops|add it to a regular shop]] instead.
  −
|}
  −
  −
====Game logic====
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
 +
! index
 
! field
 
! field
 
! purpose
 
! purpose
 
|-
 
|-
| <samp>CanBeLostOnDeath</samp>
+
| 7
| Whether the player can [[Adventurer's Guild#Item Recovery Service|lose this tool when they die]]. Default false.
+
| hat position
 +
| The pixel position of the hat on the sprite, specified as an object with <samp>X</samp> and <samp>Y</samp> values.
 
|}
 
|}
   −
====Extensibility====
+
===Context tag changes===
 +
{{/doc status|[[Modding:Items#Context tags]]|done=false}}
 +
 
 +
====New context tags====
 +
1.6 adds several new [[Modding:Items#Context tags|item context tags]]:
 +
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! context tag
! purpose
+
! effect
 
|-
 
|-
| <samp>ModData</samp>
+
| <samp>campfire_item</samp>
| ''(Optional)'' The mod data values to set when the tool is created, accessible in C# code via the <samp>tool.modData</samp> dictionary. For example:
+
| Marks the item as a [[campfire]]. If the item also has the <samp>torch_item</samp> context tag, when it's placed in the world and turned on...
<syntaxhighlight lang="js">
+
* campfire flames are drawn over it;
"ModData": {
+
* if the item is [[Modding:Items#Big craftables|big craftable]], light is emitted from its center instead of the top.
    "PowerLevel": 9000
+
|-
}
+
| <samp>fish_pond_ignore</samp>
</syntaxhighlight>
+
| 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_crusher_ignored</samp>
 +
| Prevents breaking this item open in a [[Geode Crusher|geode crusher]], even if the item has geode fields in [[#Custom objects|<samp>Data/Objects</samp>]].
 +
|-
 +
| <samp>item_type_{{t|type}}</samp>
 +
| For an [[Modding:Items#Objects|object-type item]], the type value from the 'type and category' field. (Non-object items always have the exact tag <samp>item_type_</samp> with nothing after the last underscore.) This is automatic and shouldn't be set manually. The tag is checked in a few places (''e.g.'' the [[museum]] to check if an item is an artifact or mineral), but most of the game won't be affected.
 +
|-
 +
| <samp>museum_donatable</samp><br /><samp>not_museum_donatable</samp>
 +
| Set whether the item can be donated to the [[museum]], overriding the vanilla logic.
 
|-
 
|-
| <samp>SetProperties</samp>
+
| <samp>not_giftable</samp>
| ''(Optional)'' Set the value of arbitrary properties on the tool class. For example, this would disable the tool animation and require no stamina:
+
| Prevents players from gifting this item to NPCs, who'll ignore the item entirely (e.g. as if you were holding a tool).
<syntaxhighlight lang="js">
  −
"SetProperties": {
  −
    "InstantUse": true,
  −
    "IsEfficient": true
  −
}
  −
</syntaxhighlight>
  −
|}
     −
===Custom wild trees===
+
This only affects gift-giving, it doesn't affect non-gift logic like quest goals or special order objectives. If the NPC also has a <samp>reject_*</samp> dialogue for the item, the dialogue takes priority.
====Data format====
+
|-
You can now create/edit [[Trees|wild trees]] by editing the <samp>Data/WildTrees</samp> asset.
+
| <samp>not_placeable</samp><br /><samp>placeable</samp>
 +
| Sets whether the item can be placed on the ground.
 +
|-
 +
| <samp>prevent_loss_on_death</samp>
 +
| Indicates the item can't be [[Adventurer's Guild#Item Recovery Service|lost when the player dies]].
 +
|-
 +
| <samp>sign_item</samp>
 +
| Marks the item as a [[Crafting#Signs|sign]], which lets player display items on it or place it on a [[Fish Pond|fish pond]] to show the fish count.
 +
|-
 +
| <samp>torch_item</samp>
 +
| Marks the item as a [[torch]], which lets the player turn it on/off to emit light.
   −
This consists of a string → model lookup, where...
+
See also <samp>campfire_item</samp>.
* 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.
      +
Context tags which affect [[#Custom machines|machine processing]]:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! context tag
 
! effect
 
! effect
 
|-
 
|-
| <samp>Textures</samp>
+
| <samp>crystalarium_banned</samp>
| The texture to use as the tree's spritesheet in-game. If multiple textures are listed, the first matching one is used.
+
| When applied to a gem or mineral item, prevents players from placing it in a [[crystalarium]].
 
+
|-
This consists of a list of models with these fields:
+
| <samp>keg_juice</samp><br /><samp>keg_wine</samp>
{| class="wikitable"
+
| Allows processing the item in a [[keg]] to produce a juice or wine variant.
 
|-
 
|-
! field
+
| <samp>preserves_jelly</samp><br /><samp>preserves_pickle</samp>
! effect
+
| Allows processing the item in a [[Preserves Jar|preserves jar]] to produce a jelly or pickled variant.
 
|-
 
|-
| <samp>Texture</samp>
+
| <samp>seedmaker_banned</samp>
| The asset name for the tree's spritesheet.
+
| When applied to a seed item, prevents players from placing it in a [[Seed Maker|seed maker]].
 
|-
 
|-
| <samp>Season</samp>
+
| <samp>tapper_item</samp>
| ''(Optional)'' If set, the specific season when this texture should apply. For more complex conditions, see <samp>Condition</samp>.
+
| Marks the item as a [[tapper]] or [[Heavy Tapper|heavy tapper]].
 
|-
 
|-
| <samp>Condition</samp>
+
| <samp>tapper_multiplier_{{t|multiplier}}</samp>
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this texture should be applied for a tree. Defaults to always enabled.
+
| The multiplier applied to the tapper production speed. For example, <samp>2</samp> will make items take half their base time (''i.e.'' each item will finish in <sup>base time</sup>/<sub>speed multiplier</sub>). Defaults to 1 if omitted.
 +
|}
   −
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.
+
And informational tags which have no effect on the game logic:
|}
+
{| class="wikitable"
 
|-
 
|-
| <samp>SeedItemId</samp>
+
! context tag
| ''(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.
+
! effect
 
|-
 
|-
| <samp>SeedPlantable</samp>
+
| <samp>fish_legendary</samp><br /><samp>fish_legendary_family</samp>
| ''(Optional)'' Whether the seed can be planted by the player. If this is false, it can only be spawned automatically via map properties. Default true.
+
| 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>GrowthChance</samp>
+
| <samp>geode</samp>
| ''(Optional)'' The probability each day that the tree will grow to the next stage without [[Tree Fertilizer|tree fertilizer]], as a value from 0 (will never grow) to 1 (will grow every day). Defaults to 0.2 (20% chance).
+
| ''(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>FertilizedGrowthChance</samp>
+
| <samp>id_{{t|item id}}</samp>
| ''(Optional)'' Equivalent to <samp>GrowthChance</samp>, but with [[Tree Fertilizer|tree fertilizer]]. Defaults to 1 (100% chance).
+
| ''(Added automatically)'' The [[#Custom items|qualified item ID]], like <samp>id_(o)128</samp>. This can be used to match or exclude an item by ID using context tags. Any spaces in the ID are replaced with underscores, and single quotes are removed.
 
|-
 
|-
| <samp>SeedSpreadChance</samp>
+
| <samp>is_machine</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).
+
| ''(Added automatically)'' Indicates the item has [[#Custom machines|machine logic]]. This is added automatically based on <samp>Data/Machines</samp>.
 
|-
 
|-
| <samp>SeedOnShakeChance</samp>
+
| <samp>machine_input</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).
+
| ''(Added automatically)'' Whether the item is a machine which accepts items from the player. This is added automatically based on the machine's fields in <samp>Data/Machines</samp>:
 +
* if <samp>HasInput</samp> is true;
 +
* ''or'' if any output rules have an <samp>ItemPlacedInMachine</samp> trigger.
 
|-
 
|-
| <samp>SeedOnChopChance</samp>
+
| <samp>machine_output</samp>
| ''(Optional)'' The probability that a seed will drop when the player chops down the tree, as a value from 0 (never) to 1 (always). Default 0.75 (75% chance).
+
| ''(Added automatically)'' Whether the item is a machine which produces items for the player to collect. This is added automatically based on the machine's fields in <samp>Data/Machines</samp>:
|-
+
* if <samp>HasOutput</samp> is true;
| <samp>DropWoodOnChop</samp>
+
* ''or'' if it has any output rules.
| ''(Optional)'' Whether to drop [[wood]] when the player chops down the tree. Default true.
+
|}
 +
 
 +
====ItemContextTagManager class====
 +
For C# mods, 1.6 adds a new <samp>ItemContextTagManager</samp> class which simplifies working with [[Modding:Items#Context tags|item context tags]] and reduces repeated code.
 +
 
 +
This provides a few utility methods:
 +
{| class="wikitable"
 
|-
 
|-
| <samp>DropHardwoodOnLumberChop</samp>
+
! method
| ''(Optional)'' Whether to drop [[hardwood]] when the player chops down the tree, if they have the [[Skills#Foraging|Lumberjack profession]]. Default true.
+
! effect
 
|-
 
|-
| <samp>IsLeafy</samp>
+
| <code>GetBaseContextTags(id)</code>
| ''(Optional)'' Whether shaking or chopping the tree causes cosmetic leaves to drop from tree and produces a leaf rustle sound. When a leaf drops, the game will use one of the four leaf sprites in the tree's spritesheet in the slot left of the stump sprite. Default true.
+
| Get the base context tags for an item based on its raw data in <samp>Data/Objects</samp> or <samp>Data/BigCraftables</samp>. This doesn't include dynamic tags added that are based on instance info (like quality), which you can get using <code>item.GetContextTags()</code>.
 
|-
 
|-
| <samp>IsLeafyInWinter</samp>
+
| <code>DoesTagQueryMatch(query, tags)</code>
| ''(Optional)'' Whether <samp>IsLeafy</samp> also applies in winter. Default false.
+
| Get whether a context tag query matches the given tags. For example, <code>ItemContextTagManager.DoesTagQueryMatch("bone_item, !fossil_item", item.GetContextTags())</code> returns true if the item is a bone item but not a fossil (like the [[Bone Flute]]).
 
|-
 
|-
| <samp>GrowsInWinter</samp>
+
| <code>DoAllTagsMatch(requiredTags, actualTags)</code><br /><code>DoAnyTagsMatch(requiredTags, actualTags)</code>
| ''(Optional)'' Whether the tree can grow in winter (subject to <samp>GrowthChance</samp> or <samp>FertilizedGrowthChance</samp>). Default false.
+
| Get whether every (<samp>DoAllTagsMatch</samp>) or at least one (<samp>DoAnyTagsMatch</samp) required tag matches the actual item tags. This supports negated required tags like <samp>"!fossil_item"</samp> too.
 
|-
 
|-
| <samp>IsStumpDuringWinter</samp>
+
| <code>DoesTagMatch(requiredTag, actualTags)</code>
| ''(Optional)'' Whether the tree is reduced to a stump in winter and regrows in spring, like the vanilla [[Trees#Mushroom Tree|mushroom tree]]. Default false.
+
| Get whether a single tag matches the actual item tags. This supports negated required tags like <samp>"!fossil_item"</samp> too.
 
|-
 
|-
| <samp>AllowWoodpeckers</samp>
+
| <code>SanitizeContextTag(tag)</code>
| ''(Optional)'' Whether woodpeckers can spawn on the tree. Default true.
+
| ''(Specialized)'' Replace characters that may appear in item names so they're valid in context tags. For example, <code>SanitizeContextTag("Sam's Boombox")</code> returns <samp>sams_boombox</samp>.
|-
+
|}
| <samp>UseAlternateSpriteWhenNotShaken</samp><br /><samp>UseAlternateSpriteWhenSeedReady</samp>
+
 
| ''(Optional)'' Whether to render a different tree sprite when the player hasn't shaken it on that day (<samp>UseAlternateSpriteWhenNotShaken</samp>) or it has a seed ready (<samp>UseAlternateSpriteWhenSeedReady</samp>). If either field is true, the tree spritesheet must be double-width with the alternate textures on the right. If both are true, the same alternate sprites are used for both. Default false.
+
====Other context tag changes====
|-
+
* Context tags are now case-insensitive.
| <samp>DebrisColor</samp>
  −
| ''(Optional)'' The color of the cosmetic wood chips when chopping the tree. This can be...
  −
* a [[#Color fields|standard color format]];
  −
* or one of <samp>12</samp> (brown/woody), <samp>100001</samp> (white), <samp>100001</samp> (light green),  <samp>100002</samp> (light blue), <samp>100003</samp> (red), <samp>100004</samp> (yellow), <samp>100005</samp> (black), <samp>100006</samp> (gray), or <samp>100007</samp> (charcoal / dim gray).
     −
Defaults to <samp>12</samp> (brown/woody).
+
===Inventory class===
|-
+
For C# mods, 1.6 adds a new <samp>Inventory</samp> class to manage a list of items. This is used for the <samp>Farmer.items</samp> and <samp>Chest.items</samp> fields. It implements <samp>IList&lt;Item&gt;</samp>, so most existing code should still work fine.
| <samp>SeedDropItems</samp>
  −
| ''(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 has three main benefits:
 +
<ul>
 +
<li>It has methods to simplify many common operations. For example:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! method
 
! effect
 
! effect
 
|-
 
|-
| ''common fields''
+
| <code>HasAny()</code>
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields supported for chop drops.
+
| Get whether the inventory contains any items (ignoring empty slots).
 
  −
If set to an [[Modding:Item queries|item query]] which returns multiple items, one of them will be selected at random.
   
|-
 
|-
| <samp>Season</samp>
+
| <code>CountItemStacks()</code>
| ''(Optional)'' If set, the item only applies if the tree's location is in this season.
+
| Get the number of item stacks in the inventory (ignoring empty slots).
 
|-
 
|-
| <samp>Chance</samp>
+
| <code>ContainsId(id)</code>
| ''(Optional)'' The probability that the item will drop, as a value between 0 (never drops) and 1 (always drops). Default 1 (100% chance).
+
| Get whether the inventory contains any item with the given qualified or unqualified item ID.
 
|-
 
|-
| <samp>ContinueOnDrop</samp>
+
| <code>ContainsId(id, minCount)</code>
| ''(Optional)'' If this item is dropped, whether to continue as if it hadn't been dropped for the remaining drop candidates. Default false.
+
| Get whether the inventory contains items with the given qualified or unqualified item ID, and their combined stack size is at least <samp>minCount</samp>.
|}
   
|-
 
|-
| <samp>ChopItems</samp>
+
| <code>CountId(id)</code>
| ''(Optional)'' The additional items to drop when the tree is chopped down. All matching items are dropped.
+
| Get the combined stack size of all items with the given qualified or unqualified item ID.
 
  −
This consists of a list of models with these fields:
  −
{| class="wikitable"
   
|-
 
|-
! field
+
| <code>GetById(id)</code>
! effect
+
| Get a list of items in the inventory with the given qualified or unqualified item ID.
 
|-
 
|-
| ''common fields''
+
| <code>ReduceId(id, count)</code>
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields supported for chop drops.
+
| Remove the given number of items matching the given qualified or unqualified item ID. This reduces the stack size for matching items until a total of <samp>count</samp> have been removed, and clears any slots which reach a stack size of zero.
 +
|}</li>
 +
<li>Many common operations have been unified, so previously player-only methods can now be used with chests too.</li>
 +
<li>It has an internal index by item ID, so operations like <code>items.ContainsId("(O)128")</code> are much more efficient since they no longer iterate the list.</li>
 +
</ul>
   −
If set to an [[Modding:Item queries|item query]] which returns multiple items, one of them will be selected at random.
+
This replaces some previous methods:
|-
  −
| <samp>Season</samp>
  −
| ''(Optional)'' If set, the item only applies if the tree's location is in this season.
  −
|-
  −
| <samp>Chance</samp>
  −
| ''(Optional)'' The probability that the item will drop, as a value between 0 (never drops) and 1 (always drops). Default 1 (100% chance).
  −
|-
  −
| <samp>MinSize</samp><br /><samp>MaxSize</samp>
  −
| ''(Optional)'' The minimum and/or maximum growth stage for the tree at which this item is produced. The possible values are <samp>Seed</samp>, <samp>Sprout</samp>, <samp>Sapling</samp>, <samp>Bush</samp>, and <samp>Tree</samp>. Both default to no limit.
  −
|-
  −
| <samp>ForStump</samp>
  −
| ''(Optional)'' Whether the item is only produced if the tree is a stump (<samp>true</samp>), not a stump (<samp>false</samp>), or both (<samp>null</samp>). Defaults to <samp>false</samp> (non-stumps only).
  −
|}
  −
|-
  −
| <samp>ShakeItems</samp>
  −
| The items produced by shaking the tree when it's fully grown. This only applies the first time the tree is shaken each day. All matching items are dropped.
     −
This consists of a list of models with these fields:
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! game class
! effect
+
! old code
 +
! migration
 
|-
 
|-
| ''common fields''
+
|rowspan="6"| <samp>Farmer</samp>
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields supported for shake items.
+
| <code>getItemCount(id)</code><br /><code>GetTallyOfObject(id)</code><br /><code>GetTallyOfObject(id, isBigCraftable)</code><br /><code>hasItemInInventory(id, count)</code><br /><code>hasItemInList(list, id, count)</code>
 +
| &#32;
 +
* To check an item ID, use <code>items.CountId(id)</code> or <code>Items.ContainsId(id, count)</code>.
 +
* To check Golden Walnuts or Qi Gems, use the <samp>Game1.netWorldState.Value.GoldenWalnuts</samp> and <samp>Farmer.QiGems</samp> fields.
 +
* To check category matches or <samp>-777</samp> (seasonal wild seeds), the <samp>getItemCount</samp> and <samp>getItemCountInList</samp> still exist.
 +
|-
 +
| <code>hasItemInInventoryNamed(name)</code><br /><code>hasItemWithNameThatContains(name)</code>
 +
| In most cases, you should match items by ID instead (see the previous row).
 +
 
 +
If you really need to match items by name, you can replace it like this:
 +
<syntaxhighlight lang="c#">
 +
// exact name
 +
bool hasMatch = Game1.player.Items.Any(item => item?.Name == name);
   −
If set to an [[Modding:Item queries|item query]] which returns multiple items, one of them will be selected at random.
+
// name contains
 +
bool hasMatch = Game1.player.Items.Any(item => item?.Name?.Contains(name) is true);
 +
</syntaxhighlight>
 +
|-
 +
| <code>areAllItemsNull()</code>
 +
| Use <code>!items.HasAny()</code>.
 +
|-
 +
| <code>numberOfItemsInInventory()</code>
 +
| 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>
 +
| 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.
 
|-
 
|-
| <samp>Season</samp>
+
|rowspan="2"| <samp>Object</samp>
| ''(Optional)'' If set, the item only applies if the tree's location is in this season.
+
| <code>ConsumeInventoryItem(player, id, count)</code>
 +
| This was somewhat specialized and shouldn't be called by mod code, but the equivalent would be <code>(Object.autoLoadChest ?? player.items).ReduceId(id, count)</code>. See also notes for <samp>Farmer.removeItemsFromInventory</samp>.
 
|-
 
|-
| <samp>Chance</samp>
+
| <code>GetTallyOfObject(player, id)</code>
| ''(Optional)'' The probability that this entry is selected, as a value between 0 (never drops) and 1 (always drops). Default 1 (100% chance).
+
| 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>.
 
|}
 
|}
|-
  −
| <samp>TapItems</samp>
  −
| The items produced by [[Tapper|tapping]] the tree. If multiple items can be produced, the first available one is selected.
     −
This consists of a list of models with these fields:
+
It implements a new <samp>IInventory</samp> interface, which lets mods pass their own implementations to code which works on inventories.
 +
 
 +
===Furniture changes===
 +
{{/doc status|[[Modding:Items#Furniture]]|done=false}}
 +
 
 +
<ul>
 +
<li>[[Modding:Items#Furniture|<samp>Data/furniture</samp>]] no longer has language variants. Translations were moved into <samp>Strings/Furniture</samp>.</li>
 +
<li>
 +
There are a few changes in [[Modding:Items#Furniture|<samp>Data/furniture</samp>]]:
 +
<ul>
 +
<li>Field index 6 is now placement restrictions and field index 7 is now display name. The display name field is no longer omitted in English.</li>
 +
<li>Field index 7 (display name) now allows [[Modding:Tokenizable strings|tokenizable strings]].</li>
 +
<li>Added new fields:
 +
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
 +
! index
 
! field
 
! field
 
! effect
 
! effect
 
|-
 
|-
| ''common fields''
+
| 8
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields supported for tapper items.
+
| sprite index
 
+
| The sprite index within the spritesheet texture to draw.
If set to an [[Modding:Item queries|item query]] which returns multiple items, one of them will be selected at random.
   
|-
 
|-
| <samp>Season</samp>
+
| 9
| ''(Optional)'' If set, the item only applies if the tree's location is in this season.
+
| texture
 +
| ''(Optional)'' The asset name of the texture to draw. Defaults to <samp>TileSheets/furniture</samp>.
 
|-
 
|-
| <samp>Chance</samp>
+
| 10
| ''(Optional)'' The probability that this entry is selected, as a value between 0 (never drops) and 1 (always drops). Default 1 (100% chance).
+
| off limits for random sale
 +
| ''(Optional)'' Whether to prevent this furniture from appearing in randomly generated shop stocks and the furniture catalogue. Default false.
 
|-
 
|-
| <samp>DaysUntilReady</samp>
+
| 11
| The number of days before the tapper is ready to empty.
+
| context tags
|-
+
| ''(Optional)'' A space-delimited list of [[Modding:Items#Context tags|context tags]] which apply to this furniture. Default none.
| <samp>PreviousItemId</samp>
+
|}</li>
| ''(Optional)'' If set, the item only applies if the previous item produced by the tapper matches one of the given [[#Custom items|qualified item IDs]]. If an entry is null or an empty string, it matches when there's no previous item.
+
</ul>
 +
</li>
 +
</ul>
 +
 
 +
===Other item changes for C# mods===
 +
* Placed object changes:
 +
** Every placed object now has a <samp>Location</samp> property set to the location which contains it. This removes location parameters from many object methods.
 +
** Setting an object's tile position through <samp>obj.TileLocation</samp> now recalculcates its collision box automatically. (Setting it through the <samp>tileLocation</samp> net field directly won't though.)
 +
** The <samp>obj.IsScarecrow()</samp> and <samp>GetScarecrowRadius()</samp> methods now work for non-bigcraftable objects too.
 +
* Clothing changes:
 +
** <samp>Clothes.clothesType</samp> is now an enum field.
 +
** Clothing is no longer gender-specific. This renames <samp>indexInTileSheetMale</samp> to <samp>indexInTileSheet</samp>, obsoletes <samp>indexInTileSheetFemale</samp>, and converts gender-variant clothing into regular items.
 +
** Removed unused <samp>ClothesType.ACCESSORY</samp> value.
 +
** <samp>Farmer.pants</samp> and <samp>Farmer.shirt</samp> now store the item ID instead of the sprite index.
 +
** In <samp>Data/TailoringRecipes</samp>, added a <samp>CraftingIdFeminine</samp> field which overrides <samp>CraftingId</samp> for female characters.
 +
* Crop changes:
 +
** Added <samp>Game1.cropData</samp> to read crop info without constantly reloading the <samp>Data/Crops</samp> asset.
 +
** Removed most crop fields which only mirror the data (like <samp>harvestMethod</samp> or <samp>seasonsToGrowIn</samp>). Mods can get the info through <samp>crop.GetData()</samp> instead.
 +
** Partly de-hardcoded fertilizer logic. Almost all fertilizer logic is now centralized into a new patchable set of <samp>HoeDirt</samp> methods (see list below). The only fertilizer logic that's still embedded elsewhere is the interaction errors in <samp>Utility.tryToPlaceItem</samp>.
 +
** HoeDirt.fertilizer.Value is now set to <samp>null</samp> when there is no fertilizer. Both qualified and unqualified IDs should be expected.
 +
** Removed <samp>crop.InferSeedIndex()</samp>. This was used to support old crops, which are now fixed by a save migration instead.
 +
* Tool changes:
 +
** Fixed various logic not handling custom tool upgrade levels.
 +
<ul>
 +
<li>Other item logic:<ul>
 +
<li>Simplified the constructors for many item types, particularly <samp>Object</samp>.</li>
 +
<li>[[Honey]] items now have their <samp>preserve</samp> field set to a new <samp>Honey</samp> type (instead of null).</li>
 +
<li>The <samp>Object.performObjectDropInAction</samp> method now applies the <samp>probe</samp> argument much more consistently. This only affects method calls with <samp>probe: true</samp>.</li>
 +
<li>The <samp>Item.salePrice()</samp> method now has option to get the price without [[Multiplayer#Profit margins|profit margins]].</li>
 +
<li>Added new fields & methods:
   −
For example: <code>"PreviousItemId": [ null ]</code> only applies when a tapper is first added to the tree, and <code>"PreviousItemsId": [ "(O)420" ]</code> applies if the player just collected a [[Red Mushroom|red mushroom]] (object #420) from it.
+
{| class="wikitable"
 
|-
 
|-
| <samp>DaysUntilReadyModifiers</samp>
+
! type
| ''(Optional)'' [[#Quantity modifiers|Quantity modifiers]] applied to the <samp>DaysUntilReady</samp> value. Default none.
+
! field/method
 +
! effect
 +
|-
 +
| <samp>Chest</samp>
 +
| <samp>GetItemsForPlayer()</samp>
 +
| Shortcut for <samp>chest.GetItemsForPlayer(Game1.player.UniqueMultiplayerID)</samp>.
 
|-
 
|-
| <samp>DaysUntilReadyModifiersMode</samp>
+
| rowspan="2"| <samp>Crop</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>GetHarvestMethod()</samp>
|}
+
| Get the method used to harvest the crop (one of <samp>HarvestMethod.Grab</samp> or <samp>HarvestMethod.Scythe</samp>).
 
|-
 
|-
| <samp>PlantableLocationRules</samp>
+
| <samp>IsInSeason(location)</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.
+
| Whether the crop can grow in the location's current season (or true if crops ignore seasons in the location, like the [[greenhouse]]).
 
  −
This consists of a list of models with these fields:
  −
 
  −
{| class="wikitable"
   
|-
 
|-
! field
+
| rowspan="8"| <samp>HoeDirt</samp>
! effect
+
| <samp>HasFertilizer()</samp>
 +
| Get whether the dirt has any fertilizer applied.
 
|-
 
|-
| <samp>Id</samp>
+
| <samp>CanApplyFertilizer(itemId)</samp>
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the list.
+
| Get whether a player can apply the given fertilizer to this dirt.
 
|-
 
|-
| <samp>Result</samp>
+
| <samp>CheckApplyFertilizerRules(itemId)</samp>
| Indicates whether the seed can be planted in a location if this entry is selected. The possible values are:
+
| Get whether a player can apply the given fertilizer to this dirt, and the reason they can't if applicable.
* <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>
+
| <samp>GetFertilizerSpeedBoost()</samp>
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this entry applies. Default true.
+
| Get the crop growth speed boost from fertilizers applied to this dirt.
 
|-
 
|-
| <samp>PlantedIn</samp>
+
| <samp>GetFertilizerWaterRetentionChance()</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>.
+
| Get the water retention chance from fertilizers applied to this dirt, as a value between 0 (no change) and 1 (100% chance of staying watered).
 
  −
Note that trees can't be planted in garden pots.
   
|-
 
|-
| <samp>DeniedMessage</samp>
+
| <samp>GetFertilizerQualityBoostLevel()</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.
+
| Get the quality boost level from fertilizers applied to this dirt, which influences the chance of producing a higher-quality crop.
|}
   
|-
 
|-
| <samp>CustomFields</samp>
+
| <samp>GetFertilizerSourceRect()</samp>
| The [[#Custom data fields|custom fields]] for this entry.
+
| Get the pixel area within the dirt spritesheet to draw for any fertilizer applied to this dirt.
|}
     −
====Spawning wild trees====
+
(This method existed before, but no longer requires the fertilizer ID argument.)
Custom trees can be added to the game in two ways:
+
|-
* Spawn them on [[Modding:Maps|map tiles]] when the location is created, using the new <samp>SpawnTree: wild {{t|tree ID}} {{o|growth stage on location created}} {{o|growth stage on day-update regrowth}}</samp> tile property. This must be added on the <samp>Paths</samp> layer, which must also have tile index 34 from the <samp>paths</samp> tilesheet.
+
| <samp>isWatered()</samp>
* Or give the player a seed item in the usual ways (e.g. from [[#Custom shops|a shop]], [[Modding:Mail data|mail letter]], etc).
+
| Get whether the dirt is currently watered.
 
+
|-
===Default recipes===
+
|rowspan="5"| <samp>Item</samp>
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.
+
| <samp>IsRecipe</samp><br /><samp>Quality</samp><br /><samp>Stack</samp></samp><br /><samp>sellToStorePrice(…)</samp>
 
+
| Equivalent to the previous <samp>Object</samp> fields/methods, to simplify common code and avoid needing to special-case <samp>Object</samp> items.
For example, here's the chest entry from <samp>Data/CraftingRecipes</samp>:
+
|-
<syntaxhighlight lang="js">
+
| <samp>appliesProfitMargins()</samp>
"Chest": "388 50/Home/130/true/default/"
+
| Get whether this item should apply [[Multiplayer#Profit margins|profit margins]] to shop prices.
 +
|-
 +
| <samp>CanBeLostOnDeath()</samp>
 +
| Get whether this item can be lost when the player dies, so it can be recovered from the [[Adventurer's Guild#Item Recovery Service|item recovery service]].
 +
|-
 +
| <samp>HasTypeId(id)</samp><br /><samp>HasTypeObject()</samp><br /><samp>HasTypeBigCraftable()</samp>
 +
| Get whether the item has the given [[#Custom items|type definition ID]]. These are null-safe and double as a null check:
 +
<syntaxhighlight lang="c#">
 +
if (item.HasTypeId(ItemRegistry.type_object))
 +
{
 +
    // item is non-null and has type (O)
 +
}
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
<samp>HasTypeObject()</samp> and <samp>HasTypeBigCraftable()</samp> are shortcuts for passing <samp>ItemRegistry.type_object</samp> and <samp>ItemRegistry.type_bigCraftable</samp> respectively.
 +
|-
 +
| <samp>TryGetTempData</samp><br /><samp>SetTempData</samp>
 +
| Get or set temporary item info that's not synchronized in multiplayer or written to the save file.
   −
===Global inventories===
+
For example, the game uses this to pass spawn options to the fishing minigame:
C# mods can now set a <samp>chest.GlobalInventoryId</samp> field to make it share a global inventory with every other chest having the same ID. This replaces the equivalent hardcoded logic for [[Junimo Chest|Junimo chests]], which now just default to a <samp>"JunimoChests"</samp> global inventory ID. For example, this can be used to have multiple Junimo chest networks or make other containers share inventory.
+
<syntaxhighlight lang="c#">
 +
if (spawn.IsBossFish)
 +
    fish.SetTempData(nameof(spawn.IsBossFish), true);
   −
C# mods can also use this to store items for other mod purposes, by using <samp>Game1.player.team.globalInventories</samp> or <samp>Game1.player.team.GetOrCreateGlobalInventory(id)</samp> directly.
+
...
   −
===Hats on aquarium fish===
+
fish.TryGetTempData(nameof(SpawnFishData.IsBossFish), out bool bossFish);
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>:
+
</syntaxhighlight>
 
  −
{| class="wikitable"
   
|-
 
|-
! index
+
| <samp>FishingRod</samp>
! field
+
| <samp>CanUseBait()</samp><br /><samp>CanUseTackle()</samp><br /><samp>GetBait()</samp><br /><samp>GetTackle()</samp><br /><samp>HasMagicBait()</samp><br /><samp>HasCuriosityLure()</samp>
! purpose
+
| Simplifies working with the fishing rod's [[bait]] and [[tackle]].
 
|-
 
|-
| 7
+
|rowspan="2"| <samp>Furniture</samp>
| hat position
+
| <samp>SetPlacement</samp><br /><samp>SetHeldObject</samp>
| The pixel position of the hat on the sprite, specified as an object with <samp>X</samp> and <samp>Y</samp> values.
+
| 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.
|}
     −
===Context tag changes===
+
These are used by the game to initialize furniture in one go. For example:
====New context tags====
+
<syntaxhighlight lang="c#">
1.6 adds several new [[Modding:Items#Context tags|item context tags]]:
+
// oak table holding decorative bowl
 
+
Furniture table = ItemRegistry
{| class="wikitable"
+
    .Create<Furniture>("(F)1120")
 +
    .SetPlacement(5, 4, 0)
 +
    .SetHeldObject(ItemRegistry.Create<Furniture>("(F)1364"));
 +
</syntaxhighlight>
 
|-
 
|-
! context tag
+
| <samp>IsTable()</samp>
! effect
+
| Get whether this furniture is a table.
 
|-
 
|-
| <samp>campfire_item</samp>
+
|rowspan="2"| <samp>FruitTree</samp>
| Marks the item as a [[campfire]]. If the item also has the <samp>torch_item</samp> context tag, when it's placed in the world and turned on...
+
| <samp>GetQuality()</samp>
* campfire flames are drawn over it;
+
| Get the quality of fruit currently being produced by the fruit tree.
* if the item is [[Modding:Items#Big craftables|big craftable]], light is emitted from its center instead of the top.
   
|-
 
|-
| <samp>fish_pond_ignore</samp>
+
| <samp>TryAddFruit()</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>.
+
| Add a fruit item to the tree based on [[#Custom fruit trees|its data]].
 
|-
 
|-
| <samp>geode_crusher_ignored</samp>
+
| <samp>IndoorPot</samp>
| Prevents breaking this item open in a [[Geode Crusher|geode crusher]], even if the item has geode fields in [[#Custom objects|<samp>Data/Objects</samp>]].
+
| <samp>Water()</samp>
 +
| Simplifies watering dirt in the [[Garden Pot|garden pot]].
 
|-
 
|-
| <samp>item_type_{{t|type}}</samp>
+
| <samp>Object</samp>
| For an [[Modding:Items#Objects|object-type item]], the type value from the 'type and category' field. (Non-object items always have the exact tag <samp>item_type_</samp> with nothing after the last underscore.) This is automatic and shouldn't be set manually. The tag is checked in a few places (''e.g.'' the [[museum]] to check if an item is an artifact or mineral), but most of the game won't be affected.
+
| <samp>GetBoundingBox()</samp><br /><samp>GetBoundingBoxAt(x, y)</samp>
 +
| Get the pixel collision area for the item placed in the world. These replace the former <samp>getBoundingBox(position)</samp> method.
 
|-
 
|-
| <samp>museum_donatable</samp><br /><samp>not_museum_donatable</samp>
+
| <samp>Tool</samp>
| Set whether the item can be donated to the [[museum]], overriding the vanilla logic.
+
| <samp>isScythe()</samp>
 +
| Equivalent to the previous <samp>MeleeWeapon</samp> method, to simplify common code and avoid needing to special-case <samp>MeleeWeapon</samp> items.
 
|-
 
|-
| <samp>not_giftable</samp>
+
|rowspan="3"| <samp>Tree</samp>
| Prevents players from gifting this item to NPCs, who'll ignore the item entirely (e.g. as if you were holding a tool).
+
| <samp>CheckForNewTexture()</samp>
 
+
| Reset the tree's texture if it would change based on [[#Custom wild trees|its data]].
This only affects gift-giving, it doesn't affect non-gift logic like quest goals or special order objectives. If the NPC also has a <samp>reject_*</samp> dialogue for the item, the dialogue takes priority.
   
|-
 
|-
| <samp>not_placeable</samp><br /><samp>placeable</samp>
+
| <samp>GetMaxSizeHere</samp>
| Sets whether the item can be placed on the ground.
+
| Get the maximum size the tree can grow in its current position (e.g. accounting for nearby trees blocking growth).
 
|-
 
|-
| <samp>prevent_loss_on_death</samp>
+
| <samp>IsGrowthBlockedByNearbyTree</samp>
| Indicates the item can't be [[Adventurer's Guild#Item Recovery Service|lost when the player dies]].
+
| Get whether growth is blocked because it's too close to another fully-grown tree.
|-
+
|}
| <samp>sign_item</samp>
+
</li>
| Marks the item as a [[Crafting#Signs|sign]], which lets player display items on it or place it on a [[Fish Pond|fish pond]] to show the fish count.
+
<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>
| <samp>torch_item</samp>
+
<li>Fixed fruit trees forgetting the growth stage set in their constructor when they're updated overnight.</li>
| Marks the item as a [[torch]], which lets the player turn it on/off to emit light.
+
</ul>
 +
 
 +
===Other item changes===
 +
* Added per-object display names (''e.g.'' for custom flavored items). See the <samp>ObjectDisplayName</samp> [[Modding:Item queries#Item spawn fields|item spawn field]], or <samp>object.displayNameFormat</samp> in C#.
 +
* [[Ginger Island#Gem Birds|Item pedestals]] are now normal item, so you can spawn them using a mod like CJB Item Spawner to display items.
 +
* Added optional <samp>Condition</samp> [[Modding:Game state queries|game state query]] field to <samp>Data/SpecialOrders</samp>.
 +
* Item data changes:
 +
** The display name field now exists in English too for <samp>Data/Boots</samp>, <samp>Data/Bundles</samp>, <samp>Data/CookingRecipes</samp>, <samp>Data/CraftingRecipes</samp>, <samp>Data/Furniture</samp>, <samp>Data/Hats</samp>, and <samp>Data/Weapons</samp>.
 +
** The randomly spawned [[The Farm#Stone|stones]], [[The Farm#Wood|twigs]], and [[weeds]] have been formalized into ''litter''. They all now have object type <samp>Litter</samp>, [[Modding:Items#Categories|category]] -999 (<samp>StardewValley.Object.litterCategory</samp>), a relevant display name/description (like ''Gold Stone'' & ''Break apart to obtain gold ore'' instead of ''Stone'' & ''...''), a price of 0 (not sellable), and edibility of -300 (inedible). This also adds all mine ore nodes to <samp>Data/Objects</samp>, so the game no longer creates invalid items to show their sprite. (Doing so in 1.6 will now show an Error Item sprite instead.)
 +
** [[Honey]] items now have the <samp>honey_item</samp> context tag.
 +
** Shirts no longer have a dynamic numeric ID range; every valid shirt is now listed in [[#Custom shirts|<samp>Data/Shirts</samp>]].
 +
** You can now apply a custom buff ID when the item is eaten, via <samp>Data/Objects</samp>'s <samp>Buff</samp> field.
 +
** The type field in <samp>Data/Objects</samp> is no longer checked using substring matching (e.g. the game now uses <code>data.Type == "Fish"</code> instead of <code>typeAndCategory.Contains("Fish")</code>), which may impact mods which depended on that undocumented behavior.
 +
* Crop changes:
 +
** Paddy crops now recheck for nearby water each day, so they'll update if you add/remove a building with water or change the map layout.
 +
** In <samp>Data/Crops</samp>, each harvest option is now self-contained. For example, you can set <samp>HarvestMinStack</samp> without <samp>ExtraHarvestChance</samp>.
 +
* Fish changes:
 +
** <samp>Data/Fish</samp> is no longer translated, so there's only one <samp>Data/Fish.xnb</samp> field. Fish display names are now taken from <samp>Data/Objects</samp>.
 +
** Added a new field (index 13) in <samp>Data/Fish</samp>, which sets whether the fish can be selected for the first-catch tutorial.
 +
* Recipe changes in <samp>Data/CookingRecipes</samp> and <samp>Data/CraftingRecipes</samp>:
 +
** These assets no longer have language variants.
 +
** The display name now supports [[Modding:Tokenizable strings|tokenizable strings]].
 +
** The display name can now be left blank to get it from the first item in the output list.
 +
* Other item logic:
 +
** Missing recipes that should already be unlocked are now added to the player automatically on save load.
 +
** <samp>Data/Bundles</samp> is now loaded later, so content packs can edit it reliably.</samp>
 +
** Chests with <samp>fridge: true</samp> are now treated as mini-fridges for the cooking menu.
 +
** Gift boxes can now contain multiple items.
 +
** Fixed furniture drawn over sitting players if it has no front texture.
 +
** Fixed tool being upgraded by Clint not affected by recursive item search logic.
 +
** Fixed <samp>tool.getOne()</samp> not copying the tool name.
 +
** Fixed cooking menu constantly creating hovered item if the item/recipe names don't match.
 +
 
 +
==What's new for locations & weather==
 +
===Custom locations===
 +
{{/doc status|[[Modding:Location data]]|done=true}}
 +
 
 +
You can now add/edit locations by editing the revamped <samp>Data/Locations</samp> asset. This makes nearly everything in the location configurable — display name, default warp arrival tile, how the location is created, artifact spots / fish / forage / weeds, music, etc.
 +
 
 +
See [[Modding:Location data]] for docs on the new data format.
   −
See also <samp>campfire_item</samp>.
+
===Custom location contexts===
|}
+
{{/doc status|[[Modding:Location data]] or a new doc page|done=false}}
   −
Context tags which affect [[#Custom machines|machine processing]]:
+
====Vanilla contexts====
{| class="wikitable"
+
* 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>.
! context tag
+
 
! effect
+
====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]].
| <samp>crystalarium_banned</samp>
+
 
| When applied to a gem or mineral item, prevents players from placing it in a [[crystalarium]].
+
The data asset consists of a string → model lookup, where the key matches the <samp>Name</samp> field and the value is a model with these fields:
 +
 
 +
<dl style="margin-left: 2em;">
 +
<dt>Required fields:</dt>
 +
<dd>
 +
{| class="wikitable"
 
|-
 
|-
| <samp>keg_juice</samp><br /><samp>keg_wine</samp>
+
! field
| Allows processing the item in a [[keg]] to produce a juice or wine variant.
+
! effect
 
|-
 
|-
| <samp>preserves_jelly</samp><br /><samp>preserves_pickle</samp>
+
| <samp>Name</samp>
| Allows processing the item in a [[Preserves Jar|preserves jar]] to produce a jelly or pickled variant.
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for the location context.
|-
  −
| <samp>seedmaker_banned</samp>
  −
| When applied to a seed item, prevents players from placing it in a [[Seed Maker|seed maker]].
  −
|-
  −
| <samp>tapper_item</samp>
  −
| Marks the item as a [[tapper]] or [[Heavy Tapper|heavy tapper]].
  −
|-
  −
| <samp>tapper_multiplier_{{t|multiplier}}</samp>
  −
| The multiplier applied to the tapper production speed. For example, <samp>2</samp> will make items take half their base time (''i.e.'' each item will finish in <sup>base time</sup>/<sub>speed multiplier</sub>). Defaults to 1 if omitted.
   
|}
 
|}
 +
</dd>
   −
And informational tags which have no effect on the game logic:
+
<dt>Player actions:</dt>
 +
<dd>
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! context tag
+
! field
 
! effect
 
! effect
 
|-
 
|-
| <samp>fish_legendary</samp><br /><samp>fish_legendary_family</samp>
+
| <samp>AllowRainTotem</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>]].
+
| ''(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>RainTotemAffectsContext</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.
 
|-
 
|-
| <samp>geode</samp>
+
| <samp>MaxPassOutCost</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>]].
+
| ''(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>id_{{t|item id}}</samp>
+
| <samp>PassOutMail</samp>
| ''(Added automatically)'' The [[#Custom items|qualified item ID]], like <samp>id_(o)128</samp>. This can be used to match or exclude an item by ID using context tags. Any spaces in the ID are replaced with underscores, and single quotes are removed.
+
| ''(Optional)'' When the player passes out (due to [[energy|exhaustion]] or at 2am) in this context, the possible [[Modding:Mail data|letter IDs]] to add to their mailbox (if they haven't received it before). If multiple letters are valid, one will be chosen randomly (unless one specifies <samp>SkipRandomSelection</samp>).
 +
 
 +
This consists of a list of models with these fields:
 +
{| class="wikitable"
 
|-
 
|-
| <samp>is_machine</samp>
+
! field
| ''(Added automatically)'' Indicates the item has [[#Custom machines|machine logic]]. This is added automatically based on <samp>Data/Machines</samp>.
+
! effect
 
|-
 
|-
| <samp>machine_input</samp>
+
| <samp>Id</samp>
| ''(Added automatically)'' Whether the item is a machine which accepts items from the player. This is added automatically based on the machine's fields in <samp>Data/Machines</samp>:
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry in the list.
* if <samp>HasInput</samp> is true;
+
|-
* ''or'' if any output rules have an <samp>ItemPlacedInMachine</samp> trigger.
+
| <samp>Mail</samp>
 +
| 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>MaxPassOutCost</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.
 +
|-
 +
| <samp>Condition</samp>
 +
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this entry is active. Defaults to always true.
 
|-
 
|-
| <samp>machine_output</samp>
+
| <samp>SkipRandomSelection</samp>
| ''(Added automatically)'' Whether the item is a machine which produces items for the player to collect. This is added automatically based on the machine's fields in <samp>Data/Machines</samp>:
+
| ''(Optional)'' If true, send this mail if the <samp>Condition</samp> matches instead of choosing a random valid mail. Default false.
* if <samp>HasOutput</samp> is true;
  −
* ''or'' if it has any output rules.
   
|}
 
|}
 +
|-
 +
| <samp>PassOutLocations</samp>
 +
| ''(Optional)'' When the player passes out (due to [[energy|exhaustion]] or at 2am) in this context ''and'' they started the day in a different location context, the locations where they'll wake up. (If the player started the day in the same context, they'll wake up in the last bed they slept in instead.)
   −
====ItemContextTagManager class====
+
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.
For C# mods, 1.6 adds a new <samp>ItemContextTagManager</samp> class which simplifies working with [[Modding:Items#Context tags|item context tags]] and reduces repeated code.
     −
This provides a few utility methods:
+
This consists of a list of models with these fields:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! method
+
! field
 
! effect
 
! effect
 
|-
 
|-
| <code>GetBaseContextTags(id)</code>
+
| <samp>Id</samp>
| 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>.
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry in the list.
 
|-
 
|-
| <code>DoesTagQueryMatch(query, tags)</code>
+
| <samp>Location</samp>
| Get whether a context tag query matches the given tags. For example, <code>ItemContextTagManager.DoesTagQueryMatch("bone_item, !fossil_item", item.GetContextTags())</code> returns true if the item is a bone item but not a fossil (like the [[Bone Flute]]).
+
| The internal location name.
 
|-
 
|-
| <code>DoAllTagsMatch(requiredTags, actualTags)</code><br /><code>DoAnyTagsMatch(requiredTags, actualTags)</code>
+
| <samp>Position</samp>
| Get whether every (<samp>DoAllTagsMatch</samp>) or at least one (<samp>DoAnyTagsMatch</samp) required tag matches the actual item tags. This supports negated required tags like <samp>"!fossil_item"</samp> too.
+
| 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.
 
|-
 
|-
| <code>DoesTagMatch(requiredTag, actualTags)</code>
+
| <samp>Condition</samp>
| Get whether a single tag matches the actual item tags. This supports negated required tags like <samp>"!fossil_item"</samp> too.
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this entry is active. Defaults to always applied.
|-
  −
| <code>SanitizeContextTag(tag)</code>
  −
| ''(Specialized)'' Replace characters that may appear in item names so they're valid in context tags. For example, <code>SanitizeContextTag("Sam's Boombox")</code> returns <samp>sams_boombox</samp>.
   
|}
 
|}
   −
====Other context tag changes====
+
If no locations are specified or none match, the player will wake up in their bed at home.
* Context tags are now case-insensitive.
+
|-
 
+
| <samp>ReviveLocations</samp>
===Inventory class===
+
| ''(Optional)'' If the player just got knocked out in combat, the location names where they'll wake up.
For C# mods, 1.6 adds a new <samp>Inventory</samp> class to manage a list of items. This is used for the <samp>Farmer.items</samp> and <samp>Chest.items</samp> fields. It implements <samp>IList&lt;Item&gt;</samp>, so most existing code should still work fine.
     −
This has three main benefits:
+
This consists of a list of models with these fields:
<ul>
  −
<li>It has methods to simplify many common operations. For example:
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! method
+
! field
 
! effect
 
! effect
 
|-
 
|-
| <code>HasAny()</code>
+
| <samp>Id</samp>
| Get whether the inventory contains any items (ignoring empty slots).
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry in the list.
 
|-
 
|-
| <code>CountItemStacks()</code>
+
| <samp>Location</samp>
| Get the number of item stacks in the inventory (ignoring empty slots).
+
| The internal location name.
 
|-
 
|-
| <code>ContainsId(id)</code>
+
| <samp>Position</samp>
| Get whether the inventory contains any item with the given qualified or unqualified item ID.
+
| The tile position within the location, specified as an object with <samp>X</samp> and <samp>Y</samp> fields.
 
|-
 
|-
| <code>ContainsId(id, minCount)</code>
+
| <samp>Condition</samp>
| Get whether the inventory contains items with the given qualified or unqualified item ID, and their combined stack size is at least <samp>minCount</samp>.
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this entry is active. Defaults to always applied.
|-
+
|}
| <code>CountId(id)</code>
+
 
| Get the combined stack size of all items with the given qualified or unqualified item ID.
+
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.
|-
  −
| <code>GetById(id)</code>
  −
| Get a list of items in the inventory with the given qualified or unqualified item ID.
  −
|-
  −
| <code>ReduceId(id, count)</code>
  −
| Remove the given number of items matching the given qualified or unqualified item ID. This reduces the stack size for matching items until a total of <samp>count</samp> have been removed, and clears any slots which reach a stack size of zero.
  −
|}</li>
  −
<li>Many common operations have been unified, so previously player-only methods can now be used with chests too.</li>
  −
<li>It has an internal index by item ID, so operations like <code>items.ContainsId("(O)128")</code> are much more efficient since they no longer iterate the list.</li>
  −
</ul>
     −
This replaces some previous methods:
+
If no locations are specified or none match, the player will wake up at [[Harvey's Clinic|Harvey's clinic]].
 +
|}
 +
</dd>
    +
<dt>Season:</dt>
 +
<dd>
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! game class
+
! field
! old code
+
! effect
! migration
   
|-
 
|-
|rowspan="6"| <samp>Farmer</samp>
+
| <samp>SeasonOverride</samp>
| <code>getItemCount(id)</code><br /><code>GetTallyOfObject(id)</code><br /><code>GetTallyOfObject(id, isBigCraftable)</code><br /><code>hasItemInInventory(id, count)</code><br /><code>hasItemInList(list, id, count)</code>
+
| ''(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.
| &#32;
+
|}
* To check an item ID, use <code>items.CountId(id)</code> or <code>Items.ContainsId(id, count)</code>.
+
</dd>
* 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.
+
<dt>Weather:</dt>
 +
<dd>
 +
{| class="wikitable"
 +
|-
 +
! field
 +
! effect
 
|-
 
|-
| <code>hasItemInInventoryNamed(name)</code><br /><code>hasItemWithNameThatContains(name)</code>
+
| <samp>WeatherConditions</samp>
| In most cases, you should match items by ID instead (see the previous row).
+
| ''(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.
   −
If you really need to match items by name, you can replace it like this:
+
This consists of a list of models with these fields:
<syntaxhighlight lang="c#">
+
{| class="wikitable"
// 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>
+
! field
| Use <code>!items.HasAny()</code>.
+
! effect
 
|-
 
|-
| <code>numberOfItemsInInventory()</code>
+
| <samp>Id</samp>
| 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.
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry in the list.
 
|-
 
|-
| <code>consumeObject(id, count)</code>
+
| <samp>Weather</samp>
| Use <code>items.ReduceId(id, count)</code>.
+
| The [[#Custom weather|weather ID]] to set.
 
|-
 
|-
| <code>removeItemsFromInventory(id, count)</code>
+
| <samp>Condition</samp>
| &#32;
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether to apply the weather. Defaults to always applied.
* 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>
+
| <samp>CopyWeatherFromLocation</samp>
| <code>ConsumeInventoryItem(player, id, count)</code>
+
| ''(Optional)'' The <samp>Name</samp> (i.e. unique ID) of the location context from which to inherit weather.
| 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>
  −
| 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.
+
If a [[#Custom passive festivals|passive festival]] is active in any location within this context, the weather is sunny for the entire context regardless of these fields.
 +
 
 +
</dd>
   −
===Furniture changes===
+
<dt>Music:</dt>
<ul>
+
<dd>
<li>[[Modding:Items#Furniture|<samp>Data/furniture</samp>]] no longer has language variants. Translations were moved into <samp>Strings/Furniture</samp>.</li>
+
{| class="wikitable"
<li>
+
|-
There are a few changes in [[Modding:Items#Furniture|<samp>Data/furniture</samp>]]:
+
! field
<ul>
+
! effect
<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>
+
| <samp>DefaultMusic</samp>
<li>Added new fields:
+
| ''(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 [[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>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>Music</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.
    +
This consists of a list of models with these fields:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! index
   
! field
 
! field
 
! effect
 
! effect
 
|-
 
|-
| 8
+
| <samp>Id</samp>
| sprite index
+
| ''(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.
| The sprite index within the spritesheet texture to draw.
+
|-
 +
| <samp>Track</samp>
 +
| The [[Modding:Migrate to Stardew Valley 1.6#Custom audio|audio track ID]] to play.
 
|-
 
|-
| 9
+
| <samp>Condition</samp>
| texture
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this entry applies. Default true.
| ''(Optional)'' The asset name of the texture to draw. Defaults to <samp>TileSheets/furniture</samp>.
+
|}
 
|-
 
|-
| 10
+
| <samp>DayAmbience</samp><br /><samp>NightAmbience</samp>
| off limits for random sale
+
| ''(Optional)'' The [[#Custom audio|cue ID]] for the background ambience to play when there's no music active, depending on the [[Day Cycle|time of day]]. Both default to none.
| ''(Optional)'' Whether to prevent this furniture from appearing in randomly generated shop stocks and the furniture catalogue. Default false.
   
|-
 
|-
| 11
+
| <samp>PlayRandomAmbientSounds</samp>
| context tags
+
| ''(Optional)'' Whether to play random outdoor ambience sounds depending on factors like the season and time of day (e.g. birds, crickets, and mysterious groan sounds in the rain). This is unrelated to the <samp>DayAmbience</samp> and <samp>NightAmbience</samp> fields. Default true.
| ''(Optional)'' A space-delimited list of [[Modding:Items#Context tags|context tags]] which apply to this furniture. Default none.
+
|}
|}</li>
+
</dd>
</ul>
  −
</li>
  −
</ul>
  −
 
  −
===Other item changes for C# mods===
  −
* Placed object changes:
  −
** Every placed object now has a <samp>Location</samp> property set to the location which contains it. This removes location parameters from many object methods.
  −
** Setting an object's tile position through <samp>obj.TileLocation</samp> now recalculcates its collision box automatically. (Setting it through the <samp>tileLocation</samp> net field directly won't though.)
  −
** The <samp>obj.IsScarecrow()</samp> and <samp>GetScarecrowRadius()</samp> methods now work for non-bigcraftable objects too.
  −
* Clothing changes:
  −
** <samp>Clothes.clothesType</samp> is now an enum field.
  −
** Clothing is no longer gender-specific. This renames <samp>indexInTileSheetMale</samp> to <samp>indexInTileSheet</samp>, obsoletes <samp>indexInTileSheetFemale</samp>, and converts gender-variant clothing into regular items.
  −
** Removed unused <samp>ClothesType.ACCESSORY</samp> value.
  −
** <samp>Farmer.pants</samp> and <samp>Farmer.shirt</samp> now store the item ID instead of the sprite index.
  −
** In <samp>Data/TailoringRecipes</samp>, added a <samp>CraftingIdFeminine</samp> field which overrides <samp>CraftingId</samp> for female characters.
  −
* Crop changes:
  −
** Added <samp>Game1.cropData</samp> to read crop info without constantly reloading the <samp>Data/Crops</samp> asset.
  −
** Removed most crop fields which only mirror the data (like <samp>harvestMethod</samp> or <samp>seasonsToGrowIn</samp>). Mods can get the info through <samp>crop.GetData()</samp> instead.
  −
** Partly de-hardcoded fertilizer logic. Almost all fertilizer logic is now centralized into a new patchable set of <samp>HoeDirt</samp> methods (see list below). The only fertilizer logic that's still embedded elsewhere is the interaction errors in <samp>Utility.tryToPlaceItem</samp>.
  −
** HoeDirt.fertilizer.Value is now set to <samp>null</samp> when there is no fertilizer. Both qualified and unqualified IDs should be expected.
  −
** Removed <samp>crop.InferSeedIndex()</samp>. This was used to support old crops, which are now fixed by a save migration instead.
  −
* Tool changes:
  −
** Fixed various logic not handling custom tool upgrade levels.
  −
<ul>
  −
<li>Other item logic:<ul>
  −
<li>Simplified the constructors for many item types, particularly <samp>Object</samp>.</li>
  −
<li>[[Honey]] items now have their <samp>preserve</samp> field set to a new <samp>Honey</samp> type (instead of null).</li>
  −
<li>The <samp>Object.performObjectDropInAction</samp> method now applies the <samp>probe</samp> argument much more consistently. This only affects method calls with <samp>probe: true</samp>.</li>
  −
<li>The <samp>Item.salePrice()</samp> method now has option to get the price without [[Multiplayer#Profit margins|profit margins]].</li>
  −
<li>Added new fields & methods:
      +
<dt>Advanced:</dt>
 +
<dd>
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! type
+
! field
! field/method
   
! effect
 
! effect
 
|-
 
|-
| <samp>Chest</samp>
+
| <samp>CustomFields</samp>
| <samp>GetItemsForPlayer()</samp>
+
| The [[#Custom data fields|custom fields]] for this entry.
| Shortcut for <samp>chest.GetItemsForPlayer(Game1.player.UniqueMultiplayerID)</samp>.
+
|}
 +
</dd>
 +
</dl>
 +
 
 +
===Custom garbage cans===
 +
{{/doc status|a new doc page|done=false}}
 +
 
 +
====Format====
 +
You can now add or edit [[Garbage Can|garbage cans]] on any map by editing the new <samp>Data/GarbageCans</samp> asset (see examples below).
 +
 
 +
The asset consists of a data model with these fields:
 +
 
 +
{| class="wikitable"
 
|-
 
|-
| rowspan="2"| <samp>Crop</samp>
+
! field
| <samp>GetHarvestMethod()</samp>
+
! effect
| Get the method used to harvest the crop (one of <samp>HarvestMethod.Grab</samp> or <samp>HarvestMethod.Scythe</samp>).
   
|-
 
|-
| <samp>IsInSeason(location)</samp>
+
| <samp>DefaultBaseChance</samp>
| Whether the crop can grow in the location's current season (or true if crops ignore seasons in the location, like the [[greenhouse]]).
+
| 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.
 
|-
 
|-
| rowspan="8"| <samp>HoeDirt</samp>
+
| <samp>BeforeAll</samp><br /><samp>AfterAll</samp>
| <samp>HasFertilizer()</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).
| Get whether the dirt has any fertilizer applied.
   
|-
 
|-
| <samp>CanApplyFertilizer(itemId)</samp>
+
| <samp>GarbageCans</samp>
| Get whether a player can apply the given fertilizer to this dirt.
+
| The data for individual garbage cans. This consists of a string → model lookup with these fields:
 +
 
 +
{| class="wikitable"
 +
|-
 +
! field
 +
! effect
 
|-
 
|-
| <samp>CheckApplyFertilizerRules(itemId)</samp>
+
| ''entry key''
| Get whether a player can apply the given fertilizer to this dirt, and the reason they can't if applicable.
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this garbage can.
 
|-
 
|-
| <samp>GetFertilizerSpeedBoost()</samp>
+
| <samp>BaseChance</samp>
| Get the crop growth speed boost from fertilizers applied to this dirt.
+
| ''(Optional)'' If set, overrides the root <samp>DefaultBaseChance</samp> field for this garbage can. Defaults to <samp>DefaultBaseChance</samp>.
 
|-
 
|-
| <samp>GetFertilizerWaterRetentionChance()</samp>
+
| <samp>Items</samp>
| Get the water retention chance from fertilizers applied to this dirt, as a value between 0 (no change) and 1 (100% chance of staying watered).
+
| ''(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:
 +
{| class="wikitable"
 
|-
 
|-
| <samp>GetFertilizerQualityBoostLevel()</samp>
+
! field
| Get the quality boost level from fertilizers applied to this dirt, which influences the chance of producing a higher-quality crop.
+
! effect
 
|-
 
|-
| <samp>GetFertilizerSourceRect()</samp>
+
| ''common fields''
| Get the pixel area within the dirt spritesheet to draw for any fertilizer applied to this dirt.
+
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields supported by garbage cans.
   −
(This method existed before, but no longer requires the fertilizer ID argument.)
+
If set to an [[Modding:Item queries|item query]] which returns multiple items, one of them will be selected at random.
 
|-
 
|-
| <samp>isWatered()</samp>
+
| <samp>IgnoreBaseChance</samp>
| Get whether the dirt is currently watered.
+
| ''(Optional)'' Whether this item can spawn even if the <samp>BaseChance</samp> probability check didn't pass. Default false.
 
|-
 
|-
|rowspan="5"| <samp>Item</samp>
+
| <samp>IsMegaSuccess</samp>
| <samp>IsRecipe</samp><br /><samp>Quality</samp><br /><samp>Stack</samp></samp><br /><samp>sellToStorePrice()</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.
| Equivalent to the previous <samp>Object</samp> fields/methods, to simplify common code and avoid needing to special-case <samp>Object</samp> items.
   
|-
 
|-
| <samp>appliesProfitMargins()</samp>
+
| <samp>IsDoubleMegaSuccess</samp>
| Get whether this item should apply [[Multiplayer#Profit margins|profit margins]] to shop prices.
+
| ''(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>CanBeLostOnDeath()</samp>
+
| <samp>AddToInventoryDirectly</samp>
| Get whether this item can be lost when the player dies, so it can be recovered from the [[Adventurer's Guild#Item Recovery Service|item recovery service]].
+
| ''(Optional)'' Whether to add the item to the player's inventory directly, opening an item grab menu if they don't have room in their inventory. If false, the item will be dropped on the ground next to the garbage can instead. Default false.
 
|-
 
|-
| <samp>HasTypeId(id)</samp><br /><samp>HasTypeObject()</samp><br /><samp>HasTypeBigCraftable()</samp>
+
| <samp>CreateMultipleDebris</samp>
| Get whether the item has the given [[#Custom items|type definition ID]]. These are null-safe and double as a null check:
+
| ''(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.
<syntaxhighlight lang="c#">
+
|}
if (item.HasTypeId(ItemRegistry.type_object))
+
|}
{
+
 
    // item is non-null and has type (O)
+
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.
}
  −
</syntaxhighlight>
  −
<samp>HasTypeObject()</samp> and <samp>HasTypeBigCraftable()</samp> are shortcuts for passing <samp>ItemRegistry.type_object</samp> and <samp>ItemRegistry.type_bigCraftable</samp> respectively.
   
|-
 
|-
| <samp>TryGetTempData</samp><br /><samp>SetTempData</samp>
+
| <samp>CustomFields</samp>
| Get or set temporary item info that's not synchronized in multiplayer or written to the save file.
+
| 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>:
   −
For example, the game uses this to pass spawn options to the fishing minigame:
+
{{#tag:syntaxhighlight|<nowiki>
<syntaxhighlight lang="c#">
+
{
if (spawn.IsBossFish)
+
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
    fish.SetTempData(nameof(spawn.IsBossFish), true);
+
    "Changes": [
 +
        {
 +
            "Action": "EditData",
 +
            "Target": "Data/GarbageCans",
 +
            "TargetField": [ "GarbageCans" ],
 +
            "Entries": {
 +
                "{{ModId}}_Carpenter": {
 +
                    "Items": [
 +
                        // 25% chance of pufferfish
 +
                        {
 +
                            "ID": "{{ModId}}_Pufferfish",
 +
                            "Condition": "RANDOM 0.25",
 +
                            "ItemId": "(O)128"
 +
                        },
   −
...
+
                        // else guaranteed random House Plant item
 +
                        {
 +
                            "ID": "{{ModId}}_RandomHousePlant",
 +
                            "ItemID": "RANDOM_ITEMS (F) 1376 1390"
 +
                        }
 +
                    ]
 +
                }
 +
            }
 +
        }
 +
    ]
 +
}</nowiki>|lang=javascript}}
   −
fish.TryGetTempData(nameof(SpawnFishData.IsBossFish), out bool bossFish);
+
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.
</syntaxhighlight>
  −
|-
  −
| <samp>FishingRod</samp>
  −
| <samp>CanUseBait()</samp><br /><samp>CanUseTackle()</samp><br /><samp>GetBait()</samp><br /><samp>GetTackle()</samp><br /><samp>HasMagicBait()</samp><br /><samp>HasCuriosityLure()</samp>
  −
| Simplifies working with the fishing rod's [[bait]] and [[tackle]].
  −
|-
  −
|rowspan="2"| <samp>Furniture</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.
     −
These are used by the game to initialize furniture in one go. For example:
+
====Example change for existing garbage can====
<syntaxhighlight lang="c#">
+
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.
// oak table holding decorative bowl
+
 
Furniture table = ItemRegistry
+
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.
    .Create<Furniture>("(F)1120")
+
 
    .SetPlacement(5, 4, 0)
+
{{#tag:syntaxhighlight|<nowiki>
     .SetHeldObject(ItemRegistry.Create<Furniture>("(F)1364"));
+
{
</syntaxhighlight>
+
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
 +
    "Changes": [
 +
        {
 +
            "Action": "EditData",
 +
            "Target": "Data/GarbageCans",
 +
            "TargetField": [ "GarbageCans", "Saloon", "Items" ],
 +
            "Entries": {
 +
                // 25% chance of pufferfish
 +
               
 +
                "{{ModId}}_Pufferfish":{
 +
                    "ID": "{{ModId}}_Pufferfish",
 +
                    "Condition": "RANDOM 0.25",
 +
                    "ItemId": "(O)128"
 +
                }
 +
            },
 +
            "MoveEntries": [
 +
                { "ID": "{{ModId}}_Pufferfish", "BeforeId": "Base_DishOfTheDay" }
 +
            ]
 +
        }
 +
     ]
 +
}</nowiki>|lang=javascript}}
 +
 
 +
====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"
 
|-
 
|-
| <samp>IsTable()</samp>
+
! action
| Get whether this furniture is a table.
+
! code in 1.5.6
 +
! code in 1.6
 
|-
 
|-
|rowspan="2"| <samp>FruitTree</samp>
+
| check if a garbage can was searched
| <samp>GetQuality()</samp>
+
| <syntaxhighlight lang="js">
| Get the quality of fruit currently being produced by the fruit tree.
+
Town town = (Town)Game1.getLocationFromName("Town");
 +
if (town.garbageChecked[5])
 +
  ...
 +
</syntaxhighlight>
 +
| <syntaxhighlight lang="js">
 +
if (Game1.netWorldState.Value.CheckedGarbage.Contains("Saloon"))
 +
  ...
 +
</syntaxhighlight>
 
|-
 
|-
| <samp>TryAddFruit()</samp>
+
| mark a garbage can searched
| Add a fruit item to the tree based on [[#Custom fruit trees|its data]].
+
| <syntaxhighlight lang="js">
 +
Town town = (Town)Game1.getLocationFromName("Town");
 +
town.garbageChecked[5] = true;
 +
</syntaxhighlight>
 +
| <syntaxhighlight lang="js">
 +
Game1.netWorldState.Value.CheckedGarbage.Add("Saloon");
 +
</syntaxhighlight>
 +
|}
 +
 
 +
To migrate former vanilla trash can IDs:
 +
{| class="wikitable"
 +
|-
 +
! position
 +
! 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>
 
|-
 
|-
| <samp>IndoorPot</samp>
+
| Near [[Lewis]]' house
| <samp>Water()</samp>
+
| <code>2</code>
| Simplifies watering dirt in the [[Garden Pot|garden pot]].
+
| <code>Mayor</code>
 
|-
 
|-
| <samp>Object</samp>
+
| Near [[Museum]]
| <samp>GetBoundingBox()</samp><br /><samp>GetBoundingBoxAt(x, y)</samp>
+
| <code>3</code>
| Get the pixel collision area for the item placed in the world. These replace the former <samp>getBoundingBox(position)</samp> method.
+
| <code>Museum</code>
 
|-
 
|-
| <samp>Tool</samp>
+
| Near [[Blacksmith|Clint's blacksmith]]
| <samp>isScythe()</samp>
+
| <code>4</code>
| Equivalent to the previous <samp>MeleeWeapon</samp> method, to simplify common code and avoid needing to special-case <samp>MeleeWeapon</samp> items.
+
| <code>Blacksmith</code>
 
|-
 
|-
|rowspan="3"| <samp>Tree</samp>
+
| Near [[The Stardrop Saloon|the Saloon]]
| <samp>CheckForNewTexture()</samp>
+
| <code>5</code>
| Reset the tree's texture if it would change based on [[#Custom wild trees|its data]].
+
| <code>Saloon</code>
 
|-
 
|-
| <samp>GetMaxSizeHere</samp>
+
| Near [[Evelyn]] and [[George]]'s house
| Get the maximum size the tree can grow in its current position (e.g. accounting for nearby trees blocking growth).
+
| <code>6</code>
 +
| <code>Evelyn</code>
 
|-
 
|-
| <samp>IsGrowthBlockedByNearbyTree</samp>
+
| Near [[JojaMart]]
| Get whether growth is blocked because it's too close to another fully-grown tree.
+
| <code>7</code>
 +
| <code>JojaMart</code>
 
|}
 
|}
</li>
  −
<li>Modularized <samp>Object.CheckForAction</samp> to simplify mod patches.</li>
  −
<li>Reworked <samp>Item.getOne()</samp> implementation to avoid common pitfalls. (This only affects mods with custom item classes, or which patch <samp>Item.getOne</samp> or <samp>Item._GetOneFrom</samp>.)</li>
  −
<li>Fixed fruit trees forgetting the growth stage set in their constructor when they're updated overnight.</li>
  −
</ul>
     −
===Other item changes===
+
===Custom map actions===
* 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#.
+
{{/doc status|[[Modding:Maps]]|done=false}}
* [[Ginger Island#Gem Birds|Item pedestals]] are now normal item, so you can spawn them using a mod like CJB Item Spawner to display items.
+
 
* Added optional <samp>Condition</samp> [[Modding:Game state queries|game state query]] field to <samp>Data/SpecialOrders</samp>.
+
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.
* Item data changes:
  −
** The display name field now exists in English too for <samp>Data/Boots</samp>, <samp>Data/Bundles</samp>, <samp>Data/CookingRecipes</samp>, <samp>Data/CraftingRecipes</samp>, <samp>Data/Furniture</samp>, <samp>Data/Hats</samp>, and <samp>Data/Weapons</samp>.
  −
** The randomly spawned [[The Farm#Stone|stones]], [[The Farm#Wood|twigs]], and [[weeds]] have been formalized into ''litter''. They all now have object type <samp>Litter</samp>, [[Modding:Items#Categories|category]] -999 (<samp>StardewValley.Object.litterCategory</samp>), a relevant display name/description (like ''Gold Stone'' & ''Break apart to obtain gold ore'' instead of ''Stone'' & ''...''), a price of 0 (not sellable), and edibility of -300 (inedible). This also adds all mine ore nodes to <samp>Data/Objects</samp>, so the game no longer creates invalid items to show their sprite. (Doing so in 1.6 will now show an Error Item sprite instead.)
  −
** [[Honey]] items now have the <samp>honey_item</samp> context tag.
  −
** Shirts no longer have a dynamic numeric ID range; every valid shirt is now listed in [[#Custom shirts|<samp>Data/Shirts</samp>]].
  −
** You can now apply a custom buff ID when the item is eaten, via <samp>Data/Objects</samp>'s <samp>Buff</samp> field.
  −
** The type field in <samp>Data/Objects</samp> is no longer checked using substring matching (e.g. the game now uses <code>data.Type == "Fish"</code> instead of <code>typeAndCategory.Contains("Fish")</code>), which may impact mods which depended on that undocumented behavior.
  −
* Crop changes:
  −
** Paddy crops now recheck for nearby water each day, so they'll update if you add/remove a building with water or change the map layout.
  −
** In <samp>Data/Crops</samp>, each harvest option is now self-contained. For example, you can set <samp>HarvestMinStack</samp> without <samp>ExtraHarvestChance</samp>.
  −
* Fish changes:
  −
** <samp>Data/Fish</samp> is no longer translated, so there's only one <samp>Data/Fish.xnb</samp> field. Fish display names are now taken from <samp>Data/Objects</samp>.
  −
** Added a new field (index 13) in <samp>Data/Fish</samp>, which sets whether the fish can be selected for the first-catch tutorial.
  −
* Recipe changes in <samp>Data/CookingRecipes</samp> and <samp>Data/CraftingRecipes</samp>:
  −
** These assets no longer have language variants.
  −
** The display name now supports [[Modding:Tokenizable strings|tokenizable strings]].
  −
** The display name can now be left blank to get it from the first item in the output list.
  −
* Other item logic:
  −
** Missing recipes that should already be unlocked are now added to the player automatically on save load.
  −
** <samp>Data/Bundles</samp> is now loaded later, so content packs can edit it reliably.</samp>
  −
** Chests with <samp>fridge: true</samp> are now treated as mini-fridges for the cooking menu.
  −
** Gift boxes can now contain multiple items.
  −
** Fixed furniture drawn over sitting players if it has no front texture.
  −
** Fixed tool being upgraded by Clint not affected by recursive item search logic.
  −
** Fixed <samp>tool.getOne()</samp> not copying the tool name.
  −
** Fixed cooking menu constantly creating hovered item if the item/recipe names don't match.
     −
==What's new for locations & weather==
+
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:
===Custom locations===
+
<syntaxhighlight lang="c#">
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.
+
internal class ModEntry : Mod
 +
{
 +
    /// <inheritdoc />
 +
    public override void Entry(IModHelper helper)
 +
    {
 +
        GameLocation.RegisterTouchAction("Example.ModId_UnlockGate", this.HandleUnlockGate);
 +
    }
   −
See [[Modding:Location data]] for docs on the new data format.
+
    private void HandleUnlockGate(GameLocation location, string[] args, Farmer player, Vector2 tile)
 +
    {
 +
        const string mailFlag = "Example.ModId_GateUnlocked";
 +
        const string keyId = "Example.ModId_GateKey";
   −
===Custom location contexts===
+
        // unlock gate if locked
====Vanilla contexts====
+
        if (!player.mailReceived.Contains(mailFlag))
* 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>.
+
            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);
 +
        }
   −
====Format====
+
        // apply open-gate map edit
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]].
+
        // NOTE: this is a quick example which changes the location's current map. If another mod reloads the map
 +
        // (e.g. a content pack editing it), the change will be lost. For persistent changes, you should use the
 +
        // AssetRequested event to apply the change when the map is reloaded.
 +
        IAssetDataForMap mapHelper = this.Helper.GameContent.GetPatchHelper(location.map).AsMap();
 +
        mapHelper.PatchMap(
 +
            this.Helper.Content.Load<Map>("assets/unlocked-gate.tmx"),
 +
            targetArea: new Rectangle((int)tile.X - 1, (int)tile.Y - 1, 2, 2)
 +
        );
 +
    }
 +
}
 +
</syntaxhighlight>
   −
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:
+
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#">
 +
internal class ModEntry : Mod
 +
{
 +
    /// <inheritdoc />
 +
    public override void Entry(IModHelper helper)
 +
    {
 +
        GameLocation.RegisterTileAction("Example.ModId_UnlockGate", this.HandleUnlockGate);
 +
    }
   −
<dl style="margin-left: 2em;">
+
    private bool HandleUnlockGate(GameLocation location, string[] args, Farmer player, Microsoft.Xna.Framework.Point point)
<dt>Required fields:</dt>
+
    {
<dd>
+
        const string mailFlag = "Example.ModId_GateUnlocked";
{| class="wikitable"
+
        const string keyId = "Example.ModId_GateKey";
|-
  −
! field
  −
! effect
  −
|-
  −
| <samp>Name</samp>
  −
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for the location context.
  −
|}
  −
</dd>
     −
<dt>Player actions:</dt>
+
        // unlock gate if locked
<dd>
+
        if (!player.mailReceived.Contains(mailFlag))
{| class="wikitable"
+
        {
|-
+
            if (!Game1.player.Items.ContainsId(id, count))
! field
+
            {
! effect
+
                Game1.activeClickableMenu = new DialogueBox("This gate is locked. I wonder where the key is?");
|-
+
                return false;
| <samp>AllowRainTotem</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.
+
 
 +
            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"
 
|-
 
|-
| <samp>RainTotemAffectsContext</samp>
+
! field
| ''(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.
+
! effect
 
|-
 
|-
| <samp>MaxPassOutCost</samp>
+
| <samp>Destinations</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).
+
| The destinations which the player can travel to from minecarts in this network. This consists of a list of model with these fields:
|-
  −
| <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:
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 3,074: Line 3,184:  
|-
 
|-
 
| <samp>Id</samp>
 
| <samp>Id</samp>
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry in the list.
+
| A [[Modding:Common data field types#Unique string ID|unique string ID]] for this destination within the network.
 +
|-
 +
| <samp>DisplayName</samp>
 +
| 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>Mail</samp>
+
| <samp>TargetLocation</samp>
| The [[Modding:Mail data|letter ID]] to add.
+
| The [[#Custom locations|location ID]] for the destination.
 
+
|-
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>TargetTile</samp>
* <samp>{{t|letter id}}_{{t|billed}}_{{t|gender}}</samp>
+
| The destination tile position within the location, specified as a model with <samp>X</samp> and <samp>Y</samp> fields.
* <samp>{{t|letter id}}_{{t|billed}}</samp>
  −
* <samp>{{t|letter id}}</samp>
  −
 
  −
If no match is found in <samp>Data/mail</samp>, the game will send <samp>passedOut2</samp> instead.
  −
 
  −
If the mail ID starts with <samp>passedOut</samp>, <samp>{0}</samp> in the letter text will be replaced with the gold amount lost, and it won't appear in the [[collections]] page.
   
|-
 
|-
| <samp>MaxPassOutCost</samp>
+
| <samp>TargetDirection</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.
+
| 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>
 
| <samp>Condition</samp>
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this entry is active. Defaults to always true.
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this minecart destination is available. Defaults to always available.
 
|-
 
|-
| <samp>SkipRandomSelection</samp>
+
| <samp>Price</samp>
| ''(Optional)'' If true, send this mail if the <samp>Condition</samp> matches instead of choosing a random valid mail. Default false.
+
| ''(Optional)'' The gold price that must be paid each time to use this destination. Default none.
|}
   
|-
 
|-
| <samp>PassOutLocations</samp>
+
| <samp>BuyTicketMessage</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)'' 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.
 
  −
If the selected location doesn't contain a bed and doesn't have the [[#New map properties|<samp>AllowWakeUpWithoutBed</samp> map property]], the player will wake up in the farmhouse instead.
  −
 
  −
This consists of a list of models with these fields:
  −
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>CustomFields</samp>
! effect
+
| ''(Optional)'' The [[#Custom data fields|custom fields]] for this entry.
 +
|}
 
|-
 
|-
| <samp>Id</samp>
+
| <samp>UnlockCondition</samp>
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry in the list.
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this minecart network is unlocked. Default always enabled.
 
|-
 
|-
| <samp>Location</samp>
+
| <samp>LockedMessage</samp>
| The internal location name.
+
| ''(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>Position</samp>
+
| <samp>ChooseDestinationMessage</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.
+
| ''(Optional)'' A [[Modding:Tokenizable strings|tokenizable string]] for the message shown when listing destinations to choose from. Defaults to a "''Choose destination:''" translation.
 
|-
 
|-
| <samp>Condition</samp>
+
| <samp>BuyTicketMessage</samp>
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this entry is active. Defaults to always applied.
+
| ''(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 no locations are specified or none match, the player will wake up in their bed at home.
+
====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>ReviveLocations</samp>
+
 
| ''(Optional)'' If the player just got knocked out in combat, the location names where they'll wake up.
+
From a C# mod, you can call <code>Game1.currentLocation.ShowMineCartMenu(networkId, excludeDestinationId)</code> which works the same way (except that <samp>networkId</samp> is required).
 +
 
 +
====Example====
 +
This [[Modding:Content Patcher|Content Patcher]] content pack adds the [[Railroad]] as a minecart destination, complete with a map edit adding a decorative minecart. It is available after the [[Random Events|Earthquake]] has occurred and minecarts have been unlocked.
 +
 
 +
{{#tag:syntaxhighlight|<nowiki>
 +
{
 +
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
 +
    "Changes": [
 +
        // add minecart destination
 +
        {
 +
            "Action": "EditData",
 +
            "Target": "Data/Minecarts",
 +
            "TargetField": [ "Default", "Destinations" ], // for the "Default" network, edit the "Destinations" field
 +
            "Entries": {
 +
                "Railroad": {
 +
                    "Id": "Railroad",
 +
                    "DisplayName": "[LocationName Railroad]",
 +
                    "Condition": "LOCATION_ACCESSIBLE Railroad",
 +
 
 +
                    "TargetLocation": "Railroad",
 +
                    "TargetTile": { "X": 16, "Y": 39 },
 +
                    "TargetDirection": "down",
 +
                }
 +
            }
 +
        },
 +
 
 +
        // add decorative minecart
 +
        {
 +
            "Action": "EditMap",
 +
            "Target": "Maps/Railroad",
 +
            "FromFile": "assets/Custom_Railroad_Minecart.tmx",
 +
            "ToArea": { "X": 15, "Y": 35, "Width": 4, "Height": 5 }
 +
        }
 +
    ]
 +
}</nowiki>|lang=javascript}}
 +
 
 +
===Custom passive festivals===
 +
{{/doc status|[[Modding:Festival data]] or a new doc page|done=false}}
 +
 
 +
You can now add or modify passive festivals by editing the <samp>Data/PassiveFestivals</samp> asset.
 +
 
 +
(A ''passive festival'' is a [[festivals|festival]] like the [[Night Market]]. They replace a location for a period of time, the player can enter/leave them anytime, and time continues passing while at the festival.)
   −
This consists of a list of models with these fields:
+
====Data format====
 +
The <samp>Data/PassiveFestivals</samp> asset consists of a string → model lookup, where...
 +
* The key is a [[Modding:Common data field types#Unique string ID|unique string ID]] for the festival.
 +
* The value is a model with the fields listed below.
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 3,133: Line 3,280:  
! effect
 
! effect
 
|-
 
|-
| <samp>Id</samp>
+
| <samp>DisplayName</samp>
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry in the list.
+
| A [[Modding:Tokenizable strings|tokenizable string]] for the display name shown on the [[calendar]].
 
|-
 
|-
| <samp>Location</samp>
+
| <samp>Season</samp>
| The internal location name.
+
| The [[season]] when the festival becomes active.
 
|-
 
|-
| <samp>Position</samp>
+
| <samp>StartDay</samp><br /><samp>EndDay</samp>
| The tile position within the location, specified as an object with <samp>X</samp> and <samp>Y</samp> fields.
+
| The days of month when the festival becomes active.
 +
|-
 +
| <samp>StartTime</samp>
 +
| The time of day when the festival opens each day.
 +
|-
 +
| <samp>StartMessage</samp>
 +
| 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.
 +
 
 +
This is specified as a string → string lookup, where the key is the original location to replace and the value is the new location. Both use the internal location name, as shown by the {{nexus mod|679|Debug Mode}} mod. For example, this swaps the <samp>Beach</samp> location with <samp>BeachNightMarket</samp> during the [[Night Market]]:
 +
<syntaxhighlight lang="js">
 +
"MapReplacements": {
 +
    "Beach": "BeachNightMarket"
 +
}
 +
</syntaxhighlight>
 
|-
 
|-
 
| <samp>Condition</samp>
 
| <samp>Condition</samp>
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this entry is active. Defaults to always applied.
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether the festival is enabled (subject to the other fields like <samp>StartDay</samp> and <samp>EndDay</samp>). Defaults to always enabled.
 +
|-
 +
| <samp>ShowOnCalendar</samp>
 +
| ''(Optional)'' Whether the festival appears on the [[calendar]], using the same iridium-star icon as the [[Calendar#Winter|Night Market]]. Default true.
 +
|-
 +
| <samp>DailySetupMethod</samp><br /><samp>CleanupMethod</samp>
 +
| ''(Optional)'' A C# method which applies custom logic when the day starts (<samp>DailySetupMethod</samp>) and/or overnight after the last day of the festival (<samp>CleanupMethod</samp>).
 +
 
 +
These must be specified in the form <samp>{{t|full type name}}: {{t|method name}}</samp> (like <samp>ExampleMod.Namespace.Type, ExampleMod: MethodName</samp>). The methods must be static, take zero arguments, and return void.
 +
|-
 +
| <samp>CustomFields</samp>
 +
| The [[#Custom data fields|custom fields]] for this entry.
 
|}
 
|}
   −
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.
+
====NPC schedules====
 
+
When a passive festival is active, NPCs will check for [[Modding:Schedule data|a schedule entry]] in this order:
If no locations are specified or none match, the player will wake up at [[Harvey's Clinic|Harvey's clinic]].
  −
|}
  −
</dd>
     −
<dt>Season:</dt>
  −
<dd>
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! syntax
! effect
+
! summary
 +
|-
 +
| <samp>{{t|festival ID}}_{{t|festival day}}</samp>
 +
| Applies on the given date. The {{t|festival day}} is relative, so <samp>1</samp> matches the festival <samp>StartDay</samp>.<br /><small>Example: <samp>NightMarket_3</samp> or <samp>marriage_NightMarket_3</samp></small>
 
|-
 
|-
| <samp>SeasonOverride</samp>
+
| <samp>{{t|festival ID}}</samp>
| ''(Optional)'' The season which is always active for locations within this context (one of <samp>spring</samp>, <samp>summer</samp>, <samp>fall</samp>, or <samp>winter</samp>). For example, setting <samp>summer</samp> will make it always [[summer]] there regardless of the calendar season. If not set, the calendar season applies.
+
| Applies if there's no date-specific entry.<br /><small>Example: <samp>NightMarket</samp> or <samp>marriage_NightMarket</samp></small>
 
|}
 
|}
</dd>
     −
<dt>Weather:</dt>
+
If the NPC is married to a player, they'll add a <samp>marriage_</samp> prefix to the keys (like <samp>marriage_{{t|festival ID}}_{{t|festival day}}</samp>) and ignore any entry without the prefix.
<dd>
+
 
{| class="wikitable"
+
===Custom weather===
|-
+
{{/doc status|[[Modding:Weather data]]|done=false}}
! field
+
 
! effect
+
You can now change the weather algorithm by editing [[#Custom location contexts|location context data]], and (with a C# mod) implement custom weathers.
|-
+
 
| <samp>WeatherConditions</samp>
+
Fields like <samp>Game1.weather</samp> and <samp>Game1.weatherForTomorrow</samp> are now strings to support custom mod weather IDs. The change for vanilla weather has no effect on Content Patcher packs, since the new weather IDs match the ones Content Patcher was using before (i.e. <samp>Sun</samp>, <samp>Rain</samp>, <samp>Snow</samp>, <samp>Storm</samp>, and <samp>Wind</samp>). C# mods may also see a <samp>Festival</samp> weather, while Content Patcher packs will see <samp>Sun</samp> for it. The constants like <samp>Game1.weather_sunny</samp> have the new string values (with new constants like <samp>Game1.legacy_weather_sunny</samp> for the legacy values).
| ''(Optional)'' The weather logic to apply for locations in this context (ignored if <samp>CopyWeatherFromLocation</samp> is set). Defaults to always sunny. If multiple are specified, the first matching weather is applied.
+
 
 +
The 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]].
   −
This consists of a list of models with these fields:
+
====Building construction====
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! property
! effect
+
! explanation
 
|-
 
|-
| <samp>Id</samp>
+
| <samp>CanBuildHere T</samp><br />''(valid in any outdoor location)''
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry in the list.
+
| 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>Weather</samp>
+
| <samp>BuildConditions {{t|query}}</samp><br />''(valid in any outdoor location)''
| The [[#Custom weather|weather ID]] to set.
+
| If <samp>CanBuildHere</samp> is set, an optional [[Modding:Game state queries|game state query]] which indicates whether building is allowed currently.
 
|-
 
|-
| <samp>Condition</samp>
+
| <samp>LooserBuildRestrictions T</samp><br />''(valid in any outdoor location)''
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether to apply the weather. Defaults to always applied.
+
| 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>CopyWeatherFromLocation</samp>
+
| <samp>ValidBuildRect {{t|x}} {{t|y}} {{t|width}} {{t|height}}</samp><br />''(valid in any outdoor location)''
| ''(Optional)'' The <samp>Name</samp> (i.e. unique ID) of the location context from which to inherit weather.
+
| The tile area within the map where buildings may be placed. If omitted, buildings may be placed in any open space in the map.
 
|}
 
|}
   −
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.
+
====Crops====
 
  −
</dd>
  −
 
  −
<dt>Music:</dt>
  −
<dd>
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! property
! effect
+
! explanation
 
|-
 
|-
| <samp>DefaultMusic</samp>
+
| <samp>AllowGiantCrops T</samp>
| ''(Optional)'' The [[#Custom audio|cue ID]] for the music to play when the player is in the location, unless overridden by a <samp>Music</samp> map property. Despite the name, this has a higher priority than the seasonal music fields below. Ignored if omitted.
+
| 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>DefaultMusicCondition</samp>
+
| <samp>DirtDecayChance {{t|chance}}</samp>
| ''(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.
+
| The probability that each dirt tile will disappear overnight if it doesn't contain a crop, as a value between 0 (never) and 1 (always). Defaults to 0 (greenhouses), 0.1 (farms), and 1 (anywhere else).
 +
|}
 +
 
 +
====Farmhouse interior====
 +
{| class="wikitable"
 
|-
 
|-
| <samp>DefaultMusicDelayOneScreen</samp>
+
! property
| ''(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.
+
! explanation
 
|-
 
|-
| <samp>Music</samp>
+
| <samp>FarmHouseStarterGift [{{t|id}} {{o|count}}]+</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.
+
| The items that should appear in the initial gift box placed in the farmhouse when the save is created. This consists of one or more pairs of item ID (which can be qualified or unqualified) and count. The count is optional on the last entry.
 +
 
 +
For example, this will add 10 pufferfish (object 128) and a blobfish mask (hat 56):
 +
<pre>FarmHouseStarterGift (O)128 10 (H)56 1</pre>
 +
 
 +
If omitted, the default items (usually a 15 parsnip seeds) are added instead.
 +
|}
   −
This consists of a list of models with these fields:
+
====Warps & map positions====
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! property
! effect
+
! explanation
 
|-
 
|-
| <samp>Id</samp>
+
| <samp>AllowWakeUpWithoutBed {{t|allow}}</samp>
| ''(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.
+
| 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>Track</samp>
+
| <samp>DefaultWarpLocation {{t|x}} {{t|y}}</samp><br />''(valid in any location)''
| The [[Modding:Migrate to Stardew Valley 1.6#Custom audio|audio track ID]] to play.
+
| 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>Condition</samp>
+
| <samp>PetBowlLocation {{t|x}} {{t|y}}</samp><br />''(valid in the farm)''
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this entry applies. Default true.
+
| The default position of the pet bowl
|}
   
|-
 
|-
| <samp>DayAmbience</samp><br /><samp>NightAmbience</samp>
+
| <samp>SpouseRoomPosition {{t|x}} {{t|y}}</samp><br />''(valid in farmhouse)''
| ''(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.
+
| The top-left position at which to place the [[Marriage#Spouse Rooms|spouse room]].
 
|-
 
|-
| <samp>PlayRandomAmbientSounds</samp>
+
| <samp>TravelingCartPosition {{t|x}} {{t|y}}</samp><br />''(valid in the forest)''
| ''(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.
+
| The top-left position at which to place the [[Traveling Cart]]. This is the top-left corner of the collision box, so the roof will extend two tiles above this tile.
 
|}
 
|}
</dd>
     −
<dt>Advanced:</dt>
+
===Other map property changes===
<dd>
+
{{/doc status|[[Modding:Maps]]|done=false}}
 +
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! map property
! effect
+
! changes
 +
|-
 +
| <samp>Arch</samp><br /><samp>asdf</samp><br /><samp>Debris</samp><br /><samp>Fish</samp>
 +
| Removed (these were unused).
 
|-
 
|-
| <samp>CustomFields</samp>
+
| <samp>FarmHouseFlooring</samp><br /><samp>FarmHouseFurniture</samp><br /><samp>FarmHouseStarterSeedsPosition</samp><br /><samp>FarmHouseWallpaper</samp>
| The [[#Custom data fields|custom fields]] for this entry.
+
| These now work independently. For example, you can now use <samp>FarmHouseFlooring</samp> without needing to set <samp>FarmHouseFurniture</samp> too.
|}
  −
</dd>
  −
</dl>
  −
 
  −
===Custom garbage cans===
  −
====Format====
  −
You can now add or edit [[Garbage Can|garbage cans]] on any map by editing the new <samp>Data/GarbageCans</samp> asset (see examples below).
  −
 
  −
The asset consists of a data model with these fields:
  −
 
  −
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>Music</samp>
! effect
+
| Deprecated; use the music fields in [[#Custom locations|<samp>Data/Locations</samp>]] instead. This property is only applied if the location has no music in <samp>Data/Locations</samp>. This was removed from all vanilla maps.
 
|-
 
|-
| <samp>DefaultBaseChance</samp>
+
| <samp>NPCWarp</samp><br /><samp>Warp</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.
+
| 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>BeforeAll</samp><br /><samp>AfterAll</samp>
+
| <samp>Stumps</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).
+
| Now works in all locations.
 
|-
 
|-
| <samp>GarbageCans</samp>
+
| <samp>UniquePortrait</samp><br /><samp>UniqueSprite</samp>
| The data for individual garbage cans. This consists of a string → model lookup with these fields:
+
| Deprecated; use [[#Custom NPC appearance|custom NPC appearances]] instead. These properties will override NPC appearances. This was removed from all vanilla maps.
 +
|}
 +
 
 +
===Tile property changes===
 +
{{/doc status|[[Modding:Maps]]|done=false}}
    +
<ul>
 +
<li>You can now override a tile index property by setting it as a tile property.</li>
 +
<li>Added new [[Modding:Maps|tile properties]]:
 
{| class="wikitable"
 
{| class="wikitable"
 +
! layer
 +
! property
 +
! explanation
 
|-
 
|-
! field
+
| <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]].
 +
|}
 +
</li>
 +
<li>Added new <samp>Action</samp> [[Modding:Maps|tile properties]]:
 +
{| class="wikitable"
 
|-
 
|-
| ''entry key''
+
! layer
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this garbage can.
+
! property
 +
! explanation
 
|-
 
|-
| <samp>BaseChance</samp>
+
| <samp>Buildings</samp>
| ''(Optional)'' If set, overrides the root <samp>DefaultBaseChance</samp> field for this garbage can. Defaults to <samp>DefaultBaseChance</samp>.
+
| <samp>Action BuildingSilo</samp>
 +
| If a building covers this tile, enables [[silo]] interactions on this tile subject to the building's <samp>HayCapacity</samp> field in <samp>Data/Buildings</samp>.
 
|-
 
|-
| <samp>Items</samp>
+
| <samp>Buildings</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.
+
| <samp>Action BuildingToggleAnimalDoor</samp>
 
+
| If a building covers this tile, opens or closes its animal door.
This consists of a list of models with these fields:
  −
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>Buildings</samp>
! effect
+
| <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.
 
|-
 
|-
| ''common fields''
+
| <samp>Buildings</samp>
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields supported by garbage cans.
+
| <samp>Action Forge</samp>
 
+
| Opens the [[Forge]] menu.
If set to an [[Modding:Item queries|item query]] which returns multiple items, one of them will be selected at random.
   
|-
 
|-
| <samp>IgnoreBaseChance</samp>
+
| <samp>Buildings</samp>
| ''(Optional)'' Whether this item can spawn even if the <samp>BaseChance</samp> probability check didn't pass. Default false.
+
| <samp>Action None</samp>
 +
| Does nothing. This is used to mark the tile interactive if the click will be handled separately.
 
|-
 
|-
| <samp>IsMegaSuccess</samp>
+
| <samp>Buildings</samp>
| ''(Optional)'' Whether to treat this item as a 'mega success' if it's selected, which plays a special <samp>crit</samp> sound and bigger animation. Default false.
+
| <samp>Action ObeliskWarp {{t|location name}} {{t|x}} {{t|y}} {{o|whether to dismount}}</samp>
 +
| Warps the player to the specified location name and position with the [[Warp Totem|Obelisk]] animation/sound effects.
 
|-
 
|-
| <samp>IsDoubleMegaSuccess</samp>
+
| <samp>Buildings</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.
+
| <samp>Action OpenShop {{t|shop id}} {{o|from direction}} {{o|open time}} {{o|close time}} {{o|owner tile area}}</samp>
 +
| Open the [[#Custom shops|shop]] with the given {{t|shop id}}. All arguments besides the ID are optional:
 +
* {{o|from direction}}: if specified, the player must be standing in this direction relative to the shop (one of <samp>down</samp>, <samp>up</samp>, <samp>left</samp>, <samp>right</samp>, or <samp>none</samp>). Setting this to <samp>none</samp> disables the requirement. The default for most vanilla shops is <samp>down</samp>.
 +
* {{o|open time}} and {{o|close time}}: the start & end times in 26-hour format when the shop is available. Interacting with the tile outside those times does nothing.
 +
* {{o|owner tile area}}: if specified, the tile area which must contain one of the shop owners for the shop to be available. For a custom shop, these are defined by its <samp>Owners</samp> field. This can be specified in two forms: <samp>{{t|x}} {{t|y}}</samp> for a single tile, or <samp>{{t|x}} {{t|y}} {{t|width}} {{t|height}}</samp> for a multi-tile area.
 
|-
 
|-
| <samp>AddToInventoryDirectly</samp>
+
| <samp>Buildings</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.
+
| <samp>Action PlayEvent {{t|event id}} {{o|check preconditions}} {{o|skip if seen}} {{o|fallback action}}</samp>
|-
+
| Immediately start an [[Modding:Event data|event]], subject to the conditions:
| <samp>CreateMultipleDebris</samp>
+
* {{o|check preconditions}}: whether to ignore the action if the [[Modding:Event data#Event preconditions|event's preconditions]] don't match (one of <samp>true</samp> or <samp>false</samp>). Default true.
| ''(Optional)'' 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.
+
* {{o|skip if seen}}: whether to ignore the action if the player has already seen the given event. Default true.
|}
  −
|}
     −
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.
+
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>
 +
<li>Added new <samp>TouchAction</samp> [[Modding:Maps|tile properties]]:
 +
{| class="wikitable"
 +
|-
 +
! layer
 +
! property
 +
! explanation
 +
|-
 +
| <samp>Back</samp>
 +
| <samp>TouchAction PlayEvent {{t|event id}} {{o|check preconditions}} {{o|skip if seen}} {{o|fallback action}}</samp>
 +
| Equivalent to <samp>Action PlayEvent</samp>, but activated on touch. Note that {{o|fallback action}} is an <samp>Action</samp> tile property, ''not'' a <samp>TouchAction</samp> tile property.
 +
|}</li>
 +
<li>Changed existing tile properties:
 +
{| class="wikitable"
 +
|-
 +
! layer
 +
! property
 +
! reason
 +
|-
 +
|rowspan="4"| <samp>Back</samp>
 +
| <samp>NoSpawn</samp>
 +
| Added <samp>NoSpawn false</samp> form, which disables any previous <samp>NoSpawn</samp> property on the tile. For example, this can be used to enable spawning on a tile which has a <samp>NoSpawn</samp> tile index property.
 +
|-
 +
| <samp>TouchAction Bus</samp>
 +
| Removed. This wasn't used by the game or mods.
 +
|-
 +
| <samp>TouchAction Emote</samp>
 +
| Fixed error if the specified NPC isn't found.
 +
|-
 +
| <samp>Treasure</samp>
 +
| Added <samp>Treasure Item {{t|item ID}}</samp> form which accepts a [[#Custom items|qualified or unqualified item ID]].
 +
|-
 +
|rowspan="2"| <samp>Buildings</samp>
 +
| <samp>Action ItemChest</samp><br /><samp>Action Minecart</samp><br /><samp>Action RemoveChest</samp>
 +
| Removed. These weren't used by the game or mods.
 
|-
 
|-
| <samp>CustomFields</samp>
+
| <samp>Action Kitchen</samp>
| The [[#Custom data fields|custom fields]] for this entry.
+
| Now works in any location (including those without a fridge).
 
|}
 
|}
 +
</li>
 +
</ul>
   −
====Example new garbage can====
+
===Other location/map changes===
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>:
+
{{/doc status|[[Modding:Maps]] and other pages as needed|done=false}}
   −
{{#tag:syntaxhighlight|<nowiki>
+
* 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]].
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
+
** Fixed crash on new-save screen if the farm type's tooltip has no description.
    "Changes": [
+
* General location data:
        {
+
** All locations can now have animals. The <samp>IAnimalLocation</samp> is now obsolete and implemented by <samp>GameLocation</samp>.
            "Action": "EditData",
+
** Added new [[Modding:Fish data|fishing areas]] to simplify compatibility between fish & map mods (specifically for hilltop farm, wilderness farm, town, and desert).
            "Target": "Data/GarbageCans",
+
** 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.
            "TargetField": [ "GarbageCans" ],
+
** 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.
            "Entries": {
+
** Game logic which checks tile indexes is now more fault-tolerant, so it won't crash if an expected tile was edited.
                "{{ModId}}_Carpenter": {
+
** Finished migrating <samp>DecoratableLocation</samp> flooring/wallpaper areas to string IDs (started in Stardew Valley 1.5.5).
                    "Items": [
+
* General map changes:
                        // 25% chance of pufferfish
+
** 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.
                            "ID": "{{ModId}}_Pufferfish",
+
* Location context data:
                            "Condition": "RANDOM 0.25",
+
** Building interiors now inherit their parent's location context by default.
                            "ItemId": "(O)128"
+
** 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).
                        // else guaranteed random House Plant item
+
** Removed the <samp>Name</samp> field in <samp>Data/LocationContexts</samp>, which duplicated the ID.
                        {
+
<ul>
                            "ID": "{{ModId}}_RandomHousePlant",
+
<li>Added methods to simplify common operations:
                            "ItemID": "RANDOM_ITEMS (F) 1376 1390"
+
{| class="wikitable"
                        }
+
|-
                    ]
+
! type
                }
+
! method
            }
+
! effect
        }
+
|-
    ]
+
|rowspan="7"| <samp>Building</samp>
}</nowiki>|lang=javascript}}
+
| <samp>GetParentLocation</samp>
 
+
| Get the location which contains this building.
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.
+
|-
 
+
| <samp>IsInCurrentLocation</samp>
====Example change for existing garbage can====
+
| Get whether the building is in the same location as the current player.
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.
+
|-
 
+
| <samp>HasIndoors</samp>
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.
+
| Get whether the building has an interior location.
 
+
|-
{{#tag:syntaxhighlight|<nowiki>
+
| <samp>GetIndoors</samp>
{
+
| Get the location within this building, if applicable.
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
+
|-
    "Changes": [
+
| <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>).
            "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
+
| <samp>GetIndoorsName</samp>
! code in 1.5.6
+
| Get the unique name of the location within this building, if applicable.
! code in 1.6
   
|-
 
|-
| check if a garbage can was searched
+
| ...
| <syntaxhighlight lang="js">
+
| ''see also [[#Other building changes|other building changes]] for non-location methods.''
Town town = (Town)Game1.getLocationFromName("Town");
  −
if (town.garbageChecked[5])
  −
  ...
  −
</syntaxhighlight>
  −
| <syntaxhighlight lang="js">
  −
if (Game1.netWorldState.Value.CheckedGarbage.Contains("Saloon"))
  −
  ...
  −
</syntaxhighlight>
   
|-
 
|-
| mark a garbage can searched
+
|rowspan="7"|<samp>Cabin</samp><br /><samp>FarmHouse</samp>
| <syntaxhighlight lang="js">
+
| <samp>GetCellar</samp>
Town town = (Town)Game1.getLocationFromName("Town");
+
| Get the [[cellar]] location linked to this cabin, if any.
town.garbageChecked[5] = true;
  −
</syntaxhighlight>
  −
| <syntaxhighlight lang="js">
  −
Game1.netWorldState.Value.CheckedGarbage.Add("Saloon");
  −
</syntaxhighlight>
  −
|}
  −
 
  −
To migrate former vanilla trash can IDs:
  −
{| class="wikitable"
   
|-
 
|-
! position
+
| <samp>CanAssignFarmhand</samp><br /><samp>AssignFarmhand</samp>
! ID in 1.5.6
+
| ''(Cabin only)'' Check whether the cabin is available to assign to a farmhand, or perform the assignment.
! ID in 1.6
   
|-
 
|-
| Near [[Jodi]] and [[Kent]]'s house
+
| <samp>HasOwner</samp>
| <code>0</code>
+
| Get whether the home has an assigned player, regardless of whether they've finished creating their character.
| <code>JodiAndKent</code>
   
|-
 
|-
| Near [[Emily]] and [[Haley]]'s house
+
| <samp>OwnerId</samp>
| <code>1</code>
+
| Get the unique ID of the player who owns this home, if any.
| <code>EmilyAndHaley</code>
   
|-
 
|-
| Near [[Lewis]]' house
+
| <samp>IsOwnedByCurrentPlayer</samp>
| <code>2</code>
+
| Get whether the cabin belongs to the current player.
| <code>Mayor</code>
   
|-
 
|-
| Near [[Museum]]
+
| <samp>IsOwnerActivated</samp>
| <code>3</code>
+
| Get whether the home has an assigned player and they've finished creating their character.
| <code>Museum</code>
   
|-
 
|-
| Near [[Blacksmith|Clint's blacksmith]]
+
| <samp>HasNpcSpouse</samp>
| <code>4</code>
+
| 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>.
| <code>Blacksmith</code>
   
|-
 
|-
| Near [[The Stardrop Saloon|the Saloon]]
+
|rowspan="2"| <samp>Farm</samp>
| <code>5</code>
+
| <samp>GetStarterFarmhouseLocation</samp>
| <code>Saloon</code>
+
| Get the default tile position for the farmhouse. (See also <samp>farm.GetMainFarmHouseEntry()</samp>.)
 
|-
 
|-
| Near [[Evelyn]] and [[George]]'s house
+
| <samp>GetStarterPetBowlLocation</samp>
| <code>6</code>
+
| Get the default tile position for the pet bowl.
| <code>Evelyn</code>
   
|-
 
|-
| Near [[JojaMart]]
+
|rowspan="19"| <samp>GameLocation</samp>
| <code>7</code>
+
| <samp>AddDefaultBuildings</samp>
| <code>JojaMart</code>
+
| 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).
|}
     −
===Custom map actions===
+
This replaces the former <samp>farm.AddModularShippingBin()</samp> method.
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.
+
|-
 +
| <samp>GetFridge</samp><br /><samp>GetFridgePosition</samp>
 +
| Get the fridge's chest or tile position, if the location has one.
 +
|-
 +
| <samp>GetSeason</samp><br /><samp>GetSeasonIndex</samp><br /><samp>GetSeasonKey</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>GetWeather</samp><br /><samp>IsDebrisWeatherHere</samp><br /><samp>IsLightningHere</samp><br /><samp>IsRainingHere</samp><br /><samp>IsSnowingHere</samp>
 +
| Get the current weather in this location's context, regardless of whether the player is indoors and sheltered from it.
 +
|-
 +
| <samp>InDesertContext</samp><br /><samp>InIslandContext</samp><br /><samp>InValleyContext</samp>
 +
| Get whether this location is within the <samp>Island</samp> or <samp>Default</samp> location context respectively.
 +
|-
 +
| <samp>IsActiveLocation</samp>
 +
| Get whether this location is actively synced to the current player (see [[Modding:Modder Guide/Game Fundamentals#Farmhand shadow world|farmhand shadow world]]).
 +
|-
 +
| <samp>IsTemporary</samp>
 +
| 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>GetLocationContextId</samp>
 +
| Get the ID of the location context in <samp>Data/LocationContexts</samp> which contains this building.
 +
|-
 +
| <samp>GetContainingBuilding</samp>
 +
| Get the building instance which contains this location (like the cabin for a cabin interior), if applicable.
 +
|-
 +
| <samp>GetParentLocation</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.
 +
|-
 +
| <samp>GetRootLocation</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>GetInstancedBuildingInteriors</samp>
 +
| Get all building interiors within this location which are instanced to the building (i.e. not in <samp>Game1.locations</samp> separately).
 +
|-
 +
| <samp>GetMapPropertySplitBySpaces</samp><br /><samp>GetTilePropertySplitBySpaces</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.
   −
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:
+
For example:
 
<syntaxhighlight lang="c#">
 
<syntaxhighlight lang="c#">
internal class ModEntry : Mod
+
string[] fields = Game1.currentLocation.GetMapPropertySplitBySpaces("ScreenshotRegion");
{
+
</syntaxhighlight>
    /// <inheritdoc />
+
|-
    public override void Entry(IModHelper helper)
+
| <samp>HasMapPropertyWithValue</samp>
    {
+
| Get whether a map property is defined and has a non-empty value.
        GameLocation.RegisterTouchAction("Example.ModId_UnlockGate", this.HandleUnlockGate);
  −
    }
     −
    private void HandleUnlockGate(GameLocation location, string[] args, Farmer player, Vector2 tile)
+
For example:
    {
+
<syntaxhighlight lang="c#">
        const string mailFlag = "Example.ModId_GateUnlocked";
+
bool canUseCasks = Game1.currentLocation.HasMapPropertyWithValue("CanCaskHere");
        const string keyId = "Example.ModId_GateKey";
+
</syntaxhighlight>
 +
|-
 +
| <samp>StoreHayInAnySilo</samp>
 +
| Add hay to any silo with free space (preferring silos in the current location, then the farm, then anywhere).
 +
|-
 +
| <samp>TryGetMapProperty</samp>
 +
| Get a map property value as a string, if it's defined.
   −
        // unlock gate if locked
+
For example:
        if (!player.mailReceived.Contains(mailFlag))
+
<syntaxhighlight lang="c#">
        {
+
if (this.TryGetMapProperty("Warps", out string warps))
            if (!Game1.player.Items.ContainsId(id, count))
+
{
            {
+
    // ...
                Game1.activeClickableMenu = new DialogueBox("This gate is locked. I wonder where the key is?");
  −
                return;
  −
            }
  −
 
  −
            player.removeFirstOfThisItemFromInventory(keyId);
  −
            player.mailReceived.Add(mailFlag);
  −
        }
  −
 
  −
        // apply open-gate map edit
  −
        // NOTE: this is a quick example which changes the location's current map. If another mod reloads the map
  −
        // (e.g. a content pack editing it), the change will be lost. For persistent changes, you should use the
  −
        // AssetRequested event to apply the change when the map is reloaded.
  −
        IAssetDataForMap mapHelper = this.Helper.GameContent.GetPatchHelper(location.map).AsMap();
  −
        mapHelper.PatchMap(
  −
            this.Helper.Content.Load<Map>("assets/unlocked-gate.tmx"),
  −
            targetArea: new Rectangle((int)tile.X - 1, (int)tile.Y - 1, 2, 2)
  −
        );
  −
    }
   
}
 
}
 
</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.
   −
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:
+
For example:
 
<syntaxhighlight lang="c#">
 
<syntaxhighlight lang="c#">
internal class ModEntry : Mod
+
if (!this.TryGetMapPropertyAs("MailboxLocation", out Point position))
 
{
 
{
     /// <inheritdoc />
+
     position = new Point(68, 16); // default value
    public override void Entry(IModHelper helper)
+
}
    {
+
</syntaxhighlight>
        GameLocation.RegisterTileAction("Example.ModId_UnlockGate", this.HandleUnlockGate);
+
|-
    }
+
| <samp>removeObjectsAndSpawned</samp>
 
+
| Remove all objects, bushes, resource clumps, and terrain features within a tile area.
    private bool HandleUnlockGate(GameLocation location, string[] args, Farmer player, Microsoft.Xna.Framework.Point point)
+
|-
    {
+
| <samp>OnBuildingConstructed</samp><br /><samp>OnBuildingMoved</samp><br /><samp>OnBuildingDemolished</samp>
        const string mailFlag = "Example.ModId_GateUnlocked";
+
| These methods are called for all players when any player constructs, moves, or demolishes a building.
        const string keyId = "Example.ModId_GateKey";
+
|-
 
+
|rowspan="3"| <samp>LibraryMuseum</samp>
        // unlock gate if locked
+
| <samp>HasDonatedArtifacts()</samp>
        if (!player.mailReceived.Contains(mailFlag))
+
| Get whether any items have been donated to the [[museum]].
        {
+
|-
            if (!Game1.player.Items.ContainsId(id, count))
+
| <samp>HasDonatedArtifactAt(tile)</samp>
            {
+
| Get whether any donated item is currently placed at the given tile position within the [[museum]].
                Game1.activeClickableMenu = new DialogueBox("This gate is locked. I wonder where the key is?");
+
|-
                return false;
+
| <samp>HasDonatedArtifact(itemId)</samp>
            }
+
| Get whether an artifact with the given qualified or unqualified item ID has been donated to the [[museum]].
 +
|-
 +
|rowspan="2"| <samp>MineShaft</samp>
 +
| <samp>GetLevelName</samp>
 +
| Get the location name for a generated [[The Mines|mine]] or [[Skull Cavern]] level.
   −
            player.removeFirstOfThisItemFromInventory(keyId);
+
For example:
            player.mailReceived.Add(mailFlag);
+
<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.
   −
        // apply open-gate map edit
+
For example:
        // NOTE: this is a quick example which changes the location's current map. If another mod reloads the map
+
<syntaxhighlight lang="c#">
        // (e.g. a content pack editing it), the change will be lost. For persistent changes, you should use the
+
string locationName = "UndergroundMine10";
        // AssetRequested event to apply the change when the map is reloaded.
+
bool isMine = MineShaft.IsGeneratedLevel(locationName, out int level); // returns true, 10
        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>
 
</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>
 +
* 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.
   −
===Custom map layers===
+
==What's new for buildings==
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.
+
===Custom buildings===
 +
{{/doc status|[[Modding:Blueprint data]]|done=false}}
   −
This only affects layer rendering. Tile properties must still be set on the original layers.
+
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 [[Modding:Common data field types#Unique string ID|unique string ID]] for the building type.
===Custom minecarts===
  −
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.
 
* The value is a model with the fields listed below.
    +
====Required fields====
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 3,561: Line 3,793:  
! effect
 
! effect
 
|-
 
|-
| <samp>Destinations</samp>
+
| <samp>Name</samp><br /><samp>Description</samp>
| The destinations which the player can travel to from minecarts in this network. This consists of a list of model with these fields:
+
| A [[Modding:Tokenizable strings|tokenizable string]] for the display name and description (e.g. shown in the construction menu).
 +
|-
 +
| <samp>Texture</samp>
 +
| The asset name for the texture under the game's Content folder.
 +
|}
 +
 
 +
====Construction====
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 3,568: Line 3,806:  
! effect
 
! effect
 
|-
 
|-
| <samp>Id</samp>
+
| <samp>Builder</samp>
| A [[Modding:Common data field types#Unique string ID|unique string ID]] for this destination within the network.
+
| ''(Optional)'' The NPC from whom you can request construction. The vanilla values are [[Carpenter's Shop|<samp>Robin</samp>]] and [[Wizard's Tower#Buildings|<samp>Wizard</samp>]], but you can specify a different name if a C# mod opens a construction menu for them. Defaults to <samp>Robin</samp>. If omitted, it won't appear in any menu.
 
|-
 
|-
| <samp>DisplayName</samp>
+
| <samp>BuildCost</samp>
| 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]]).
+
| ''(Optional)'' The gold cost to construct the building. Defaults to {{price|0}}.
 
|-
 
|-
| <samp>TargetLocation</samp>
+
| <samp>BuildMaterials</samp>
| The [[#Custom locations|location ID]] for the destination.
+
| ''(Optional)'' The materials you must provide to start construction, as a list of models with these fields:
 +
{| class="wikitable"
 
|-
 
|-
| <samp>TargetTile</samp>
+
! field
| The destination tile position within the location, specified as a model with <samp>X</samp> and <samp>Y</samp> fields.
+
! effect
 
|-
 
|-
| <samp>TargetDirection</samp>
+
| <samp>Id</samp>
| The direction the player should face after arrival (one of <samp>down</samp>, <samp>left</samp>, <samp>right</samp>, or <samp>up</samp>).
+
| ''(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>Condition</samp>
+
| <samp>ItemId</samp>
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this minecart destination is available. Defaults to always available.
+
| The required item ID (qualified or unqualified).
 
|-
 
|-
| <samp>Price</samp>
+
| <samp>Amount</samp>
| ''(Optional)'' The gold price that must be paid each time to use this destination. Default none.
+
| The number of the item required.
 +
|}
 
|-
 
|-
| <samp>BuyTicketMessage</samp>
+
| <samp>BuildDays</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.
+
| ''(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>CustomFields</samp>
+
| <samp>BuildCondition</samp>
| ''(Optional)'' The [[#Custom data fields|custom fields]] for this entry.
+
| ''(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>BuildMenuDrawOffset</samp>
 +
| ''(Optional)'' A pixel offset to apply to the building sprite when drawn in the construction menu. Default none.
 +
|-
 +
| <samp>AdditionalPlacementTiles</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:
 +
{| class="wikitable"
 +
|-
 +
! field
 +
! 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>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"
 +
|-
 +
! field
 +
! 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>UnlockCondition</samp>
+
| <samp>Tile</samp>
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this minecart network is unlocked. Default always enabled.
+
| The tile position at which to place the item, specified as an object with <samp>X</samp> and <samp>Y</samp> fields.
 
|-
 
|-
| <samp>LockedMessage</samp>
+
| <samp>Indestructible</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.
+
| ''(Optional)'' Whether to prevent the player from destroying, picking up, or moving the item. Default false.
 +
|}
 
|-
 
|-
| <samp>ChooseDestinationMessage</samp>
+
| <samp>MagicalConstruction</samp>
| ''(Optional)'' A [[Modding:Tokenizable strings|tokenizable string]] for the message shown when listing destinations to choose from. Defaults to a "''Choose destination:''" translation.
+
| ''(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>BuyTicketMessage</samp>
+
| <samp>AddMailOnBuild</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.
+
| ''(Optional)'' A list of [[Modding:Mail data|letter IDs]] to send to all players when the building is constructed for the first time.
 
|}
 
|}
   −
====Open a minecart menu====
+
====Upgrades====
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>.
+
{| class="wikitable"
 
+
|-
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).
+
! field
 
+
! effect
====Example====
+
|-
This [[Modding:Content Patcher|Content Patcher]] content pack adds the [[Railroad]] as a minecart destination, complete with a map edit adding a decorative minecart. It is available after the [[Random Events|Earthquake]] has occurred and minecarts have been unlocked.
+
| <samp>BuildingToUpgrade</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.
{{#tag:syntaxhighlight|<nowiki>
+
|-
{
+
| <samp>IndoorItemMoves</samp>
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
+
| ''(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:
    "Changes": [
  −
        // add minecart destination
  −
        {
  −
            "Action": "EditData",
  −
            "Target": "Data/Minecarts",
  −
            "TargetField": [ "Default", "Destinations" ], // for the "Default" network, edit the "Destinations" field
  −
            "Entries": {
  −
                "Railroad": {
  −
                    "Id": "Railroad",
  −
                    "DisplayName": "[LocationName Railroad]",
  −
                    "Condition": "LOCATION_ACCESSIBLE Railroad",
  −
 
  −
                    "TargetLocation": "Railroad",
  −
                    "TargetTile": { "X": 16, "Y": 39 },
  −
                    "TargetDirection": "down",
  −
                }
  −
            }
  −
        },
  −
 
  −
        // add decorative minecart
  −
        {
  −
            "Action": "EditMap",
  −
            "Target": "Maps/Railroad",
  −
            "FromFile": "assets/Custom_Railroad_Minecart.tmx",
  −
            "ToArea": { "X": 15, "Y": 35, "Width": 4, "Height": 5 }
  −
        }
  −
    ]
  −
}</nowiki>|lang=javascript}}
  −
 
  −
===Custom passive festivals===
  −
You can now add or modify passive festivals by editing the <samp>Data/PassiveFestivals</samp> asset.
  −
 
  −
(A ''passive festival'' is a [[festivals|festival]] like the [[Night Market]]. They replace a location for a period of time, the player can enter/leave them anytime, and time continues passing while at the festival.)
  −
 
  −
====Data format====
  −
The <samp>Data/PassiveFestivals</samp> asset consists of a string → model lookup, where...
  −
* The key is a [[Modding:Common data field types#Unique string ID|unique string ID]] for the festival.
  −
* The value is a model with the fields listed below.
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 3,663: Line 3,895:  
! effect
 
! effect
 
|-
 
|-
| <samp>DisplayName</samp>
+
| <samp>Id</samp>
| A [[Modding:Tokenizable strings|tokenizable string]] for the display name shown on the [[calendar]].
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the current list.
 
|-
 
|-
| <samp>Season</samp>
+
| <samp>Source</samp>
| The [[season]] when the festival becomes active.
+
| The tile position on which any item will be moved.
 
|-
 
|-
| <samp>StartDay</samp><br /><samp>EndDay</samp>
+
| <samp>Destination</samp>
| The days of month when the festival becomes active.
+
| The tile position to which to move the item.
 
|-
 
|-
| <samp>StartTime</samp>
+
| <samp>Size</samp>
| The time of day when the festival opens each day.
+
| ''(Optional)'' The tile size of the area to move, specified as a model with <samp>X</samp> and <samp>Y</samp> fields. Defaults to a 1×1 area. If this is multiple tiles, the <samp>Source</samp> and <samp>Destination</samp> specify the top-left coordinate of the area.
 +
|}
 
|-
 
|-
| <samp>StartMessage</samp>
+
| <samp>UpgradeSignTile</samp>
| A [[Modding:Tokenizable strings|tokenizable string]] for the in-game [[wikipedia:Pop-up notification|toast notification]] shown when the festival begins each day.
+
| ''(Optional)'' The tile position relative to the top-left corner of the building where the upgrade sign will be placed when Robin is building an upgrade, in the form <samp>"{{t|x}}, {{t|y}}"</samp>. Defaults to approximately <samp>"5, 1"</samp> if the building interior type is <samp>Shed</samp>, else <samp>"0, 0"</samp>.
 
|-
 
|-
| <samp>MapReplacements</samp>
+
| <samp>UpgradeSignHeight</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.
+
| ''(Optional)'' The pixel height of the upgrade sign when Robin is building an upgrade. Defaults to 0.
 +
|}
   −
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]]:
+
====Exterior behavior====
<syntaxhighlight lang="js">
+
{| class="wikitable"
"MapReplacements": {
  −
    "Beach": "BeachNightMarket"
  −
}
  −
</syntaxhighlight>
   
|-
 
|-
| <samp>Condition</samp>
+
! field
| ''(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.
+
! effect
 
|-
 
|-
| <samp>ShowOnCalendar</samp>
+
| <samp>Size</samp>
| ''(Optional)'' Whether the festival appears on the [[calendar]], using the same iridium-star icon as the [[Calendar#Winter|Night Market]]. Default true.
+
| ''(Optional)'' The building's width and height when constructed, measured in tiles. Defaults to a 1 x 1 area.
 
|-
 
|-
| <samp>DailySetupMethod</samp><br /><samp>CleanupMethod</samp>
+
| <samp>CollisionMap</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>).
+
| ''(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.
   −
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.
+
For example, a [[stable]] covers a 2x4 tile area with the front two tiles passable:
|-
+
<pre>XXXX
| <samp>CustomFields</samp>
+
XOOX</pre>
| The [[#Custom data fields|custom fields]] for this entry.
  −
|}
     −
====NPC schedules====
+
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:
When a passive festival is active, NPCs will check for [[Modding:Schedule data|a schedule entry]] in this order:
+
<syntaxhighlight lang="js">
 +
// single line with \n line breaks
 +
"CollisionMap": "XXXX\nXOOX"
   −
{| class="wikitable"
+
// multi-line with optional indentation
 +
"CollisionMap": "
 +
    XXXX
 +
    XOOX
 +
"
 +
</syntaxhighlight>
 
|-
 
|-
! syntax
+
| <samp>HumanDoor</samp>
! summary
+
| ''(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>{{t|festival ID}}_{{t|festival day}}</samp>
+
| <samp>AnimalDoor</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>
+
| ''(Optional)'' The position and size of the door that animals use to enter/exit the building, if the building interior is an animal location, specified as an object with <samp>X</samp>, <samp>Y</samp>, <samp>Width</samp>, and <samp>Height</samp> fields. This is measured in tiles relative to the top-left corner tile. Defaults to disabled.
 +
|-
 +
| <samp>AnimalDoorOpenDuration</samp><br /><samp>AnimalDoorCloseDuration</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.
 
|-
 
|-
| <samp>{{t|festival ID}}</samp>
+
| <samp>AnimalDoorOpenSound</samp><br /><samp>AnimalDoorCloseSound</samp>
| Applies if there's no date-specific entry.<br /><small>Example: <samp>NightMarket</samp> or <samp>marriage_NightMarket</samp></small>
+
| ''(Optional)'' The sound which is played once each time the animal door is opened/closed. Disabled by default.
 
|}
 
|}
   −
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.
+
====Exterior appearance====
 
  −
===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===
  −
: ''Main article: [[Modding:World map]].''
  −
 
  −
[[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===
  −
1.6 adds several new [[Modding:Maps|map properties]].
  −
 
  −
====Building construction====
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! property
+
! field
! explanation
+
! effect
 
|-
 
|-
| <samp>CanBuildHere T</samp><br />''(valid in any outdoor location)''
+
| <samp>SourceRect</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]].
+
| ''(Optional)'' The building's pixel area within the <samp>Texture</samp>, specified as an object with <samp>X</samp>, <samp>Y</samp>, <samp>Width</samp>, and <samp>Height</samp> fields. Defaults to the entire texture.
 
|-
 
|-
| <samp>BuildConditions {{t|query}}</samp><br />''(valid in any outdoor location)''
+
| <samp>Skins</samp>
| If <samp>CanBuildHere</samp> is set, an optional [[Modding:Game state queries|game state query]] which indicates whether building is allowed currently.
+
| ''(Optional)'' The appearances which can be selected from Robin's menu (like stone/plank/log [[cabin]]s), in addition to the default appearance based on <samp>Texture</samp>. This consists of a list of models with these fields:
 +
{| class="wikitable"
 
|-
 
|-
| <samp>LooserBuildRestrictions T</samp><br />''(valid in any outdoor location)''
+
! field
| 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.
+
! effect
 
|-
 
|-
| <samp>ValidBuildRect {{t|x}} {{t|y}} {{t|width}} {{t|height}}</samp><br />''(valid in any outdoor location)''
+
| <samp>Id</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.
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for the skin.
|}
+
|-
 
+
| <samp>Name</samp><br /><samp>Description</samp>
====Crops====
+
| [[Modding:Tokenizable strings|Tokenizable strings]] for the skin's display name and description.
{| class="wikitable"
   
|-
 
|-
! property
+
| <samp>Texture</samp>
! explanation
+
| The asset name for the texture under the game's Content folder.
 
|-
 
|-
| <samp>AllowGiantCrops T</samp>
+
| <samp>Condition</samp>
| 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]]).
+
| ''(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>DirtDecayChance {{t|chance}}</samp>
+
| <samp>BuildDays</samp><br /><samp>BuildCost</samp><br /><samp>BuildMaterials</samp>
| 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).
+
| ''(Optional)'' If set, overrides the equivalent field in the building data.
|}
  −
 
  −
====Farmhouse interior====
  −
{| class="wikitable"
   
|-
 
|-
! property
+
| <samp>ShowAsSeparateConstructionEntry</samp>
! explanation
+
| ''(Optional)'' Whether this skin should be shown as a separate building option in the construction menu (like cabins). Default false.
 
|-
 
|-
| <samp>FarmHouseStarterGift [{{t|id}} {{o|count}}]+</samp>
+
| <samp>Metadata</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.
+
| ''(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.
 
  −
For example, this will add 10 pufferfish (object 128) and a blobfish mask (hat 56):
  −
<pre>FarmHouseStarterGift (O)128 10 (H)56 1</pre>
  −
 
  −
If omitted, the default items (usually a 15 parsnip seeds) are added instead.
   
|}
 
|}
  −
====Warps & map positions====
  −
{| class="wikitable"
   
|-
 
|-
! property
+
| <samp>FadeWhenBehind</samp>
! explanation
+
| ''(Optional)'' Whether the building should become semi-transparent when the player is behind it. Default true.
 
|-
 
|-
| <samp>AllowWakeUpWithoutBed {{t|allow}}</samp>
+
| <samp>DrawOffset</samp>
| 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>]].
+
| ''(Optional)'' A pixel offset applied to the building sprite's placement in the world. Default 0.
 
|-
 
|-
| <samp>DefaultWarpLocation {{t|x}} {{t|y}}</samp><br />''(valid in any location)''
+
| <samp>SeasonOffset</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)'' 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>PetBowlLocation {{t|x}} {{t|y}}</samp><br />''(valid in the farm)''
+
| <samp>SortTileOffset</samp>
| The default position of the pet bowl
+
| ''(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>SpouseRoomPosition {{t|x}} {{t|y}}</samp><br />''(valid in farmhouse)''
+
| <samp>DrawLayers</samp>
| The top-left position at which to place the [[Marriage#Spouse Rooms|spouse room]].
+
| ''(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>TravelingCartPosition {{t|x}} {{t|y}}</samp><br />''(valid in the forest)''
+
! field
| 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.
+
! effect
|}
+
|-
 
+
| <samp>Id</samp>
===Other map property changes===
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the current list.
{| class="wikitable"
+
|-
 +
| <samp>SourceRect</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.
 +
|-
 +
| <samp>DrawPosition</samp>
 +
| The tile position at which to draw the top-left corner of the texture, relative to the building's top-left corner tile.
 
|-
 
|-
! map property
+
| <samp>Texture</samp>
! changes
+
| ''(Optional)'' The asset name of the texture to draw. Defaults to the building's default <samp>Texture</samp> field.
 
|-
 
|-
| <samp>Arch</samp><br /><samp>asdf</samp><br /><samp>Debris</samp><br /><samp>Fish</samp>
+
| <samp>DrawInBackground</samp>
| Removed (these were unused).
+
| ''(Optional)'' Whether to draw the texture behind the building sprite (i.e. underlay) instead of over it.
 
|-
 
|-
| <samp>FarmHouseFlooring</samp><br /><samp>FarmHouseFurniture</samp><br /><samp>FarmHouseStarterSeedsPosition</samp><br /><samp>FarmHouseWallpaper</samp>
+
| <samp>SortTileOffset</samp>
| These now work independently. For example, you can now use <samp>FarmHouseFlooring</samp> without needing to set <samp>FarmHouseFurniture</samp> too.
+
| ''(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>Music</samp>
+
| <samp>OnlyDrawIfChestHasContents</samp>
| 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.
+
| ''(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>NPCWarp</samp><br /><samp>Warp</samp>
+
| <samp>FrameCount</samp><br /><samp>FramesPerRow</samp><br /><samp>FrameDuration</samp>
| 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.
+
| ''(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>Stumps</samp>
+
| <samp>AnimalDoorOffset</samp>
| Now works in all locations.
+
| ''(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>UniquePortrait</samp><br /><samp>UniqueSprite</samp>
+
| <samp>DrawShadow</samp>
| Deprecated; use [[#Custom NPC appearance|custom NPC appearances]] instead. These properties will override NPC appearances. This was removed from all vanilla maps.
+
| ''(Optional)'' Whether to draw an automatic shadow along the bottom edge of the building's sprite. Default true.
 
|}
 
|}
   −
===Tile property changes===
+
====Interior====
<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
   
|-
 
|-
| <samp>Paths</samp>
+
! field
| <samp>SpawnTree {{t|category}} {{t|ID}} {{t|Growth stage}} {{t|Regrowth stage}}</samp>
+
! effect
| 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]].
  −
|}
  −
</li>
  −
<li>Added new <samp>Action</samp> [[Modding:Maps|tile properties]]:
  −
{| class="wikitable"
   
|-
 
|-
! layer
+
| <samp>IndoorMap</samp>
! property
+
| ''(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.
! explanation
   
|-
 
|-
| <samp>Buildings</samp>
+
| <samp>IndoorMapType</samp>
| <samp>Action BuildingSilo</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...
| 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>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>Buildings</samp>
+
| <samp>NonInstancedIndoorLocation</samp>
| <samp>Action BuildingToggleAnimalDoor</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.
| If a building covers this tile, opens or closes its animal door.
+
 
 +
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>Buildings</samp>
+
| <samp>MaxOccupants</samp>
| <samp>Action Dialogue</samp>
+
| ''(Optional)'' The maximum number of animals who can live in this building.
| &#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>AllowAnimalPregnancy</samp>
| <samp>Action Forge</samp>
+
| ''(Optional)'' Whether animals can get pregnant and produce offspring in this building. Default false.
| Opens the [[Forge]] menu.
   
|-
 
|-
| <samp>Buildings</samp>
+
| <samp>ValidOccupantTypes</samp>
| <samp>Action None</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.
| Does nothing. This is used to mark the tile interactive if the click will be handled separately.
+
|}
 +
 
 +
====Item processing====
 +
{| class="wikitable"
 
|-
 
|-
| <samp>Buildings</samp>
+
! field
| <samp>Action ObeliskWarp {{t|location name}} {{t|x}} {{t|y}} {{o|whether to dismount}}</samp>
+
! effect
| Warps the player to the specified location name and position with the [[Warp Totem|Obelisk]] animation/sound effects.
   
|-
 
|-
| <samp>Buildings</samp>
+
| <samp>HayCapacity</samp>
| <samp>Action OpenShop {{t|shop id}} {{o|from direction}} {{o|open time}} {{o|close time}} {{o|owner tile area}}</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.
| Open the [[#Custom shops|shop]] with the given {{t|shop id}}. All arguments besides the ID are optional:
  −
* {{o|from direction}}: if specified, the player must be standing in this direction relative to the shop (one of <samp>down</samp>, <samp>up</samp>, <samp>left</samp>, <samp>right</samp>, or <samp>none</samp>). Setting this to <samp>none</samp> disables the requirement. The default for most vanilla shops is <samp>down</samp>.
  −
* {{o|open time}} and {{o|close time}}: the start & end times in 26-hour format when the shop is available. Interacting with the tile outside those times does nothing.
  −
* {{o|owner tile area}}: if specified, the tile area which must contain one of the shop owners for the shop to be available. For a custom shop, these are defined by its <samp>Owners</samp> field. This can be specified in two forms: <samp>{{t|x}} {{t|y}}</samp> for a single tile, or <samp>{{t|x}} {{t|y}} {{t|width}} {{t|height}}</samp> for a multi-tile area.
   
|-
 
|-
| <samp>Buildings</samp>
+
| <samp>ItemConversions</samp>
| <samp>Action PlayEvent {{t|event id}} {{o|check preconditions}} {{o|skip if seen}} {{o|fallback action}}</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:
| 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>
  −
<li>Added new <samp>TouchAction</samp> [[Modding:Maps|tile properties]]:
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! layer
+
! field
! property
+
! effect
! explanation
   
|-
 
|-
| <samp>Back</samp>
+
| <samp>Id</samp>
| <samp>TouchAction PlayEvent {{t|event id}} {{o|check preconditions}} {{o|skip if seen}} {{o|fallback action}}</samp>
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this rule within the current list.
| Equivalent to <samp>Action PlayEvent</samp>, but activated on touch. Note that {{o|fallback action}} is an <samp>Action</samp> tile property, ''not'' a <samp>TouchAction</samp> tile property.
  −
|}</li>
  −
<li>Changed existing tile properties:
  −
{| class="wikitable"
   
|-
 
|-
! layer
+
| <samp>RequiredTags</samp>
! property
+
| 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.
! reason
   
|-
 
|-
|rowspan="4"| <samp>Back</samp>
+
| <samp>SourceChest</samp>
| <samp>NoSpawn</samp>
+
| The ID of the inventory defined in <samp>Chests</samp> from which to take input items.
| Added <samp>NoSpawn false</samp> form, which disables any previous <samp>NoSpawn</samp> property on the tile. For example, this can be used to enable spawning on a tile which has a <samp>NoSpawn</samp> tile index property.
   
|-
 
|-
| <samp>TouchAction Bus</samp>
+
| <samp>DestinationChest</samp>
| Removed. This wasn't used by the game or mods.
+
| The ID of the inventory defined in <samp>Chests</samp> in which to store output items.
 
|-
 
|-
| <samp>TouchAction Emote</samp>
+
| <samp>ProducedItems</samp>
| Fixed error if the specified NPC isn't found.
+
| The output items produced when an input item is converted. This consists of a list of models with these fields:
 +
{| class="wikitable"
 
|-
 
|-
| <samp>Treasure</samp>
+
! field
| Added <samp>Treasure Item {{t|item ID}}</samp> form which accepts a [[#Custom items|qualified or unqualified item ID]].
+
! effect
 +
|-
 +
| ''common fields''
 +
| 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>Chance</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).
 +
|}
 
|-
 
|-
|rowspan="2"| <samp>Buildings</samp>
+
| <samp>RequiredCount</samp>
| <samp>Action ItemChest</samp><br /><samp>Action Minecart</samp><br /><samp>Action RemoveChest</samp>
+
| ''(Optional)'' The number of the input item to consume. Default 1.
| Removed. These weren't used by the game or mods.
   
|-
 
|-
| <samp>Action Kitchen</samp>
+
| <samp>MaxDailyConversions</samp>
| Now works in any location (including those without a fridge).
+
| ''(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.
 
|}
 
|}
</li>
+
|-
</ul>
+
| <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:
===Other location/map changes===
  −
* Farm data:
  −
** Added <samp>SpawnMonstersByDefault</samp> field to <samp>Data/AdditionalFarms</samp> to set the default value of the 'spawn monsters at night' [[Options#Advanced Game Options|advanced save option]].
  −
** Fixed crash on new-save screen if the farm type's tooltip has no description.
  −
* General location data:
  −
** All locations can now have animals. The <samp>IAnimalLocation</samp> is now obsolete and implemented by <samp>GameLocation</samp>.
  −
** Added new [[Modding:Fish data|fishing areas]] to simplify compatibility between fish & map mods (specifically for hilltop farm, wilderness farm, town, and desert).
  −
** Added a descriptive error when a required location or layer isn't found. Mods can use <samp>map.RequireLayer</samp> and <samp>Game1.RequireLocation</samp> to get a location with similar error-checking.
  −
** Added <samp>WarpPathfindingCache</samp> for C# mods, which modularizes the NPC warp route logic. You can edit its <samp>IgnoreLocationNames</samp>, <samp>OverrideTargetNames</samp>, and <samp>GenderRestrictions</samp> fields if needed for custom locations.
  −
** Game logic which checks tile indexes is now more fault-tolerant, so it won't crash if an expected tile was edited.
  −
** Finished migrating <samp>DecoratableLocation</samp> flooring/wallpaper areas to string IDs (started in Stardew Valley 1.5.5).
  −
* General map changes:
  −
** Added validation for [[Modding:Maps|map properties and tile properties]]. If the format is invalid, the game will now log a detailed error and skip it.
  −
** Removed unused [[Modding:Maps#Paths layer|path tiles]] in <samp>Maps/paths</samp> and all map files.
  −
* Location context data:
  −
** Building interiors now inherit their parent's location context by default.
  −
** Added <samp>Game1.locationContextData</samp> to cache the data from <samp>Data/LocationContexts</samp>.
  −
** Added constants for the vanilla context IDs like <samp>LocationContexts.IslandId</samp>.
  −
** Added validation for required location context IDs (and <samp>LocationContexts.Require(id)</samp> for mod logic).
  −
** Removed the <samp>Name</samp> field in <samp>Data/LocationContexts</samp>, which duplicated the ID.
  −
<ul>
  −
<li>Added methods to simplify common operations:
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! 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 this chest within the current list.
| Get the location which contains this building.
+
 
 +
This is referenced from the <samp>ItemConversions</samp> field.
 
|-
 
|-
| <samp>IsInCurrentLocation</samp>
+
| <samp>Type</samp>
| Get whether the building is in the same location as the current player.
+
| 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>HasIndoors</samp>
+
| <samp>Sound</samp>
| Get whether the building has an interior location.
+
| ''(Optional)'' The sound to play once when the player clicks the chest.
 
|-
 
|-
| <samp>GetIndoors</samp>
+
| <samp>InvalidItemMessage</samp><br /><samp>InvalidCountMessage</samp><br /><samp>ChestFullMessage</samp>
| Get the location within this building, if applicable.
+
| ''(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>HasIndoorsName</samp>
+
| <samp>InvalidItemMessageCondition</samp>
| Get whether the building has an interior location and its unique name matches the given value (like <code>building.HasIndoorsName("FarmHouse")</code>).
+
| ''(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>GetIndoorsName</samp>
+
| <samp>DisplayTile</samp>
| Get the unique name of the location within this building, if applicable.
+
| ''(Optional)'' The chest's position on the building exterior, measured in tiles from the top-left corner of the building, specified in the form <samp>"{{t|x}}, {{t|y}}"</samp>. This affects the position of the 'item ready to collect' bubble. If omitted, the bubble is disabled.
 
|-
 
|-
| ...
+
| <samp>DisplayHeight</samp>
| ''see also [[#Other building changes|other building changes]] for non-location methods.''
+
| ''(Optional)'' If <samp>DisplayTile</samp> is set, the chest's tile height like <samp>1.5</samp>.
 +
|}
 +
|}
 +
 
 +
====Tile interactions====
 +
{| class="wikitable"
 
|-
 
|-
|rowspan="7"|<samp>Cabin</samp><br /><samp>FarmHouse</samp>
+
! field
| <samp>GetCellar</samp>
+
! effect
| Get the [[cellar]] location linked to this cabin, if any.
   
|-
 
|-
| <samp>CanAssignFarmhand</samp><br /><samp>AssignFarmhand</samp>
+
| <samp>ActionTiles</samp>
| ''(Cabin only)'' Check whether the cabin is available to assign to a farmhand, or perform the assignment.
+
| ''(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:
 +
{| class="wikitable"
 
|-
 
|-
| <samp>HasOwner</samp>
+
! field
| Get whether the home has an assigned player, regardless of whether they've finished creating their character.
+
! effect
 
|-
 
|-
| <samp>OwnerId</samp>
+
| <samp>Id</samp>
| Get the unique ID of the player who owns this home, if any.
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the current list.
 
|-
 
|-
| <samp>IsOwnedByCurrentPlayer</samp>
+
| <samp>Tile</samp>
| Get whether the cabin belongs to the current player.
+
| The tile position, relative to the building's top-left corner tile.
 
|-
 
|-
| <samp>IsOwnerActivated</samp>
+
| <samp>Action</samp>
| Get whether the home has an assigned player and they've finished creating their character.
+
| 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>HasNpcSpouse</samp>
+
| <samp>DefaultAction</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>.
+
| ''(Optional)'' The default tile action if the clicked tile isn't in <samp>ActionTiles</samp>. Default none.
 
|-
 
|-
|rowspan="2"| <samp>Farm</samp>
+
| <samp>TileProperties</samp>
| <samp>GetStarterFarmhouseLocation</samp>
+
| ''(Optional)'' The [[Modding:Maps|map tile properties]] to set. This consists of a list of models with these fields:
| Get the default tile position for the farmhouse. (See also <samp>farm.GetMainFarmHouseEntry()</samp>.)
+
{| class="wikitable"
 
|-
 
|-
| <samp>GetStarterPetBowlLocation</samp>
+
! field
| Get the default tile position for the pet bowl.
+
! effect
 
|-
 
|-
|rowspan="19"| <samp>GameLocation</samp>
+
| <samp>Id</samp>
| <samp>AddDefaultBuildings</samp>
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the current list.
| 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>Name</samp>
| Get the fridge's chest or tile position, if the location has one.
+
| The tile property name to set.
 
|-
 
|-
| <samp>GetSeason</samp><br /><samp>GetSeasonIndex</samp><br /><samp>GetSeasonKey</samp>
+
| <samp>Value</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)'' The tile property value to set, or omit to set a null value.
 
|-
 
|-
| <samp>GetWeather</samp><br /><samp>IsDebrisWeatherHere</samp><br /><samp>IsLightningHere</samp><br /><samp>IsRainingHere</samp><br /><samp>IsSnowingHere</samp>
+
| <samp>Layer</samp>
| Get the current weather in this location's context, regardless of whether the player is indoors and sheltered from it.
+
| The name of the map layer whose tiles to change.
 
|-
 
|-
| <samp>InDesertContext</samp><br /><samp>InIslandContext</samp><br /><samp>InValleyContext</samp>
+
| <samp>TileArea</samp>
| Get whether this location is within the <samp>Island</samp> or <samp>Default</samp> location context respectively.
+
| 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>IsActiveLocation</samp>
+
| <samp>AdditionalTilePropertyRadius</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)'' 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"
 
|-
 
|-
| <samp>IsTemporary</samp>
+
! field
| 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).
+
! effect
 
|-
 
|-
| <samp>GetLocationContextId</samp>
+
| <samp>Metadata</samp>
| Get the ID of the location context in <samp>Data/LocationContexts</samp> which contains this building.
+
| ''(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>GetContainingBuilding</samp>
+
! property
| Get the building instance which contains this location (like the cabin for a cabin interior), if applicable.
+
! description
 
|-
 
|-
| <samp>GetParentLocation</samp>
+
| <samp>ChimneyPosition: {{t|x}} {{t|y}}</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 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>GetRootLocation</samp>
+
| <samp>ChimneyPosition{{o|upgrade level}}: {{t|x}} {{t|y}}</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, 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>).
|-
+
|}
| <samp>GetInstancedBuildingInteriors</samp>
  −
| Get all building interiors within this location which are instanced to the building (i.e. not in <samp>Game1.locations</samp> separately).
  −
|-
  −
| <samp>GetMapPropertySplitBySpaces</samp><br /><samp>GetTilePropertySplitBySpaces</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.
     −
For example:
+
This can also contain arbitrary custom properties, which C# mods can read using <samp>building.GetMetadata(key)</samp>.
<syntaxhighlight lang="c#">
  −
string[] fields = Game1.currentLocation.GetMapPropertySplitBySpaces("ScreenshotRegion");
  −
</syntaxhighlight>
   
|-
 
|-
| <samp>HasMapPropertyWithValue</samp>
+
| <samp>BuildingType</samp>
| Get whether a map property is defined and has a non-empty value.
+
| ''(Optional)'' The full name of the C# type to instantiate for the building instance. Defaults to a generic <samp>Building</samp> instance.
   −
For example:
+
'''⚠ 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.
<syntaxhighlight lang="c#">
  −
bool canUseCasks = Game1.currentLocation.HasMapPropertyWithValue("CanCaskHere");
  −
</syntaxhighlight>
   
|-
 
|-
| <samp>StoreHayInAnySilo</samp>
+
| <samp>ModData</samp>
| Add hay to any silo with free space (preferring silos in the current location, then the farm, then anywhere).
+
| ''(Optional)'' A string → string lookup of arbitrary <samp>modData</samp> values to attach to the building when it's constructed.
 
|-
 
|-
| <samp>TryGetMapProperty</samp>
+
| <samp>CustomFields</samp>
| Get a map property value as a string, if it's defined.
+
| The [[#Custom data fields|custom fields]] for this entry.
 +
|}
 +
 
 +
===Build anywhere===
 +
{{/doc status|[[Modding:Blueprint data]] and [[Modding:Maps]]|done=false}}
   −
For example:
+
* 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).
<syntaxhighlight lang="c#">
+
* Buildings and animals are no longer hardcoded to the [[The Farm|farm]] location (except [[cabin]]s and the [[farmhouse]] which still are).
if (this.TryGetMapProperty("Warps", out string warps))
+
* Scything hay will now add hay to silos in any location, and animals will be auto-fed from hay in any location.
{
  −
    // ...
  −
}
  −
</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.
     −
For example:
+
===Other building changes===
<syntaxhighlight lang="c#">
+
{{/doc status|[[Modding:Blueprint data]]|done=false}}
if (!this.TryGetMapPropertyAs("MailboxLocation", out Point position))
+
 
{
+
: ''See also: [[#Other location/map changes|other location changes]] for location-related building changes.''
    position = new Point(68, 16); // default value
+
 
}
+
; General building changes
 +
* Building display names & descriptions are now in <samp>Strings/Buildings</samp> for reuse.
 +
* Removed <samp>Data/Blueprints</samp>. This has been replaced by <samp>Data/Buildings</samp> (building data) and <samp>Strings/Buildings</samp> (display names & descriptions).
 +
<ul>
 +
<li>Added methods to simplify common operations:
 +
{| class="wikitable"
 +
|-
 +
! type
 +
! method
 +
! effect
 +
|-
 +
|rowspan="7"| <samp>Building</samp>
 +
| <samp>CreateInstanceFromId</samp>
 +
| Create a building instance from its type ID in <samp>Data/Buildings</samp>. For example:
 +
<syntaxhighlight lang="c#">
 +
Building shippingBin = Building.CreateInstanceFromId("Shipping Bin", Vector2.Zero); // creates an instance of StardewValley.Buildings.ShippingBin
 
</syntaxhighlight>
 
</syntaxhighlight>
 
|-
 
|-
| <samp>removeObjectsAndSpawned</samp>
+
| <samp>GetData</samp><br /><samp>TryGetData</samp>
| Remove all objects, bushes, resource clumps, and terrain features within a tile area.
+
| Get the data for the building's type from <samp>Data/Building</samp>.
 
|-
 
|-
| <samp>OnBuildingConstructed</samp><br /><samp>OnBuildingMoved</samp><br /><samp>OnBuildingDemolished</samp>
+
| <samp>GetMetadata</samp>
| These methods are called for all players when any player constructs, moves, or demolishes a building.
+
| Get a value from [[#Custom buildings|the <samp>Metadata</samp> field in <samp>Data/Buildings</samp>]] for this building.
 
|-
 
|-
|rowspan="3"| <samp>LibraryMuseum</samp>
+
| <samp>GetPaintDataKey</samp>
| <samp>HasDonatedArtifacts()</samp>
+
| Get the key in <samp>Data/PaintData</samp> for this building, if it has any.
| Get whether any items have been donated to the [[museum]].
   
|-
 
|-
| <samp>HasDonatedArtifactAt(tile)</samp>
+
| <samp>ReloadBuildingData</samp>
| Get whether any donated item is currently placed at the given tile position within the [[museum]].
+
| Apply the latest data in <samp>Data/Buildings</samp> to this building.
 
|-
 
|-
| <samp>HasDonatedArtifact(itemId)</samp>
+
| <samp>FinishConstruction</samp>
| Get whether an artifact with the given qualified or unqualified item ID has been donated to the [[museum]].
+
| If the building is being constructed or upgrade, instantly finish doing so.
 
|-
 
|-
|rowspan="2"| <samp>MineShaft</samp>
+
| <samp>UpdateTransparency</samp>
| <samp>GetLevelName</samp>
+
| Update the building transparency on tick for the local player's position.
| Get the location name for a generated [[The Mines|mine]] or [[Skull Cavern]] level.
     −
For example:
+
This method mainly exists to let mods override/patch the transparency logic.
<syntaxhighlight lang="c#">
  −
string locationName = MineShaft.GetLevelName(10); // returns "UndergroundMine10"
  −
Game1.warpFarmer(locationName, 0, 0, false);
  −
</syntaxhighlight>
   
|-
 
|-
| <samp>IsGeneratedLevel</samp>
+
| <samp>Farm</samp>
| Get whether a location or location name is a generated [[The Mines|mine]] or [[Skull Cavern]] level.
+
| <samp>GetMainFarmHouse</samp>
 
+
| Get the main [[farmhouse]] building.
For example:
  −
<syntaxhighlight lang="c#">
  −
string locationName = "UndergroundMine10";
  −
bool isMine = MineShaft.IsGeneratedLevel(locationName, out int level); // returns true, 10
  −
</syntaxhighlight>
   
|-
 
|-
| <samp>VolcanoDungeon</samp>
+
| <samp>GameLocation</samp>
| <samp>GetLevelName</samp><br /><samp>IsGeneratedLevel</samp>
+
| <samp>OnParentBuildingUpgraded</samp>
| Equivalent to the matching <samp>MineShaft</samp> methods, but for the [[Volcano Dungeon]].
+
| Called when the building containing this location is upgraded, if applicable.
 
|}
 
|}
 
</li>
 
</li>
 
</ul>
 
</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>.
+
* Added building <samp>id</samp> field, which uniquely identifies each building in the world.
* <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==
+
; [[Junimo Hut|Junimo hut]] changes
===Custom buildings===
+
* The <samp>JunimoHut.cropHarvestRange</samp> field is now per-building and editable.
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 [[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.
     −
====Required fields====
+
; [[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"
 
|-
 
|-
! field
+
! precedence
! effect
+
! used for
 +
|-
 +
| 0<br /><small>(default value)</small>
 +
| specific fish
 +
|-
 +
| 100
 +
| custom groups (e.g. desert fish)
 
|-
 
|-
| <samp>Name</samp><br /><samp>Description</samp>
+
| 500
| A [[Modding:Tokenizable strings|tokenizable string]] for the display name and description (e.g. shown in the construction menu).
+
| broad fish type (e.g. ocean fish)
 
|-
 
|-
| <samp>Texture</samp>
+
| 1000
| The asset name for the texture under the game's Content folder.
+
| 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>
   −
====Construction====
+
==What's new for NPCs==
{| class="wikitable"
+
===Custom NPCs===
|-
+
{{/doc status|[[Modding:NPC data]]|done=false}}
! field
+
 
! effect
+
[[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.
|-
+
 
| <samp>Builder</samp>
+
====Format====
| ''(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.
+
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>).
| <samp>BuildCost</samp>
+
* The value is a model with the following fields.
| ''(Optional)'' The gold cost to construct the building. Defaults to {{price|0}}.
+
 
|-
+
<dl style="margin-left: 2em;">
| <samp>BuildMaterials</samp>
+
<dt>Basic info:</dt>
| ''(Optional)'' The materials you must provide to start construction, as a list of models with these fields:
+
<dd>
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 4,190: Line 4,378:  
! effect
 
! effect
 
|-
 
|-
| <samp>Id</samp>
+
| <samp>DisplayName</samp>
| ''(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.
+
| A [[Modding:Tokenizable strings|tokenizable string]] for the NPC's display name.
 
|-
 
|-
| <samp>ItemId</samp>
+
| <samp>Language</samp>
| The required item ID (qualified or unqualified).
+
| ''(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>Amount</samp>
+
| <samp>Gender</samp>
| The number of the item required.
+
| ''(Optional)'' The NPC's gender identity. One of <samp>Female</samp>, <samp>Male</samp>, or <samp>Undefined</samp>. Default <samp>Undefined</samp>.
|}
   
|-
 
|-
| <samp>BuildDays</samp>
+
| <samp>Age</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)'' 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>BuildCondition</samp>
+
| <samp>Manner</samp>
| ''(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.
+
| ''(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>BuildMenuDrawOffset</samp>
+
| <samp>SocialAnxiety</samp>
| ''(Optional)'' A pixel offset to apply to the building sprite when drawn in the construction menu. Default none.
+
| ''(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>AdditionalPlacementTiles</samp>
+
| <samp>Optimism</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)'' A measure of the character's overall optimism. One of <samp>Neutral</samp>, <samp>Negative</samp>, or <samp>Positive</samp>. Default <samp>Neutral</samp>.
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>BirthSeason</samp>
! effect
+
| ''(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>TileArea</samp>
+
| <samp>BirthDay</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 if non-social)'' The day number for the NPC's birthday. Default 0.
 
|-
 
|-
| <samp>OnlyNeedsToBePassable</samp>
+
| <samp>HomeRegion</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.
+
| ''(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>IsDarkSkinned</samp>
 +
| ''(Optional)'' Whether the NPC has dark skin, which affects the chance of children with the player having dark skin too. Default false.
 
|}
 
|}
|-
+
</dd>
| <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:
+
<dt>Social features:</dt>
 +
<dd>
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 4,230: Line 4,422:  
! effect
 
! effect
 
|-
 
|-
| <samp>Id</samp>
+
| <samp>CanSocialize</samp>
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the current list.
+
| ''(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>ItemId</samp>
+
| <samp>CanBeRomanced</samp>
| The [[#Custom items|qualified item ID]] for the item to place.
+
| ''(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>Tile</samp>
+
| <samp>CanReceiveGifts</samp>
| The tile position at which to place the item, specified as an object with <samp>X</samp> and <samp>Y</samp> fields.
+
| ''(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>Indestructible</samp>
+
| <samp>CanCommentOnPurchasedShopItems</samp>
| ''(Optional)'' Whether to prevent the player from destroying, picking up, or moving the item. Default false.
+
| ''(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>MagicalConstruction</samp>
+
| <samp>CanGreetNearbyCharacters</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)'' Whether this NPC can show a speech bubble greeting nearby players or NPCs, and or be greeted by other NPCs. Default true.
 
|-
 
|-
| <samp>AddMailOnBuild</samp>
+
| <samp>CanVisitIsland</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)'' 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.
|}
     −
====Upgrades====
+
The NPC must also be social per <samp>CanSocialize</samp> to visit the island, regardless of this value.
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>LoveInterest</samp>
! effect
+
| ''(Optional)'' Unused.
 
|-
 
|-
| <samp>BuildingToUpgrade</samp>
+
| <samp>Calendar</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.
+
| ''(Optional)'' Determines when the NPC's birthday is shown in the [[calendar]]. Possible values:
|-
  −
| <samp>IndoorItemMoves</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:
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! value
 
! effect
 
! effect
 
|-
 
|-
| <samp>Id</samp>
+
| <samp>HiddenAlways</samp>
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the current list.
+
| They never appear in the calendar.
 
|-
 
|-
| <samp>Source</samp>
+
| <samp>HiddenUntilMet</samp>
| The tile position on which any item will be moved.
+
| Until the player meets them, they don't appear in the calendar.
 
|-
 
|-
| <samp>Destination</samp>
+
| <samp>AlwaysShown</samp>
| The tile position to which to move the item.
+
| They always appear in the calendar.
|-
  −
| <samp>Size</samp>
  −
| ''(Optional)'' The tile size of the area to move, specified as a model with <samp>X</samp> and <samp>Y</samp> fields. Defaults to a 1×1 area. If this is multiple tiles, the <samp>Source</samp> and <samp>Destination</samp> specify the top-left coordinate of the area.
   
|}
 
|}
 +
 +
Defaults to <samp>AlwaysShown</samp>.
 
|-
 
|-
| <samp>UpgradeSignTile</samp>
+
| <samp>SocialTab</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)'' Determines how the NPC is shown on the [[friendship|social tab]] when unlocked. Possible values:
|-
  −
| <samp>UpgradeSignHeight</samp>
  −
| ''(Optional)'' The pixel height of the upgrade sign when Robin is building an upgrade. Defaults to 0.
  −
|}
  −
 
  −
====Exterior behavior====
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! value
 
! effect
 
! effect
 
|-
 
|-
| <samp>Size</samp>
+
| <samp>HiddenAlways</samp>
| ''(Optional)'' The building's width and height when constructed, measured in tiles. Defaults to a 1 x 1 area.
+
| 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>CollisionMap</samp>
+
| <samp>AlwaysShown</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.
+
| They always appear in the social tab (including their name).
 +
|}
   −
For example, a [[stable]] covers a 2x4 tile area with the front two tiles passable:
+
Defaults to <samp>UnknownUntilMet</samp>.
<pre>XXXX
+
|-
XOOX</pre>
+
| <samp>SpouseAdopts</samp>
 +
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether the player will need to adopt children with this spouse, instead of either the player or NPC giving birth. If null, defaults to true for same-gender and false for opposite-gender spouses.
   −
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:
+
The <samp>Target</samp> player is the one they're married to.
<syntaxhighlight lang="js">
+
|-
// single line with \n line breaks
+
| <samp>SpouseWantsChildren</samp>
"CollisionMap": "XXXX\nXOOX"
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether the spouse will ask to have children. Defaults to true.
   −
// multi-line with optional indentation
+
The <samp>Target</samp> player is the one they're married to.
"CollisionMap": "
+
|-
    XXXX
+
| <samp>SpouseGiftJealousy</samp>
    XOOX
+
| ''(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.
"
+
 
</syntaxhighlight>
+
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>HumanDoor</samp>
+
| <samp>SpouseGiftJealousyFriendshipChange</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.
+
| ''(Optional)'' The [[Friendship|friendship point]] effect when the <samp>SpouseGiftJealously</samp> is triggered. Default -30.
 
|-
 
|-
| <samp>AnimalDoor</samp>
+
| <samp>SpouseRoom</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.
+
| ''(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.
|-
  −
| <samp>AnimalDoorOpenDuration</samp><br /><samp>AnimalDoorCloseDuration</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.
  −
|-
  −
| <samp>AnimalDoorOpenSound</samp><br /><samp>AnimalDoorCloseSound</samp>
  −
| ''(Optional)'' The sound which is played once each time the animal door is opened/closed. Disabled by default.
  −
|}
     −
====Exterior appearance====
+
This consists of a model with these fields:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 4,333: Line 4,517:  
! effect
 
! effect
 
|-
 
|-
| <samp>SourceRect</samp>
+
| <samp>MapAsset</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.
+
| ''(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>Skins</samp>
+
| <samp>SpousePatio</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:
+
| ''(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,343: Line 4,533:  
! effect
 
! effect
 
|-
 
|-
| <samp>Id</samp>
+
| <samp>MapAsset</samp>
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for the skin.
+
| ''(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>Name</samp><br /><samp>Description</samp>
+
| <samp>MapSourceRect</samp>
| [[Modding:Tokenizable strings|Tokenizable strings]] for the skin's display name and description.
+
| ''(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>Texture</samp>
+
| <samp>SpriteAnimationFrames</samp>
| The asset name for the texture under the game's Content folder.
+
| ''(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>Condition</samp>
+
For example, here is Abigail playing the flute:
| ''(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.
+
<syntaxhighlight lang="js">
|-
+
"SpriteAnimationFrames": [
| <samp>BuildDays</samp><br /><samp>BuildCost</samp><br /><samp>BuildMaterials</samp>
+
    [16, 500], // show index 16 for 500ms
| ''(Optional)'' If set, overrides the equivalent field in the building data.
+
    [17, 500],
 +
    [18, 500],
 +
    [19]      // if duration is omitted, defaults to 100ms
 +
]
 +
</syntaxhighlight>
 
|-
 
|-
| <samp>ShowAsSeparateConstructionEntry</samp>
+
| <samp>SpriteAnimationPixelOffset</samp>
| ''(Optional)'' Whether this skin should be shown as a separate building option in the construction menu (like cabins). Default false.
+
| ''(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>Metadata</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.
   
|}
 
|}
 
|-
 
|-
| <samp>FadeWhenBehind</samp>
+
| <samp>SpouseFloors</samp><br /><samp>SpouseWallpapers</samp>
| ''(Optional)'' Whether the building should become semi-transparent when the player is behind it. Default true.
+
| ''(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>DrawOffset</samp>
+
| <samp>IntroductionsQuest</samp>
| ''(Optional)'' A pixel offset applied to the building sprite's placement in the world. Default 0.
+
| ''(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>SeasonOffset</samp>
+
| <samp>ItemDeliveryQuests</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)'' 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>SortTileOffset</samp>
+
| <samp>PerfectionScore</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)'' 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>DrawLayers</samp>
+
| <samp>EndSlideShow</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)'' How the NPC appears in the end-game perfection slide show. Possible values:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! value
 
! effect
 
! effect
 
|-
 
|-
| <samp>Id</samp>
+
| <samp>Hidden</samp>
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the current list.
+
| The NPC doesn't appear in the slide show.
 
|-
 
|-
| <samp>SourceRect</samp>
+
| <samp>MainGroup</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.
+
| The NPC is added to the main group of NPCs which walk across the screen.
 
|-
 
|-
| <samp>DrawPosition</samp>
+
| <samp>TrailingGroup</samp>
| The tile position at which to draw the top-left corner of the texture, relative to the building's top-left corner tile.
+
| The NPC is added to the trailing group of NPCs which follow the main group.
 +
|}
 +
 
 +
Defaults to <samp>MainGroup</samp>.
 
|-
 
|-
| <samp>Texture</samp>
+
| <samp>FriendsAndFamily</samp>
| ''(Optional)'' The asset name of the texture to draw. Defaults to the building's default <samp>Texture</samp> field.
+
| ''(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>Dumpster diving:</dt>
 +
<dd>
 +
{| class="wikitable"
 
|-
 
|-
| <samp>DrawInBackground</samp>
+
! field
| ''(Optional)'' Whether to draw the texture behind the building sprite (i.e. underlay) instead of over it.
+
! effect
 +
|-
 +
| <samp>DumpsterDiveEmote</samp>
 +
| ''(Optional)'' The emote ID to show above the NPC's head when they see a player rummaging through trash. See [[Modding:event data#Emotes|emote IDs]]. If omitted or <samp>null</samp>, the default depends on the NPC's age: a child will show sad (28), a teen will show a question mark (8), and an adult will show angry (12).
 
|-
 
|-
| <samp>SortTileOffset</samp>
+
| <samp>DumpsterDiveFriendshipEffect</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)'' The friendship point change if this NPC sees a player rummaging through trash. Default -25.
 +
|}</dd>
 +
 
 +
<dt>Festivals:</dt>
 +
<dd>
 +
{| class="wikitable"
 
|-
 
|-
| <samp>OnlyDrawIfChestHasContents</samp>
+
! field
| ''(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>FlowerDanceCanDance</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.
+
| ''(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>.
   −
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>):
+
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).
<pre>
  −
┌───┬───┬───┐
  −
│ 1 │ 2 │ 3 │
  −
├───┼───┼───┤
  −
│ 4 │ 5 │ 6 │
  −
└───┴───┴───┘
  −
</pre>
   
|-
 
|-
| <samp>AnimalDoorOffset</samp>
+
| <samp>WinterStarParticipant</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).
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this NPC can give and receive gifts at the [[Feast of the Winter Star]]. If <samp>null</samp> (or omitted), this will default to true if the <samp>HomeRegion</samp> field is set to <samp>Town</samp>.
|}
   
|-
 
|-
| <samp>DrawShadow</samp>
+
| <samp>WinterStarGifts</samp>
| ''(Optional)'' Whether to draw an automatic shadow along the bottom edge of the building's sprite. Default true.
+
| At the [[Feast of the Winter Star]], the possible gifts this NPC can give to players. A matching entry is selected at random.
|}
     −
====Interior====
+
This consists of a list of models with these fields:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 4,431: Line 4,636:  
! effect
 
! effect
 
|-
 
|-
| <samp>IndoorMap</samp>
+
| ''common fields''
| ''(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.
+
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields.
|-
+
 
| <samp>IndoorMapType</samp>
+
If set to an [[Modding:Item queries|item query]] which returns multiple items, one of them will be selected at random.
| ''(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>NonInstancedIndoorLocation</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.
  −
 
  −
Each location can only be used by one building. If the location is already in use (e.g. because the player has two of this building), each subsequent building will use the <samp>IndoorMap</samp> and <samp>IndoorMapType</samp> instead. For example, the first greenhouse will use the global <samp>Greenhouse</samp> location, and any subsequent greenhouse will use a separate instanced location.
  −
|-
  −
| <samp>MaxOccupants</samp>
  −
| ''(Optional)'' The maximum number of animals who can live in this building.
  −
|-
  −
| <samp>AllowAnimalPregnancy</samp>
  −
| ''(Optional)'' Whether animals can get pregnant and produce offspring in this building. Default false.
  −
|-
  −
| <samp>ValidOccupantTypes</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.
   
|}
 
|}
   −
====Item processing====
+
<dt>Spawn rules:</dt>
 +
<dd>
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 4,467: Line 4,650:  
! effect
 
! effect
 
|-
 
|-
| <samp>HayCapacity</samp>
+
| <samp>UnlockConditions</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)'' 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>ItemConversions</samp>
+
| <samp>Home</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 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,477: Line 4,665:  
! effect
 
! effect
 
|-
 
|-
| <samp>Id</samp>
+
| <samp>ID</samp>
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this rule within the current list.
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the current list.
 
|-
 
|-
| <samp>RequiredTags</samp>
+
| <samp>Location</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 internal name for the home location where this NPC spawns and returns each day. Default none.
 
|-
 
|-
| <samp>SourceChest</samp>
+
| <samp>Tile</samp>
| The ID of the inventory defined in <samp>Chests</samp> from which to take input items.
+
| ''(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>DestinationChest</samp>
+
| <samp>Direction</samp>
| The ID of the inventory defined in <samp>Chests</samp> in which to store output items.
+
| ''(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>ProducedItems</samp>
+
| <samp>Condition</samp>
| The output items produced when an input item is converted. This consists of a list of models with these fields:
+
| ''(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"
 
{| class="wikitable"
 
|-
 
|-
Line 4,496: Line 4,690:  
! effect
 
! effect
 
|-
 
|-
| ''common fields''
+
| <samp>TextureName</samp>
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields supported by machine output.
+
| ''(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>Appearance</samp>
 +
| ''(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.
   −
If set to an [[Modding:Item queries|item query]] which returns multiple items, one of them will be selected at random.
+
This consists of a list of models with these fields:  
|-
  −
| <samp>Chance</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).
  −
|}
  −
|-
  −
| <samp>RequiredCount</samp>
  −
| ''(Optional)'' The number of the input item to consume. Default 1.
  −
|-
  −
| <samp>MaxDailyConversions</samp>
  −
| ''(Optional)'' The maximum number of the input item which can be processed each day. Each conversion rule has its own separate maximum (e.g. if you have two rules each with a max of 1, then you can convert one of each daily). Set to -1 to allow unlimited conversions. Default 1.
  −
|}
  −
|-
  −
| <samp>Chests</samp>
  −
| ''(Optional)'' The input/output inventories that can be accessed from a tile on the building exterior. The allowed items are defined by the separate <samp>ItemConversions</samp> field. This is a list of models with these fields:
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 4,520: Line 4,707:  
|-
 
|-
 
| <samp>Id</samp>
 
| <samp>Id</samp>
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this chest within the current list.
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the current list.
 
  −
This is referenced from the <samp>ItemConversions</samp> field.
   
|-
 
|-
| <samp>Type</samp>
+
| <samp>Season</samp>
| The inventory type. This must be one of:
+
| ''(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>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>Indoors</samp><br /><samp>Outdoors</samp>
| ''(Optional)'' The sound to play once when the player clicks the chest.
+
| ''(Optional)'' Whether this appearance should be used when indoors and/or outdoors. Both default to true.
 
|-
 
|-
| <samp>InvalidItemMessage</samp><br /><samp>InvalidCountMessage</samp><br /><samp>ChestFullMessage</samp>
+
| <samp>Condition</samp>
| ''(Optional)'' A [[Modding:Tokenizable strings|tokenizable string]] to show when the player tries to add an item to the chest when...
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this entry can be selected. Default true.
* 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>Portrait</samp><br /><samp>Sprite</samp>
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether <samp>InvalidItemMessage</samp> should be shown. This can use item-related queries like <samp>ITEM_TYPE</samp>. Defaults to always true.
+
| ''(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>IsIslandAttire</samp>
 +
| ''(Optional)'' Whether this is island beach attire worn at the resort. Default false.
 +
 
 +
This is mutually exclusive: NPCs will never wear it in other contexts if it's true, and will never wear it as island attire if it's false.
 
|-
 
|-
| <samp>DisplayTile</samp>
+
| <samp>Precedence</samp>
| ''(Optional)'' The chest's position on the building exterior, measured in tiles from the top-left corner of the building, specified in the form <samp>"{{t|x}}, {{t|y}}"</samp>. This affects the position of the 'item ready to collect' bubble. If omitted, the bubble is disabled.
+
| ''(Optional)'' The order in which this entry should be checked, where lower values are checked first. This can be a negative value. Default 0.
 
|-
 
|-
| <samp>DisplayHeight</samp>
+
| <samp>Weight</samp>
| ''(Optional)'' If <samp>DisplayTile</samp> is set, the chest's tile height like <samp>1.5</samp>.
+
| ''(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.
 
|}
 
|}
   −
====Tile interactions====
+
'''Note:''' the default textures based on <samp>TextureName</samp> must still exist, even if you use this field to override them.
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>MugShotSourceRect</samp>
! effect
+
| ''(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>ActionTiles</samp>
+
| <samp>Size</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)'' 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>.
{| class="wikitable"
+
 
 +
'''Note:''' sizes bigger than 16×32 will cause issues like broken spawning, pathfinding, misalignment in the [[perfection]] end-game slide show, etc.
 
|-
 
|-
! field
+
| <samp>Breather</samp>
! effect
+
| ''(Optional)'' Whether the chest on the NPC's overworld sprite puffs in and out as they breathe. Default true</samp>.
 
|-
 
|-
| <samp>Id</samp>
+
| <samp>BreathChestRect</samp>
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the current list.
+
| ''(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.
 
|-
 
|-
| <samp>Tile</samp>
+
| <samp>BreathChestPosition</samp>
| The tile position, relative to the building's top-left corner tile.
+
| ''(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>Action</samp>
+
| <samp>Shadow</samp>
| 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.
+
| ''(Optional)'' The options for the shadow to draw under the NPC, or omit to apply the default shadow behavior.
|}
+
 
|-
+
This consists of a model with these fields:
| <samp>DefaultAction</samp>
+
 
| ''(Optional)'' The default tile action if the clicked tile isn't in <samp>ActionTiles</samp>. Default none.
  −
|-
  −
| <samp>TileProperties</samp>
  −
| ''(Optional)'' The [[Modding:Maps|map tile properties]] to set. This consists of a list of models with these fields:
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 4,584: Line 4,764:  
! effect
 
! effect
 
|-
 
|-
| <samp>Id</samp>
+
| <samp>Visible</samp>
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the current list.
+
| ''(Optional)'' Whether the shadow should be drawn. Default true.
 +
|-
 +
| <samp>Offset</samp>
 +
| ''(Optional)'' A [[Modding:Common data field types#Point|point]] pixel offset applied to the shadow position. Default zero.
 
|-
 
|-
| <samp>Name</samp>
+
| <samp>Scale</samp>
| The tile property name to set.
+
| ''(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>Value</samp>
+
| <samp>EmoteOffset</samp>
| ''(Optional)'' The tile property value to set, or omit to set a null value.
+
| ''(Optional)'' A [[Modding:Common data field types#Point|point]] pixel offset applied to emote drawn over the NPC. Default zero.
 
|-
 
|-
| <samp>Layer</samp>
+
| <samp>ShakePortraits</samp>
| The name of the map layer whose tiles to change.
+
| ''(Optional)'' The portrait indexes which should shake when displayed. Default none.
 
|-
 
|-
| <samp>TileArea</samp>
+
| <samp>KissSpriteIndex</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)'' If the NPC can be married, the sprite index within their <samp>Texture</samp> to use when kissing a player. Default 28.
|}
   
|-
 
|-
| <samp>AdditionalTilePropertyRadius</samp>
+
| <samp>KissSpriteFacingDirection</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 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>
   −
====Advanced====
+
<dt>[[Secrets#Gift Log|Hidden gift log emote]]:</dt>
 +
<dd>
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 4,610: Line 4,797:  
! effect
 
! effect
 
|-
 
|-
| <samp>Metadata</samp>
+
| <samp>HiddenProfileEmoteSound</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)'' 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>.
 
  −
The base game recognizes these properties:
  −
{| class="wikitable"
   
|-
 
|-
! property
+
| <samp>HiddenProfileEmoteDuration</samp>
! description
+
| ''(Optional)'' For the [[Secrets#Gift Log|hidden gift log emote]], how long the animation plays measured in milliseconds. Defaults to 4000 (4 seconds).
 
|-
 
|-
| <samp>ChimneyPosition: {{t|x}} {{t|y}}</samp>
+
| <samp>HiddenProfileEmoteStartFrame</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)'' 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>ChimneyPosition{{o|upgrade level}}: {{t|x}} {{t|y}}</samp>
+
| <samp>HiddenProfileEmoteFrameCount</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)'' 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.
|}
     −
This can also contain arbitrary custom properties, which C# mods can read using <samp>building.GetMetadata(key)</samp>.
+
This has no effect if <samp>HiddenProfileEmoteStartFrame</samp> isn't set.
 
|-
 
|-
| <samp>BuildingType</samp>
+
| <samp>HiddenProfileEmoteFrameDuration</samp>
| ''(Optional)'' The full name of the C# type to instantiate for the building instance. Defaults to a generic <samp>Building</samp> instance.
+
| ''(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.
   −
'''⚠ 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.
+
This has no effect if <samp>HiddenProfileEmoteStartFrame</samp> isn't set.
 +
|}
 +
</dd>
 +
 
 +
<dt>Advanced:</dt>
 +
<dd>
 +
{| class="wikitable"
 
|-
 
|-
| <samp>ModData</samp>
+
! field
| ''(Optional)'' A string → string lookup of arbitrary <samp>modData</samp> values to attach to the building when it's constructed.
+
! effect
 
|-
 
|-
 
| <samp>CustomFields</samp>
 
| <samp>CustomFields</samp>
 
| The [[#Custom data fields|custom fields]] for this entry.
 
| The [[#Custom data fields|custom fields]] for this entry.
|}
+
|-
 +
| <samp>FormerCharacterNames</samp>
 +
| ''(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).
   −
===Build anywhere===
+
A former name is only applied if:
* 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).
+
# it doesn't match a current ID in <samp>Data/Characters</samp>;
* Buildings and animals are no longer hardcoded to the [[The Farm|farm]] location (except [[cabin]]s and the [[farmhouse]] which still are).
+
# the save has an NPC with the former name;
* Scything hay will now add hay to silos in any location, and animals will be auto-fed from hay in any location.
+
# the save doesn't already have an NPC with the new name.
   −
===Other building changes===
+
For example:
: ''See also: [[#Other location/map changes|other location changes]] for location-related building changes.''
+
<syntaxhighlight lang="js">
 +
"FormerCharacterNames": [ "SomeOldName" ]
 +
</syntaxhighlight>
   −
; General building changes
+
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).
* Building display names & descriptions are now in <samp>Strings/Buildings</samp> for reuse.
  −
* Removed <samp>Data/Blueprints</samp>. This has been replaced by <samp>Data/Buildings</samp> (building data) and <samp>Strings/Buildings</samp> (display names & descriptions).
  −
<ul>
  −
<li>Added methods to simplify common operations:
  −
{| class="wikitable"
   
|-
 
|-
! type
+
| <samp>FestivalVanillaActorIndex</samp>
! method
+
| ''(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.
! effect
+
|}
|-
+
</dd>
|rowspan="7"| <samp>Building</samp>
+
</dl>
| <samp>CreateInstanceFromId</samp>
+
 
| Create a building instance from its type ID in <samp>Data/Buildings</samp>. For example:
+
====Examples====
<syntaxhighlight lang="c#">
+
For example, this content pack adds a new ''Amabel'' NPC with full social features:
Building shippingBin = Building.CreateInstanceFromId("Shipping Bin", Vector2.Zero); // creates an instance of StardewValley.Buildings.ShippingBin
+
 
</syntaxhighlight>
+
{{#tag:syntaxhighlight|<nowiki>
|-
+
{
| <samp>GetData</samp><br /><samp>TryGetData</samp>
+
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
| Get the data for the building's type from <samp>Data/Building</samp>.
+
    "Changes": [
|-
+
        {
| <samp>GetMetadata</samp>
+
            "Action": "EditData",
| Get a value from [[#Custom buildings|the <samp>Metadata</samp> field in <samp>Data/Buildings</samp>]] for this building.
+
            "Target": "Data/Characters",
|-
+
            "Entries": {
| <samp>GetPaintDataKey</samp>
+
                "{{ModId}}_Amabel": {
| Get the key in <samp>Data/PaintData</samp> for this building, if it has any.
+
                    "DisplayName": "Amabel", // this would normally use {{i18n:}} to support translations
|-
+
                    "BirthSeason": "Fall",
| <samp>ReloadBuildingData</samp>
+
                    "BirthDay": 14,
| Apply the latest data in <samp>Data/Buildings</samp> to this building.
+
                    "HomeRegion": "Town",
|-
+
                    "Gender": "Female",
| <samp>FinishConstruction</samp>
+
                    "Age": "Teen",
| If the building is being constructed or upgrade, instantly finish doing so.
+
                    "Manner": "Rude",
|-
+
                    "SocialAnxiety": "Outgoing",
| <samp>UpdateTransparency</samp>
+
                    "Optimism": "Neutral",
| Update the building transparency on tick for the local player's position.
     −
This method mainly exists to let mods override/patch the transparency logic.
+
                    "CanBeRomanced": true,
|-
+
                    "LoveInterest": "Abigail",
| <samp>Farm</samp>
  −
| <samp>GetMainFarmHouse</samp>
  −
| Get the main [[farmhouse]] building.
  −
|-
  −
| <samp>GameLocation</samp>
  −
| <samp>OnParentBuildingUpgraded</samp>
  −
| Called when the building containing this location is upgraded, if applicable.
  −
|}
  −
</li>
  −
</ul>
  −
* Added building <samp>id</samp> field, which uniquely identifies each building in the world.
     −
; [[Junimo Hut|Junimo hut]] changes
+
                    "Home": [
* The <samp>JunimoHut.cropHarvestRange</samp> field is now per-building and editable.
+
                        {
 +
                            "Id": "Default",
 +
                            "Location": "SeedShop",
 +
                            "Tile": { "X": 1, "Y": 9 },
 +
                            "Direction": "Left"
 +
                        }
 +
                    ]
 +
                }
 +
            }
 +
        }
 +
    ]
 +
}</nowiki>|lang=javascript}}
   −
; [[Fish Pond|Fish pond]] changes
+
You can also add non-social NPCs which don't have birthdays or friendship points, accept gifts, give quests, etc:
<ul>
+
{{#tag:syntaxhighlight|<nowiki>
<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"
+
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
|-
+
    "Changes": [
! precedence
+
        {
! used for
+
            "Action": "EditData",
|-
+
            "Target": "Data/Characters",
| 0<br /><small>(default value)</small>
+
            "Entries": {
| specific fish
+
                "{{ModId}}_Belwick": {
|-
+
                    "DisplayName": "Belwick", // this would normally use {{i18n:}} to support translations
| 100
+
 
| custom groups (e.g. desert fish)
+
                    "SocialTab": "HiddenAlways",
|-
+
                    "CanSocialize": "FALSE",
| 500
+
                    "IntroductionsQuest": false,
| broad fish type (e.g. ocean fish)
+
                    "PerfectionScore": false,
|-
+
                    "EndSlideShow": true
| 1000
+
                }
| 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>
+
}</nowiki>|lang=javascript}}
<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 NPC appearance===
===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====
+
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.
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;">
+
For example, you can load indoor/outdoor outfits for a custom NPC to swap between automatically:
<dt>Basic info:</dt>
+
<syntaxhighlight lang="js">
<dd>
+
// add base indoor/outdoor sprites
 +
{
 +
    "Action": "Load",
 +
    "Target": "Characters/Johnny_Indoor, Characters/Johnny_Outdoor, Portraits/Johnny_Indoor, Portraits/Johnny_Outdoor",
 +
    "FromFile": "assets/{{Target}}.png"
 +
},
 +
 
 +
// apply any overlays needed
 +
{
 +
    "Action": "EditImage",
 +
    "Target": "Characters/Johnny_Indoor, Portraits/Johnny_Indoor",
 +
    "FromFile": "assets/overlays/{{Target}}_married.png",
 +
    "When": {
 +
        "Spouse": "Johnny"
 +
    }
 +
},
 +
 
 +
// add NPC
 +
{
 +
    "Action": "EditData",
 +
    "Target": "Data/Characters",
 +
    "Entries": {
 +
        "SomeMod.Id_Johnny": {
 +
            ...,
 +
            "Appearance": [
 +
                {
 +
                    "Id": "Outdoors",
 +
                    "Indoors": false,
 +
                    "Portrait": "Portraits/Johnny_Outdoor",
 +
                    "Sprite": "Characters/Johnny_Outdoor"
 +
                },
 +
                {
 +
                    "Id": "Default",
 +
                    "Portrait": "Portraits/Johnny_Indoor",
 +
                    "Sprite": "Characters/Johnny_Indoor"
 +
                }
 +
            ]
 +
        }
 +
    }
 +
}
 +
</syntaxhighlight>
 +
 
 +
See the <samp>Appearance</samp> field in [[#Custom NPCs|custom NPC data]] for more info.
 +
 
 +
===Custom farm animals===
 +
{{/doc status|[[Modding:Animal data]]|done=true}}
 +
 
 +
You can now create and edit [[Animals|farm animals]] by editing the revamped <samp>Data/FarmAnimals</samp> asset. This changes to a data model, adds built-in support for custom animals, and allows far more customizability per animal (like its size, growth, produce, appearance and sounds, etc).
 +
 
 +
===Custom pets===
 +
{{/doc status|a new doc page|done=false}}
 +
 
 +
====Format====
 +
You can now create and customize [[Animals#Cat or Dog|pet]]s & pet breeds by editing the new <samp>Data/Pets</samp> asset.
 +
 
 +
This consists of a string → model lookup, where...
 +
* The key is a [[Modding:Common data field types#Unique string ID|unique string ID]] for the pet (not the pet breed). The vanilla IDs are <samp>Cat</samp> and <samp>Dog</samp>.
 +
* The value is a model with the fields listed below.
 +
 
 +
=====Basic info=====
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 4,744: Line 4,984:  
|-
 
|-
 
| <samp>DisplayName</samp>
 
| <samp>DisplayName</samp>
| A [[Modding:Tokenizable strings|tokenizable string]] for the NPC's display name.
+
| 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>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.
+
=====Audio & sprites=====
 +
{| class="wikitable"
 
|-
 
|-
| <samp>Manner</samp>
+
! field
| ''(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>.
+
! effect
 
|-
 
|-
| <samp>SocialAnxiety</samp>
+
| <samp>BarkSound</samp>
| ''(Optional)'' A measure of the character's comfort with social situations, which affects some generic dialogue lines. One of <samp>Neutral</samp>, <samp>Outgoing</samp>, or <samp>Shy</samp>. Default <samp>Neutral</samp>.
+
| The [[#Custom audio|cue ID]] for the pet's occasional 'bark' sound.
 
|-
 
|-
| <samp>Optimism</samp>
+
| <samp>ContentSound</samp>
| ''(Optional)'' A measure of the character's overall optimism. One of <samp>Neutral</samp>, <samp>Negative</samp>, or <samp>Positive</samp>. Default <samp>Neutral</samp>.
+
| The [[#Custom audio|cue ID]] for the sound which the pet makes when you pet it.
 
|-
 
|-
| <samp>BirthSeason</samp>
+
| <samp>RepeatContentSoundAfter</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.
+
| ''(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>BirthDay</samp>
+
| <samp>EmoteOffset</samp>
| ''(Optional if non-social)'' The day number for the NPC's birthday. Default 0.
+
| ''(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.
|-
  −
| <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>.
  −
|-
  −
| <samp>IsDarkSkinned</samp>
  −
| ''(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>
+
=====Events=====
<dd>
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 4,787: Line 5,012:  
! effect
 
! effect
 
|-
 
|-
| <samp>CanSocialize</samp>
+
| <samp>EventOffset</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.
+
| ''(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>CanBeRomanced</samp>
+
| <samp>AdoptionEventLocation</samp><br /><samp>AdoptionEventId</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.
+
| ''(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>CanReceiveGifts</samp>
+
| <samp>SummitPerfectionEvent</samp>
| ''(Optional)'' Whether players can give gifts to this NPC. Default true.
+
| ''(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:
   −
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.
+
{| class="wikitable"
 
|-
 
|-
| <samp>CanCommentOnPurchasedShopItems</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>.
+
! effect
 
+
|-
The NPC must also be social per <samp>CanSocialize</samp> to allow it, regardless of this value.
+
| <samp>SourceRect</samp>
 +
| The source rectangle within the pet's texture to draw.
 
|-
 
|-
| <samp>CanGreetNearbyCharacters</samp>
+
| <samp>AnimationLength</samp>
| ''(Optional)'' Whether this NPC can show a speech bubble greeting nearby players or NPCs, and or be greeted by other NPCs. Default true.
+
| The number of frames to show starting from the <samp>SourceRect</samp>.
 
|-
 
|-
| <samp>CanVisitIsland</samp>
+
| <samp>Motion</samp>
| ''(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 motion to apply to the pet sprite.
 
  −
The NPC must also be social per <samp>CanSocialize</samp> to visit the island, regardless of this value.
   
|-
 
|-
| <samp>LoveInterest</samp>
+
| <samp>Flipped</samp>
| ''(Optional)'' Unused.
+
| ''(Optional)'' Whether to flip the pet sprite left-to-right. Default false.
 
|-
 
|-
| <samp>Calendar</samp>
+
| <samp>PingPong</samp>
| ''(Optional)'' Determines when the NPC's birthday is shown in the [[calendar]]. Possible values:
+
| ''(Optional)'' Whether to apply the 'ping pong' effect to the pet sprite animation. Default false.
 +
|}
 +
|}
 +
 
 +
=====Gifts=====
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! value
+
! field
 
! effect
 
! effect
 
|-
 
|-
| <samp>HiddenAlways</samp>
+
| <samp>GiftChance</samp>
| They never appear in the calendar.
+
| ''(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>HiddenUntilMet</samp>
+
| <samp>Gifts</samp>
| Until the player meets them, they don't appear in the calendar.
+
| ''(Optional)'' The list of gifts that this pet can give if the <samp>GiftChance</samp> is successful. Default none.
|-
+
 
| <samp>AlwaysShown</samp>
+
This consists of a list of models with these fields:
| They always appear in the calendar.
  −
|}
     −
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"
 
|-
 
|-
! value
+
! field
 
! effect
 
! effect
 
|-
 
|-
| <samp>HiddenAlways</samp>
+
| <samp>Id</samp>
| They never appear in the social tab.
+
| 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>HiddenUntilMet</samp>
+
| <samp>Stack</samp>
| Until the player meets them, they don't appear on the social tab.
+
| ''(Optional)'' The stack size of the gift item to produce. Default 1.
 
|-
 
|-
| <samp>UnknownUntilMet</samp>
+
| <samp>MinimumFriendshipThreshold</samp>
| Until the player meets them, their name on the social tab is replaced with "???".
+
| ''(Optional)'' The friendship level that this pet must be at before it can give this gift. Defaults to 1000 (max friendship).
 
|-
 
|-
| <samp>AlwaysShown</samp>
+
| <samp>Weight</samp>
| They always appear in the social tab (including their name).
+
| ''(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.
 +
|}
 
|}
 
|}
   −
Defaults to <samp>UnknownUntilMet</samp>.
+
=====Behavior=====
 +
{| class="wikitable"
 
|-
 
|-
| <samp>SpouseAdopts</samp>
+
! field
| ''(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.
+
! effect
 
  −
The <samp>Target</samp> player is the one they're married to.
   
|-
 
|-
| <samp>SpouseWantsChildren</samp>
+
| <samp>Id</samp>
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether the spouse will ask to have children. Defaults to true.
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the list.
 
  −
The <samp>Target</samp> player is the one they're married to.
   
|-
 
|-
| <samp>SpouseGiftJealousy</samp>
+
| <samp>MoveSpeed</samp>
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether the [[Marriage#Jealousy|spouse will get jealous of gifts to other NPCs]]. Defaults to true.
+
| ''(Optional)'' How quickly the pet can move. Default 2.
 
  −
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>SpouseGiftJealousyFriendshipChange</samp>
+
| <samp>SleepOnBedChance</samp><br /><samp>SleepNearBedChance</samp><br /><samp>SleepOnRugChance</samp>
| ''(Optional)'' The [[Friendship|friendship point]] effect when the <samp>SpouseGiftJealously</samp> is triggered. Default -30.
+
| ''(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>SpouseRoom</samp>
+
| <samp>Behaviors</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.
+
| The pet's possible actions and behaviors, defined as the states in a state machine. Essentially the pet will be in one state at any given time, which also determines which state they can transition to next. For example, a cat can transition from <samp>Walk</samp> to <samp>BeginSitDown</samp>, but it can't skip instantly from <samp>Walk</samp> to <samp>SitDownLick</samp>.
 +
 
 +
This consists of a list of models with these fields:
   −
This consists of a model with these fields:
+
<dl>
 +
<dt>Required fields:</dt>
 +
<dd>
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 4,882: Line 5,109:  
! effect
 
! effect
 
|-
 
|-
| <samp>MapAsset</samp>
+
| <samp>Id</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>.
+
| 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>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>.
   
|}
 
|}
|-
+
</dd>
| <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:
+
<dt>Direction:</dt>
 +
<dd>
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 4,898: Line 5,121:  
! effect
 
! effect
 
|-
 
|-
| <samp>MapAsset</samp>
+
| <samp>Direction</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>.
+
| ''(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>MapSourceRect</samp>
+
| <samp>RandomizeDirection</samp>
| ''(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>.
+
| ''(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>SpriteAnimationFrames</samp>
+
| <samp>IsSideBehavior</samp>
| ''(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.
+
| ''(Optional)'' Whether to constrain the pet's facing direction to left and right while the state is active. Default false.
 
  −
For example, here is Abigail playing the flute:
  −
<syntaxhighlight lang="js">
  −
"SpriteAnimationFrames": [
  −
    [16, 500], // show index 16 for 500ms
  −
    [17, 500],
  −
    [18, 500],
  −
    [19]      // if duration is omitted, defaults to 100ms
  −
]
  −
</syntaxhighlight>
  −
|-
  −
| <samp>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.
   
|}
 
|}
|-
+
</dd>
| <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.
+
<dt>Movement:</dt>
|-
+
<dd>
| <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>EndSlideShow</samp>
  −
| ''(Optional)'' How the NPC appears in the end-game perfection slide show. Possible values:
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! value
+
! field
 
! effect
 
! effect
 
|-
 
|-
| <samp>Hidden</samp>
+
| <samp>WalkInDirection</samp>
| The NPC doesn't appear in the slide show.
+
| ''(Optional)'' Whether to walk in the pet's facing direction. Default false.
 
|-
 
|-
| <samp>MainGroup</samp>
+
| <samp>MoveSpeed</samp>
| The NPC is added to the main group of NPCs which walk across the screen.
+
| ''(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).
|-
  −
| <samp>TrailingGroup</samp>
  −
| The NPC is added to the trailing group of NPCs which follow the main group.
  −
|}
  −
 
  −
Defaults to <samp>MainGroup</samp>.
  −
|-
  −
| <samp>FriendsAndFamily</samp>
  −
| ''(Optional)'' The NPC's closest friends and family, as a dictionary where the key is the other NPC's internal name and the value is an optional tokenizable string for the name to use in dialogue text (like 'mom'). Default none.
  −
 
  −
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>
 
</dd>
   −
<dt>Dumpster diving:</dt>
+
<dt>Audio:</dt>
 
<dd>
 
<dd>
 
{| class="wikitable"
 
{| class="wikitable"
Line 4,970: Line 5,154:  
! effect
 
! effect
 
|-
 
|-
| <samp>DumpsterDiveEmote</samp>
+
| <samp>SoundOnStart</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).
+
| ''(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>DumpsterDiveFriendshipEffect</samp>
+
| <samp>SoundIsVoice</samp>
| ''(Optional)'' The friendship point change if this NPC sees a player rummaging through trash. Default -25.
+
| ''(Optional)'' Whether to mute the <samp>SoundOnStart</samp> when the 'mute animal sounds' option is set. Default false.
|}</dd>
+
|}
 +
</dd>
   −
<dt>Festivals:</dt>
+
<dt>Behavior transitions:</dt>
 
<dd>
 
<dd>
 
{| class="wikitable"
 
{| class="wikitable"
Line 4,984: Line 5,172:  
! effect
 
! effect
 
|-
 
|-
| <samp>FlowerDanceCanDance</samp>
+
| <samp>AnimationEndBehaviorChanges</samp><br /><samp>TimeoutBehaviorChanges</samp><br /><samp>PlayerNearbyBehaviorChanges</samp><br /><samp>RandomBehaviorChanges</samp><br /><samp>JumpLandBehaviorChanges</samp>
| ''(Optional)'' Whether players can ask the NPC to dance at the Flower Dance festival. The possible values are <samp>true</samp> (can always ask), <samp>false</samp> (can never ask), or <samp>null</samp> (can ask if they're romanceable). Default <samp>null</samp>.
+
| ''(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.
   −
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).
+
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>).
|-
  −
| <samp>WinterStarParticipant</samp>
  −
| ''(Optional)''  A [[Modding:Game state queries|game state query]] which indicates whether this NPC can give and receive gifts at the [[Feast of the Winter Star]]. If <samp>null</samp> (or omitted), this will default to true if the <samp>HomeRegion</samp> field is set to <samp>Town</samp>.
  −
|-
  −
| <samp>WinterStarGifts</samp>
  −
| At the [[Feast of the Winter Star]], the possible gifts this NPC can give to players. A matching entry is selected at random.
     −
This consists of a list of models with these fields:
+
These consist of a list of models with these fields:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 5,001: Line 5,183:  
! effect
 
! effect
 
|-
 
|-
| ''common fields''
+
| <samp>Behavior</samp><br /><samp>LeftBehavior</samp><br /><samp>RightBehavior</samp><br /><samp>UpBehavior</samp><br /><samp>DownBehavior</samp>
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields.
+
| 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.
 
+
|-
If set to an [[Modding:Item queries|item query]] which returns multiple items, one of them will be selected at random.
+
| <samp>OutsideOnly</samp>
 +
| ''(Optional)'' Whether the transition can only happen if the pet is outside. Default false.
 +
|-
 +
| <samp>Weight</samp>
 +
| ''(Optional)'' The option's weight when randomly choosing a behavior, relative to other behaviors in the list (e.g. <samp>2</samp> is twice as likely as <samp>1</samp>). Default 1.
 
|}
 
|}
 +
|-
 +
| <samp>Duration</samp><br /><samp>MinimumDuration</samp><br /><samp>MaximumDuration</samp>
 +
| ''(Optional)'' The millisecond duration until the pet transitions to a behavior in the <samp>TimeoutBehaviorChanges</samp> field, if set. You must specify either a specific duration, or an inclusive minimum-to-maximum range in which the game will choose a random duration. If omitted, the behavior won't have a duration limit.
 +
|-
 +
| <samp>RandomBehaviorChangeChance</samp>
 +
| ''(Optional)'' The random probability at the start of each frame that the pet will transition to a behavior in the <samp>RandomBehaviorChanges</samp> field, if set. Specified as a value between 0 (never) and 1 (always). Default 0.
 
|}
 
|}
 +
</dd>
   −
<dt>Spawn rules:</dt>
+
<dt>Animation and per-frame sounds:</dt>
 
<dd>
 
<dd>
 
{| class="wikitable"
 
{| class="wikitable"
Line 5,015: Line 5,208:  
! effect
 
! effect
 
|-
 
|-
| <samp>UnlockConditions</samp>
+
| <samp>Animation</samp>
| ''(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.
+
| ''(Optional)'' The animation frames to play while this state is active. This consists of a list of models with these fields:
|-
  −
| <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 5,030: Line 5,215:  
! effect
 
! effect
 
|-
 
|-
| <samp>ID</samp>
+
| <samp>Frame</samp>
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the current list.
+
| The frame index in the animation. This should be an incremental number starting at 0.
 +
|-
 +
| <samp>Duration</samp>
 +
| The millisecond duration for which the frame should be kept on-screen before continuing to the next frame.
 
|-
 
|-
| <samp>Location</samp>
+
| <samp>HitGround</samp>
| ''(Optional)'' The internal name for the home location where this NPC spawns and returns each day. Default none.
+
| ''(Optional)'' Whether to play the footstep sound for the tile under the pet when the frame starts. Default false.
 
|-
 
|-
| <samp>Tile</samp>
+
| <samp>Jump</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)'' Whether the pet should perform a small hop when the frame starts, including a 'dwop' sound. Default false.
 
|-
 
|-
| <samp>Direction</samp>
+
| <samp>Sound</samp>
| ''(Optional)'' The default direction the NPC faces when they start each day. The possible values are <samp>down</samp>, <samp>left</samp>, <samp>right</samp>, and <samp>up</samp>. Defaults to <samp>up</samp>.
+
| ''(Optional)'' The [[#Custom audio|audio cue ID]] for the sound to play when the animation starts or loops. If set to <samp>BARK</samp>, the pet's <samp>BarkSound</samp> (or breed's <samp>BarkOverride</samp>) field is used. Defaults to none.
 
|-
 
|-
| <samp>Condition</samp>
+
| <samp>SoundRange</samp><br /><samp>SoundRangeFromBorder</samp><br /><samp>SoundIsVoice</samp>
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this entry can be selected. Default true.
+
| See description for the equivalent behavior fields, but applies to the frame's <samp>Sound</samp> field instead.
 
|}
 
|}
 +
|-
 +
| <samp>Shake</samp>
 +
| ''(Optional)'' The millisecond duration for which to shake the pet when the state starts. Default 0.
 +
|-
 +
| <samp>LoopMode</samp>
 +
| ''(Optional)'' What to do when the last animation frame is reached while the behavior is still active. The possible values are <samp>Hold</samp> (keep the last frame visible until the animation ends), <samp>Loop</samp> (restart from the first frame), or <samp>None</samp> (equivalent to <samp>Loop</samp>). Default <samp>None</samp>.
 +
|-
 +
| <samp>AnimationMinimumLoops</samp><br /><samp>AnimationMaximumLoops</samp>
 +
| ''(Optional)'' The minimum and maximum number of times to play the animation. Both must be specified to have any effect. The game will choose an inclusive random value between them. Both default to -1 (don't repeat animation).
 
|}
 
|}
 
</dd>
 
</dd>
 +
</dl>
 +
|}
   −
<dt>Appearance & sprite:</dt>
+
=====Breeds=====
<dd>
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 5,055: Line 5,253:  
! effect
 
! effect
 
|-
 
|-
| <samp>TextureName</samp>
+
| <samp>Breeds</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 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:
|-
  −
| <samp>Appearance</samp>
  −
| ''(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 5,071: Line 5,260:  
! effect
 
! effect
 
|-
 
|-
| <samp>Id</samp>
+
| <samp>ID</samp>
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this entry within the current list.
+
| The unique ID for the breed within the pet type.
 
|-
 
|-
| <samp>Season</samp>
+
| <samp>Texture</samp>
| ''(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.
+
| 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>Indoors</samp><br /><samp>Outdoors</samp>
+
| <samp>IconTexture</samp>
| ''(Optional)'' Whether this appearance should be used when indoors and/or outdoors. Both default to true.
+
| 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>Condition</samp>
+
| <samp>IconSourceRect</samp>
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this entry can be selected. Default true.
+
| 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>Portrait</samp><br /><samp>Sprite</samp>
+
| <samp>BarkOverride</samp>
| ''(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.
+
| ''(Optional)'' Override the pet's <samp>BarkSound</samp> field for this breed, if set.
 
|-
 
|-
| <samp>IsIslandAttire</samp>
+
| <samp>VoicePitch</samp>
| ''(Optional)'' Whether this is island beach attire worn at the resort. Default false.
+
| ''(Optional)'' The [[wikipedia:Pitch (music)|pitch]] applied to the pet's bark sound, measured as a decimal value relative to 1. Defaults to 1.
 +
|}
 +
|}
   −
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.
+
=====Advanced=====
 +
{| class="wikitable"
 
|-
 
|-
| <samp>Precedence</samp>
+
! field
| ''(Optional)'' The order in which this entry should be checked, where lower values are checked first. This can be a negative value. Default 0.
+
! effect
 
|-
 
|-
| <samp>Weight</samp>
+
| <samp>CustomFields</samp>
| ''(Optional)'' If multiple entries with the same <samp>Precedence</samp> match, the relative weight to use when randomly choosing one. Default 1.
+
| The [[#Custom data fields|custom fields]] for this entry.
 +
|}
 +
 
 +
====Other changes====
 +
* The pet bowl is now a building which can be constructed or moved. Each pet is assigned to an available pet bowl. For C# mods, each pet now has a <samp>guid</samp> field populated with a unique ID, and each pet bowl has a <samp>petGuid</samp> field which tracks its owner (see the <samp>PetBowl::HasPet()</samp> and <samp>PetBowl::FindPet()</samp> methods).
 +
* In the [[Modding:Event data#Basic format|event character setup]], you can now use <samp>pet</samp> to add a pet of the player's selected type. Its actor name will be <samp>PetActor</samp> in other event commands. This supersedes <samp>cat</samp> (with name <samp>Cat</samp>) and <samp>dog</samp> (with name <samp>Dog</samp>), though those still work too.
 +
* For C# mods:
 +
** All pets now use a generic <samp>Pet</samp> class, instead of <samp>Cat</samp> or <samp>Dog</samp>. The pet type is tracked by the pet's <samp>petType</samp> field.
 +
** The player's preferred pet type is tracked by <samp>Game1.player.whichPetType</samp>. The former <samp>catPerson</samp> field is now readonly and checks that field.
 +
** Added <samp>Pet.type_cat</samp> and <samp>Pet.type_dog</samp> constants for the default pet types.
 +
 
 +
===Custom monster eradication goals===
 +
{{/doc status|a new doc page|done=false}}
 +
 
 +
: ''See also: [[#Monster eradication goal flag changes|Monster eradication goal flag changes]].''
   −
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.
+
You can now add/edit [[Adventurer's Guild]] monster eradication goals by editing the new <samp>Data/MonsterSlayerQuests</samp> data asset.
|}
     −
'''Note:''' the default textures based on <samp>TextureName</samp> must still exist, even if you use this field to override them.
+
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.
| <samp>MugShotSourceRect</samp>
+
* The value is a model with the fields listed below.
| ''(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>Size</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>.
     −
'''Note:''' sizes bigger than 16×32 will cause issues like broken spawning, pathfinding, misalignment in the [[perfection]] end-game slide show, etc.
+
{| class="wikitable"
 
|-
 
|-
| <samp>Breather</samp>
+
! field
| ''(Optional)'' Whether the chest on the NPC's overworld sprite puffs in and out as they breathe. Default true</samp>.
+
! effect
 
|-
 
|-
| <samp>BreathChestRect</samp>
+
| <samp>DisplayName</samp>
| ''(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.
+
| A [[Modding:Tokenizable strings|tokenizable string]] for the goal's display name, shown on the board in the Adventurer's Guild.
 
|-
 
|-
| <samp>BreathChestPosition</samp>
+
| <samp>Targets</samp>
| ''(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.
+
| A list of [[Modding:Monster data#Monster IDs|monster IDs]] that are counted towards the <samp>Count</samp>.
 
|-
 
|-
| <samp>Shadow</samp>
+
| <samp>Count</samp>
| ''(Optional)'' The options for the shadow to draw under the NPC, or omit to apply the default shadow behavior.
+
| The total number of monsters (matching the <samp>Targets</samp>) which must be defeated to complete this goal.
 
  −
This consists of a model with these fields:
  −
 
  −
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>RewardItemId</samp>
! effect
+
| ''(Optional)'' The [[#Custom items|qualified ID]] for the item that can be collected from [[Gil]] when this goal is completed. Default none.
 
|-
 
|-
| <samp>Visible</samp>
+
| <samp>RewardItemPrice</samp>
| ''(Optional)'' Whether the shadow should be drawn. Default true.
+
| ''(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>Offset</samp>
+
| <samp>RewardDialogue</samp><br /><samp>RewardDialogueFlag</samp>
| ''(Optional)'' A [[Modding:Common data field types#Point|point]] pixel offset applied to the shadow position. Default zero.
+
| ''(Optional)'' A [[Modding:Tokenizable strings|tokenizable string]] for custom [[Gil]] dialogue shown when talking to him after completing the goal, and an optional [[Modding:Mail data|mail flag]] to set when the player has seen the dialogue. Both default to none.
 +
 
 +
If there are reward items, they're shown after this dialogue.
 +
 
 +
If <samp>RewardDialogue</samp> is used without <samp>RewardDialogueFlag</samp>, then this dialogue will be shown each time the reward menu is opened after completing the goal, until the player collects the reward items. If the <samp>RewardItems</samp> isn't set, this can safely be omitted since the goal will be marked collected immediately.
 +
 
 +
This doesn't send a letter; see <samp>RewardMail</samp> or <samp>RewardMailAll</samp> for that.
 
|-
 
|-
| <samp>Scale</samp>
+
| <samp>RewardFlag</samp><br /><samp>RewardFlagAll</samp>
| ''(Optional)'' The scale at which to draw the shadow. Default 1.
+
| ''(Optional)'' The [[Modding:Mail data|mail flag ID]] to set for the current player (<samp>RewardFlag</samp>) or all players (<samp>RewardFlagAll</samp>) when talking to [[Gil]] after completing the goal. Default none.
 +
 
 +
Note that <samp>RewardFlag</samp> is usually not needed, since the game will also set a <samp>Gil_{{t|goal ID}}</samp> flag regardless.
   −
This 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.
+
This doesn't send a letter; see <samp>RewardMail</samp> or <samp>RewardMailAll</samp> for that.
|}
   
|-
 
|-
| <samp>EmoteOffset</samp>
+
| <samp>RewardMail</samp><br /><samp>RewardMailAll</samp>
| ''(Optional)'' A [[Modding:Common data field types#Point|point]] pixel offset applied to emote drawn over the NPC. Default zero.
+
| ''(Optional)'' The mail letter ID to add to the mailbox tomorrow for the current player (<samp>RewardMail</samp>) or all players (<samp>RewardMailAll</samp>). Default none.
 
|-
 
|-
| <samp>ShakePortraits</samp>
+
| <samp>CustomFields</samp>
| ''(Optional)'' The portrait indexes which should shake when displayed. Default none.
+
| The [[#Custom data fields|custom fields]] for this entry.
|-
  −
| <samp>KissSpriteIndex</samp>
  −
| ''(Optional)'' If the NPC can be married, the sprite index within their <samp>Texture</samp> to use when kissing a player. Default 28.
  −
|-
  −
| <samp>KissSpriteFacingDirection</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.
   
|}
 
|}
</dd>
     −
<dt>[[Secrets#Gift Log|Hidden gift log emote]]:</dt>
+
===Custom phone calls===
<dd>
+
{{/doc status|a new doc page|done=false}}
 +
 
 +
Mods can now extend the [[telephone]] with custom calls (both incoming calls, and phone numbers which the player can call).
 +
 
 +
====Incoming calls====
 +
You can add or customize incoming calls by editing the <samp>Data/IncomingPhoneCalls</samp> asset.
 +
 
 +
This consists of a string → model lookup, where...
 +
* The key is a [[Modding:Common data field types#Unique string ID|unique string ID]] for the incoming call data.
 +
* The value is a model with the fields listed below.
 +
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 5,162: Line 5,369:  
! effect
 
! effect
 
|-
 
|-
| <samp>HiddenProfileEmoteSound</samp>
+
| <samp>Dialogue</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>.
+
| The dialogue text to show when the player answers the phone. This can use the full [[Modding:Dialogue|dialogue format]] (including questions and different dialogue based on the selected answer).
 +
|-
 +
| <samp>FromNpc</samp>
 +
| ''(Optional)'' The internal name of the NPC making the call. If specified, that NPC's name and portrait will be shown.
 +
|-
 +
| <samp>FromPortrait</samp>
 +
| ''(Optional)'' The asset name for the portrait spritesheet to display (like <samp>Portraits/Abigail</samp>). If <samp>FromNpc</samp> is specified too, this overrides the portrait from that NPC. If both <samp>FromNpc</samp> and <samp>FromDisplayName</samp> are null, this portrait will be shown with the display name "???".
 
|-
 
|-
| <samp>HiddenProfileEmoteDuration</samp>
+
| <samp>FromDisplayName</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)'' 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>HiddenProfileEmoteStartFrame</samp>
+
| <samp>MaxCalls</samp>
| ''(Optional)'' For the [[Secrets#Gift Log|hidden gift log emote]], the index within the NPC's overworld sprite spritesheet at which the animation starts. If omitted for a vanilla NPC, the game plays a default animation specific to that NPC; if omitted for a custom NPC, the game just shows them walking while facing down.
+
| ''(Optional)'' The maximum number of times a player can receive this phone call, or <samp>-1</samp> for no limit. Default 1.
 
|-
 
|-
| <samp>HiddenProfileEmoteFrameCount</samp>
+
| <samp>TriggerCondition</samp><br /><samp>RingCondition</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)'' 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>).
   −
This has no effect if <samp>HiddenProfileEmoteStartFrame</samp> isn't set.
+
Whether a player receives this call depends on both fields: <samp>TriggerCondition</samp> is checked on the main player before sending the call to all players, then <samp>RingCondition</samp> is checked on each player to determine whether the phone rings for them.
 +
|-
 +
| <samp>IgnoreBaseChance</samp>
 +
| ''(Optional)'' Whether to ignore the 1% base chance when checking whether to trigger an incoming call. If true, the game will check if this call can be received regardless of the base chance. Default false.
 
|-
 
|-
| <samp>HiddenProfileEmoteFrameDuration</samp>
+
| <samp>SimpleDialogueSplitBy</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.
+
| ''(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.
   −
This has no effect if <samp>HiddenProfileEmoteStartFrame</samp> isn't set.
+
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.
|}
  −
</dd>
  −
 
  −
<dt>Advanced:</dt>
  −
<dd>
  −
{| class="wikitable"
  −
|-
  −
! field
  −
! effect
   
|-
 
|-
 
| <samp>CustomFields</samp>
 
| <samp>CustomFields</samp>
 
| The [[#Custom data fields|custom fields]] for this entry.
 
| The [[#Custom data fields|custom fields]] for this entry.
|-
+
|}
| <samp>FormerCharacterNames</samp>
  −
| ''(Optional)'' The former NPC names which may appear in save data. If matched, the game will rename the NPC and update related data (e.g. friendship).
     −
A former name is only applied if:
+
====Custom handlers in C#====
# it doesn't match a current ID in <samp>Data/Characters</samp>;
+
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:
# the save has an NPC with the former name;
+
 
# the save doesn't already have an NPC with the new name.
+
<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());
 +
    }
 +
}
   −
For example:
+
/// <summary>A custom phone handler.</summary>
<syntaxhighlight lang="js">
+
internal sealed class CustomPhoneHandler : IPhoneHandler
"FormerCharacterNames": [ "SomeOldName" ]
+
{
 +
    ...
 +
}
 
</syntaxhighlight>
 
</syntaxhighlight>
   −
Former names can have any format, but they must be '''globally''' unique. They can't match the ID or <samp>FormerCharacterNames</samp> of any other NPC in <samp>Data/Characters</samp> (whether vanilla or custom).
+
See <samp>StardewValley.PhoneCalls.DefaultPhoneHandler</samp> in the [[Modding:Modder Guide/Get Started#decompile|decompiled game code]] for an example implementation.
|-
  −
| <samp>FestivalVanillaActorIndex</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.
  −
|}
  −
</dd>
  −
</dl>
     −
====Examples====
+
===Custom shops===
For example, this content pack adds a new ''Amabel'' NPC with full social features:
+
{{/doc status|[[Modding:Shops]]|done=true}}
   −
{{#tag:syntaxhighlight|<nowiki>
+
You can now create and edit shops via the new <samp>Data/Shops</samp> asset. See [[Modding:Shops]] for documentation and examples.
{
  −
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
  −
    "Changes": [
  −
        {
  −
            "Action": "EditData",
  −
            "Target": "Data/Characters",
  −
            "Entries": {
  −
                "{{ModId}}_Amabel": {
  −
                    "DisplayName": "Amabel", // this would normally use {{i18n:}} to support translations
  −
                    "BirthSeason": "Fall",
  −
                    "BirthDay": 14,
  −
                    "HomeRegion": "Town",
  −
                    "Gender": "Female",
  −
                    "Age": "Teen",
  −
                    "Manner": "Rude",
  −
                    "SocialAnxiety": "Outgoing",
  −
                    "Optimism": "Neutral",
     −
                    "CanBeRomanced": true,
+
===Dialogue changes===
                    "LoveInterest": "Abigail",
+
{{/doc status|[[Modding:Dialogue]]|done=false}}
   −
                    "Home": [
+
<ul>
                        {
+
<li>Added new [[Modding:Dialogue|dialogue]] keys:
                            "Id": "Default",
+
{| class="wikitable"
                            "Location": "SeedShop",
+
|-
                            "Tile": { "X": 1, "Y": 9 },
+
! asset
                            "Direction": "Left"
+
! 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.
}</nowiki>|lang=javascript}}
     −
You can also add non-social NPCs which don't have birthdays or friendship points, accept gifts, give quests, etc:
+
The first matching dialogue is used in this order:
{{#tag:syntaxhighlight|<nowiki>
+
# by item ID (like <samp>AcceptBirthdayGift_(O)128</samp>);
{
+
# by context tag (like <samp>AcceptBirthdayGift_category_fish</samp>);
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
+
# 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>);
    "Changes": [
+
# <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>).
            "Action": "EditData",
  −
            "Target": "Data/Characters",
  −
            "Entries": {
  −
                "{{ModId}}_Belwick": {
  −
                    "DisplayName": "Belwick", // this would normally use {{i18n:}} to support translations
     −
                    "SocialTab": "HiddenAlways",
+
|-
                    "CanSocialize": "FALSE",
+
| <samp>AcceptBouquet</samp>
                    "IntroductionsQuest": false,
+
| Shown when the NPC accepts a [[bouquet]] from the player. Defaults to a generic dialogue.
                    "PerfectionScore": false,
+
|-
                    "EndSlideShow": true
+
| <samp>AcceptGift_{{t|id}}</samp><br /><samp>AcceptGift_{{t|tag}}</samp>
                }
+
| Shown when receiving a non-birthday gift from the player. This can be by item ID (like <samp>AcceptGift_(O)128</samp>) or context tag (like <samp>AcceptGift_category_fish</samp>). If omitted, defaults to the dialogue in <samp>Data/NPCGiftTastes</samp>.
            }
+
|-
        }
+
| <samp>DumpsterDiveComment</samp>
    ]
+
| Shown when the NPC catches the player digging through a trash can. Defaults to a generic dialogue based on the NPC's age.
}</nowiki>|lang=javascript}}
+
|-
 
+
| <samp>HitBySlingshot</samp>
===Custom NPC appearance===
+
| Shown when the player shoots them with a [[slingshot]]. Defaults to a generic dialogue.
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.
+
|-
 +
| <samp>RejectBouquet_Divorced</samp><br /><samp>RejectBouquet_NotDatable</samp><br /><samp>RejectBouquet_NpcAlreadyMarried</samp><br /><samp>RejectBouquet_VeryLowHearts</samp><br /><samp>RejectBouquet_LowHearts</samp><br /><samp>RejectBouquet</samp>
 +
| Shown when the NPC rejects a [[bouquet]].
 +
 
 +
A specific dialogue is shown if possible:
 +
* <samp>RejectBouquet_Divorced</samp>: the NPC won't accept this bouquet because you divorced them.
 +
* <samp>RejectBouquet_NotDatable</samp>: the NPC isn't romanceable.
 +
* <samp>RejectBouquet_NpcAlreadyMarried</samp>: the NPC is already married to another player. You can use <samp>{0}</samp> in the dialogue for the other player's name.
 +
* <samp>RejectBouquet_VeryLowHearts</samp>: you have less than 4 hearts with the NPC.
 +
* <samp>RejectBouquet_LowHearts</samp>: you have less than 8 hearts with the NPC.
   −
For example, you can load indoor/outdoor outfits for a custom NPC to swap between automatically:
+
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.
<syntaxhighlight lang="js">
+
|-
// add base indoor/outdoor sprites
+
| <samp>RejectGift_Divorced</samp>
{
+
| Shown when the NPC rejects a gift because you divorced them.
    "Action": "Load",
+
|-
    "Target": "Characters/Johnny_Indoor, Characters/Johnny_Outdoor, Portraits/Johnny_Indoor, Portraits/Johnny_Outdoor",
+
| <samp>RejectItem_{{t|id}}</samp><br /><samp>RejectItem_{{t|tag}}</samp>
    "FromFile": "assets/{{Target}}.png"
+
| If set, the NPC will refuse to accept any matching item and show this dialogue instead. This can be by item ID (like <samp>RejectItem_(O)128</samp>) or context tag (like <samp>RejectItem_category_fish</samp>). This can prevent gifting, movie tickets, bouquets, mermaid pendants, etc. However it won't prevent accepting an item for an active quest or special order.
},
+
|-
 +
| <samp>RejectMermaidPendant_Divorced</samp><br /><samp>RejectMermaidPendant_NeedHouseUpgrade</samp><br /><samp>RejectMermaidPendant_NotDatable</samp><br /><samp>RejectMermaidPendant_NpcWithSomeoneElse</samp><br /><samp>RejectMermaidPendant_PlayerWithSomeoneElse</samp><br /><samp>RejectMermaidPendant_Under8Hearts</samp><br /><samp>RejectMermaidPendant_Under10Hearts</samp><br /><samp>RejectMermaidPendant_Under10Hearts_AskedAgain</samp><br /><samp>RejectMermaidPendant</samp>
 +
| Shown when the NPC rejects a [[Mermaid's Pendant|mermaid's pendant]].
   −
// apply any overlays needed
+
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.
    "Action": "EditImage",
+
# <samp>RejectMermaidPendant_NotDatable</samp>: the NPC isn't romanceable.
    "Target": "Characters/Johnny_Indoor, Portraits/Johnny_Indoor",
+
# <samp>RejectMermaidPendant_Divorced</samp>: you divorced them, so they won't accept gifts or proposals from you.
    "FromFile": "assets/overlays/{{Target}}_married.png",
+
# <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.
    "When": {
+
# <samp>RejectMermaidPendant_Under8Hearts</samp>: you have under 8 hearts with the NPC.
        "Spouse": "Johnny"
+
# <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.
   −
// add NPC
+
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.
{
+
|-
    "Action": "EditData",
+
| <samp>RejectMovieTicket_AlreadyInvitedBySomeoneElse</samp><br /><samp>RejectMovieTicket_AlreadyWatchedThisWeek</samp><br /><samp>RejectMovieTicket_Divorced</samp><br /><samp>RejectMovieTicket_DontWantToSeeThatMovie</samp><br /><samp>RejectMovieTicket</samp>
    "Target": "Data/Characters",
+
| Show when the NPC rejects a [[Movie Ticket|movie ticket]].
    "Entries": {
  −
        "SomeMod.Id_Johnny": {
  −
            ...,
  −
            "Appearance": [
  −
                {
  −
                    "Id": "Outdoors",
  −
                    "Indoors": false,
  −
                    "Portrait": "Portraits/Johnny_Outdoor",
  −
                    "Sprite": "Characters/Johnny_Outdoor"
  −
                },
  −
                {
  −
                    "Id": "Default",
  −
                    "Portrait": "Portraits/Johnny_Indoor",
  −
                    "Sprite": "Characters/Johnny_Indoor"
  −
                }
  −
            ]
  −
        }
  −
    }
  −
}
  −
</syntaxhighlight>
     −
See the <samp>Appearance</samp> field in [[#Custom NPCs|custom NPC data]] for more info.
+
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).
   −
===Custom farm animals===
+
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.
: ''Main article: [[Modding:Animal data]].''
  −
 
  −
You can now create and edit [[Animals|farm animals]] by editing the revamped <samp>Data/FarmAnimals</samp> asset. This changes to a data model, adds built-in support for custom animals, and allows far more customizability per animal (like its size, growth, produce, appearance and sounds, etc).
  −
 
  −
===Custom pets===
  −
====Format====
  −
You can now create and customize [[Animals#Cat or Dog|pet]]s & pet breeds by editing the new <samp>Data/Pets</samp> asset.
  −
 
  −
This consists of a string → model lookup, where...
  −
* The key is a [[Modding:Common data field types#Unique string ID|unique string ID]] for the pet (not the pet breed). The vanilla IDs are <samp>Cat</samp> and <samp>Dog</samp>.
  −
* The value is a model with the fields listed below.
  −
 
  −
=====Basic info=====
  −
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>SpouseFarmhouseClutter</samp>
! effect
+
| Shown by an NPC spouse when they couldn't pathfind to their kitchen standing spot in the farmhouse.
 
|-
 
|-
| <samp>DisplayName</samp>
+
| <samp>SpouseGiftJealous</samp>
| 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.
+
| 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.
|}
  −
 
  −
=====Audio & sprites=====
  −
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>Spouse_MonstersInHouse</samp>
! effect
+
| Shown by an NPC spouse when they're in the farmhouse and there's a monster close to them.
 
|-
 
|-
| <samp>BarkSound</samp>
+
| <samp>SpouseStardrop</samp>
| The [[#Custom audio|cue ID]] for the pet's occasional 'bark' sound.
+
| Shown when receiving the [[stardrop]] from your spouse.
 
|-
 
|-
| <samp>ContentSound</samp>
+
| <samp>Fair_Judging</samp>
| The [[#Custom audio|cue ID]] for the sound which the pet makes when you pet it.
+
| Shown at the [[Stardew Valley Fair]] while Lewis is judging the grange displays. If omitted, the NPC will keep their normal festival dialogue.
 +
 
 +
If this is set without <samp>Fair_Judged*</samp>, the NPC will keep this dialogue after judging is done.
 +
 
 +
''This replaces the previously hardcoded translations in <samp>Strings/StringsFromCSFiles</samp>: <samp>Event.cs.1602</samp> (Marnie), <samp>Event.cs.1604</samp> (Pierre), and <samp>Event.cs.1606</samp> (Willy).''
 
|-
 
|-
| <samp>RepeatContentSoundAfter</samp>
+
| <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>
| ''(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).
+
| 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>EmoteOffset</samp>
+
| <samp>FlowerDance_Accept_Roommate</samp><br /><samp>FlowerDance_Accept_Spouse</samp><br /><samp>FlowerDance_Accept</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.
+
| 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.
|}
     −
=====Events=====
+
''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>).''
{| class="wikitable"
+
|-
 +
| <samp>FlowerDance_Decline</samp>
 +
| Shown at the [[Flower Dance]] when the NPC declines to dance. This replaces the former <samp>danceRejection</samp> key (which still works as a fallback).
 
|-
 
|-
! field
+
| <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>
! effect
+
| 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>EventOffset</samp>
+
| <samp>WinterStar_ReceiveGift_{{t|id}}</samp><br /><samp>WinterStar_ReceiveGift_{{t|tag}}</samp><br /><samp>WinterStar_ReceiveGift</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.
+
| 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>AdoptionEventLocation</samp><br /><samp>AdoptionEventId</samp>
+
| <samp>WipedMemory</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.
+
| Shown the first time you talk to the NPC after erasing their memory using the [[Dark Shrine of Memory]].
 +
|}
 +
</li>
 +
<li>Added new [[Modding:Dialogue|dialogue]] commands:
 +
{| class="wikitable"
 
|-
 
|-
| <samp>SummitPerfectionEvent</samp>
+
! command
| ''(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.
+
! 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>.
   −
This consists of a model with these fields:
+
You can optionally use <samp>¦</samp> instead of <samp>^</samp>, in which case any <samp>^</samp> characters are left as-is.
   −
{| class="wikitable"
+
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.
 
|-
 
|-
! field
+
| <samp>$action {{t|action}}</samp>
! effect
+
| Run a [[Modding:Trigger actions|trigger action string]], like <samp>$action AddMoney 500</samp> to add {{price|500}} to the current player.
 
|-
 
|-
| <samp>SourceRect</samp>
+
| <samp>$query {{t|query}}#{{t|if true}}&#124;{{t|if false}}</samp>
| The source rectangle within the pet's texture to draw.
+
| Show different dialogue text depending on the [[Modding:Game state queries|game state query]] in {{t|query}}. For example:
 +
<syntaxhighlight lang="js">
 +
"Mon": "$query !PLAYER_VISITED_LOCATION Current Mine#Did you know there's an old abandoned mine up in the mountain? Apparently it's crawling with monsters!|I heard you went into the old mines up in the mountain!#Did you find anything tasty?$h"
 +
</syntaxhighlight>
 
|-
 
|-
| <samp>AnimationLength</samp>
+
| <samp>$t {{t|topic ID}} {{o|day length}}</samp>
| The number of frames to show starting from the <samp>SourceRect</samp>.
+
| Add a [[Modding:Dialogue#Conversation topics|conversation topic]] for the next {{o|day length}} days (default 4 days).
 
|-
 
|-
| <samp>Motion</samp>
+
| <samp>$v {{t|event id}} {{o|check preconditions}} {{o|skip if seen}}</samp>
| The motion to apply to the pet sprite.
+
| 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>Flipped</samp>
+
* {{o|skip if seen}}: whether to ignore the command if the player has already seen the given event. Default true.
| ''(Optional)'' Whether to flip the pet sprite left-to-right. Default false.
  −
|-
  −
| <samp>PingPong</samp>
  −
| ''(Optional)'' Whether to apply the 'ping pong' effect to the pet sprite animation. Default false.
  −
|}
  −
|}
     −
=====Behavior=====
+
If the event is not played, the dialogue continues to the next line instead.
{| class="wikitable"
  −
|-
  −
! field
  −
! effect
  −
|-
  −
| <samp>MoveSpeed</samp>
  −
| ''(Optional)'' How quickly the pet can move. Default 2.
  −
|-
  −
| <samp>SleepOnBedChance</samp><br /><samp>SleepNearBedChance</samp><br /><samp>SleepOnRugChance</samp>
  −
| ''(Optional)'' The percentage chances for the locations where the pet will sleep each night, as a decimal value between 0 (never) and 1 (always). Each value is checked in the order listed at left until a match is found. If none of them match, the pet will choose a random empty spot in the farmhouse; if none was found, it'll sleep next to its pet bowl outside.
  −
|-
  −
| <samp>Behaviors</samp>
  −
| The pet's possible actions and behaviors, defined as the states in a state machine. Essentially the pet will be in one state at any given time, which also determines which state they can transition to next. For example, a cat can transition from <samp>Walk</samp> to <samp>BeginSitDown</samp>, but it can't skip instantly from <samp>Walk</samp> to <samp>SitDownLick</samp>.
     −
This consists of a list of models with these fields:
+
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. 
   −
<dl>
+
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.  
<dt>Required fields:</dt>
  −
<dd>
  −
{| class="wikitable"
  −
|-
  −
! field
  −
! effect
  −
|-
  −
| <samp>Name</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).
   
|}
 
|}
</dd>
+
</li>
 
+
<li>Improved dialogue commands:
<dt>Direction:</dt>
  −
<dd>
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! command
! effect
+
! changes
 
|-
 
|-
| <samp>Direction</samp>
+
| <samp>$p</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>.  
+
| 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>
| <samp>RandomizeDirection</samp>
+
|}</li>
| ''(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.
+
<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>
| <samp>IsSideBehavior</samp>
+
<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}}):
| ''(Optional)'' Whether to constrain the pet's facing direction to left and right while the state is active. Default false.
+
<syntaxhighlight lang="c#">
|}
+
private void OnMenuChanged(object sender, MenuChangedEventArgs e)
</dd>
+
{
 +
    bool isDanceRejection =
 +
        Game1.currentLocation?.currentEvent?.FestivalName == "Flower Dance"
 +
        && e.NewMenu is DialogueBox dialogueBox
 +
        && dialogueBox.characterDialogue is {} dialogue
 +
        && dialogue.TranslationKey == $"Characters\\Dialogue\\{dialogue.speaker?.Name}:danceRejection";
 +
}
 +
</syntaxhighlight>
 +
 
 +
For C# mods that create <samp>Dialogue</samp> instances directly, there's a few ways to do it now:
 +
<syntaxhighlight lang="c#">
 +
// from a translation key
 +
var dialogue = new Dialogue(npc, "Strings\\StringsFromCSFiles:Utility.cs.5360");
 +
 
 +
// from custom text (with or without a translation key)
 +
var dialogue = new Dialogue(npc, null, "Some arbitrary text to show as-is");
   −
<dt>Movement:</dt>
+
// from a translation with tokens
<dd>
+
var dialogue = Dialogue.FromTranslation(npc, "Data\\ExtraDialogue:PurchasedItem_2_QualityLow_Willy", whatToCallPlayer, particle, i.DisplayName);
{| class="wikitable"
+
</syntaxhighlight>
|-
  −
! field
  −
! effect
  −
|-
  −
| <samp>WalkInDirection</samp>
  −
| ''(Optional)'' Whether to walk in the pet's facing direction. Default false.
  −
|-
  −
| <samp>MoveSpeed</samp>
  −
| ''(Optional)'' Overrides the pet's <samp>MoveSpeed</samp> field while this state is active. Default -1 (which uses the pet's <samp>MoveSpeed</samp> value).
  −
|}
  −
</dd>
     −
<dt>Audio:</dt>
+
You can also easily add fallback logic using <samp>Dialogue.TryGetDialogue</samp> or <samp>npc.TryGetDialogue</samp>. For example:
<dd>
+
<syntaxhighlight lang="c#">
{| class="wikitable"
+
Dialogue dialogue =
|-
+
    npc.TryGetDialogue($"rejection_{itemId}_{locationName}_{x}_{y}")
! field
+
    ?? npc.TryGetDialogue($"rejection_{itemId}_{locationName}")
! effect
+
    ?? npc.TryGetDialogue($"rejection_{itemId}")
|-
+
    ?? new Dialogue(npc, "Strings\\StringsFromCSFiles:NPC.cs.3971");
| <samp>SoundOnStart</samp>
+
</syntaxhighlight>
| ''(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.
+
</li>
|-
+
<li>For C# mods, added a <samp>dialogue.sideEffects</samp> field to run code when the dialogue is displayed.</li>
| <samp>SoundRange</samp><br /><samp>SoundRangeFromBorder</samp>
+
<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>
| ''(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).
+
<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>
| <samp>SoundIsVoice</samp>
+
<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>
| ''(Optional)'' Whether to mute the <samp>SoundOnStart</samp> when the 'mute animal sounds' option is set. Default false.
+
<li>Fixed NPCs only using the <code>MovieInvitation</code> dialogue key in English.</li>
|}
+
</ul>
</dd>
+
 
 +
===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:
   −
<dt>Behavior transitions:</dt>
  −
<dd>
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! type
 +
! field/method
 
! effect
 
! effect
 
|-
 
|-
| <samp>AnimationEndBehaviorChanges</samp><br /><samp>TimeoutBehaviorChanges</samp><br /><samp>PlayerNearbyBehaviorChanges</samp><br /><samp>RandomBehaviorChanges</samp><br /><samp>JumpLandBehaviorChanges</samp>
+
|rowspan="2"| <samp>AdventureGuild</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.
+
| <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.
These are triggered when this behavior's animation finishes (<samp>AnimationEndBehaviorChanges</samp>), when the set duration ends (<samp>TimeoutBehaviorChanges</samp>), when the player is within 2 tiles of the pet (<samp>PlayerNearbyBehaviorChanges</samp>), randomly at the start of each frame based on the <samp>RandomBehaviorChangeChance</samp> field (<samp>RandomBehaviorChanges</samp>), and when the pet finishes a jump (<samp>JumpLandBehaviorChanges</samp>).
  −
 
  −
These consist of a list of models with these fields:
  −
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>HasCollectedReward(player, id)</samp>
! effect
+
| 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>Behavior</samp><br /><samp>LeftBehavior</samp><br /><samp>RightBehavior</samp><br /><samp>UpBehavior</samp><br /><samp>DownBehavior</samp>
+
| <samp>AnimalHouse</samp>
| The name of the behavior to start. The pet will check for a behavior field matching its current facing direction first, then try the <samp>Behavior</samp>. If none are specified, the current behavior will continue unchanged.
+
| <samp>adoptAnimal</samp>
 +
| Add an animal to this location and set the location as the animal's home.
 
|-
 
|-
| <samp>OutsideOnly</samp>
+
| <samp>AnimatedSprite</samp>
| ''(Optional)'' Whether the transition can only happen if the pet is outside. Default false.
+
| <samp>Owner</samp>
 +
| The NPC which owns the sprite.
 
|-
 
|-
| <samp>Weight</samp>
+
|rowspan="3"| <samp>Character</samp>
| ''(Optional)'' The option's weight when randomly choosing a behavior, relative to other behaviors in the list (e.g. <samp>2</samp> is twice as likely as <samp>1</samp>). Default 1.
+
| <samp>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>Duration</samp><br /><samp>MinimumDuration</samp><br /><samp>MaximumDuration</samp>
+
| <samp>StandingPixel</samp>
| ''(Optional)'' The millisecond duration until the pet transitions to a behavior in the <samp>TimeoutBehaviorChanges</samp> field, if set. You must specify either a specific duration, or an inclusive minimum-to-maximum range in which the game will choose a random duration. If omitted, the behavior won't have a duration limit.
+
| The character's cached pixel position within the current location, based on the center pixel of their bounding box.
 
|-
 
|-
| <samp>RandomBehaviorChangeChance</samp>
+
| <samp>Tile</samp><br /><samp>TilePoint</samp>
| ''(Optional)'' The random probability at the start of each frame that the pet will transition to a behavior in the <samp>RandomBehaviorChanges</samp> field, if set. Specified as a value between 0 (never) and 1 (always). Default 0.
+
| 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.
|}
  −
</dd>
  −
 
  −
<dt>Animation and per-frame sounds:</dt>
  −
<dd>
  −
{| class="wikitable"
   
|-
 
|-
! field
+
|rowspan="7"| <samp>FarmAnimal</samp>
! effect
+
| <samp>isAdult</samp>
 +
| Get whether the farm animal is fully grown (opposite of <samp>isBaby()</samp>).
 
|-
 
|-
| <samp>Animation</samp>
+
| <samp>CanGetProduceWithTool</samp>
| ''(Optional)'' The animation frames to play while this state is active. This consists of a list of models with these fields:
+
| Get whether the farm animal's produce can be collected with a given tool (e.g. milk pail for a cow).
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>CanLiveIn</samp>
! effect
+
| Get whether the animal can be added to a building.
 
|-
 
|-
| <samp>Frame</samp>
+
| <samp>GetDisplayName</samp><br /><samp>GetShopDescription</samp>
| The frame index in the animation. This should be an incremental number starting at 0.
+
| Get the translated display name or shop description for this animal.
 
|-
 
|-
| <samp>Duration</samp>
+
| <samp>GetHarvestType</samp>
| The millisecond duration for which the frame should be kept on-screen before continuing to the next frame.
+
| Get whether the animal's produce is dropped or collected with a tool.
 
|-
 
|-
| <samp>HitGround</samp>
+
| <samp>growFully</samp>
| ''(Optional)'' Whether to play the footstep sound for the tile under the pet when the frame starts. Default false.
+
| Instantly age the animal to adulthood if it's still a baby.
 
|-
 
|-
| <samp>Jump</samp>
+
| <samp>ReloadTextureIfNeeded</samp>
| ''(Optional)'' Whether the pet should perform a small hop when the frame starts, including a 'dwop' sound. Default false.
+
| Update the animal sprite based on the current state + data.
 
|-
 
|-
| <samp>Sound</samp>
+
| rowspan="2"| <samp>Farmer</samp>
| ''(Optional)'' The [[#Custom audio|audio cue ID]] for the sound to play when the animation starts or loops. If set to <samp>BARK</samp>, the pet's <samp>BarkSound</samp> (or breed's <samp>BarkOverride</samp>) field is used. Defaults to none.
+
| <samp>GetDisplayPants</samp><br /><samp>GetDisplayShirt</samp>
 +
| Get the texture and sprite index to draw for the player's pants or shirt. This accounts for override clothing, worn clothing, and the default clothing drawn when the farmer isn't wearing anything.
 +
 
 +
For example:
 +
<syntaxhighlight lang="c#">
 +
Game1.player.GetDisplayShirt(out Texture2D texture, out int spriteIndex);
 +
</syntaxhighlight>
 
|-
 
|-
| <samp>SoundRange</samp><br /><samp>SoundRangeFromBorder</samp><br /><samp>SoundIsVoice</samp>
+
| <samp>CanDyePants</samp><br /><samp>CanDyeShirt</samp>
| See description for the equivalent behavior fields, but applies to the frame's <samp>Sound</samp> field instead.
+
| Get whether the currently equipped pants or shirt can be [[Dyeing|dyed]].
|}
   
|-
 
|-
| <samp>Shake</samp>
+
| <samp>Monster</samp>
| ''(Optional)'' The millisecond duration for which to shake the pet when the state starts. Default 0.
+
| <samp>GetDisplayName(name)</samp>
 +
| Get the translated display name for a monster type.
 
|-
 
|-
| <samp>LoopMode</samp>
+
|rowspan="4"| <samp>NPC</samp>
| ''(Optional)'' What to do when the last animation frame is reached while the behavior is still active. The possible values are <samp>Hold</samp> (keep the last frame visible until the animation ends), <samp>Loop</samp> (restart from the first frame), or <samp>None</samp> (equivalent to <samp>Loop</samp>). Default <samp>None</samp>.
+
| <samp>CanReceiveGifts</samp>
 +
| Get whether this NPC can receive gifts from the player (regardless of whether they've already received one today).
 
|-
 
|-
| <samp>AnimationMinimumLoops</samp><br /><samp>AnimationMaximumLoops</samp>
+
| <samp>GetData</samp><br /><samp>NPC.TryGetData</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).
+
| Get the underlying data from <samp>Data/Characters</samp> for this NPC, if any.
|}
  −
</dd>
  −
</dl>
  −
|}
  −
 
  −
=====Breeds=====
  −
{| 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>Breeds</samp>
+
| <samp>hasDarkSkin</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:
+
| Whether this character has dark skin for the purposes of child genetics.
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>Pet</samp>
! effect
+
| <samp>GetPetData</samp><br /><samp>TryGetData</samp>
 +
| Get the underlying data from <samp>Data/Pets</samp> for this pet, if any.
 
|-
 
|-
| <samp>ID</samp>
+
| <samp>ShopMenu</samp>
| The unique ID for the breed within the pet type.
+
| <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.
| <samp>Texture</samp>
  −
| The asset name for the breed spritesheet for the pet's in-game sprite. This should be 128 pixels wide, and 256 (cat) or 288 (dog) pixels high.
  −
|-
  −
| <samp>IconTexture</samp>
  −
| The asset name for the breed icon texture, shown on the character customization screen and in-game menu. This should be a 16x16 pixel icon.
  −
|-
  −
| <samp>IconSourceRect</samp>
  −
| The icon's pixel area within the <samp>IconTexture</samp>, specified as an object with <samp>X</samp>, <samp>Y</samp>, <samp>Width</samp>, and <samp>Height</samp> fields.
  −
|-
  −
| <samp>BarkOverride</samp>
  −
| ''(Optional)'' Override the pet's <samp>BarkSound</samp> field for this breed, if set.
  −
|-
  −
| <samp>VoicePitch</samp>
  −
| ''(Optional)'' The [[wikipedia:Pitch (music)|pitch]] applied to the pet's bark sound, measured as a decimal value relative to 1. Defaults to 1.
  −
|}
  −
|}
     −
=====Advanced=====
+
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.
{| 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>CustomFields</samp>
  −
| The [[#Custom data fields|custom fields]] for this entry.
   
|}
 
|}
 +
</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>
   −
====Other changes====
+
==What's new for everything else==
* 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).
+
===Buff overhaul===
* 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.
+
{{/doc status|a new doc page|done=false}}
* 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===
+
: ''See also: [[#Custom buffs|custom buffs]].''
: ''See also: [[#Monster eradication goal flag changes|Monster eradication goal flag changes]].''
+
 
 +
1.6 rewrites buffs to work more consistently and be more extensible:
 +
 
 +
* Buff logic is unified into <samp>Game1.player.buffs</samp>, which is the single source of truth for buff data. This replaces the previous <samp>player.added*</samp> and <samp>player.appliedBuffs</samp> fields, <samp>BuffsDisplay</samp> logic, enchantment stat bonuses, and boots/ring attribute changes on (un)equip.
 +
* This also removes limitations on buff types (e.g. buffs can add weapon bonuses and weapons can add attribute buffs) and buffable equipment (e.g. equipped tools can have buffs too).
 +
* Buff effects are now fully recalculated when they change, to fix a range of longstanding bugs like attribute drift and double-debuffs. Just like before, the buffs are managed locally; only the buff IDs and aggregate attribute effects are synced.
 +
 
 +
'''For C# mods:'''
 +
* Each buff now has a unique string ID. You can apply a new buff with the same ID to replace it (so you no longer need to manually find and remove previous instances of the buff).
 +
* The buff duration can now be set to <samp>Buff.ENDLESS</samp> to remove the duration. It'll last all day until the player sleeps.
 +
* You can add standard buff effects to any equipment by overriding <samp>Item.AddEquipmentEffects</samp>, or add custom behaviour/buffs by overriding <samp>Item.onEquip</samp> and <samp>Item.onUnequip</samp>.
 +
* You can add custom food or drink buffs by overriding <samp>Item.GetFoodOrDrinkBuffs()</samp>.
 +
* The <samp>Buff</samp> constructor now supports a custom icon texture, sprite index, display name, description, and millisecond duration to fully support custom buffs.
 +
* You can change how buff attributes are displayed (or add new attributes) by extending the <samp>BuffsDisplay.displayAttributes</samp> list.
 +
* You can have invisible buffs by setting <samp>buff.visible = false</samp>.
 +
 
 +
For example, here's how to add a custom buff which adds +3 speed:
 +
 
 +
<syntaxhighlight lang="c#">
 +
Buff buff = new Buff(
 +
    id: "Example.ModId_ZoomZoom",
 +
    displayName: "Zoom Zoom", // can optionally specify description text too
 +
    iconTexture: this.Helper.ModContent.Load<Texture2D>("assets/zoom.png"),
 +
    iconSheetIndex: 0,
 +
    duration: 30_000, // 30 seconds
 +
    effects: new BuffEffects()
 +
    {
 +
        Speed = { 10 } // shortcut for buff.Speed.Value = 10
 +
    }
 +
);
 +
Game1.player.applyBuff(buff);
 +
</syntaxhighlight>
 +
 
 +
You can also implement your own custom effects in code by checking if the buff is active, like <code>Game1.player.hasBuff("Example.ModId_ZoomZoom")</code>.
 +
 
 +
===Custom audio===
 +
{{/doc status|[[Modding:Audio]]|done=true}}
 +
 
 +
You can now add or edit music tracks or sound effects by editing the new <samp>Data/AudioChanges</samp> asset. New cues are added to the game's soundbank, so they can be used anywhere normal audio can be used (e.g. the <samp>Music</samp> [[Modding:Maps|map property]]). This supports <samp>.ogg</samp> and <samp>.wav</samp> files, and the vanilla audio features (e.g. randomizing audio from one ID).
 +
 
 +
Audio is also more fault-tolerant in 1.6: the game no longer crashes when playing audio which doesn't exist, it now logs an error and returns a default quiet click sound instead. (If you use <code>try..catch</code> to check if an audio cue exists, you should check <code>Game1.soundbank.Exists(name)</code> instead.)
 +
 
 +
===Custom buffs===
 +
{{/doc status|a new doc page|done=false}}
 +
 
 +
: ''See also: [[#Buff overhaul|buff overhaul]].''
   −
You can now add/edit [[Adventurer's Guild]] monster eradication goals by editing the new <samp>Data/MonsterSlayerQuests</samp> data asset.
+
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...
 
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 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.
 
* The value is a model with the fields listed below.
   Line 5,632: Line 5,850:  
|-
 
|-
 
! field
 
! field
! effect
+
! purpose
 
|-
 
|-
 
| <samp>DisplayName</samp>
 
| <samp>DisplayName</samp>
| A [[Modding:Tokenizable strings|tokenizable string]] for the goal's display name, shown on the board in the Adventurer's Guild.
+
| A [[Modding:Tokenizable strings|tokenizable string]] for the buff name.
 
|-
 
|-
| <samp>Targets</samp>
+
| <samp>Description</samp>
| A list of [[Modding:Monster data#Monster IDs|monster IDs]] that are counted towards the <samp>Count</samp>.
+
| ''(Optional)'' A [[Modding:Tokenizable strings|tokenizable string]] for the buff name. Default none.
 
|-
 
|-
| <samp>Count</samp>
+
| <samp>IsDebuff</samp>
| The total number of monsters (matching the <samp>Targets</samp>) which must be defeated to complete this goal.
+
| ''(Optional)'' >Whether this buff counts as a debuff, so its duration should be halved when wearing a [[Sturdy Ring|sturdy ring]]. Default false.
 
|-
 
|-
| <samp>RewardItemId</samp>
+
| <samp>GlowColor</samp>
| ''(Optional)'' The [[#Custom items|qualified ID]] for the item that can be collected from [[Gil]] when this goal is completed. Default none.
+
| ''(Optional)'' The glow color to apply to the player. See [[#Color fields|color format]]. Default none.
 
|-
 
|-
| <samp>RewardItemPrice</samp>
+
| <samp>Duration</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.
+
| 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>RewardDialogue</samp><br /><samp>RewardDialogueFlag</samp>
+
| <samp>MaxDuration</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.
+
| ''(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.
 
  −
If there are reward items, they're shown after this dialogue.
  −
 
  −
If <samp>RewardDialogue</samp> is used without <samp>RewardDialogueFlag</samp>, then this dialogue will be shown each time the reward menu is opened after completing the goal, until the player collects the reward items. If the <samp>RewardItems</samp> isn't set, this can safely be omitted since the goal will be marked collected immediately.
  −
 
  −
This doesn't send a letter; see <samp>RewardMail</samp> or <samp>RewardMailAll</samp> for that.
   
|-
 
|-
| <samp>RewardFlag</samp><br /><samp>RewardFlagAll</samp>
+
| <samp>IconTexture</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.
+
| The asset name for the texture containing the buff's sprite.
 
  −
Note that <samp>RewardFlag</samp> is usually not needed, since the game will also set a <samp>Gil_{{t|goal ID}}</samp> flag regardless.
  −
 
  −
This doesn't send a letter; see <samp>RewardMail</samp> or <samp>RewardMailAll</samp> for that.
   
|-
 
|-
| <samp>RewardMail</samp><br /><samp>RewardMailAll</samp>
+
| <samp>IconSpriteIndex</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)'' The sprite index for the buff icon within the <samp>IconTexture</samp>. Default 0.
 
|-
 
|-
| <samp>CustomFields</samp>
+
| <samp>Effects</samp>
| The [[#Custom data fields|custom fields]] for this entry.
+
| ''(Optional)'' The buff attributes to apply. Default none.
|}
  −
 
  −
===Custom phone calls===
  −
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.
      +
This consists of a model with any combination of these fields:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
 
! field
 
! field
! effect
+
! purpose
 
|-
 
|-
| <samp>Dialogue</samp>
+
| <samp>FarmingLevel</samp><br /><samp>FishingLevel</samp><br /><samp>ForagingLevel</samp><br /><samp>LuckLevel</samp><br /><samp>MiningLevel</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)'' An amount applied to the matching [[Skills|skill level]] while the buff is active. This can be negative for a debuff. Default 0.
 
|-
 
|-
| <samp>FromNpc</samp>
+
| <samp>Attack</samp><br /><samp>Defense</samp><br /><samp>MagneticRadius</samp><br /><samp>MaxStamina</samp><br /><samp>Speed</samp>
| ''(Optional)'' The internal name of the NPC making the call. If specified, that NPC's name and portrait will be shown.
+
| ''(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>FromPortrait</samp>
+
| <samp>ActionsOnApply</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)'' 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">
| <samp>FromDisplayName</samp>
+
"ActionsOnApply": [
| ''(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.
+
    "IncrementStat {{ModId}}_NumberEaten 1"
|-
+
]
| <samp>MaxCalls</samp>
+
</syntaxhighlight>
| ''(Optional)'' The maximum number of times a player can receive this phone call, or <samp>-1</samp> for no limit. Default 1.
  −
|-
  −
| <samp>TriggerCondition</samp><br /><samp>RingCondition</samp>
  −
| ''(Optional)'' If set, a game state query which indicates whether to trigger this phone call (<samp>TriggerCondition</samp>) or whether the phone rings when this call is received (<samp>RingCondition</samp>).
  −
 
  −
Whether a player receives this call depends on both fields: <samp>TriggerCondition</samp> is checked on the main player before sending the call to all players, then <samp>RingCondition</samp> is checked on each player to determine whether the phone rings for them.
  −
|-
  −
| <samp>IgnoreBaseChance</samp>
  −
| ''(Optional)'' Whether to ignore the 1% base chance when checking whether to trigger an incoming call. If true, the game will check if this call can be received regardless of the base chance. Default false.
  −
|-
  −
| <samp>SimpleDialogueSplitBy</samp>
  −
| ''(Optional, specialized)'' If set, marks the call as having a simple dialogue string without an NPC name and portrait, with lines split into multiple boxes by this substring. For example, <code>"SimpleDialogueSplitBy": "#"</code> will split <code>Box A#Box B#Box C</code> into three consecutive dialogue boxes.
  −
 
  −
You should omit this in most cases, and use the regular dialogue format in <samp>Dialogue</samp> to split lines if needed. This is mainly intended to support some older vanilla phone calls.
   
|-
 
|-
 
| <samp>CustomFields</samp>
 
| <samp>CustomFields</samp>
| The [[#Custom data fields|custom fields]] for this entry.
+
| ''(Optional)'' The [[#Custom data fields|custom fields]] for this entry.  
 
|}
 
|}
   −
====Custom handlers in C#====
+
===Custom data fields===
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:
+
{{/doc status|[[Modding:Common data field types#Custom fields]]|done=true}}
   −
<syntaxhighlight lang="c#">
+
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).
/// <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>
+
For example, a content pack can [[#Custom crops|add a crop]] with custom fields:
internal sealed class CustomPhoneHandler : IPhoneHandler
+
{{#tag:syntaxhighlight|<nowiki>
 
{
 
{
     ...
+
     "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
}
+
    "Changes": [
</syntaxhighlight>
+
        {
 +
            "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,
   −
See <samp>StardewValley.PhoneCalls.DefaultPhoneHandler</samp> in the [[Modding:Modder Guide/Get Started#decompile|decompiled game code]] for an example implementation.
+
                    "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.
   −
===Custom shops===
+
This consists of a string → model lookup, where...
You can now create and edit shops via the new <samp>Data/Shops</samp> asset. See [[Modding:Shops]] for documentation and examples.
+
* 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.
   −
===Dialogue changes===
  −
<ul>
  −
<li>Added new [[Modding:Dialogue|dialogue]] keys:
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! asset
+
! field
! key format
+
! effect
! description
   
|-
 
|-
|rowspan="22"| <samp>Characters/Dialogue/&lt;name&gt;</samp>
+
| <samp>FromItemId</samp>
 +
| The [[#Custom items|item ID]] (qualified or unqualified) for the harvest ID of the regular crop which can turn into this giant crop. For example, <samp>(O)254</samp> is [[melon]].
 +
 
 +
Any number of giant crops can use the same <samp>FromItemId</samp> value. The first giant crop whose other fields match (if any) will spawn.
 
|-
 
|-
| <samp>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>
+
| <samp>HarvestItems</samp>
| Shown when receiving a birthday gift from the player. If omitted, defaults to the generic translations for all NPCs.
+
| The items which can be dropped when you break the giant crop. If multiple items match, they'll all be dropped.
 
  −
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>).
      +
This consists of a list of models with these fields:
 +
{| class="wikitable"
 
|-
 
|-
| <samp>AcceptBouquet</samp>
+
! field
| Shown when the NPC accepts a [[bouquet]] from the player. Defaults to a generic dialogue.
+
! effect
 
|-
 
|-
| <samp>AcceptGift_{{t|id}}</samp><br /><samp>AcceptGift_{{t|tag}}</samp>
+
| ''common fields''
| 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>.
+
| 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>DumpsterDiveComment</samp>
+
| <samp>Chance</samp>
| Shown when the NPC catches the player digging through a trash can. Defaults to a generic dialogue based on the NPC's age.
+
| ''(Optional)'' The probability that this entry is selected, as a value between 0 (never drops) and 1 (always drops). Default 1 (100% chance).
 
|-
 
|-
| <samp>HitBySlingshot</samp>
+
| <samp>ForShavingEnchantment</samp>
| Shown when the player shoots them with a [[slingshot]]. Defaults to a generic dialogue.
+
| ''(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>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>
+
| <samp>ScaledMinStackWhenShaving</samp><br /><samp>ScaledMaxStackWhenShaving</samp>
| Shown when the NPC rejects a [[bouquet]].
+
| ''(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.
   −
A specific dialogue is shown if possible:
+
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.
* <samp>RejectBouquet_Divorced</samp>: the NPC won't accept this bouquet because you divorced them.
  −
* <samp>RejectBouquet_NotDatable</samp>: the NPC isn't romanceable.
  −
* <samp>RejectBouquet_NpcAlreadyMarried</samp>: the NPC is already married to another player. You can use <samp>{0}</samp> in the dialogue for the other player's name.
  −
* <samp>RejectBouquet_VeryLowHearts</samp>: you have less than 4 hearts with the NPC.
  −
* <samp>RejectBouquet_LowHearts</samp>: you have less than 8 hearts with the NPC.
     −
If the specific dialogue isn't set, the game will use the <samp>RejectBouquet</samp> dialogue (if set), else it'll default to generic dialogue for each case.
+
If both fields are set, the stack size is randomized between them. If only one is set, it's applied as a limit after the generic fields. If neither is set, the generic <samp>MinStack</samp>/<samp>MaxStack</samp> fields are applied as usual without scaling.
 +
|}
 +
|-
 +
| <samp>Texture</samp>
 +
| The asset name for the texture containing the giant crop's sprite.
 +
|-
 +
| <samp>TexturePosition</samp>
 +
| ''(Optional)'' The top-left pixel position of the sprite within the <samp>Texture</samp>, specified as a model with <samp>X</samp> and <samp>Y</samp> fields. Defaults to (0, 0).
 
|-
 
|-
| <samp>RejectGift_Divorced</samp>
+
| <samp>TileSize</samp>
| Shown when the NPC rejects a gift because you divorced them.
+
| ''(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>RejectItem_{{t|id}}</samp><br /><samp>RejectItem_{{t|tag}}</samp>
+
| <samp>Health</samp>
| If set, the NPC will refuse to accept any matching item and show this dialogue instead. This can be by item ID (like <samp>RejectItem_(O)128</samp>) or context tag (like <samp>RejectItem_category_fish</samp>). This can prevent gifting, movie tickets, bouquets, mermaid pendants, etc. However it won't prevent accepting an item for an active quest or special order.
+
| ''(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>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>
+
| <samp>Chance</samp>
| Shown when the NPC rejects a [[Mermaid's Pendant|mermaid's pendant]].
+
| ''(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%).
   −
A specific dialogue is shown if possible. The cases are checked in this order:
+
Note that the chance is checked for each giant crop that applies. If three giant crops each have a 1% chance of spawning for the same crop, then there's a 3% chance that one of them will spawn.
# <samp>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>Condition</samp>
# <samp>RejectMermaidPendant_Divorced</samp>: you divorced them, so they won't accept gifts or proposals from you.
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this giant crop is available to spawn. Defaults to always true.
# <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>CustomFields</samp>
# <samp>RejectMermaidPendant_Under10Hearts</samp>: you have under 10 hearts with the NPC.
+
| The [[#Custom data fields|custom fields]] for this entry.
# <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.
+
 
 +
===Custom jukebox tracks===
 +
{{/doc status|a new doc page|done=false}}
 +
 
 +
You can now change [[jukebox]] audio tracks by editing the new <samp>Data/JukeboxTracks</samp> data asset.
   −
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.
+
This consists of a string → model lookup, where...
|-
+
* The key is the [[#Custom audio|audio cue ID]] to play (case-sensitive).
| <samp>RejectMovieTicket_AlreadyInvitedBySomeoneElse</samp><br /><samp>RejectMovieTicket_AlreadyWatchedThisWeek</samp><br /><samp>RejectMovieTicket_Divorced</samp><br /><samp>RejectMovieTicket_DontWantToSeeThatMovie</samp><br /><samp>RejectMovieTicket</samp>
+
* The value is a model with the fields listed below.
| Show when the NPC rejects a [[Movie Ticket|movie ticket]].
     −
A specific dialogue is shown if possible:
+
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>.
* <samp>RejectMovieTicket_AlreadyInvitedBySomeoneElse</samp>: someone else already invited the NPC to a movie. You can use <samp>{0}</samp> in the dialogue for the other player's name.
  −
* <samp>RejectMovieTicket_AlreadyWatchedThisWeek</samp>: the NPC already watched a movie this week.
  −
* <samp>RejectMovieTicket_Divorced</samp>: you divorced the NPC, so they won't accept gifts from you.
  −
* <samp>RejectMovieTicket_DontWantToSeeThatMovie</samp>: the movie data marks that NPC as unwilling to watch it (e.g. kids for horror movies).
     −
If the specific dialogue isn't set, the game will use the <samp>RejectMovieTicket</samp> dialogue (if set), else it'll default to generic dialogue for each case.
+
{| class="wikitable"
 
|-
 
|-
| <samp>SpouseFarmhouseClutter</samp>
+
! field
| Shown by an NPC spouse when they couldn't pathfind to their kitchen standing spot in the farmhouse.
+
! effect
 
|-
 
|-
| <samp>SpouseGiftJealous</samp>
+
| <samp>Name</samp>
| Shown by an NPC spouse when you gave a gift to another eligible NPC of the same gender as your spouse (unless it's their birthday). You can use <samp>{0}</samp> in the dialogue for the other NPC's name, and <samp>{1}</samp> for the gifted item name.
+
| ''(Optional)'' A [[Modding:Tokenizable strings|tokenizable string]] for the music track's in-game title. Defaults to the ID.
 
|-
 
|-
| <samp>Spouse_MonstersInHouse</samp>
+
| <samp>Available</samp>
| Shown by an NPC spouse when they're in the farmhouse and there's a monster close to them.
+
| ''(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>SpouseStardrop</samp>
+
| <samp>AlternativeTrackIds</samp>
| Shown when receiving the [[stardrop]] from your spouse.
+
| ''(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>Fair_Judging</samp>
  −
| Shown at the [[Stardew Valley Fair]] while Lewis is judging the grange displays. If omitted, the NPC will keep their normal festival dialogue.
     −
If this is set without <samp>Fair_Judged*</samp>, the NPC will keep this dialogue after judging is done.
+
For example, this can be used when renaming a track to keep it unlocked for existing players:
 +
<syntaxhighlight lang="js">
 +
"{{ModId}}_TrackName": {
 +
    "Name": "{{i18n: track-name}}",
 +
    "AlternativeTrackIds": [ "OldTrackName" ]
 +
}
 +
</syntaxhighlight>
 +
|}
   −
''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).''
+
===Custom movies===
|-
+
{{/doc status|[[Modding:Movie theater data]]|done=false}}
| <samp>Fair_Judged_PlayerLost_PurpleShorts</samp><br /><samp>Fair_Judged_PlayerLost_Skipped</samp><br /><samp>Fair_Judged_PlayerLost</samp><br /><samp>Fair_Judged_PlayerWon</samp><br /><samp>Fair_Judged</samp>
  −
| Shown at the [[Stardew Valley Fair]] after Lewis finishes judging the grange displays.
     −
The first matching dialogue is used in this order:
+
: ''See also: [[#Custom movie concessions|custom movie concessions]].''
# <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.
+
[[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.
# <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.
+
Stardew Valley 1.6 revamps how movies work to address those limitations.
 +
 
 +
<dl>
 +
<dt>Movie selection</dt>
 +
<dd><p>Movies were previously selected based on a specific ID pattern: <samp>spring_movie_0</samp> would play in spring the year you built the movie theater, <samp>spring_movie_1</samp> would play in spring the next year, etc. That meant it'd take two in-game years to see the first custom movie, and ID conflicts had to be managed manually.</p>
   −
''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).''
+
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>
|-
  −
| <samp>FlowerDance_Accept_Roommate</samp><br /><samp>FlowerDance_Accept_Spouse</samp><br /><samp>FlowerDance_Accept</samp>
  −
| Shown at the [[Flower Dance]] when the NPC agrees to dance. The game will prefer the <samp>_Roommate</samp> (if roommates) or <samp>_Spouse</samp> (if married) variant if applicable, else it'll check for the normal key. If omitted, defaults to a generic accept dialogue.
     −
''This replaces the previously hardcoded translations in <samp>Strings/StringsFromCSFiles</samp> (<samp>Event.cs.1613</samp>, <samp>Event.cs.1615</samp>, <samp>Event.cs.1617</samp>, <samp>Event.cs.1619</samp>, <samp>Event.cs.1621</samp>, <samp>Event.cs.1623</samp>, <samp>Event.cs.1625</samp>, <samp>Event.cs.1627</samp>, <samp>Event.cs.1629</samp>, and <samp>Event.cs.1631</samp>).''
+
<dt>New data fields</dd>
 +
<dd>
 +
{| class="wikitable"
 
|-
 
|-
| <samp>FlowerDance_Decline</samp>
+
! field
| 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).
+
! effect
 
|-
 
|-
| <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>
+
| <samp>Seasons</samp>
| Shown at the [[Feast of the Winter Star]] when the NPC gives the player their gift (before and after the player opens it). The game will prefer the <samp>_Roommate</samp> (if roommates) or <samp>_Spouse</samp> (if married) variant if applicable, else it'll check for the normal key. If omitted, the before/after dialogues each separately default to a generic translation for all NPCs.
+
| ''(Optional)'' The seasons when the movie should play, or omit for any season. For example:
 +
<syntaxhighlight lang="js">"Seasons": [ "Spring", "Summer" ]</syntaxhighlight>
 
|-
 
|-
| <samp>WinterStar_ReceiveGift_{{t|id}}</samp><br /><samp>WinterStar_ReceiveGift_{{t|tag}}</samp><br /><samp>WinterStar_ReceiveGift</samp>
+
| <samp>YearModulus</samp><br /><samp>YearRemainder</samp>
| Shown at the [[Feast of the Winter Star]] when receiving their gift from the player. This can be by item ID (like <samp>WinterStar_ReceiveGift_(O)128</samp>), context tag (like <samp>WinterStar_ReceiveGift_category_fish</samp>), or for any item (like <samp>WinterStar_ReceiveGift</samp>). If omitted, defaults to the generic translation for all NPCs.
+
| ''(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.
|-
  −
| <samp>WipedMemory</samp>
  −
| Shown the first time you talk to the NPC after erasing their memory using the [[Dark Shrine of Memory]].
  −
|}
  −
</li>
  −
<li>Added new [[Modding:Dialogue|dialogue]] commands:
  −
{| class="wikitable"
  −
|-
  −
! command
  −
! description
  −
|- id="gender-switch"
  −
| <samp>${male^female}$</samp><br /><samp>${male^female^non-binary}$</samp>
  −
| Change text depending on the player's gender. This largely supersedes the <samp>^</samp> dialogue token (which still works), and is supported in many more places than that token. This is applied before most other commands or parsing, so it can safely be used in cases where <samp>^</samp> might have a different meaning (e.g. mail text). For example: <code>Ahoy there ${lad^lass}$!</code> or <code>Ahoy there ${lad^lass^matey}$!</code>.
     −
You can optionally use <samp>¦</samp> instead of <samp>^</samp>, in which case any <samp>^</samp> characters are left as-is.
+
For example:
   −
Note that the non-binary value is only used if a mod overrides the player's gender, since the in-game UI only allows male or female.
  −
|-
  −
| <samp>$action {{t|action}}</samp>
  −
| Run a [[Modding:Trigger actions|trigger action string]], like <samp>$action AddMoney 500</samp> to add {{price|500}} to the current player.
  −
|-
  −
| <samp>$query {{t|query}}#{{t|if true}}&#124;{{t|if false}}</samp>
  −
| Show different dialogue text depending on the [[Modding:Game state queries|game state query]] in {{t|query}}. For example:
   
<syntaxhighlight lang="js">
 
<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"
+
// 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>
 
</syntaxhighlight>
 
|-
 
|-
| <samp>$t {{t|topic ID}} {{o|day length}}</samp>
+
| <samp>Texture</samp>
| Add a [[Modding:Dialogue#Conversation topics|conversation topic]] for the next {{o|day length}} days (default 4 days).
+
| ''(Optional)'' The asset name for the movie poster and screen images, or omit to use <samp>LooseSprites\Movies</samp>.
 +
 
 +
This must be a spritesheet with one 490×128 pixel row per movie. A 13×19 area in the top-left corner of the row should contain the movie poster. With a 16-pixel offset from the left edge, there should be two rows of five 90×61 pixel movie screen images, with a six-pixel gap between each image. (The movie doesn't need to use all of the image slots.)
 
|-
 
|-
| <samp>$v {{t|event id}} {{o|check preconditions}} {{o|skip if seen}}</samp>
+
| <samp>CranePrizes</samp>
| Immediately start an [[Modding:Event data|event]] and end the current dialogue, subject to the conditions:
+
| ''(Optional)'' The items to add to the [[Movie Theater#Crane Game|crane game]] prize pool on days when this movie is playing, if any.
* {{o|check preconditions}}: whether to ignore the command if the [[Modding:Event data#Event preconditions|event's preconditions]] don't match (one of <samp>true</samp> or <samp>false</samp>). Default true.
  −
* {{o|skip if seen}}: whether to ignore the command if the player has already seen the given event. Default true.
     −
If the event is not played, the dialogue continues to the next line instead.
+
This consists of a list of models with these fields:
 
  −
For example, <code>$v 60367 false false</code> will replay the bus arrival event from the start of the game. <code>$v SomeMod.Test true false#$b#Wow! Good timing!$1</code> will play the event "SomeMod.Test" if the player meets the precondition requirements. If they do not, the dialogue "Wow! Good timing!$1" will play instead. 
  −
 
  −
Note: The command will only work if it is at the very start of the dialogue. Adding any dialogue or other commands before it will cause it not to trigger the event and display the event commands as dialogue instead.
  −
|}
  −
</li>
  −
<li>Improved dialogue commands:
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! command
+
! field
! changes
+
! effect
 
|-
 
|-
| <samp>$p</samp>
+
| ''common fields''
| 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:
+
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields supported for ammo items.
<pre>$p 17|18|19#I guess you think nothing would happen, right?$u|Maybe a wicked ghost would appear!</pre>
  −
|}</li>
  −
<li>[[Modding:Dialogue#Response IDs|Dialogue response IDs]] are now [[Modding:Common data field types#Unique string ID|unique string IDs]].</li>
  −
<li>[[Secrets#Item Spawn Cheat|Item spawn codes]] now use string item IDs. That means you can spawn any item using its [[#Custom items|qualified item ID]] (like <code>[(F)1664]</code> for a [[Mystic Rug]]), but can no longer prepend zeros (e.g. <code>[128]</code> is a pufferfish but <code>[0128]</code> is an error item).</li>
  −
<li>For C# mods, <samp>Dialogue</samp> now tracks the translation key used to build it (when applicable). For example, you can detect when the player is rejected at the [[Flower Dance]] (derived from {{github|spacechase0/StardewValleyMods|Three-Heart Dance Partner}}):
  −
<syntaxhighlight lang="c#">
  −
private void OnMenuChanged(object sender, MenuChangedEventArgs e)
  −
{
  −
    bool isDanceRejection =
  −
        Game1.currentLocation?.currentEvent?.FestivalName == "Flower Dance"
  −
        && e.NewMenu is DialogueBox dialogueBox
  −
        && dialogueBox.characterDialogue is {} dialogue
  −
        && dialogue.TranslationKey == $"Characters\\Dialogue\\{dialogue.speaker?.Name}:danceRejection";
  −
}
  −
</syntaxhighlight>
     −
For C# mods that create <samp>Dialogue</samp> instances directly, there's a few ways to do it now:
+
If set to an [[Modding:Item queries|item query]] which returns multiple items, one of them will be selected at random.
<syntaxhighlight lang="c#">
+
|-
// from a translation key
+
| <samp>Rarity</samp>
var dialogue = new Dialogue(npc, "Strings\\StringsFromCSFiles:Utility.cs.5360");
+
| ''(Optional)'' The prize pool to add the item to. The possible values are <samp>1</samp> (common), <samp>2</samp> (rare), and <samp>3</samp> (deluxe). Default <samp>1</samp>.
 +
|}
 +
|-
 +
| <samp>ClearDefaultCranePrizeGroups</samp>
 +
| ''(Optional)'' The prize pools whose default items to discard, so only those specified by <samp>CranePrizes</samp> are available. Default none.
 +
 
 +
For example:
 +
<syntaxhighlight lang="js">"ClearDefaultCranePrizeGroups": [ 2, 3 ]</syntaxhighlight>
 +
|}
 +
</dd>
   −
// from custom text (with or without a translation key)
+
<dt>Other changes</dt>
var dialogue = new Dialogue(npc, null, "Some arbitrary text to show as-is");
+
<dd>
 +
* <samp>Data/Movies</samp>, <samp>Data/Concessions</samp>, and <samp>Data/MoviesReactions</samp> no longer have language variants. Instead translations were moved into <samp>Strings/*</samp> assets, and the data assets use [[Modding:Tokenizable strings|tokenizable strings]] to get text.
 +
* <samp>Data/Movies</samp> is now a list instead of a dictionary. The order determines the order movies are shown within a season. Content packs can edit them the same way as before.
 +
* Added a <samp>debug movieSchedule {{o|year}}</samp> command to help troubleshoot movie selection.
 +
* Added methods for C# mods: <samp>MovieTheater.GetMovieToday()</samp>, <samp>GetUpcomingMovie()</samp>, and <samp>GetUpcomingMovie(afterDate)</samp>.
 +
</dd>
 +
</dl>
   −
// from a translation with tokens
+
For example, this content pack adds a new 'Pufferchick II' movie which plays in winter every third year:
var dialogue = Dialogue.FromTranslation(npc, "Data\\ExtraDialogue:PurchasedItem_2_QualityLow_Willy", whatToCallPlayer, particle, i.DisplayName);
+
{{#tag:syntaxhighlight|<nowiki>
</syntaxhighlight>
+
{
 +
    "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
   −
You can also easily add fallback logic using <samp>Dialogue.TryGetDialogue</samp> or <samp>npc.TryGetDialogue</samp>. For example:
+
                    "Seasons": [ "winter" ],
<syntaxhighlight lang="c#">
+
                    "YearModulus": 3,
Dialogue dialogue =
+
                    "YearRemainder": 0,
    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===
+
                    "Title": "Pufferchick II", // display text should usually use {{i18n}} for translations in actual usage
<ul>
+
                    "Description": "A sequel to the breakthrough adventure anime Pufferchick. The world is saved; what happens next?",
<li>Schedule keys are now case-insensitive.</li>
+
                    "Tags": [ "family", "adventure" ],
<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>
+
                    "Texture": "{{InternalAssetKey: assets/movie.png}}", // an image in your content pack
<li>Schedule commands now trim surrounding whitespace, so they can be multilined for readability. For example:
+
                    "SheetIndex": 0,
<syntaxhighlight lang="js">"Wed": "
+
 
    1000 ArchaeologyHouse 11 9 0/
+
                    "Scenes": [ ... ]
    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:
+
}</nowiki>|lang=javascript}}
* 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>).
+
===Custom wedding event===
* Fixed error if a schedule command is empty.</li>
+
{{/doc status|a new doc page|done=false}}
</ul>
     −
===Other NPC changes===
+
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).
<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"
 
|-
 
|-
! type
+
! field
! field/method
   
! effect
 
! effect
 
|-
 
|-
|rowspan="2"| <samp>AdventureGuild</samp>
+
| <samp>EventScript</samp>
| <samp>IsComplete(data)</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.
| Get whether an [[Adventurer's Guild]] monster eradication goal has been completed, regardless of whether the player collected its rewards yet.
+
 
 +
This consists of a string → string dictionary, where...
 +
* The key is an NPC internal name (like <samp>Abigail</samp>), unique player ID, or <samp>default</samp> for the default script (which handles marrying either an NPC or player);
 +
* The value is a [[Modding:Tokenizable strings|tokenizable strings]] for the event script to play.
 +
 
 +
The event scripts also have access to three extra tokens:
 +
{| class="wikitable"
 
|-
 
|-
| <samp>HasCollectedReward(player, id)</samp>
+
! token
| Get whether a given player has completed an [[Adventurer's Guild]] monster eradication goal and collected its rewards. For example:
+
! effect
<syntaxhighlight lang="c#">
  −
bool isPhoneUnlocked = AdventureGuild.HasCollectedReward(Game1.player, "Gil_FlameSpirits");
  −
</syntaxhighlight>
   
|-
 
|-
| <samp>AnimalHouse</samp>
+
| <samp>[SetupContextualWeddingAttendees]</samp>
| <samp>adoptAnimal</samp>
+
| The concatenated <samp>Setup</samp> values for each of the <samp>Attendees</samp> present in the wedding.
| Add an animal to this location and set the location as the animal's home.
   
|-
 
|-
| <samp>AnimatedSprite</samp>
+
| <samp>[ContextualWeddingCelebrations]</samp>
| <samp>Owner</samp>
+
| The concatenated <samp>Celebration</samp> values for each of the <samp>Attendees</samp> present in the wedding.
| The NPC which owns the sprite.
   
|-
 
|-
|rowspan="3"| <samp>Character</samp>
+
| <samp>[SpouseActor]</samp>
| <samp>IsVillager</samp>
+
| The actor ID for the NPC or other player being married (like <samp>Abigail</samp> for an NPC or <samp>farmer2</samp> for a player). This can be used in event commands like <code>faceDirection [SpouseActor] 1</code>.
| 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).
+
 
 +
(You can also use <samp>spouse</samp> as an actor ID, but that will only work when marrying an NPC.)
 +
|}
 
|-
 
|-
| <samp>StandingPixel</samp>
+
| <samp>Attendees</samp>
| The character's cached pixel position within the current location, based on the center pixel of their bounding box.
+
| 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>Tile</samp><br /><samp>TilePoint</samp>
+
! field
| 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.
+
! effect
 
|-
 
|-
|rowspan="7"| <samp>FarmAnimal</samp>
+
| <samp>ID</samp>
| <samp>isAdult</samp>
+
| The internal NPC name.
| Get whether the farm animal is fully grown (opposite of <samp>isBaby()</samp>).
   
|-
 
|-
| <samp>CanGetProduceWithTool</samp>
+
| <samp>Setup</samp>
| Get whether the farm animal's produce can be collected with a given tool (e.g. milk pail for a cow).
+
| 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>CanLiveIn</samp>
+
| <samp>Celebration</samp>
| Get whether the animal can be added to a building.
+
| ''(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>GetDisplayName</samp><br /><samp>GetShopDescription</samp>
+
| <samp>Condition</samp>
| Get the translated display name or shop description for this animal.
+
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether the NPC should attend. Defaults to true.
 
|-
 
|-
| <samp>GetHarvestType</samp>
+
| <samp>IgnoreUnlockConditions</samp>
| Get whether the animal's produce is dropped or collected with a tool.
+
| ''(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>growFully</samp>
+
|}
| Instantly age the animal to adulthood if it's still a baby.
+
 
|-
+
===Game state queries===
| <samp>ReloadTextureIfNeeded</samp>
+
{{/doc status|[[Modding:Game state queries]]|done=true}}
| Update the animal sprite based on the current state + data.
+
 
|-
+
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.
| rowspan="2"| <samp>Farmer</samp>
  −
| <samp>GetDisplayPants</samp><br /><samp>GetDisplayShirt</samp>
  −
| Get the texture and sprite index to draw for the player's pants or shirt. This accounts for override clothing, worn clothing, and the default clothing drawn when the farmer isn't wearing anything.
     −
For example:
+
===Gender changes===
<syntaxhighlight lang="c#">
+
{{/doc status|[[Modding:Dialogue]]|done=false}}
Game1.player.GetDisplayShirt(out Texture2D texture, out int spriteIndex);
  −
</syntaxhighlight>
  −
|-
  −
| <samp>CanDyePants</samp><br /><samp>CanDyeShirt</samp>
  −
| Get whether the currently equipped pants or shirt can be [[Dyeing|dyed]].
  −
|-
  −
| <samp>Monster</samp>
  −
| <samp>GetDisplayName(name)</samp>
  −
| Get the translated display name for a monster type.
  −
|-
  −
|rowspan="4"| <samp>NPC</samp>
  −
| <samp>CanReceiveGifts</samp>
  −
| Get whether this NPC can receive gifts from the player (regardless of whether they've already received one today).
  −
|-
  −
| <samp>GetData</samp><br /><samp>NPC.TryGetData</samp>
  −
| Get the underlying data from <samp>Data/Characters</samp> for this NPC, if any.
  −
|-
  −
| <samp>NPC.GetDisplayName(name)</samp>
  −
| Get the translated display name in the current language for an NPC by their internal name.
  −
|-
  −
| <samp>hasDarkSkin</samp>
  −
| Whether this character has dark skin for the purposes of child genetics.
  −
|-
  −
| <samp>Pet</samp>
  −
| <samp>GetPetData</samp><br /><samp>TryGetData</samp>
  −
| Get the underlying data from <samp>Data/Pets</samp> for this pet, if any.
  −
|-
  −
| <samp>ShopMenu</samp>
  −
| <samp>ShopId</samp>
  −
| A key which identifies the current shop. This may be the unique shop ID in <samp>Data/Shops</samp> for a standard shop, <samp>Dresser</samp> or <samp>FishTank</samp> for furniture, etc. This is guaranteed to be set to a relevant shop ID.
     −
This replaces the former <samp>shopContext</samp> field, and will usually have the same value in cases where that was set to a unique shop ID.
+
* 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.
| <samp>Utility</samp>
+
* Gender-specific clothing variants can now be worn by any gender.
| <samp>getAllVillagers</samp>
+
* Removed French-only support for using <samp>^</samp> dialogue token in non-dialogue text. This is superseded by the new inline gender-switch command.
| Get all villager NPCs (excluding horses, pets, monsters, player children, etc). This works just like <samp>getAllCharacters</samp> with an added filter.
  −
|}
  −
</li>
  −
<li>NPCs now update on save loaded when their home data changes.</li>
  −
<li><samp>NPC.reloadSprite()</samp> now has an argument to only reload the appearance, without changing other data.</li>
  −
<li><samp>Utility.getAllCharacters()</samp> now returns a plain <samp>List&lt;NPC&gt;</samp> value instead of a custom <samp>DisposableList&lt;NPC&gt;</samp>, so you can use normal LINQ querying on it.</li>
  −
<li><samp>Utility.GetHorseWarpRestrictionsForFarmer(player)</samp> now returns an enum (which is more efficient and easier for mods to patch), and added a new <samp>Utility.GetHorseWarpErrorMessage(restrictions)</samp> method to get the error message to show for it.</li>
  −
<li><samp>Farmer.hasAFriendWithHeartLevel</samp> now has an optional max-hearts argument.</li>
  −
<li>Removed most <samp>FarmAnimal</samp> fields/properties which just mirror the underlying data.</li>
  −
<li>Removed invalid item IDs in <samp>Data/NPCGiftTastes</samp>.</li>
  −
<li>Fixed NPCs sometimes duplicated on save load (particularly if their home location changed).</li>
  −
<li>Fixed child NPCs like [[Jas]] or [[Vincent]] ignoring relative titles like "mom" in <samp>Data/NPCDispositions</samp> (now <samp>Data/Characters</samp>) for reveal-gift-taste dialogues.</li>
  −
<li>Fixed custom NPCs ignoring dialogue when they use a subclass of <samp>NPC</samp>.</li>
  −
<li>Fixed monsters not loading their display name from <samp>Data/Monsters</samp> for English players.</li>
  −
<li>Fixed player children not applying the <samp>IsInvisible</samp> flag.</li>
  −
</ul>
     −
==What's new for everything else==
+
===Item queries===
===Buff overhaul===
+
{{/doc status|[[Modding:Item queries]]|done=true}}
: ''See also: [[#Custom buffs|custom buffs]].''
     −
1.6 rewrites buffs to work more consistently and be more extensible:
+
''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]].
   −
* 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.
+
For example, a shop can sell a random [[House Plant|house plant]] using the <samp>RANDOM_ITEMS</samp> query:
* 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).
+
<syntaxhighlight lang="js">
* 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.
+
{
 +
    "ItemId": "RANDOM_ITEMS (F) 1376 1390",
 +
    "MaxItems": 1
 +
}
 +
</syntaxhighlight>
 +
 
 +
===Item spawn fields===
 +
{{/doc status|[[Modding:Item queries#Item spawn fields]]|done=true}}
 +
 
 +
Several data assets (like [[#Custom machines|machines]] and [[#Custom shops|shops]]) let you configure items to create using item queries. For consistency, these all share a set of common fields.
   −
'''For C# mods:'''
+
===Color fields===
* 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).
+
{{/doc status|[[Modding:Common data field types#Color]]|done=true}}
* The buff duration can now be set to <samp>Buff.ENDLESS</samp> to remove the duration. It'll last all day until the player sleeps.
  −
* You can add standard buff effects to any equipment by overriding <samp>Item.AddEquipmentEffects</samp>, or add custom behaviour/buffs by overriding <samp>Item.onEquip</samp> and <samp>Item.onUnequip</samp>.
  −
* You can add custom food or drink buffs by overriding <samp>Item.GetFoodOrDrinkBuffs()</samp>.
  −
* The <samp>Buff</samp> constructor now supports a custom icon texture, sprite index, display name, description, and millisecond duration to fully support custom buffs.
  −
* You can change how buff attributes are displayed (or add new attributes) by extending the <samp>BuffsDisplay.displayAttributes</samp> list.
  −
* You can have invisible buffs by setting <samp>buff.visible = false</samp>.
     −
For example, here's how to add a custom buff which adds +3 speed:
+
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.
   −
<syntaxhighlight lang="c#">
+
For example, you can set debris color in [[#Custom wild trees|<samp>Data/WildTrees</samp>]]:
Buff buff = new Buff(
+
<syntaxhighlight lang="js">
    id: "Example.ModId_ZoomZoom",
+
"DebrisColor": "White"
    displayName: "Zoom Zoom", // can optionally specify description text too
  −
    iconTexture: this.Helper.ModContent.Load<Texture2D>("assets/zoom.png"),
  −
    iconSheetIndex: 0,
  −
    duration: 30_000, // 30 seconds
  −
    effects: new BuffEffects()
  −
    {
  −
        Speed = { 10 } // shortcut for buff.Speed.Value = 10
  −
    }
  −
);
  −
Game1.player.applyBuff(buff);
   
</syntaxhighlight>
 
</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>.
+
===<samp>modData</samp> field changes===
 +
The <samp>modData</samp> fields are dictionaries of arbitrary string values which are synchronized in multiplayer and persisted in the save file, so mods can store custom data about the instances. The game already has the field for buildings, characters (including NPCs and players), items, locations, and terrain features.
   −
===Custom audio===
+
Stardew Valley 1.6...
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]]).
+
* Adds <samp>modData</samp> fields to the <samp>Crop</samp>, <samp>Projectile</samp>, and <samp>Quest</samp> types too.
 +
* Moves <samp>ModDataDictionary</samp> into the <samp>StardewValley.Mods</samp> namespace.
 +
* Fixes <samp>Item.modData</samp> not copied when performing special equipment replacement (e.g. for the [[Pans|copper pan]] work as a hat).
   −
====Format====
+
===Quantity modifiers===
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.
+
{{/doc status|[[Modding:Common data field types]]|done=false}}
   −
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.
+
''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"
 
{| class="wikitable"
 
|-
 
|-
Line 6,150: Line 6,289:  
! effect
 
! effect
 
|-
 
|-
| <samp>ID</samp>
+
| <samp>Id</samp>
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for the audio cue, used when playing the sound in-game.
+
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this modifier within the current list.
 
|-
 
|-
| <samp>FilePaths</samp>
+
| <samp>Modification</samp>
| A list of absolute file paths (not asset names) from which to load the audio. Each file can be <samp>.ogg</samp> or <samp>.wav</samp>. If you list multiple paths, a random one will be chosen each time it's played.
+
| The type of change to apply. The possible values are <samp>Add</samp>, <samp>Subtract</samp>, <samp>Multiply</samp>, <samp>Divide</samp>, and <samp>Set</samp>.
 
|-
 
|-
| <samp>Category</samp>
+
| <samp>Amount</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>.
+
| ''(Optional if <samp>RandomAmount</samp> specified)'' The operand applied to the target value (e.g. the multiplier if used with <samp>Multiply</samp>).
 
|-
 
|-
| <samp>StreamedVorbis</samp>
+
| <samp>RandomAmount</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.
+
| ''(Optional)'' A list of possible amounts to randomly choose from. If set, <samp>Amount</samp> is optional and ignored. Each entry in the list has an equal probability of being chosen, and the choice is persisted for the current day. For example:
 +
<syntaxhighlight lang="js">
 +
"RandomAmount": [ 1, 2, 3.5, 4 ]
 +
</syntaxhighlight>
 +
|-
 +
| <samp>Condition</samp>
 +
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this change should be applied. Defaults to always true.
 +
|}
 +
 
 +
====Modifier mode====
 +
Quality modifier fields are often accompanied by a ''mode'' field (like <samp>PriceModifiers</samp> and <samp>PriceModifierMode</samp>), which indicate what to do when multiple modifiers apply to the same value. Available modes:
   −
This is a tradeoff between memory usage and performance, so you should consider which value is best for each audio cue:
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 6,168: Line 6,316:  
! effect
 
! effect
 
|-
 
|-
| <samp>true</samp>
+
| <samp>Stack</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).
+
| Apply each modifier to the result of the previous one. For example, two modifiers which double a value will quadruple it.
 
|-
 
|-
| <samp>false</samp>
+
| <samp>Minimum</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.
+
| Apply the modifier which results in the lowest value.
|}
   
|-
 
|-
| <samp>Looped</samp>
+
| <samp>Maximum</samp>
| Whether the audio cue loops continuously until stopped. Default false.
+
| Apply the modifier which results in the highest value.
|-
  −
| <samp>UseReverb</samp>
  −
| Whether to apply a [[wikipedia:Reverberation|reverb]] effect to the audio. Default false.
  −
|-
  −
| <samp>CustomFields</samp>
  −
| The [[#Custom data fields|custom fields]] for this entry.
   
|}
 
|}
   −
====Example====
+
====Examples====
This content pack adds a new music cue to the game, and plays it when the player enters the bus stop:
+
For example, this will double the price of a shop item in <samp>Data/Shops</samp>:
 +
<syntaxhighlight lang="js">
 +
"PriceModifiers": [
 +
    {
 +
        "Modification": "Multiply",
 +
        "Amount": 2.0
 +
    }
 +
]
 +
</syntaxhighlight>
 +
 
 +
This will set the price to a random value between 100–1000, ''or'' 3–5 times the item's normal sell price, whichever is higher (like the [[Traveling Cart]]):
 +
<syntaxhighlight lang="js">
 +
"PriceModifierMode": "Maximum",
 +
"PriceModifiers": [
 +
    {
 +
        "Modification": "Set",
 +
        "RandomAmount": [ 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000 ]
 +
    },
 +
    {
 +
        "Modification": "Multiply",
 +
        "RandomAmount": [ 3, 4, 5 ]
 +
    }
 +
]
 +
</syntaxhighlight>
   −
{{#tag:syntaxhighlight|<nowiki>
+
===Tokenizable string format===
{
+
{{/doc status|[[Modding:Tokenizable strings]]|done=true}}
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
  −
    "Changes": [
  −
        // add music cue
  −
        {
  −
            "Action": "EditData",
  −
            "Target": "Data/AudioChanges",
  −
            "Entries": {
  −
                "{{ModId}}_Music": {
  −
                    "ID": "{{ModId}}_Music",
  −
                    "Category": "Music",
  −
                    "FilePaths": [ "{{AbsoluteFilePath: assets/music.ogg}}" ],
  −
                    "StreamedVorbis": true,
  −
                    "Looped": true
  −
                }
  −
            }
  −
        },
     −
        // add to bus stop
+
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.
        {
+
 
            "Action": "EditMap",
+
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):
            "Target": "Maps/BusStop",
  −
            "MapProperties": {
  −
                "Music": "{{ModId}}_Music"
  −
            }
  −
        }
  −
    ]
  −
}</nowiki>|lang=javascript}}
     −
====Other changes====
+
<syntaxhighlight lang="js">
* 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.)
+
// before
 +
"Dialogue": "Strings\\StringsFromCSFiles:ShopMenu.cs.11488",
   −
===Custom buffs===
+
// after: any combination of literal text and tokens
: ''See also: [[#Buff overhaul|buff overhaul]].''
+
"Dialogue": "Welcome to Pierre's, {{PlayerName}}! How is [FarmName] doing?",
 +
</syntaxhighlight>
   −
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.
+
Tokenizable strings are only usable in specific fields (as indicated in their wiki or code docs).
   −
This consists of a string → model lookup, where...
+
See [[Modding:Tokenizable strings]] for usage.
* The key is a [[Modding:Common data field types#Unique string ID|unique string ID]] for the buff.
  −
* The value is a model with the fields listed below.
     −
{| class="wikitable"
+
===[[Modding:Event data|Event]] changes===
|-
+
{{/doc status|[[Modding:Event data]]|done=false}}
! field
  −
! purpose
  −
|-
  −
| <samp>DisplayName</samp>
  −
| A [[Modding:Tokenizable strings|tokenizable string]] for the buff name.
  −
|-
  −
| <samp>Description</samp>
  −
| ''(Optional)'' A [[Modding:Tokenizable strings|tokenizable string]] for the buff name. Default none.
  −
|-
  −
| <samp>IsDebuff</samp>
  −
| ''(Optional)'' >Whether this buff counts as a debuff, so its duration should be halved when wearing a [[Sturdy Ring|sturdy ring]]. Default false.
  −
|-
  −
| <samp>GlowColor</samp>
  −
| ''(Optional)'' The glow color to apply to the player. See [[#Color fields|color format]]. Default none.
  −
|-
  −
| <samp>Duration</samp>
  −
| The duration in milliseconds for which the buff should be active. This can be set to value <samp>-2</samp> for a buff that should last for the rest of the day.
  −
|-
  −
| <samp>MaxDuration</samp>
  −
| ''(Optional)'' The maximum buff duration in milliseconds. If specified and larger than <samp>Duration</samp>, a random value between <samp>Duration</samp> and <samp>MaxDuration</samp> will be selected for each buff. Default none.
  −
|-
  −
| <samp>IconTexture</samp>
  −
| The asset name for the texture containing the buff's sprite.
  −
|-
  −
| <samp>IconSpriteIndex</samp>
  −
| ''(Optional)'' The sprite index for the buff icon within the <samp>IconTexture</samp>. Default 0.
  −
|-
  −
| <samp>Effects</samp>
  −
| ''(Optional)'' The buff attributes to apply. Default none.
     −
This consists of a model with any combination of these fields:
+
====High-level changes====
{| class="wikitable"
+
* 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.
! field
+
* Event script errors are now logged (in addition to being shown in the chatbox like before).
! purpose
+
* 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>).
| <samp>FarmingLevel</samp><br /><samp>FishingLevel</samp><br /><samp>ForagingLevel</samp><br /><samp>LuckLevel</samp><br /><samp>MiningLevel</samp>
+
** Added <samp>Event.fromAssetName</samp>, which indicates which data asset (if any) the event was loaded from.
| ''(Optional)'' An amount applied to the matching [[Skills|skill level]] while the buff is active. This can be negative for a debuff. Default 0.
+
** Added <samp>Game1.eventsSeenSinceLastLocationChange</samp> to track the events that played since the player arrived in their current location.
|-
  −
| <samp>Attack</samp><br /><samp>Defense</samp><br /><samp>MagneticRadius</samp><br /><samp>MaxStamina</samp><br /><samp>Speed</samp>
  −
| ''(Optional)'' An amount applied to the player's [[attack]], [[defense]], [[Magnetism|magnetic radius]], maximum [[Energy|stamina]], or [[speed]] while the buff is active. This can be negative for a debuff. Default 0.
  −
|}
  −
|-
  −
| <samp>ActionsOnApply</samp>
  −
| ''(Optional)'' Run any number of [[Modding:Trigger actions|trigger action strings]] when the buff is applied to the current player. For example, this increments a player stat:
  −
<syntaxhighlight lang="js">
  −
"ActionsOnApply": [
  −
    "IncrementStat {{ModId}}_NumberEaten 1"
  −
]
  −
</syntaxhighlight>
  −
|-
  −
| <samp>CustomFields</samp>
  −
| ''(Optional)'' The [[#Custom data fields|custom fields]] for this entry.  
  −
|}
  −
 
  −
===Custom data fields===
  −
Many data assets now have a <samp>CustomFields</samp> field. This is ignored by the game, but lets mods add their own data (e.g. to enable mod framework features).
  −
 
  −
For example, a content pack can [[#Custom crops|add a crop]] with custom fields:
  −
{{#tag:syntaxhighlight|<nowiki>
  −
{
  −
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
  −
    "Changes": [
  −
        {
  −
            "Action": "EditData",
  −
            "Target": "Data/Crops",
  −
            "Entries": {
  −
                "Example.Id_CucumberSeeds": {
  −
                    "Seasons": [ "summer" ],
  −
                    "DaysInPhase": [ 1, 2, 2, 2 ],
  −
                    "HarvestItemId": "Example.Id_Cucumber",
  −
                    "Texture": "{{InternalAssetKey: assets/crops.png}}",
  −
                    "SpriteIndex": 0,
  −
 
  −
                    "CustomFields": {
  −
                        "Example.FrameworkMod/WetTexture": "{{InternalAssetKey: assets/crops-wet.png}}"
  −
                    }
  −
                }
  −
            }
  −
        }
  −
    ]
  −
}</nowiki>|lang=javascript}}
  −
 
  −
And then a C# mod could handle the custom field if it's set:
  −
<syntaxhighlight lang="c#">
  −
if (Game1.currentLocation.IsRainingHere())
  −
{
  −
    CropData data = crop.GetData();
  −
    if (data != null && data.CustomFields.TryGetValue("Example.FrameworkMod/WetTexture", out string textureName))
  −
    {
  −
        // do magic
  −
    }
  −
}
  −
</syntaxhighlight>
  −
 
  −
See <samp>CustomFields</samp> in the docs for each asset type to see if it's supported. Besides the sections listed on this page, custom fields were also added to <samp>Data/AdditionalFarms</samp>, <samp>Data/AdditionalLanguages</samp>, <samp>Data/FishPondData</samp>, <samp>Data/HomeRenovations</samp>, <samp>Data/Movies</samp>, and <samp>Data/SpecialOrders</samp>.
  −
 
  −
See [[Modding:Common data field types#Custom fields]] for the main docs.
  −
 
  −
===Custom giant crops===
  −
You can now add/edit [[Crops#Giant Crops|giant crops]] by editing the <samp>Data/GiantCrops</samp> data asset.
  −
 
  −
This consists of a string → model lookup, where...
  −
* The key is a [[Modding:Common data field types#Unique string ID|unique string ID]] for the giant crop.
  −
* The value is a model with the fields listed below.
      +
====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"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! precondition
! effect
+
! description
 
|-
 
|-
| <samp>FromItemId</samp>
+
| <samp>!</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]].
+
| 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.
 
  −
Any number of giant crops can use the same <samp>FromItemId</samp> value. The first giant crop whose other fields match (if any) will spawn.
   
|-
 
|-
| <samp>HarvestItems</samp>
+
| <samp>ActiveDialogueEvent {{t|id}}</samp>
| The items which can be dropped when you break the giant crop. If multiple items match, they'll all be dropped.
+
| The special dialogue event with the given ID (including [[Modding:Dialogue#Conversation_topics|Conversation Topics]]) is in progress.
 
  −
This consists of a list of models with these fields:
  −
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>DayOfWeek {{t|day}}+</samp>
! effect
+
| 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>).
 
|-
 
|-
| ''common fields''
+
| <samp>FestivalDay</samp>
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields supported for harvest items.
+
| Today is a [[Festivals|festival]] day.
 
  −
If set to an [[Modding:Item queries|item query]] which returns multiple items, one of them will be selected at random.
   
|-
 
|-
| <samp>Chance</samp>
+
| <samp>GameStateQuery {{t|query}}</samp>
| ''(Optional)'' The probability that this entry is selected, as a value between 0 (never drops) and 1 (always drops). Default 1 (100% chance).
+
| A [[Modding:Game state queries|game state query]] matches, like <code>G !WEATHER Here Sun</code> for 'not sunny in this location'.
 
|-
 
|-
| <samp>ForShavingEnchantment</samp>
+
| <samp>Season {{t|season}}+</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.
+
| The current season is one of the given values (may specify multiple seasons).
 
|-
 
|-
| <samp>ScaledMinStackWhenShaving</samp><br /><samp>ScaledMaxStackWhenShaving</samp>
+
| <samp>Skill {{t|skill name}} {{t|min level}}</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.
+
| 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>).
 
  −
This value is multiplied by the health deducted by the tool hit which triggered the enchantment. For example, an iridium axe which reduced the giant crop's health by 3 points will produce three times this value per hit.
  −
 
  −
If both fields are set, the stack size is randomized between them. If only one is set, it's applied as a limit after the generic fields. If neither is set, the generic <samp>MinStack</samp>/<samp>MaxStack</samp> fields are applied as usual without scaling.
  −
|}
   
|-
 
|-
| <samp>Texture</samp>
+
| <samp>UpcomingFestival {{t|day offset}}</samp>
| The asset name for the texture containing the giant crop's sprite.
+
| A [[Festivals|festival]] day will occur within the given number of days.
 +
|}</li>
 +
<li>Changed specific preconditions:
 +
{| class="wikitable"
 
|-
 
|-
| <samp>TexturePosition</samp>
+
! name
| ''(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).
+
! changes
 
|-
 
|-
| <samp>TileSize</samp>
+
| <samp>ChoseDialogueAnswers</samp> (<samp>q</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).
+
| &#32;
 +
* Fixed precondition ignoring every second answer ID.
 
|-
 
|-
| <samp>Health</samp>
+
| <samp>InUpgradedHouse</samp> (<samp>L</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.
+
| &#32;
 +
* Added optional argument for the min upgrade level.
 
|-
 
|-
| <samp>Chance</samp>
+
| <samp>MissingPet</samp> (<samp>h</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%).
+
| &#32;
 
+
* You can now specify any pet type ID.
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.
+
* You can now omit the argument to check for a pet of any type.
 
|-
 
|-
| <samp>Condition</samp>
+
| <samp>NotDayOfWeek</samp> (<samp>d</samp>)
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this giant crop is available to spawn. Defaults to always true.
+
| &#32;
 +
* You can now specify a full name like <samp>Monday</samp>.
 +
* The day of week is now case-insensitive.
 
|-
 
|-
| <samp>CustomFields</samp>
+
| <samp>NotSeason</samp> (<samp>z</samp>)
| The [[#Custom data fields|custom fields]] for this entry.
+
| &#32;
|}
+
* You can now list values (like <code>notSeason spring summer fall</code> instead of <code>notSeason fall/notSeason winter/notSeason fall</code>).
 
  −
===Custom jukebox tracks===
  −
You can now change [[jukebox]] audio tracks by editing the new <samp>Data/JukeboxTracks</samp> data asset.
  −
 
  −
This consists of a string → model lookup, where...
  −
* The key is the [[#Custom audio|audio cue ID]] to play (case-sensitive).
  −
* The value is a model with the fields listed below.
  −
 
  −
If the player has heard a music track not listed in <samp>Data/JukeboxTracks</samp>, it's automatically available with the title set to the cue name. To disable a track, add an entry with <samp>"Available": false</samp>.
  −
 
  −
{| class="wikitable"
   
|-
 
|-
! field
+
| <samp>ReachedMineBottom</samp> (<samp>b</samp>)
! effect
+
| &#32;
 +
* Argument is now optional (default 1).
 
|-
 
|-
| <samp>Name</samp>
+
| <samp>SendMail</samp> (<samp>x</samp>)
| ''(Optional)'' A [[Modding:Tokenizable strings|tokenizable string]] for the music track's in-game title. Defaults to the ID.
+
| &#32;
 +
* Deprecated; see [[#Send-mail (x) precondition deprecated|''Send-mail (x) precondition deprecated'']] for more info.
 
|-
 
|-
| <samp>Available</samp>
+
| <samp>Tile</samp> (<samp>a</samp>)
| ''(Optional)'' Whether the track should be shown in the jukebox menu. This can be <samp>true</samp> (always shown), <samp>false</samp> (never shown), or <samp>null</samp> (show if the player has heard it before). Default <samp>null</samp>.
+
| &#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>
   −
Tracks with <samp>"Available": true</samp> are listed first in the jukebox menu.
+
====Command changes====
 +
<ul>
 +
<li>Added validation for event commands. If a format or assumption is invalid, the game now logs a detailed error and (if applicable) skips the command, instead of crashing or silently ignoring it. This also means event arguments are stricter (e.g. you can no longer set a true/false field to an invalid value, inner quotes in quoted arguments now need to be escaped, etc).</li>
 +
<li>Event commands are now quote-aware, so you can escape spaces and slashes in arguments like <code>/speak "I'm running A/B tests"/</code>.</li>
 +
<li>Event commands now trim surrounding whitespace, so they can be multilined for readability. Line breaks must be before or after the <samp>/</samp> delimiter. For example:
 +
<syntaxhighlight lang="js">
 +
"SomeEventId/": "
 +
    none/
 +
    -1000 -1000/
 +
    farmer 5 7 0/
 +
    ...
 +
"
 +
</syntaxHighlight>
 +
This can be also combined with the [[Modding:Event data#Comments|comment syntax]] to add notes. For example:
 +
<syntaxhighlight lang="js">
 +
"SomeEventId/": "
 +
    none/            -- music/
 +
    -1000 -1000/    -- initial viewport position/
 +
    farmer 5 7 0/    -- actor positions/
 +
    ...
 +
"
 +
</syntaxHighlight>
 +
</li>
 +
<li>You can now mark NPCs optional in event commands by suffixing their name with <code>?</code>. For example, <code>jump Kent?</code> won't log an error if Kent is missing. When used in the initial event positions, the NPC is only added in they exist in <samp>Data/Characters</samp> and their <samp>UnlockConditions</samp> match.</li>
 +
<li>Added new event commands:
 +
{| class="wikitable"
 +
|-
 +
! command
 +
! description
 +
|-
 +
| <samp>action {{t|action}}</samp>
 +
| Run a [[Modding:Trigger actions|trigger action string]], like <samp>action AddMoney 500</samp> to add {{price|500}} to the current player.
 +
|-
 +
| <samp>addItem {{t|item ID}} {{o|count}} {{o|quality}}</samp>
 +
| Add an item to the player inventory (or open a grab menu if their inventory is full). The {{t|item ID}} is the [[#Custom items|qualified or unqualified item ID]], and {{o|quality}} is a [[Modding:Items#Quality|numeric quality value]].
 +
|-
 +
| <samp>addSpecialOrder {{t|order ID}}</samp><br /><samp>removeSpecialOrder {{t|order ID}}</samp>
 +
| Add or remove a special order to the player team. This affects all players, since special orders are shared.
 
|-
 
|-
| <samp>AlternativeTrackIds</samp>
+
| <samp>eventSeen {{t|event ID}} {{o|seen}}</samp>
| ''(Optional)'' A list of other cue names for this audio track (not case-sensitive). If the player has heard any of these track IDs, this entry is available in the menu. Default none.
+
| Add or remove an event ID from the player's list of seen events, based on {{o|seen}} (default <samp>true</samp> to add).
   −
For example, this can be used when renaming a track to keep it unlocked for existing players:
+
An event can mark ''itself'' unseen using <samp>eventSeen {{t|event ID}} false</samp>. This takes effect immediately (i.e. the event won't be added to the list when it completes), but the game will prevent the event from playing again until the player changes location to avoid event loops. The event will still replay when re-entering the location.
 +
|-
 +
| <samp>mailToday {{t|mail key}}</samp>
 +
| Adds a letter to the mailbox immediately, given the {{t|mail key}} in <samp>Data/Mail</samp>.
 +
|-
 +
| <samp>questionAnswered {{t|answer ID}} {{o|answered}}</samp>
 +
| Add or remove an answer ID from the player's list of chosen dialogue answers, based on {{o|answered}} (default <samp>true</samp> to add).
 +
|-
 +
| <samp>replaceWithClone {{t|NPC name}}</samp>
 +
| Replace an NPC already in the event with a temporary copy. This allows changing the NPC for the event without affecting the real NPC.
 +
 
 +
For example, this event changes Marnie's name/portrait only within the event:
 
<syntaxhighlight lang="js">
 
<syntaxhighlight lang="js">
"{{ModId}}_TrackName": {
+
"Some.ModId_ExampleEvent/": "continue/64 15/farmer 64 15 2 Marnie 64 17 0/replaceWithClone Marnie/changeName Marnie Pufferchick/changePortrait Marnie Pufferchick/[...]/end"
    "Name": "{{i18n: track-name}}",
  −
    "AlternativeTrackIds": [ "OldTrackName" ]
  −
}
   
</syntaxhighlight>
 
</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.
   −
===Custom movies===
+
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:
: ''See also: [[#Custom movie concessions|custom movie concessions]].''
+
<pre>
 +
/setSkipActions AddCraftingRecipe Current "Garden Pot"#AddItem (BC)62
 +
/skippable
 +
/...
 +
/addItem (BC)62
 +
/setSkipActions AddCraftingRecipe Current "Garden Pot"
 +
</pre>
   −
[[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.
+
Skip actions aren't applied if the event completes normally without being skipped.
 +
|-
 +
| <samp>stopSound {{t|sound ID}} {{o|immediate}}</samp>
 +
| Stop a sound started with the <samp>startSound</samp> command. This has no effect if the sound has already stopped playing on its own (or hasn't been started). If you started multiple sounds with the same ID, this will stop all of them (e.g. <code>startSound fuse/startSound fuse/stopSound fuse</code>).
   −
Stardew Valley 1.6 revamps how movies work to address those limitations.
+
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>).
 
+
|-
<dl>
+
| <samp>temporaryAnimatedSprite ...</samp>
<dt>Movie selection</dt>
+
| Add a temporary animated sprite to the event, using these space-delimited fields:
<dd><p>Movies were previously selected based on a specific ID pattern: <samp>spring_movie_0</samp> would play in spring the year you built the movie theater, <samp>spring_movie_1</samp> would play in spring the next year, etc. That meant it'd take two in-game years to see the first custom movie, and ID conflicts had to be managed manually.</p>
  −
 
  −
In 1.6, we can now have multiple movies per month based on the new fields listed below. If multiple movies can play in the same season, each movie will be shown for an equal block of days within the month (e.g. four movies will each play for seven consecutive days). If there are more movies than days, 28 movies will be chosen at random to play that month.</dd>
  −
 
  −
<dt>New data fields</dd>
  −
<dd>
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
 +
! index
 
! field
 
! field
 
! effect
 
! effect
 
|-
 
|-
| <samp>Seasons</samp>
+
| 0
| ''(Optional)'' The seasons when the movie should play, or omit for any season. For example:
+
| <samp>texture</samp>
<syntaxhighlight lang="js">"Seasons": [ "Spring", "Summer" ]</syntaxhighlight>
+
| The asset name for texture to draw.
 
|-
 
|-
| <samp>YearModulus</samp><br /><samp>YearRemainder</samp>
+
| 1&ndash;4
| ''(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.
+
| <samp>rectangle</samp>
 
+
| The pixel area within the <samp>texture</samp> to draw, in the form <samp>{{t|x}} {{t|y}} {{t|width}} {{t|height}}</samp>.
For example:
+
|-
 
+
| 5
<syntaxhighlight lang="js">
+
| <samp>interval</samp>
// play in the first year, and every second year thereafter
+
| The millisecond duration for each frame in the animation.
"YearModulus": 2,
  −
"YearRemainder": 0
  −
</syntaxhighlight>
  −
<syntaxhighlight lang="js">
  −
// play in the second year, and every second year thereafter
  −
"YearModulus": 2,
  −
"YearRemainder": 1
  −
</syntaxhighlight>
   
|-
 
|-
| <samp>Texture</samp>
+
| 6
| ''(Optional)'' The asset name for the movie poster and screen images, or omit to use <samp>LooseSprites\Movies</samp>.
+
| <samp>frames</samp>
 
+
| The number of frames in the animation.
This must be a spritesheet with one 490×128 pixel row per movie. A 13×19 area in the top-left corner of the row should contain the movie poster. With a 16-pixel offset from the left edge, there should be two rows of five 90×61 pixel movie screen images, with a six-pixel gap between each image. (The movie doesn't need to use all of the image slots.)
   
|-
 
|-
| <samp>CranePrizes</samp>
+
| 7
| ''(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>loops</samp>
 
+
| The number of times to repeat the animation.
This consists of a list of models with these fields:
  −
{| class="wikitable"
   
|-
 
|-
! field
+
| 8&ndash;9
! effect
+
| <samp>tile</samp>
 +
| The tile position at which to draw the sprite, in the form <samp>{{t|x}} {{t|y}}</samp>.
 
|-
 
|-
| ''common fields''
+
| 10
| See [[Modding:Item queries#Item spawn fields|item spawn fields]] for the generic item fields supported for ammo items.
+
| <samp>flicker</samp>
 
+
| Causes the sprite to flicker in and out of view repeatedly. (one of <samp>true</samp> or <samp>false</samp>).
If set to an [[Modding:Item queries|item query]] which returns multiple items, one of them will be selected at random.
   
|-
 
|-
| <samp>Rarity</samp>
+
| 11
| ''(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>flip</samp>
|}
+
| Whether to flip the sprite horizontally when it's drawn (one of <samp>true</samp> or <samp>false</samp>).
 
|-
 
|-
| <samp>ClearDefaultCranePrizeGroups</samp>
+
| 12
| ''(Optional)'' The prize pools whose default items to discard, so only those specified by <samp>CranePrizes</samp> are available. Default none.
+
| <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.
For example:
+
|-
<syntaxhighlight lang="js">"ClearDefaultCranePrizeGroups": [ 2, 3 ]</syntaxhighlight>
+
| 13
|}
+
| <samp>alpha fade</samp>
</dd>
+
| Fades out the sprite based on alpha set. The larger the number, the faster the fade out. 1 is instant.  
 
  −
<dt>Other changes</dt>
  −
<dd>
  −
* <samp>Data/Movies</samp>, <samp>Data/Concessions</samp>, and <samp>Data/MoviesReactions</samp> no longer have language variants. Instead translations were moved into <samp>Strings/*</samp> assets, and the data assets use [[Modding:Tokenizable strings|tokenizable strings]] to get text.
  −
* <samp>Data/Movies</samp> is now a list instead of a dictionary. The order determines the order movies are shown within a season. Content packs can edit them the same way as before.
  −
* Added a <samp>debug movieSchedule {{o|year}}</samp> command to help troubleshoot movie selection.
  −
* Added methods for C# mods: <samp>MovieTheater.GetMovieToday()</samp>, <samp>GetUpcomingMovie()</samp>, and <samp>GetUpcomingMovie(afterDate)</samp>.
  −
</dd>
  −
</dl>
  −
 
  −
For example, this content pack adds a new 'Pufferchick II' movie which plays in winter every third year:
  −
{{#tag:syntaxhighlight|<nowiki>
  −
{
  −
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
  −
    "Changes": [
  −
        {
  −
            "Action": "EditData",
  −
            "Target": "Data/Movies",
  −
            "Entries": {
  −
                "{{ModId}}_PufferchickII": {
  −
                    "Id": "{{ModId}}_PufferchickII", // must specify ID again when creating a new entry
  −
 
  −
                    "Seasons": [ "winter" ],
  −
                    "YearModulus": 3,
  −
                    "YearRemainder": 0,
  −
 
  −
                    "Title": "Pufferchick II", // display text should usually use {{i18n}} for translations in actual usage
  −
                    "Description": "A sequel to the breakthrough adventure anime Pufferchick. The world is saved; what happens next?",
  −
                    "Tags": [ "family", "adventure" ],
  −
 
  −
                    "Texture": "{{InternalAssetKey: assets/movie.png}}", // an image in your content pack
  −
                    "SheetIndex": 0,
  −
 
  −
                    "Scenes": [ ... ]
  −
                }
  −
            }
  −
        }
  −
    ]
  −
}</nowiki>|lang=javascript}}
  −
 
  −
===Custom wedding event===
  −
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
+
| 14
! effect
+
| <samp>scale</samp>
 +
| A multiplier applied to the sprite size (in addition to the normal 4× pixel zoom).
 
|-
 
|-
| <samp>EventScript</samp>
+
| 15
| 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>scale change</samp>
 
+
| Changes the scale based on the multiplier applied on top of the normal zoom. Continues endlessly.
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);
+
| 16
* The value is a [[Modding:Tokenizable strings|tokenizable strings]] for the event script to play.
+
| <samp>rotation</samp>
 
+
| The rotation to apply to the sprite, measured in [[wikipedia:radians|radians]].
The event scripts also have access to three extra tokens:
  −
{| class="wikitable"
   
|-
 
|-
! token
+
| 17
! effect
+
| <samp>rotation change</samp>
 +
| Continuously rotates the sprite, causing it to spin. The speed is determined by input value.
 
|-
 
|-
| <samp>[SetupContextualWeddingAttendees]</samp>
+
| 18+
| The concatenated <samp>Setup</samp> values for each of the <samp>Attendees</samp> present in the wedding.
+
| ''flags''
 +
| Any combination of these space-delimited flags:
 +
* <samp>color {{t|color}}</samp>: apply a [[#Color fields|standard color]] to the sprite.
 +
* <samp>hold_last_frame</samp>: after playing the animation once, freeze the last frame as long as the sprite is shown.
 +
* <samp>ping_pong</samp>: Causes the animation frames to play forwards and backwards alternatingly. Example: An animation with the frames 0, 1, 2 will play "0 1 2 0 1 2" without the ping_pong flag and play "0 1 2 1 0" with the ping_pong flag.
 +
* <samp>motion {{t|x}} {{t|y}}</samp>: Sprite moves based on the values set. Numbers can be decimals or negative.
 +
* <samp>acceleration {{t|x}} {{t|y}}</samp>: '''[TODO: document what this does]'''
 +
* <samp>acceleration_change {{t|x}} {{t|y}}</samp>: '''[TODO: document what this does]'''
 +
|}
 
|-
 
|-
| <samp>[ContextualWeddingCelebrations]</samp>
+
| <samp>translateName {{t|actor}} {{t|translation key}}</samp>
| The concatenated <samp>Celebration</samp> values for each of the <samp>Attendees</samp> present in the wedding.
+
| Set the display name for an NPC in the event to match the given translation key.
 
|-
 
|-
| <samp>[SpouseActor]</samp>
+
| <samp>warpFarmers [{{t|x}} {{t|y}} {{t|direction}}]+ {{t|default offset}} {{t|default x}} {{t|default}} {{t|direction}}</samp>
| The actor ID for the NPC or other player being married (like <samp>Abigail</samp> for an NPC or <samp>farmer2</samp> for a player). This can be used in event commands like <code>faceDirection [SpouseActor] 1</code>.
+
| 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.
 
  −
(You can also use <samp>spouse</samp> as an actor ID, but that will only work when marrying an NPC.)
   
|}
 
|}
|-
+
</li>
| <samp>Attendees</samp>
+
<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>
| 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:
+
<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"
 
{| class="wikitable"
 
|-
 
|-
! field
+
! command
! effect
+
! changes
 
|-
 
|-
| <samp>ID</samp>
+
| <samp>addCookingRecipe</samp>
| The internal NPC name.
+
| Fixed error if player already knows the recipe.
 
|-
 
|-
| <samp>Setup</samp>
+
| <samp>addMailReceived</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]].
+
| &#32;
 +
* Renamed to <samp>mailReceived</samp>. (The old name is now an alias, so it'll still work.)
 +
* You can now remove a mail received by setting the optional third argument to false, like <samp>mailReceived {{t|id}} false</samp>.
 +
|-
 +
| <samp>addTemporaryActor</samp>
 +
| &#32;
 +
* Underscores in the asset name are now only replaced with spaces if an exact match wasn't found. You should quote arguments containing spaces instead, like <code>addTemporaryActor "White Chicken" …</code>.
 +
* Underscores in the display name are no longer replaced with spaces. You should quote arguments containing spaces instead.
 +
* Argument 9 ({{o|animal name}}) is now {{o|override name}}, and can be used to set the name for non-animals too.
 +
|-
 +
| <samp>animate</samp>
 +
| Underscores in the NPC name are now only replaced with spaces if an exact match wasn't found. You should quote arguments containing spaces instead, like <code>animate "Mr Qi" …</code>.
 +
|-
 +
| <samp>ambientLight</samp>
 +
| Removed four-argument form (which was unused and had confusing behavior). The other versions of <samp>ambientLight</samp> still work like before.
 +
|-
 +
| <samp>awardFestivalPrize</samp>
 +
| Added support for arbitrary item IDs, like <code>awardFestivalPrize (O)128</code> for a pufferfish.
 +
|-
 +
| <samp>changeLocation</samp>
 +
| It now updates the event position offset if needed.
 +
|-
 +
| <samp>changeName</samp>
 +
| Underscores in the NPC name are no longer replaced with spaces. You should quote arguments containing spaces instead, like <code>changeName Leo "Neo Leo"</code>.
 +
|-
 +
| <samp>changePortrait</samp><br /><samp>changeSprite</samp>
 +
| You can now omit the suffix argument to reset the NPC back to their normal portrait/sprite.
 
|-
 
|-
| <samp>Celebration</samp>
+
| <samp>faceDirection</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.
+
| You can now specify the direction in words, like <samp>faceDirection up</samp>
 
|-
 
|-
| <samp>Condition</samp>
+
| <samp>ignoreMovementAnimation</samp>
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether the NPC should attend. Defaults to true.
+
| &#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>IgnoreUnlockConditions</samp>
+
| <samp>itemAboveHead</samp>
| ''(Optional)'' Whether to add the NPC even if their entry in <samp>Data/Characters</samp> has an <samp>UnlockConditions</samp> field which doesn't match. Default false.
+
| Added support for arbitrary item IDs, like <code>itemAboveHead (O)128</code> for a pufferfish.
|}
  −
|}
  −
 
  −
===Game state queries===
  −
: ''Main article: [[Modding:Game state queries]].''
  −
 
  −
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===
  −
* Added an [[#gender-switch|''inline gender-switch token'']] to change text depending on the player's gender. This reduces duplicate text, works in more places than the <samp>^</samp> dialogue token, works in mail and other places where <samp>^</samp> has a different meaning, and supports non-binary gender.
  −
* For C# mod authors, added a unified <samp>Gender</samp> field for players and NPCs with the possible values <samp>Male</samp>, <samp>Female</samp>, and <samp>Unspecified</samp>. This replaces <samp>Farmer.isMale</samp> and the numeric NPC gender constants. Note that vanilla still only sets players to male or female, though mods can override it.
  −
* Gender-specific clothing variants can now be worn by any gender.
  −
* Removed French-only support for using <samp>^</samp> dialogue token in non-dialogue text. This is superseded by the new inline gender-switch command.
  −
 
  −
===Item queries===
  −
: ''Main article: [[Modding:Item queries]].''
  −
 
  −
''Item queries'' are a new built-in way to choose one or more items dynamically, instead of specifying a single item ID. These are used in various places like [[#Custom machines|machine data]] and [[#Custom shops|shop data]].
  −
 
  −
For example, a shop can sell a random [[House Plant|house plant]] using the <samp>RANDOM_ITEMS</samp> query:
  −
<syntaxhighlight lang="js">
  −
{
  −
    "ItemId": "RANDOM_ITEMS (F) 1376 1390",
  −
    "MaxItems": 1
  −
}
  −
</syntaxhighlight>
  −
 
  −
===Item spawn fields===
  −
: ''Main article: [[Modding:Item queries#Item spawn fields]].''
  −
 
  −
Several data assets (like [[#Custom machines|machines]] and [[#Custom shops|shops]]) let you configure items to create using item queries. For consistency, these all share a set of common fields.
  −
 
  −
===Color fields===
  −
: ''Main article: [[Modding:Common data field types#Color]].''
  −
 
  −
1.6 adds a standardized color format used in various data fields. This can be a color name, hexadecimal color code, or 8-bit RGB color code.
  −
 
  −
For example, you can set debris color in [[#Custom wild trees|<samp>Data/WildTrees</samp>]]:
  −
<syntaxhighlight lang="js">
  −
"DebrisColor": "White"
  −
</syntaxhighlight>
  −
 
  −
===<samp>modData</samp> field changes===
  −
The <samp>modData</samp> fields are dictionaries of arbitrary string values which are synchronized in multiplayer and persisted in the save file, so mods can store custom data about the instances. The game already has the field for buildings, characters (including NPCs and players), items, locations, and terrain features.
  −
 
  −
Stardew Valley 1.6...
  −
* Adds <samp>modData</samp> fields to the <samp>Crop</samp>, <samp>Projectile</samp>, and <samp>Quest</samp> types too.
  −
* Moves <samp>ModDataDictionary</samp> into the <samp>StardewValley.Mods</samp> namespace.
  −
* Fixes <samp>Item.modData</samp> not copied when performing special equipment replacement (e.g. for the [[Copper Pan|copper pan]] work as a hat).
  −
 
  −
===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>makeInvisible</samp>
! effect
+
| Fixed terrain features not hidden when using the default area size.
 
|-
 
|-
| <samp>Id</samp>
+
| <samp>playSound</samp>
| The [[Modding:Common data field types#Unique string ID|unique string ID]] for this modifier within the current list.
+
| Sounds started via <samp>playSound</samp> now stop automatically when the event ends.
 
|-
 
|-
| <samp>Modification</samp>
+
| <samp>removeItem</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>.
+
| Added argument for an optional count, like <code>removeItem (O)128 10</code> to remove 10 pufferfish.
 
|-
 
|-
| <samp>Amount</samp>
+
| <samp>speak</samp>
| ''(Optional if <samp>RandomAmount</samp> specified)'' The operand applied to the target value (e.g. the multiplier if used with <samp>Multiply</samp>).
+
| Fixed friendship & socialize quest not updated when calling it with a translation key.
 +
|}</li>
 +
<li>Removed some commands:
 +
{| class="wikitable"
 
|-
 
|-
| <samp>RandomAmount</samp>
+
! command
| ''(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:
+
! changes
<syntaxhighlight lang="js">
  −
"RandomAmount": [ 1, 2, 3.5, 4 ]
  −
</syntaxhighlight>
   
|-
 
|-
| <samp>Condition</samp>
+
| <samp>addToTable</samp>
| ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this change should be applied. Defaults to always true.
+
| Removed (it was unused and worked in counterintuitive ways).
 +
|-
 +
| <samp>addTool</samp>
 +
| Removed (it was unused and only supported the [[Return Scepter|return scepter]]). Use <samp>addItem</samp> instead, which supports adding tools.
 +
|-
 +
| <samp>grabObject</samp>
 +
| Removed (it was unused and broken).
 +
|-
 +
| <samp>showRivalFrame</samp><br /><samp>taxVote</samp>
 +
| Removed (they were part of unimplemented features).
 +
|-
 +
| <samp>weddingSprite</samp>
 +
| Removed (it was broken and unused).
 
|}
 
|}
 +
</ul>
 +
 +
====Festival changes====
 +
* Festivals can now have a custom festival-started notification message by setting the <samp>startedMessage</samp> field in <samp>Data/Festivals/*</samp> to a [[Modding:Tokenizable strings|tokenizable string]].
 +
* Festivals now set the event ID to a value like <samp>festival_fall16</samp>, instead of <samp>-1</samp>.
 +
* All in-festival data fields now support [[Modding:Festival data#Year variants|year variants]].
 +
* Fixed NPCs getting duplicated in festivals if they're added to the <samp>set-up</samp> fields multiple times. Subsequent entries now move them instead.
 +
* Fixed [[Modding:Festival data#Year variants|year variants]] for festival <samp>set-up</samp> field being appended to the main script instead of replacing it.
   −
====Modifier mode====
+
====Send-mail (<samp>x</samp>) precondition deprecated====
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:
+
Using the <samp>x</samp> event precondition as a way to send mail is now deprecated (but still works). You should use [[#Trigger actions|trigger actions]] instead to perform actions like that.
    +
All vanilla events which used it have been replaced by equivalent trigger actions. This event IDs below no longer exist; if you check them (e.g. via <samp>HasSeenEvent</samp>), you'll need to check the new action or the mail flag they set instead.
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! value
+
! old event ID
! effect
+
! new action ID
 +
! mail flag
 +
|-
 +
| <samp>68</samp>
 +
| <samp>Mail_Mom_5K</samp>
 +
| <samp>mom1</samp>
 
|-
 
|-
| <samp>Stack</samp>
+
| <samp>69</samp>
| Apply each modifier to the result of the previous one. For example, two modifiers which double a value will quadruple it.
+
| <samp>Mail_Mom_15K</samp>
 +
| <samp>mom2</samp>
 
|-
 
|-
| <samp>Minimum</samp>
+
| <samp>70</samp>
| Apply the modifier which results in the lowest value.
+
| <samp>Mail_Mom_32K</samp>
 +
| <samp>mom3</samp>
 
|-
 
|-
| <samp>Maximum</samp>
+
| <samp>71</samp>
| Apply the modifier which results in the highest value.
+
| <samp>Mail_Mom_120K</samp>
|}
+
| <samp>mom4</samp>
 
+
|-
====Examples====
+
| <samp>72</samp>
For example, this will double the price of a shop item in <samp>Data/Shops</samp>:
+
| <samp>Mail_Dad_5K</samp>
<syntaxhighlight lang="js">
+
| <samp>dad1</samp>
"PriceModifiers": [
+
|-
    {
+
| <samp>73</samp>
        "Modification": "Multiply",
+
| <samp>Mail_Dad_15K</samp>
        "Amount": 2.0
+
| <samp>dad2</samp>
    }
+
|-
]
+
| <samp>74</samp>
</syntaxhighlight>
+
| <samp>Mail_Dad_32K</samp>
 
+
| <samp>dad3</samp>
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">
+
| <samp>75</samp>
"PriceModifierMode": "Maximum",
+
| <samp>Mail_Dad_120K</samp>
"PriceModifiers": [
+
| <samp>dad4</samp>
    {
+
|-
        "Modification": "Set",
+
| <samp>76</samp>
        "RandomAmount": [ 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000 ]
+
| <samp>Mail_Tribune_UpAndComing</samp>
    },
+
| <samp>newsstory</samp>
    {
+
|-
        "Modification": "Multiply",
+
| <samp>706</samp>
        "RandomAmount": [ 3, 4, 5 ]
+
| <samp>Mail_Pierre_Fertilizers</samp>
    }
+
| <samp>fertilizers</samp>
]
+
|-
</syntaxhighlight>
+
| <samp>707</samp>
 
+
| <samp>Mail_Pierre_FertilizersHighQuality</samp>
===Tokenizable string format===
+
| <samp>fertilizers2</samp>
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.
+
|-
 
+
| <samp>909</samp>
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):
+
| <samp>Mail_Robin_Woodchipper</samp>
 
+
| <samp>WoodChipper</samp>
<syntaxhighlight lang="js">
+
|-
// before
+
| <samp>2111194</samp>
"Dialogue": "Strings\\StringsFromCSFiles:ShopMenu.cs.11488",
+
| <samp>Mail_Emily_8heart</samp>
 
+
| <samp>EmilyClothingTherapy</samp>
// after: any combination of literal text and tokens
+
|-
"Dialogue": "Welcome to Pierre's, {{PlayerName}}! How is [FarmName] doing?",
+
| <samp>2111294</samp>
</syntaxhighlight>
+
| <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>
 +
|}
   −
Tokenizable strings are only usable in specific fields (as indicated in their wiki or code docs).
+
===[[Modding:Mail data|Mail]] changes===
 +
{{/doc status|[[Modding:Mail data]]|done=false}}
   −
See [[Modding:Tokenizable strings]] for usage.
+
<ul>
 
+
<li>Mail can now have multiple items attached (using multiple <samp>%item</samp> commands). When the player grabs the top item, the next one will appear in the slot to grab next.</li>
===[[Modding:Event data|Event]] changes===
+
<li>Added mail commands:
====High-level changes====
+
{| class="wikitable"
* 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.
+
! command
* Event script errors are now logged (in addition to being shown in the chatbox like before).
+
! effect
* 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>).
+
| <samp>%action {{t|action}}%%</samp>
** Added <samp>Event.fromAssetName</samp>, which indicates which data asset (if any) the event was loaded from.
+
| Run a [[Modding:Trigger actions|trigger action string]], like <samp>%action AddMoney 500%%</samp> to add {{price|500}} to the current player.
** Added <samp>Game1.eventsSeenSinceLastLocationChange</samp> to track the events that played since the player arrived in their current location.
+
|}</li>
 +
<li>Improved mail commands:
 +
{| class="wikitable"
 +
|-
 +
! command
 +
! changes
 +
|-
 +
| <samp>%item</samp>
 +
| &#32;
 +
* Added <samp>%item id {{t|item id}} {{o|count}}</samp> form which accepts a [[#Custom items|qualified or unqualified item ID]]. If multiple items are listed (''e.g.,'' <samp>%item id (BC)12 3 (O)34 5 %%</samp>) one set will be picked randomly. This deprecates the <samp>bigobject</samp>, <samp>furniture</samp>, <samp>object</samp>, and <samp>tools</samp> options.
 +
* Added <samp>%item specialOrder {{t|order id}} {{o|immediately}}</samp> form to attach a special order to the letter.
 +
* Added optional {{t|key}} argument to <samp>%item cookingRecipe {{t|key}}</samp>, to learn a specific [[Modding:Recipe data|cooking recipe]]. The previous <samp>%item cookingRecipe</samp> form (without a key) works the same way as before.
 +
* The type argument is now case-insensitive.
 +
* Fixed <samp>%item craftingRecipe</samp> not supporting recipe IDs containing underscores. It now checks for an exact match first, then tries replacing underscores with spaces like before, then logs a warning if neither was found instead of adding an invalid recipe.
 +
|}</li>
 +
<li>All wallet items are now tracked via mail flags. That adds these mail flags: <samp>HasClubCard</samp>, <samp>HasDarkTalisman</samp>, <samp>HasDwarvishTranslationGuide</samp>, <samp>HasMagicInk</samp>, <samp>HasMagnifyingGlass</samp>, <samp>HasRustyKey</samp>, <samp>HasSkullKey</samp>, <samp>HasSpecialCharm</samp>, <samp>HasTownKey</samp>, and <samp>HasUnlockedSkullDoor</samp>.</li>
 +
<li>Fixed letter viewer error when opening an invalid letter.</li>
 +
</ul>
 +
 
 +
===Stat changes for C# mods===
 +
The tracked stats API (e.g. <code>Game1.stats</code> and <code>Game1.player.stats</code>) has been overhauled.
 +
 
 +
In particular, all stats are now in the underlying stat dictionary. If you use a stat field directly (like <code>stats.dirtHoed</code>), you'll need to use the property (like <code>stats.DirtHoed</code>) or method (like <code>stats.Get(StatsKey.DirtHoed)</code>). This lets the game or mods access all stats in a standard way without reflection. 1.6 also adds <samp>StatsKey</samp> constants for all stats tracked by the game.
   −
====Precondition changes====
+
The <samp>stats</samp> API has also been redesigned:
<ul>
+
{| class="wikitable"
<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>.
+
! member
{{collapse|list of new names|content=
+
! comments
List of new event precondition names:
+
|-
<pre>
+
| <samp>Values</samp>
alias | readable name
+
| The numeric metrics tracked by the game. This replaces <samp>stats_dictionary</samp>.
----- | ------------------------------
+
|-
*    | WorldState
+
| <samp>Get(key)</samp>
*n    | HostOrLocalMail
+
| Get the value of a tracked stat. This replaces <samp>getStat</samp>.
a    | Tile
+
 
b    | ReachedMineBottom
+
For example:
B    | SpouseBed
+
<syntaxhighlight lang="c#">
C    | CommunityCenterOrWarehouseDone
+
uint daysPlayed = Game1.stats.Get(StatKeys.DaysPlayed);
c    | FreeInventorySlots
+
</syntaxhighlight>
D    | Dating
  −
e    | SawEvent
  −
f    | Friendship
  −
g    | Gender
  −
H    | IsHost
  −
h    | MissingPet
  −
Hn    | HostMail
  −
i    | HasItem
  −
j    | DaysPlayed
  −
J    | JojaBundlesDone
  −
L    | InUpgradedHouse
  −
m    | EarnedMoney
  −
M    | HasMoney
  −
N    | GoldenWalnuts
  −
n    | LocalMail
  −
O    | Spouse
  −
p    | NpcVisibleHere
  −
q    | ChoseDialogueAnswers
  −
r    | Random
  −
R    | Roommate
  −
S    | SawSecretNote
  −
s    | Shipped
  −
t    | Time
  −
u    | DayOfMonth
  −
v    | NpcVisible
  −
w    | Weather
  −
x    | SendMail
  −
y    | Year
  −
</pre>
  −
And for deprecated preconditions (e.g. <code>NotSeason</code> is superseded by <code>!Season</code>):
  −
<pre>
  −
alias | readable name
  −
----- | ---------------------------------
  −
*l    | NotHostOrLocalMail
  −
A    | NotActiveDialogueEvent
  −
d    | NotDayOfWeek
  −
F    | NotFestivalDay
  −
Hl    | NotHostMail
  −
k    | NotSawEvent
  −
l    | NotLocalMail
  −
o    | NotSpouse
  −
Rf    | NotRoommate
  −
U    | NotUpcomingFestival
  −
X    | NotCommunityCenterOrWarehouseDone
  −
z    | NotSeason
  −
</pre>
  −
}}
  −
</li>
  −
<li>Event & preconditions are now quote-aware, so you can escape spaces and slashes in arguments like <code>/G "SEASON Spring"/</code>.</li>
  −
<li>Added new preconditions:
  −
{| class="wikitable"
   
|-
 
|-
! precondition
+
| <samp>Set(key, value)</samp>
! description
+
| Set the new value of a tracked stat. This method is new.
 +
 
 +
For example:
 +
<syntaxhighlight lang="c#">
 +
Game1.stats.Set(StatKeys.ChildrenTurnedToDoves, 5);
 +
</syntaxhighlight>
 
|-
 
|-
| <samp>!</samp>
+
| <samp>Increment(key)</samp><br /><samp>Increment(key, amount)</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.
+
| Add the given amount to the stat (default 1), and return the new stat value. This improves on the original <samp>incrementStat</samp>.
 +
 
 +
For example:
 +
<syntaxhighlight lang="c#">
 +
uint stepsTaken = Game1.stats.Increment(StatKeys.StepsTaken);
 +
</syntaxhighlight>
 +
|}
 +
 
 +
This can also be used to track custom mod stats, they doesn't need to be stats normally tracked by the game. Custom stats should be prefixed with your mod's unique ID to avoid conflicts:
 +
<syntaxhighlight lang="c#">
 +
Game1.stats.Set("Your.ModId_CustomStat", 5);
 +
</syntaxhighlight>
 +
 
 +
And finally, setting a stat to 0 now removes it from the stats dictionary (since that's the default for missing stats).
 +
 
 +
===New C# utility methods===
 +
Stardew Valley 1.6 adds several new methods to simplify common logic.
 +
 
 +
====Argument handling====
 +
The new <samp>ArgUtility</samp> class handles splitting, reading, and validating <samp>string[]</samp> argument lists. The main methods are:
 +
 
 +
; Splitting arrays&#58;
 +
: {| class="wikitable"
 
|-
 
|-
| <samp>ActiveDialogueEvent {{t|id}}</samp>
+
! <samp>ArgUtility</samp> method
| The special dialogue event with the given ID (including [[Modding:Dialogue#Conversation_topics|Conversation Topics]]) is in progress.
+
! effect
 
|-
 
|-
| <samp>DayOfWeek {{t|day}}+</samp>
+
| <samp>SplitBySpace</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>).
+
| 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>FestivalDay</samp>
+
| <samp>SplitBySpaceAndGet</samp>
| Today is a [[Festivals|festival]] day.
+
| Get the value at an index in a space-delimited string (if found), else return the default value. For example:
 +
 
 +
<syntaxhighlight lang="c#">
 +
string thirdField = ArgUtility.SplitBySpaceAndGet("a b c", 2); // "c"
 +
string invalidFieldA = ArgUtility.SplitBySpaceAndGet("a b c", 5); // null
 +
string invalidFieldB = ArgUtility.SplitBySpaceAndGet("a b c", 5, defaultValue: "boop"); // "boop"
 +
</syntaxhighlight>
 +
 
 +
This is more efficient than <samp>SplitBySpace</samp> when you only need a single value, but it's slower if you need multiple values.
 
|-
 
|-
| <samp>GameStateQuery {{t|query}}</samp>
+
| <samp>SplitBySpaceQuoteAware</samp>
| A [[Modding:Game state queries|game state query]] matches, like <code>G !WEATHER Here Sun</code> for 'not sunny in this location'.
+
| 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>Season {{t|season}}+</samp>
+
| <samp>SplitQuoteAware</samp>
| The current season is one of the given values (may specify multiple seasons).
+
| Split delimited arguments in a string, with support for using quotes to protect delimiters within an argument.
 +
 
 +
A quote in the text causes any delimiter to be ignored until the next quote, unless it's escaped like <code>\"</code>. Unescaped quotes are removed from the string. (Remember that backslashes need to be escaped in C# or JSON strings, like <code>"\\"</code> for a single backslash.)
 +
 
 +
For example:
 +
<syntaxhighlight lang="c#">
 +
ArgUtility.SplitQuoteAware("A,B,C", ',');        // [ "A", "B", "C" ]
 +
ArgUtility.SplitQuoteAware("A,\"B,C\",D", ','); // [ "A", "B,C", "D" ]
 +
ArgUtility.SplitQuoteAware("A,\\\"B,C", ',');    // [ "A", "\"B", "C" ]
 +
</syntaxhighlight>
 +
 
 +
You can also set the optional arguments for more advanced cases. For example, [[Modding:Game state queries|game state queries]] use this to split twice:
 +
<syntaxhighlight lang="c#">
 +
string gameStateQuery = "BUILDINGS_CONSTRUCTED Here \"Junimo Hut\", SEASON Spring";
 +
 
 +
string[] queries = ArgUtility.SplitQuoteAware(gameStateQuery, ',', StringSplitOptions.RemoveEmptyEntries, keepQuotesAndEscapes: true); // [ "BUILDINGS_CONSTRUCTED Here \"Junimo Hut\"", "SEASON Spring" ]
 +
string buildingName = ArgUtility.SplitBySpaceQuoteAware(queries[0]); // Junimo Hut
 +
</syntaxhighlight>
 
|-
 
|-
| <samp>Skill {{t|skill name}} {{t|min level}}</samp>
+
| <samp>EscapeQuotes</samp>
| The current farmer has reached at least {{t|min level}} for the given {{t|skill name}} (one of <samp>Combat</samp>, <samp>Farming</samp>, <samp>Fishing</samp>, <samp>Foraging</samp>, <samp>Luck</samp>, or <samp>Mining</samp>).
+
| Escape quotes in a string so they're ignored by methods like <samp>SplitQuoteAware</samp>.
 +
 
 +
This isn't idempotent (e.g. calling it twice will result in double-escaped quotes).
 
|-
 
|-
| <samp>UpcomingFestival {{t|day offset}}</samp>
+
| <samp>UnsplitQuoteAware</samp>
| A [[Festivals|festival]] day will occur within the given number of days.
+
| 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.
|}</li>
+
 
<li>Changed specific preconditions:
+
For example:
{| class="wikitable"
+
<syntaxhighlight lang="c#">
 +
string args = ArgUtility.UnsplitQuoteAware(new[] { "A", "B C", "D" }, ' '); // A "B C" D
 +
</syntaxhighlight>
 +
 
 +
This isn't idempotent (e.g. calling it twice will result in double-escaped quotes).
 +
|}
 +
 
 +
; Reading arrays&#58;
 +
: {| class="wikitable"
 
|-
 
|-
! name
+
! <samp>ArgUtility</samp> method
! changes
+
! effect
 
|-
 
|-
| <samp>ChoseDialogueAnswers</samp> (<samp>q</samp>)
+
| <samp>HasIndex</samp>
| &#32;
+
| Get whether an index is within the bounds of the array. For example:
* Fixed precondition ignoring every second answer ID.
+
<syntaxhighlight lang="c#">
 +
string[] fields = ArgUtility.SplitByString("10 5");
 +
bool inRange = ArgUtility.HasIndex(fields, 1); // true (index 1 has the value '5')
 +
</syntaxhighlight>
 
|-
 
|-
| <samp>InUpgradedHouse</samp> (<samp>L</samp>)
+
| <samp>Get</samp><br /><samp>GetBool</samp><br /><samp>GetDirection</samp><br /><samp>GetEnum</samp><br /><samp>GetFloat</samp><br /><samp>GetInt</samp>
| &#32;
+
| 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.
* Added optional argument for the min upgrade level.
+
 
 +
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>MissingPet</samp> (<samp>h</samp>)
+
| <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>
| &#32;
+
| 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.
* You can now specify any pet type ID.
+
 
* You can now omit the argument to check for a pet of any type.
+
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>NotDayOfWeek</samp> (<samp>d</samp>)
+
| <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>
| &#32;
+
| Equivalent to <samp>TryGet*</samp>, except that it'll return a default value if the argument is missing. For example:
* You can now specify a full name like <samp>Monday</samp>.
+
<syntaxhighlight lang="c#">
* The day of week is now case-insensitive.
+
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>NotSeason</samp> (<samp>z</samp>)
+
| <samp>GetRemainder</samp><br /><samp>TryGetRemainder</samp><br /><samp>TryGetOptionalRemainder</samp>
| &#32;
+
| Similar to the previous methods, but gets arguments starting from an index as a concatenated string. For example:
* You can now list values (like <code>notSeason spring summer fall</code> instead of <code>notSeason fall/notSeason winter/notSeason fall</code>).
+
<syntaxhighlight lang="c#">
|-
+
string[] fields = ArgUtility.SplitByString("A B C D E F");
| <samp>ReachedMineBottom</samp> (<samp>b</samp>)
+
if (ArgUtility.TryGetRemainder(fields, 2, out string remainder, out string error))
| &#32;
+
    this.Helper.Monitor.Log($"Remainder: {remainder}"); // "Remainder: C D E F"
* Argument is now optional (default 1).
+
else
 +
    this.Helper.Monitor.Log($"Failed getting remainder: {error}", LogLevel.Warn);
 +
</syntaxhighlight>
 
|-
 
|-
| <samp>SendMail</samp> (<samp>x</samp>)
+
| <samp>GetSubsetOf</samp>
| &#32;
+
| Get a slice of the input array. For example:
* Deprecated; see [[#Send-mail (x) precondition deprecated|''Send-mail (x) precondition deprecated'']] for more info.
+
<syntaxhighlight lang="c#">
|-
+
string[] subset1 = ArgUtility.GetSubsetOf(new[] { "A", "B", "C", "D" }, startAt: 1); // B, C, D
| <samp>Tile</samp> (<samp>a</samp>)
+
string[] subset2 = ArgUtility.GetSubsetOf(new[] { "A", "B", "C", "D" }, startAt: 1, length: 2); // B, C
| &#32;
+
</syntaxhighlight>
* 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>
+
This is fault-tolerant as long as <samp>startAt</samp> isn't negative. For example:
</ul>
+
<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>
 +
|}
   −
====Command changes====
+
====Content assets====
<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"
 
{| class="wikitable"
 
|-
 
|-
! command
+
! method
! description
+
! effect
 
|-
 
|-
| <samp>action {{t|action}}</samp>
+
| <samp>LocalizedContentManager.DoesAssetExist</samp>
| Run a [[Modding:Trigger actions|trigger action string]], like <samp>action AddMoney 500</samp> to add {{price|500}} to the current player.
+
| 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>addItem {{t|item ID}} {{o|count}} {{o|quality}}</samp>
+
| <samp>LocalizedContentManager.IsValidTranslationKey</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]].
+
| Get whether a string is a translation key in the form <samp>{{t|asset name}}:{{t|key}}</samp>, and the asset and key both exist. For example:
 +
<syntaxhighlight lang="c#">
 +
bool exists = Game1.content.IsValidTranslationKey("Strings\\NPCNames:Abigail");
 +
</syntaxhighlight>
 +
|}
 +
 
 +
====Filtering====
 +
The game now has an optimized <samp>RemoveWhere</samp> method for O(n) filtering on <samp>NetCollection</samp>, <samp>NetDictionary</samp>, <samp>NetList</samp>, and (via extension) <samp>IDictionary</samp>. This also deprecates <samp>Filter</samp> methods where they existed.
 +
 
 +
For example:
 +
<syntaxhighlight lang="c#">
 +
int dirtTilesRemoved = Game1.currentLocation.terrainFeatures.RemoveWhere(pair => pair.Value is HoeDirt);
 +
</syntaxhighlight>
 +
 
 +
====Game paths====
 +
The game folder paths were previously hardcoded throughout the code. These are now centralized with a few methods:
 +
 
 +
{| class="wikitable"
 
|-
 
|-
| <samp>addSpecialOrder {{t|order ID}}</samp><br /><samp>removeSpecialOrder {{t|order ID}}</samp>
+
! method
| Add or remove a special order to the player team. This affects all players, since special orders are shared.
+
! effect
 
|-
 
|-
| <samp>eventSeen {{t|event ID}} {{o|seen}}</samp>
+
| <samp>Program.GetLocalAppDataFolder</samp><br /><samp>Program.GetAppDataFolder</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).
+
| 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.
 
  −
An event can mark ''itself'' unseen using <samp>eventSeen {{t|event ID}} false</samp>. This takes effect immediately (i.e. the event won't be added to the list when it completes), but the game will prevent the event from playing again until the player changes location to avoid event loops. The event will still replay when re-entering the location.
   
|-
 
|-
| <samp>mailToday {{t|mail key}}</samp>
+
| <samp>Program.GetSavesFolder</samp>
| Adds a letter to the mailbox immediately, given the {{t|mail key}} in <samp>Data/Mail</samp>.
+
| Get the absolute path to the game's [[saves|<samp>Saves</samp> folder]].
 
|-
 
|-
| <samp>questionAnswered {{t|answer ID}} {{o|answered}}</samp>
+
| <samp>Game1.GetScreenshotFolder</samp>
| Add or remove an answer ID from the player's list of chosen dialogue answers, based on {{o|answered}} (default <samp>true</samp> to add).
+
| Get the absolute path to the game's <samp>Screenshots</samp> folder.
 
|-
 
|-
| <samp>replaceWithClone {{t|NPC name}}</samp>
+
| <samp>options.GetFilePathForDefaultOptions</samp>
| Replace an NPC already in the event with a temporary copy. This allows changing the NPC for the event without affecting the real NPC.
+
| Get the absolute path to the game's <samp>default_options</samp> file.
 +
|}
   −
For example, this event changes Marnie's name/portrait only within the event:
+
====Hash sets====
<syntaxhighlight lang="js">
+
Since the [[#Hash set fields|game now uses hash sets]], it has a few extensions for working with them:
"Some.ModId_ExampleEvent/": "continue/64 15/farmer 64 15 2 Marnie 64 17 0/replaceWithClone Marnie/changeName Marnie Pufferchick/changePortrait Marnie Pufferchick/[...]/end"
  −
</syntaxhighlight>
  −
|-
  −
| <samp>setSkipActions {{o|actions}}</samp>
  −
| Set [[Modding:Trigger actions|trigger actions]] that should run if the player skips the event. You can list multiple actions delimited with <samp>#</samp>, or omit {{o|actions}} so no actions are run. When the player skips, the last <samp>setSkipActions</samp> before that point is applied.
     −
For example, this adds the [[Garden Pot|garden pot]] recipe and item to the player if the event is skipped, but avoids adding the item if the event already did it:
+
{| class="wikitable"
<pre>
+
|-
/setSkipActions AddCraftingRecipe Current "Garden Pot"#AddItem (BC)62
+
! method
/skippable
+
! effect
/...
+
|-
/addItem (BC)62
+
| <samp>AddRange</samp>
/setSkipActions AddCraftingRecipe Current "Garden Pot"
+
| Add all the values from a list or enumerable to the set.
</pre>
+
|-
 +
| <samp>RemoveWhere</samp>
 +
| Remove all values matching a condition.
 +
|-
 +
| <samp>Toggle</samp>
 +
| Add or remove a value in the set based on a boolean. For example:
 +
<syntaxhighlight lang="c#">
 +
public bool hasClubCard
 +
{
 +
    get { return mailReceived.Contains("HasClubCard"); }
 +
    set { mailReceived.Toggle("HasClubCard", value); }
 +
}
 +
</syntaxhighlight>
 +
|}
   −
Skip actions aren't applied if the event completes normally without being skipped.
+
====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.
| <samp>stopSound {{t|sound ID}} {{o|immediate}}</samp>
  −
| Stop a sound started with the <samp>startSound</samp> command. This has no effect if the sound has already stopped playing on its own (or hasn't been started). If you started multiple sounds with the same ID, this will stop all of them (e.g. <code>startSound fuse/startSound fuse/stopSound fuse</code>).
     −
By default the sound will stop immediately. For looping sounds, you can pass <samp>false</samp> to the {{o|immediate}} argument to stop the sound when it finishes playing the current iteration instead (e.g. <code>stopSound fuse false</code>).
  −
|-
  −
| <samp>temporaryAnimatedSprite ...</samp>
  −
| Add a temporary animated sprite to the event, using these space-delimited fields:
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! index
+
! method
! field
   
! effect
 
! effect
 
|-
 
|-
| 0
+
| <samp>Utility.ForEachBuilding</samp>
| <samp>texture</samp>
+
| Perform an action for each building in the game world.
| The asset name for texture to draw.
   
|-
 
|-
| 1&ndash;4
+
| <samp>Utility.ForEachCharacter</samp><br /><samp>Utility.ForEachVillager</samp>
| <samp>rectangle</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]].
| 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>Utility.ForEachCrop</samp>
| <samp>interval</samp>
+
| Perform an action for each crop in the game world planted in the ground or in a [[Garden Pot|garden pot]].
| The millisecond duration for each frame in the animation.
   
|-
 
|-
| 6
+
| <samp>Utility.ForEachItem</samp>
| <samp>frames</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.
| The number of frames in the animation.
   
|-
 
|-
| 7
+
| <samp>Utility.ForEachItemIn</samp>
| <samp>loops</samp>
+
| Perform an action for each item within a given location, including items within items (e.g. in a chest or on a table).
| The number of times to repeat the animation.
   
|-
 
|-
| 8&ndash;9
+
| <samp>Utility.ForEachLocation</samp>
| <samp>tile</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.
| The tile position at which to draw the sprite, in the form <samp>{{t|x}} {{t|y}}</samp>.
+
|}
 +
 
 +
For example, this code counts how many parsnips are planted everywhere in the world:
 +
<syntaxhighlight lang="c#">
 +
int parsnips = 0;
 +
Utility.ForEachCrop(crop =>
 +
{
 +
    if (crop.IndexOfHarvest == "24")
 +
        parsnips++;
 +
    return true; // whether to keep iterating after this crop
 +
});
 +
</syntaxhighlight>
 +
 
 +
Or you could replace all instances of an obsolete item with a new one:
 +
<syntaxhighlight lang="c#">
 +
Utility.ForEachItem((item, remove, replaceWith) =>
 +
{
 +
    if (item.QualifiedItemId == "(O)OldId")
 +
    {
 +
        Item newItem = ItemRegistry.Create("(O)NewId", item.Stack, item.Quality);
 +
        replaceWith(newItem);
 +
    }
 +
 
 +
    return true;
 +
});
 +
</syntaxhighlight>
 +
C# mods which add custom item types can override <samp>Item.ForEachItem</samp> to add support for nested items.
 +
 
 +
====Randomization====
 +
{| class="wikitable"
 
|-
 
|-
| 10
+
! method
| <samp>flicker</samp>
+
! effect
| Causes the sprite to flicker in and out of view repeatedly. (one of <samp>true</samp> or <samp>false</samp>).
   
|-
 
|-
| 11
+
| <samp>Utility.CreateDaySaveRandom</samp>
| <samp>flip</samp>
+
| Creates a <samp>Random</samp> instance using the most common seed (based on the save ID and total days played).
| Whether to flip the sprite horizontally when it's drawn (one of <samp>true</samp> or <samp>false</samp>).
   
|-
 
|-
| 12
+
| <samp>Utility.CreateRandom</samp><br /><samp>Utility.CreateRandomSeed</samp>
| <samp>sort tile Y</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.
| The tile Y position to use in the layer depth calculation, which affects which sprite is drawn on top if two sprites overlap. The larger the number, the higher layer the sprite is on.
   
|-
 
|-
| 13
+
| <samp>Utility.TryCreateIntervalRandom</samp>
| <samp>alpha fade</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.
| Fades out the sprite based on alpha set. The larger the number, the faster the fade out. 1 is instant.
+
 
 +
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>
 
|-
 
|-
| 14
+
| <samp>Utility.TryGetRandom</samp>
| <samp>scale</samp>
+
| Get a random entry from a dictionary.
| A multiplier applied to the sprite size (in addition to the normal 4× pixel zoom).
   
|-
 
|-
| 15
+
| <samp>random.Choose</samp>
| <samp>scale change</samp>
+
| Choose a random option from the values provided:
| Changes the scale based on the multiplier applied on top of the normal zoom. Continues endlessly.
+
<syntaxhighlight lang="c#">
 +
string npcName = Game1.random.Choose("Abigail", "Penny", "Sam");
 +
</syntaxhighlight>
 
|-
 
|-
| 16
+
| <samp>random.ChooseFrom</samp>
| <samp>rotation</samp>
+
| Choose a random option from a list or array:
| The rotation to apply to the sprite, measured in [[wikipedia:radians|radians]].
+
<syntaxhighlight lang="c#">
 +
string[] names = new[] { "Abigail", "Penny", "Sam" };
 +
string npcName = Game1.random.ChooseFrom(names);
 +
</syntaxhighlight>
 
|-
 
|-
| 17
+
| <samp>random.NextBool</samp>
| <samp>rotation change</samp>
+
| Randomly choose <samp>true</samp> or <samp>false</samp>. For example:
| Continuously rotates the sprite, causing it to spin. The speed is determined by input value.
+
<syntaxhighlight lang="c#">
|-
+
bool flipSprite = Game1.random.NextBool();
| 18+
+
</syntaxhighlight>
| ''flags''
+
 
| Any combination of these space-delimited flags:
+
You can optionally set the probability of <samp>true</samp>:
* <samp>color {{t|color}}</samp>: apply a [[#Color fields|standard color]] to the sprite.
+
<syntaxhighlight lang="c#">
* <samp>hold_last_frame</samp>: after playing the animation once, freeze the last frame as long as the sprite is shown.
+
bool flipSprite = Game1.random.NextBool(0.8);
* <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.
+
</syntaxhighlight>
* <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]'''
   
|}
 
|}
 +
 +
====Other====
 +
Here are some of the other new methods:
 +
 +
{| class="wikitable"
 
|-
 
|-
| <samp>translateName {{t|actor}} {{t|translation key}}</samp>
+
! method
| Set the display name for an NPC in the event to match the given translation key.
+
! effect
 
|-
 
|-
| <samp>warpFarmers [{{t|x}} {{t|y}} {{t|direction}}]+ {{t|default offset}} {{t|default x}} {{t|default}} {{t|direction}}</samp>
+
| <samp>Game1.getOfflineFarmhands()</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.
+
| Get all farmhands who aren't connected to the game.
|}
  −
</li>
  −
<li>Fixed some commands assuming a boolean argument is true if present, regardless of its value. This affects the <samp>changeToTemporaryMap</samp>, <samp>emote</samp>, <samp>extendSourceRect</samp>, <samp>faceDirection</samp>, <samp>globalFade</samp>, <samp>globalFadeToClear</samp>, <samp>positionOffset</samp>, and <samp>warp</samp> commands.</li>
  −
<li>Fixed some commands assuming any value except the exact case-sensitive string <samp>true</samp> is false. This affects the <samp>animate</samp>, <samp>glow</samp>, <samp>hideShadow</samp>, <samp>ignoreMovementAnimation</samp>, <samp>temporaryAnimatedSprite</samp>, <samp>temporarySprite</samp>, and <samp>viewport</samp> commands.</li>
  −
<li>Fixed some commands silently ignoring values they can't parse as the expected type. This affects the <samp>addItem</samp>, <samp>makeInvisible</samp>, and <samp>removeItem</samp> commands.</li>
  −
<li>Fixed crash when some commands are passed <samp>farmer[number]</samp> for a player who's not available, or <samp>farmer[number]</samp> when they expect <samp>farmer</samp>.</li>
  −
<li>Fixed some commands not taking into account custom farmer actors when checking <samp>farmer*</samp> actor IDs.</li>
  −
<li>Fixed warp-out event commands able to use NPC-only or gendered warps. They now use a valid warp for the player if possible.</li>
  −
<li>Changed specific commands:
  −
{| class="wikitable"
   
|-
 
|-
! command
+
| <samp>Game1.PerformActionWhenPlayerFree</samp>
! changes
+
| 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>addCookingRecipe</samp>
+
| <samp>Game1.createRadialDebris_MoreNatural</samp>
| Fixed error if player already knows the recipe.
+
| Scatter item debris around a position with a more randomized distribution than <samp>createRadialDebris</samp>.
 
|-
 
|-
| <samp>addMailReceived</samp>
+
| <samp>Object.GetCategoryColor</samp><br /><samp>Object.GetCategoryDisplayName</samp>
| &#32;
+
| Get the color and display name for the given category number when it's shown in a tooltip.
* Renamed to <samp>mailReceived</samp>. (The old name is now an alias, so it'll still work.)
  −
* You can now remove a mail received by setting the optional third argument to false, like <samp>mailReceived {{t|id}} false</samp>.
   
|-
 
|-
| <samp>addTemporaryActor</samp>
+
| <samp>Utility.distanceFromScreen</samp>
| &#32;
+
| Get the pixel distance between a position in the world and the player's screen viewport, where 0 is within the viewport.
* Underscores in the asset name are now only replaced with spaces if an exact match wasn't found. You should quote arguments containing spaces instead, like <code>addTemporaryActor "White Chicken" …</code>.
  −
* Underscores in the display name are no longer replaced with spaces. You should quote arguments containing spaces instead.
  −
* Argument 9 ({{o|animal name}}) is now {{o|override name}}, and can be used to set the name for non-animals too.
   
|-
 
|-
| <samp>animate</samp>
+
| <samp>Utility.DrawErrorTexture</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>.
+
| Draw the game's missing-texture image (🚫) to the screen, stretched to fit a given pixel area.
 
|-
 
|-
| <samp>ambientLight</samp>
+
| <samp>Utility.DrawSquare</samp>
| Removed four-argument form (which was unused and had confusing behavior). The other versions of <samp>ambientLight</samp> still work like before.
+
| Draw a square to the screen with a background color and/or borders.
 
|-
 
|-
| <samp>awardFestivalPrize</samp>
+
| <samp>Utility.GetEnumOrDefault</samp>
| Added support for arbitrary item IDs, like <code>awardFestivalPrize (O)128</code> for a pufferfish.
+
| 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>changeLocation</samp>
+
| <samp>Utility.getRandomNpcFromHomeRegion</samp>
| It now updates the event position offset if needed.
+
| 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>changeName</samp>
+
| <samp>Utility.isFestivalDay</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>.
+
| This method existed before 1.6, but you can now omit arguments to check today instead of a specific date:
 +
<syntaxhighlight lang="c#">
 +
bool festivalToday = Utility.isFestivalToday();
 +
</syntaxhighlight>
 +
 
 +
Or check for a festival in specific location context:
 +
<syntaxhighlight lang="c#">
 +
bool desertFestivalToday = Utility.isFestivalToday(LocationContexts.DesertId);
 +
</syntaxhighlight>
 
|-
 
|-
| <samp>changePortrait</samp><br /><samp>changeSprite</samp>
+
| <samp>Utility.IsPassiveFestivalDay</samp>
| You can now omit the suffix argument to reset the NPC back to their normal portrait/sprite.
+
| This method existed before 1.6, but now can now omit arguments to check today instead of a specific date:
 +
<syntaxhighlight lang="c#">
 +
bool passiveFestivalToday = Utility.IsPassiveFestivalDay();
 +
</syntaxhighlight>
 +
 
 +
Or check for a specific passive festival:
 +
<syntaxhighlight lang="c#">
 +
bool nightMarketToday = Utility.IsPassiveFestivalDay("NightMarket");
 +
</syntaxhighlight>
 
|-
 
|-
| <samp>faceDirection</samp>
+
| <samp>Utility.TryGetPassiveFestivalData</samp><br /><samp>Utility.TryGetPassiveFestivalDataForDay</samp>
| You can now specify the direction in words, like <samp>faceDirection up</samp>
+
| Get the [[#Custom passive festivals|passive festival data]] for the given ID or date.
 
|-
 
|-
| <samp>ignoreMovementAnimation</samp>
+
| <samp>Utility.TryParseDirection</samp>
| &#32;
+
| 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]].
* 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>
+
| <samp>Utility.TryParseEnum</samp>
| Added support for arbitrary item IDs, like <code>itemAboveHead (O)128</code> for a pufferfish.
+
| 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>makeInvisible</samp>
+
| <samp>Utility.fuzzyCompare</samp>
| Fixed terrain features not hidden when using the default area size.
+
| 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>playSound</samp>
+
| <samp>rectangle.GetPoints</samp><br /><samp>rectangle.GetVectors</samp>
| Sounds started via <samp>playSound</samp> now stop automatically when the event ends.
+
| 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>removeItem</samp>
+
| <samp>Utility.GetDeterministicHashCode</samp>
| Added argument for an optional count, like <code>removeItem (O)128 10</code> to remove 10 pufferfish.
+
| ''(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>speak</samp>
+
| <samp>Utility.WrapIndex</samp>
| Fixed friendship & socialize quest not updated when calling it with a translation key.
+
| 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).
|}</li>
+
 
<li>Removed some commands:
+
For example:
{| class="wikitable"
+
<syntaxhighlight lang="c#">
|-
+
string[] values = new[] { "0", "1", "2" };
! command
+
int index = Utility.WrapIndex(-1, values.Length); // 2
! changes
+
</syntaxhighlight>
|-
  −
| <samp>addToTable</samp>
  −
| Removed (it was unused and worked in counterintuitive ways).
  −
|-
  −
| <samp>addTool</samp>
  −
| Removed (it was unused and only supported the [[Return Scepter|return scepter]]). Use <samp>addItem</samp> instead, which supports adding tools.
  −
|-
  −
| <samp>grabObject</samp>
  −
| Removed (it was unused and broken).
  −
|-
  −
| <samp>showRivalFrame</samp><br /><samp>taxVote</samp>
  −
| Removed (they were part of unimplemented features).
  −
|-
  −
| <samp>weddingSprite</samp>
  −
| Removed (it was broken and unused).
   
|}
 
|}
</ul>
     −
====Festival changes====
+
===Static delegate builder===
* 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]].
+
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>]].
* 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]].
+
For example, given a static method like this:
* 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.
+
<syntaxhighlight lang="c#">
* 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.
+
public static bool OutputDeconstructor(Object machine, Item inputItem, bool probe, MachineItemOutput outputData, out int? overrideMinutesUntilReady) { ... }
 +
</syntaxhighlight>
   −
====Send-mail (<samp>x</samp>) precondition deprecated====
+
And a delegate which matches it:
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.
+
<syntaxhighlight lang="c#">
 +
public delegate bool MachineOutputDelegate(Object machine, Item inputItem, bool probe, MachineItemOutput outputData, out int? overrideMinutesUntilReady);
 +
</syntaxhighlight>
   −
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.
+
You can create an optimized delegate and call it like this:
{| class="wikitable"
+
<syntaxhighlight lang="c#">
|-
+
if (StaticDelegateBuilder.TryCreateDelegate("StardewValley.Object.OutputDeconstructor", out MachineOutputDelegate method, out string error))
! old event ID
+
    return method(this, inputItem, probe, outputData, out minutesUntilMorning);
! new action ID
+
else
! mail flag
+
    Game1.log.Warn($"Machine {ItemId} has invalid output method: {error}");
 +
</syntaxhighlight>
 +
 
 +
The <samp>TryCreateDelegate</samp> method will cache created delegates, so calling it again will just return the same delegate instance.
 +
 
 +
===Game logging changes===
 +
The game now writes debug output through an internal <samp>Game1.log</samp> wrapper, instead of using <samp>Console.WriteLine</samp> directly. For example:
 +
<syntaxhighlight lang="c#">
 +
// old code
 +
Console.WriteLine("Error playing sound: " + ex);
 +
 
 +
// new code
 +
Game1.log.Error("Error playing sound.", ex);
 +
</syntaxhighlight>
 +
 
 +
This has a few benefits:
 +
* For vanilla players, the game no longer uses time & resources writing to a console that's not visible anyway.
 +
* For modded players, SMAPI can now...
 +
** distinguish between the game's debug/warn/error messages (so many warnings/errors that would previously appear as hidden <samp>TRACE</samp> messages will now be shown with the correct level);
 +
** apply its formatting rules to exceptions logged by the game too;
 +
** redirect game output much more efficiently without console interception.
 +
 
 +
===Other changes===
 +
====Audio====
 +
<ul>
 +
<li>Added <samp>Game1.sounds</samp>, which unifies the high-level sound effect logic (e.g. distance fading and multiplayer sync).</li>
 +
<li>Added <samp>silence</samp> [[Modding:Audio|audio cue]] for music. This is different from <samp>none</samp> in that it suppresses both town music and ambient sounds.</li>
 +
<li>Added <samp>Game1.soundBank.Exists(cueName)</samp> method to check if an audio cue exists.</li>
 +
<li>Added <samp>Game1.playSound</samp> overloads to get the audio cue being played.</li>
 +
<li>Added <samp>character.playNearbySoundAll</samp> and <samp>playNearbySoundAllLocal</samp> methods to play a sound for players near the player/character.</li>
 +
<li>Added position argument to <samp>DelayedAction.playSoundAfterDelay</samp>.</li>
 +
<li>Removed <samp>NetAudioCueManager</samp> and <samp>Game1.locationCues</samp> (unused).</li>
 +
<li>Unified the methods for playing normal/pitched/positional sounds (which also adds support for pitched non-synced & pitched positional sounds):
 +
{| class="wikitable"
 
|-
 
|-
| <samp>68</samp>
+
! old methods
| <samp>Mail_Mom_5K</samp>
+
! new method
| <samp>mom1</samp>
   
|-
 
|-
| <samp>69</samp>
+
| <samp>Game1.playSound</samp><br /><samp>Game1.playSoundAt</samp><br /><samp>Game1.playSoundPitched</samp>
| <samp>Mail_Mom_15K</samp>
+
| <samp>Game1.playSound</samp>
| <samp>mom2</samp>
   
|-
 
|-
| <samp>70</samp>
+
| <samp>GameLocation.playSound</samp><br /><samp>GameLocation.playSoundAt</samp><br /><samp>GameLocation.playSoundPitched</samp>
| <samp>Mail_Mom_32K</samp>
+
| <samp>GameLocation.playSound</samp>
| <samp>mom3</samp>
   
|-
 
|-
| <samp>71</samp>
+
| <samp>GameLocation.localSound</samp><br /><samp>GameLocation.localSoundAt</samp>
| <samp>Mail_Mom_120K</samp>
+
| <samp>GameLocation.localSound</samp>
| <samp>mom4</samp>
   
|-
 
|-
| <samp>72</samp>
+
| <samp>NetAudio.Play</samp><br /><samp>NetAudio.PlayAt</samp><br /><samp>NetAudio.PlayPitched</samp>
| <samp>Mail_Dad_5K</samp>
+
| <samp>NetAudio.Play</samp>
| <samp>dad1</samp>
   
|-
 
|-
| <samp>73</samp>
+
| <samp>NetAudio.PlayLocal</samp><br /><samp>NetAudio.PlayLocalAt</samp>
| <samp>Mail_Dad_15K</samp>
+
| <samp>NetAudio.PlayLocal</samp>
| <samp>dad2</samp>
+
|}</li>
 +
</ul>
 +
 
 +
====Debug commands====
 +
{{/doc status|[[Modding:Console commands]]|done=false}}
 +
 
 +
<ul>
 +
<li>All debug commands are now quote-aware, so you can pass spaces in arguments like <code>debug build "Junimo Hut"</code>.</li>
 +
<li>Added new [[Modding:Console commands|debug commands]]:
 +
{| class="wikitable"
 
|-
 
|-
| <samp>74</samp>
+
! command
| <samp>Mail_Dad_32K</samp>
+
! description
| <samp>dad3</samp>
   
|-
 
|-
| <samp>75</samp>
+
| <samp>action {{t|action}}</samp>
| <samp>Mail_Dad_120K</samp>
+
| Run a [[Modding:Trigger actions|trigger action string]], like <samp>action AddMoney 500</samp> to add {{price|500}} to the current player.
| <samp>dad4</samp>
   
|-
 
|-
| <samp>76</samp>
+
| <samp>artifactSpots</samp>
| <samp>Mail_Tribune_UpAndComing</samp>
+
| Spawn an [[Artifact Spot|artifact spot]] in each empty tile around the player.
| <samp>newsstory</samp>
   
|-
 
|-
| <samp>706</samp>
+
| <samp>endEvent</samp> / <samp>ee</samp>
| <samp>Mail_Pierre_Fertilizers</samp>
+
| Immediately end the current event or festival, applying the event's skip logic (if any). The event is marked seen, but you can rewatch it using the <samp>eventById</samp> command if needed.
| <samp>fertilizers</samp>
+
 
 +
This replaces the pre-1.6 commands (<samp>ee</samp>, <samp>endEvent</samp>/<samp>leaveEvent</samp>, and <samp>eventOver</samp>) which worked in different ways and had side-effects like restarting the event or clearing the player's mail.
 
|-
 
|-
| <samp>707</samp>
+
| <samp>exportShops</samp>
| <samp>Mail_Pierre_FertilizersHighQuality</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>fertilizers2</samp>
   
|-
 
|-
| <samp>909</samp>
+
| <samp>filterLoadMenu</samp> / <samp>flm</samp>
| <samp>Mail_Robin_Woodchipper</samp>
+
| ''Syntax: <samp>filterLoadMenu {{t|search text}}''
| <samp>WoodChipper</samp>
+
 
 +
Filter the current list of saves to those whose player name or farm name contains the given text.
 
|-
 
|-
| <samp>2111194</samp>
+
| <samp>forcebuild</samp>
| <samp>Mail_Emily_8heart</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>EmilyClothingTherapy</samp>
   
|-
 
|-
| <samp>2111294</samp>
+
| <samp>gamequery</samp> / <samp>gq</samp>
| <samp>Mail_Emily_10heart</samp>
+
| ''Syntax:'' <samp>gq {{t|query}}</samp>
| <samp>EmilyCamping</samp>
+
 
 +
Check whether the given [[Modding:Game state queries|game state query]] matches in the current context. For example:
 +
<pre>
 +
gq !SEASON Spring, WEATHER Here Sun
 +
> Result: true.
 +
</pre>
 
|-
 
|-
| <samp>2346091</samp>
+
| <samp>itemquery</samp> / <samp>iq</samp>
| <samp>Mail_Alex_10heart</samp>
+
| ''Syntax:'' <samp>iq {{t|query}}</samp>
| <samp>joshMessage</samp>
+
 
 +
Open a shop menu with all the items matching an [[Modding:Item queries|item query]] (all items free). For example:
 +
* <samp>debug iq ALL_ITEMS</samp> shows all items;
 +
* <samp>debug iq ALL_ITEMS (W)</samp> shows all weapons;
 +
* <samp>debug iq (O)128</samp> shows a pufferfish (object 128);
 +
* <samp>debug iq FLAVORED_ITEM Wine (O)128</samp> shows Pufferfish Wine.
 
|-
 
|-
| <samp>2346092</samp>
+
| <samp>logFile</samp>
| <samp>Mail_Sam_10heart</samp>
+
| Begin writing debug messages to a log file at <samp>%appdata%/StardewValley/ErrorLogs/game-latest.txt</samp> to simplify troubleshooting. You can also enter <samp>/logtext</samp> into the in-game chatbox to enable it.
| <samp>samMessage</samp>
+
 
 +
This does nothing if SMAPI is installed, since the debug messages are already saved to SMAPI's log.
 
|-
 
|-
| <samp>2346093</samp>
+
| <samp>logSounds</samp>
| <samp>Mail_Harvey_10heart</samp>
+
| Log info about each sound effect played to the SMAPI console window.
| <samp>harveyBalloon</samp>
   
|-
 
|-
| <samp>2346094</samp>
+
| <samp>movieSchedule {{o|year}}</samp>
| <samp>Mail_Elliott_10heart</samp>
+
| Lists the movies that will play in a given {{o|year}} (default this year), with the dates they'll play.
| <samp>elliottBoat</samp>
   
|-
 
|-
| <samp>2346095</samp>
+
| <samp>qualifiedid</samp>
| <samp>Mail_Elliott_8heart</samp>
+
| Print the held item's display name and [[#Custom items|qualified item ID]].
| <samp>elliottReading</samp>
   
|-
 
|-
| <samp>2346096</samp>
+
| <samp>search</samp>
| <samp>Mail_Penny_10heart</samp>
+
| ''Syntax:'' <samp>search {{o|term}}</samp>
| <samp>pennySpa</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>2346097</samp>
+
| <samp>setFarmEvent</samp> / <samp>sfe</samp>
| <samp>Mail_Abigail_8heart</samp>
+
| ''Syntax:'' <samp>setFarmEvent {{t|event id}}</samp>
| <samp>abbySpiritBoard</samp>
+
 
|-
+
Queue an [[Random Events#Farm events|overnight farm event]] if one doesn't plan naturally instead. The {{t|event id}} can be one of...
| <samp>3333094</samp>
+
* <samp>dogs</samp>;
| <samp>Mail_Pierre_ExtendedHours</samp>
+
* [[Random Events#Earthquake|<samp>earthquake</samp>]];
| <samp>pierreHours</samp>
+
* [[Random Events#The Crop Fairy|<samp>fairy</samp>]];
 +
* [[Random Events#Meteorite|<samp>meteorite</samp>]];
 +
* [[Random Events#Stone Owl|<samp>owl</samp>]];
 +
* [[Random Events#Strange Capsule|<samp>ufo</samp>]];
 +
* [[Random Events#The Witch|<samp>witch</samp>]].
 +
 
 +
Note that even if the farm event runs, it may exit without doing anything (e.g. rare events like <samp>ufo</samp> have extra condition checks when the start).
 
|-
 
|-
| <samp>3872126</samp>
+
| <samp>shop</samp>
| <samp>Mail_Willy_BackRoomUnlocked</samp>
+
| ''Syntax:'' <samp>shop {{t|shop ID}} {{o|owner name}}</samp>
| <samp>willyBackRoomInvitation</samp>
  −
|}
     −
===[[Modding:Mail data|Mail]] changes===
+
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).
<ul>
+
|-
<li>Mail can now have multiple items attached (using multiple <samp>%item</samp> commands). When the player grabs the top item, the next one will appear in the slot to grab next.</li>
+
| <samp>skinBuilding</samp> / <samp>bsm</samp>
<li>Added mail commands:
+
| If the player is standing right under a building, open a menu to change the building appearance.
{| class="wikitable"
+
|-
 +
| <samp>testwedding</samp>
 +
| Immediately play the [[Marriage#The Wedding|wedding]] event. This requires the player to be married first - to test specific NPCs, <samp>debug marry</samp> the NPC followed by this command.
 +
|-
 +
| <samp>thishouseupgrade</samp> / <samp>thishouse</samp> / <samp>thu</samp>
 +
| Equivalent to <samp>houseupgrade</samp>, but can be used to upgrade another player's house by running it from inside or just south of its exterior.
 +
|-
 +
| <samp>toggleCheats</samp>
 +
| Enable or disable entering debug commands into the in-game chat (prefixed with <samp>/</samp>).
 
|-
 
|-
! command
+
| <samp>tokens</samp>
! effect
+
| ''Syntax:'' <samp>tokens {{t|tokenized string}}</samp>
 +
 
 +
Parses a [[Modding:Tokenizable strings|tokenizable string]] and prints its output. For example:
 +
<pre>
 +
tokens [LocalizedText Strings\StringsFromCSFiles:MapPage.cs.11064 [EscapedText [FarmName]]]
 +
> Result: "Lon Lon Farm"
 +
</pre>
 
|-
 
|-
| <samp>%action {{t|action}}%%</samp>
+
| <samp>worldMapLines</samp>
| Run a [[Modding:Trigger actions|trigger action string]], like <samp>%action AddMoney 500%%</samp> to add {{price|500}} to the current player.
+
| Toggles the [[Modding:World map#Debug view|world map's debug view]].
 
|}</li>
 
|}</li>
<li>Improved mail commands:
+
<li>Improved existing debug commands:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
Line 7,262: Line 7,583:  
! changes
 
! changes
 
|-
 
|-
| <samp>%item</samp>
+
| <samp>build</samp>
| &#32;
+
| Removed custom space handling; quote arguments with spaces instead of replacing them with 9 (e.g. <code>Junimo9Hut</code> <code>"Junimo Hut"</code>).
* 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.
+
| <samp>clearFurniture</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.
+
| Now works outside the farmhouse too.
* 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.
+
| <samp>dialogue</samp>
|}</li>
+
| 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>).
<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>
+
| <samp>ebi</samp>
</ul>
+
| Fixed event not played correctly if called from the same location as the event.
 
+
|-
===Stat changes for C# mods===
+
| <samp>fish</samp>
The tracked stats API (e.g. <code>Game1.stats</code> and <code>Game1.player.stats</code>) has been overhauled.
+
| Fixed error if you're not holding a fishing rod. It now opens the fishing minigame with no tackle instead.
 
  −
In particular, all stats are now in the underlying stat dictionary. If you use a stat field directly (like <code>stats.dirtHoed</code>), you'll need to use the property (like <code>stats.DirtHoed</code>) or method (like <code>stats.Get(StatsKey.DirtHoed)</code>). This lets the game or mods access all stats in a standard way without reflection. 1.6 also adds <samp>StatsKey</samp> constants for all stats tracked by the game.
  −
 
  −
The <samp>stats</samp> API has also been redesigned:
  −
{| class="wikitable"
   
|-
 
|-
! member
+
| <samp>frameOffset</samp>
! comments
+
| &#32;
 +
* Simplified usage. You can now pass negative offsets directly (like <samp>debug frameOffset -5 -10</samp>) instead of using the <samp>s</samp> number prefix.
 +
* Fixed command only taking the last digit in each number.
 
|-
 
|-
| <samp>Values</samp>
+
| <samp>getStat</samp><br /><samp>setStat</samp>
| The numeric metrics tracked by the game. This replaces <samp>stats_dictionary</samp>.
+
| Added argument validation.
 
|-
 
|-
| <samp>Get(key)</samp>
+
| <samp>grass</samp>
| Get the value of a tracked stat. This replaces <samp>getStat</samp>.
+
| Now applies to the current location, instead of the farm.
 
  −
For example:
  −
<syntaxhighlight lang="c#">
  −
uint daysPlayed = Game1.stats.Get(StatKeys.DaysPlayed);
  −
</syntaxhighlight>
   
|-
 
|-
| <samp>Set(key, value)</samp>
+
| <samp>growAnimals</samp><br /><samp>growAnimalsFarm</samp>
| Set the new value of a tracked stat. This method is new.
+
| Merged into one <samp>growAnimals</samp> command that supports any location and doesn't reset the age of animals which are already adults.
 
  −
For example:
  −
<syntaxhighlight lang="c#">
  −
Game1.stats.Set(StatKeys.ChildrenTurnedToDoves, 5);
  −
</syntaxhighlight>
   
|-
 
|-
| <samp>Increment(key)</samp><br /><samp>Increment(key, amount)</samp>
+
| <samp>growCrops</samp>
| Add the given amount to the stat (default 1), and return the new stat value. This improves on the original <samp>incrementStat</samp>.
+
| Fixed error growing mixed seeds or giant crops.
 
+
|-
For example:
+
| <samp>itemNamed</samp>
<syntaxhighlight lang="c#">
+
| Removed custom space handling; quote arguments with spaces instead of removing them (e.g. <code>EelRoe</code> <code>"Eel Roe"</code>).
uint stepsTaken = Game1.stats.Increment(StatKeys.StepsTaken);
+
|-
</syntaxhighlight>
+
| <samp>junimoGoodbye</samp><br /><samp><samp>junimoStar</samp>
|}
+
| Added validation to check that you're inside the community center.
 
+
|-
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:
+
| <samp>killAll</samp><br /><samp>killAllHorses</samp><br /><samp>killNpc</samp>
<syntaxhighlight lang="c#">
+
| These now remove matching NPCs inside constructed buildings too.
Game1.stats.Set("Your.ModId_CustomStat", 5);
+
|-
</syntaxhighlight>
+
| <samp>killMonsterStat</samp>
 
+
| Removed custom space handling; quote arguments with spaces instead of replacing them with 0 (e.g. <code>Dust0Spirit</code> <code>"Dust Spirit"</code>).
And finally, setting a stat to 0 now removes it from the stats dictionary (since that's the default for missing stats).
+
|-
 
+
| <samp>mailForTomorrow</samp>
===New C# utility methods===
+
| Fixed zeros in the mail ID getting replaced with underscores.
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
+
| Added validation for the monster name.
 
|-
 
|-
| <samp>SplitBySpace</samp>
+
| <samp>moveBuilding</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:
+
| Now applies to the current location, instead of the farm.
<syntaxhighlight lang="c#">
  −
string[] fields = ArgUtility.SplitBySpace("a b c");
  −
string secondField = fields[1]; // "b"
  −
</syntaxhighlight>
   
|-
 
|-
| <samp>SplitBySpaceAndGet</samp>
+
| <samp>movie</samp>
| Get the value at an index in a space-delimited string (if found), else return the default value. For example:
+
| 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.
   −
<syntaxhighlight lang="c#">
+
New usage:
string thirdField = ArgUtility.SplitBySpaceAndGet("a b c", 2); // "c"
+
: ''<samp>debug movie {{o|movie ID}} {{o|invite NPC name}}''
string invalidFieldA = ArgUtility.SplitBySpaceAndGet("a b c", 5); // null
+
: ''<samp>debug movie current {{o|invite NPC name}}''
string invalidFieldB = ArgUtility.SplitBySpaceAndGet("a b c", 5, defaultValue: "boop"); // "boop"
  −
</syntaxhighlight>
     −
This is more efficient than <samp>SplitBySpace</samp> when you only need a single value, but it's slower if you need multiple values.
+
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>SplitBySpaceQuoteAware</samp>
+
| <samp>panMode</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.
+
| 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:
  −
<syntaxhighlight lang="c#">
  −
string buildingName = ArgUtility.SplitBySpaceQuoteAware("BUILDINGS_CONSTRUCTED Here \"Junimo Hut\"")[1]; // Junimo Hut
  −
</syntaxhighlight>
   
|-
 
|-
| <samp>SplitQuoteAware</samp>
+
| <samp>paintBuilding</samp>
| Split delimited arguments in a string, with support for using quotes to protect delimiters within an argument.
+
| &#32;
 
+
* Now applies to the current location, instead of the farm.
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.)
+
* Added validation for the target building.
 
  −
For example:
  −
<syntaxhighlight lang="c#">
  −
ArgUtility.SplitQuoteAware("A,B,C", ',');        // [ "A", "B", "C" ]
  −
ArgUtility.SplitQuoteAware("A,\"B,C\",D", ','); // [ "A", "B,C", "D" ]
  −
ArgUtility.SplitQuoteAware("A,\\\"B,C", ',');    // [ "A", "\"B", "C" ]
  −
</syntaxhighlight>
  −
 
  −
You can also set the optional arguments for more advanced cases. For example, [[Modding:Game state queries|game state queries]] use this to split twice:
  −
<syntaxhighlight lang="c#">
  −
string gameStateQuery = "BUILDINGS_CONSTRUCTED Here \"Junimo Hut\", SEASON Spring";
  −
 
  −
string[] queries = ArgUtility.SplitQuoteAware(gameStateQuery, ',', StringSplitOptions.RemoveEmptyEntries, keepQuotesAndEscapes: true); // [ "BUILDINGS_CONSTRUCTED Here \"Junimo Hut\"", "SEASON Spring" ]
  −
string buildingName = ArgUtility.SplitBySpaceQuoteAware(queries[0]); // Junimo Hut
  −
</syntaxhighlight>
   
|-
 
|-
| <samp>EscapeQuotes</samp>
+
| <samp>playSound</samp>
| Escape quotes in a string so they're ignored by methods like <samp>SplitQuoteAware</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.
 
  −
This isn't idempotent (e.g. calling it twice will result in double-escaped quotes).
   
|-
 
|-
| <samp>UnsplitQuoteAware</samp>
+
| <samp>question</samp>
| Combine an array of arguments into a single string with a custom delimiter, using quotes where needed to escape delimiters within an argument. Calling <samp>SplitQuoteAware</samp> on the resulting string with the same delimiter will produce the original values.
+
| 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>.
 
  −
For example:
  −
<syntaxhighlight lang="c#">
  −
string args = ArgUtility.UnsplitQuoteAware(new[] { "A", "B C", "D" }, ' '); // A "B C" D
  −
</syntaxhighlight>
  −
 
  −
This isn't idempotent (e.g. calling it twice will result in double-escaped quotes).
  −
|}
  −
 
  −
; Reading arrays&#58;
  −
: {| class="wikitable"
   
|-
 
|-
! <samp>ArgUtility</samp> method
+
| <samp>runTestEvent</samp>
! effect
+
| Fixed support for Unix line endings.
 
|-
 
|-
| <samp>HasIndex</samp>
+
| <samp>seenEvent</samp>
| Get whether an index is within the bounds of the array. For example:
+
| You can now forget an event (instead of adding it) by setting the second argument to false, like <samp>seenEvent {{t|id}} false</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>seenMail</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.
+
| 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>.
 
  −
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>
+
| <samp>skinBuilding</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.
+
| &#32;
 
+
* Now applies to the current location, instead of the farm.
For example, this parses a numeric value from a space-delimited string:
+
* Added validation for the target building.
<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>
+
| <samp>skullGear</samp>
| Equivalent to <samp>TryGet*</samp>, except that it'll return a default value if the argument is missing. For example:
+
| &#32;
<syntaxhighlight lang="c#">
+
* Fixed command setting 32 slots instead of 36.
string[] fields = ArgUtility.SplitByString("10");
+
* Fixed command not adding empty inventory slots as expected by some game code.
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>setupFishPondFarm</samp>
| Similar to the previous methods, but gets arguments starting from an index as a concatenated string. For example:
+
| Fixed error if the farm already has non-fish-pond buildings constructed.
<syntaxhighlight lang="c#">
  −
string[] fields = ArgUtility.SplitByString("A B C D E F");
  −
if (ArgUtility.TryGetRemainder(fields, 2, out string remainder, out string error))
  −
    this.Helper.Monitor.Log($"Remainder: {remainder}"); // "Remainder: C D E F"
  −
else
  −
    this.Helper.Monitor.Log($"Failed getting remainder: {error}", LogLevel.Warn);
  −
</syntaxhighlight>
   
|-
 
|-
| <samp>GetSubsetOf</samp>
+
| <samp>speech</samp>
| Get a slice of the input array. For example:
+
| 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>).
<syntaxhighlight lang="c#">
+
|-
string[] subset1 = ArgUtility.GetSubsetOf(new[] { "A", "B", "C", "D" }, startAt: 1); // B, C, D
+
| <samp>spreadDirt</samp>
string[] subset2 = ArgUtility.GetSubsetOf(new[] { "A", "B", "C", "D" }, startAt: 1, length: 2); // B, C
+
| Now applies to the current location, instead of the farm.
</syntaxhighlight>
+
|-
 
+
| <samp>spreadSeeds</samp>
This is fault-tolerant as long as <samp>startAt</samp> isn't negative. For example:
+
| Now applies to the current location, instead of the farm.
<syntaxhighlight lang="c#">
  −
string[] subset2 = ArgUtility.GetSubsetOf(new[] { "A", "B", "C", "D" }, startAt: 100); // <empty array>
  −
string[] subset1 = ArgUtility.GetSubsetOf(new[] { "A", "B", "C", "D" }, startAt: 1, length: 100); // B, C, D
  −
</syntaxhighlight>
  −
|}
  −
 
  −
====Content assets====
  −
{| class="wikitable"
   
|-
 
|-
! method
+
| <samp>thisHouseUpgrade</samp>
! effect
+
| Now applies to the current location, instead of the farm.
 
|-
 
|-
| <samp>LocalizedContentManager.DoesAssetExist</samp>
+
| <samp>warpToPlayer</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:
+
| Removed custom space handling; quote arguments with spaces instead of removing them (e.g. <code>JohnSmith</code> <code>"John Smith"</code>).
<syntaxhighlight lang="c#">
  −
bool exists = Game1.content.DoesAssetExist<Map>("Maps/Town");
  −
</syntaxhighlight>
   
|-
 
|-
| <samp>LocalizedContentManager.IsValidTranslationKey</samp>
+
| <samp>whereIs</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:
+
| &#32;
<syntaxhighlight lang="c#">
+
* Now lists all matching NPCs instead of the first one.
bool exists = Game1.content.IsValidTranslationKey("Strings\\NPCNames:Abigail");
+
* Now searches the current event or festival, if any.
</syntaxhighlight>
+
|}</li>
|}
  −
 
  −
====Filtering====
  −
The game now has an optimized <samp>RemoveWhere</samp> method for O(n) filtering on <samp>NetCollection</samp>, <samp>NetDictionary</samp>, <samp>NetList</samp>, and (via extension) <samp>IDictionary</samp>. This also deprecates <samp>Filter</samp> methods where they existed.
  −
 
  −
For example:
  −
<syntaxhighlight lang="c#">
  −
int dirtTilesRemoved = Game1.currentLocation.terrainFeatures.RemoveWhere(pair => pair.Value is HoeDirt);
  −
</syntaxhighlight>
  −
 
  −
====Game paths====
  −
The game folder paths were previously hardcoded throughout the code. These are now centralized with a few methods:
      +
<li>Removed some debug commands:
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! method
+
! command
! effect
+
! notes
 
|-
 
|-
| <samp>Program.GetLocalAppDataFolder</samp><br /><samp>Program.GetAppDataFolder</samp>
+
| <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>
| 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.
+
| These are replaced by more general commands like <code>item (O)128</code> (spawn item by ID), <code>fuzzyItemNamed pufferfish</code> (spawn by item name), or <code>itemQuery FLAVORED_ITEM Wine (O)128</code> (spawn by [[Modding:Item queries|item query]]).
 
|-
 
|-
| <samp>Program.GetSavesFolder</samp>
+
| <samp>addQuartz</samp><br /><samp>blueBook</samp><br /><samp>blueprint</samp><br /><samp>end</samp>
| Get the absolute path to the game's [[saves|<samp>Saves</samp> folder]].
+
| These were part of unused features removed in 1.6.
 
|-
 
|-
| <samp>Game1.GetScreenshotFolder</samp>
+
| <samp>changeStat</samp>
| Get the absolute path to the game's <samp>Screenshots</samp> folder.
+
| Removed; use <samp>setStat</samp> instead.
 
|-
 
|-
| <samp>options.GetFilePathForDefaultOptions</samp>
+
| <samp>ee</samp><br /><samp>endEvent</samp>/<samp>leaveEvent</samp><br /><samp>eventOver</samp>
| Get the absolute path to the game's <samp>default_options</samp> file.
+
| Replaced by the new <samp>endEvent</samp> command.
|}
  −
 
  −
====Hash sets====
  −
Since the [[#Hash set fields|game now uses hash sets]], it has a few extensions for working with them:
  −
 
  −
{| class="wikitable"
   
|-
 
|-
! method
+
| <samp>everythingshop</samp>
! effect
+
| 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>AddRange</samp>
+
| <samp>oldMineGame</samp>
| Add all the values from a list or enumerable to the set.
+
| Removed along with the pre-1.4 [[Junimo Kart]] code.
 
|-
 
|-
| <samp>RemoveWhere</samp>
+
| <samp>pathSpouseToMe</samp>/<samp>pstm</samp>
| Remove all values matching a condition.
+
| Removed along with the unimplemented farm activities code.
|-
+
|}</li>
| <samp>Toggle</samp>
+
 
| Add or remove a value in the set based on a boolean. For example:
+
<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>
<syntaxhighlight lang="c#">
+
<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>
public bool hasClubCard
+
</ul>
{
  −
    get { return mailReceived.Contains("HasClubCard"); }
  −
    set { mailReceived.Toggle("HasClubCard", value); }
  −
}
  −
</syntaxhighlight>
  −
|}
     −
====Iteration====
+
====Location logic====
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.
+
* The [[desert]] no longer assumes the player arrived by bus unless their previous location was the [[Bus Stop|bus stop]].
 +
* The ticket price for the bus and Willy's boat can now be edited by C# mods via <samp>BusStop.TicketPrice</samp> and <samp>BoatTunnel.TicketPrice</samp> respectively.
   −
{| class="wikitable"
+
====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.
! method
+
* Added <samp>Game1.textShadowDarkerColor</samp> field for the colors previously hardcoded in <samp>Utility.drawTextWithShadow</samp>.
! effect
+
* 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>.
| <samp>Utility.ForEachBuilding</samp>
+
* The <samp>SpriteText</samp> methods now accept arbitrary <samp>Color</samp> tints instead of a few predefined color IDs.
| Perform an action for each building in the game world.
+
* 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.
| <samp>Utility.ForEachCharacter</samp><br /><samp>Utility.ForEachVillager</samp>
+
* Fixed an edge case where a custom language's fonts wouldn't be loaded when switching language.
| Perform an action for each NPC in the game world. <samp>ForEachCharacter</samp> matches all NPC types (villagers, horses, pets, monsters, player children, etc), while <samp>ForEachVillager</samp> only matches villager NPCs like [[Abigail]].
  −
|-
  −
| <samp>Utility.ForEachCrop</samp>
  −
| Perform an action for each crop in the game world planted in the ground or in a [[Garden Pot|garden pot]].
  −
|-
  −
| <samp>Utility.ForEachItem</samp>
  −
| Perform an action for each item in the game world, including items within items (e.g. in a chest or on a table), hats placed on children, items in player inventories, etc.
  −
|-
  −
| <samp>Utility.ForEachItemIn</samp>
  −
| Perform an action for each item within a given location, including items within items (e.g. in a chest or on a table).
  −
|-
  −
| <samp>Utility.ForEachLocation</samp>
  −
| Perform an action for each location in the game world, optionally including building interiors and generated [[The Mines|mine]] or [[Volcano Dungeon|volcano]] levels.
  −
|}
     −
For example, this code counts how many parsnips are planted everywhere in the world:
+
====[[Modding:Modder Guide/Game Fundamentals#Net fields|Net fields]]====
<syntaxhighlight lang="c#">
+
* 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.
int parsnips = 0;
+
* <samp>NetLocationRef</samp> now has a public <samp>LocationName</samp> and <samp>IsStructure</samp>, and its <samp>Update</samp> method allows forcing an update.
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:
+
====Quests====
<syntaxhighlight lang="c#">
+
{{/doc status|[[Modding:Quest data]]|done=false}}
Utility.ForEachItem((item, remove, replaceWith) =>
  −
{
  −
    if (item.QualifiedItemId == "(O)OldId")
  −
    {
  −
        Item newItem = ItemRegistry.Create("(O)NewId", item.Stack, item.Quality);
  −
        replaceWith(newItem);
  −
    }
     −
    return true;
+
* Quests now have string IDs, to simplify custom quest frameworks.
});
+
* Added validation for quest data parsing.
</syntaxhighlight>
+
* In [[Modding:Special orders|<samp>Data/SpecialOrders</samp>]], the <samp>Duration</samp> and <samp>Repeatable</samp> fields are now strongly-typed and case-insensitive.
C# mods which add custom item types can override <samp>Item.ForEachItem</samp> to add support for nested items.
+
* For C# mods, fixed <samp>DescriptionElement</samp> not allowing more than four translation token substitutions.
   −
====Randomization====
+
====Dates & seasons====
{| class="wikitable"
+
* Added a <samp>Season</samp> enum for strongly-typed, case-insensitive season checks (like <code>Game1.season == Season.Spring</code> instead of <code>Game1.currentSeason == "spring"</code>).
|-
+
* Added <samp>Game1.season</samp>, <samp>Game1.GetSeasonForLocation</samp>, <samp>Game1.WorldDate.Season</samp>, and <samp>location.GetSeason()</samp> to get the season enum.
! method
+
* Added <samp>Utility.getSeasonKey</samp> to get the key form from a season enum.
! effect
+
* Improved <samp>WorldDate</samp>:
|-
+
** added <samp>Now()</samp> to get a new instance matching the current date;
| <samp>Utility.CreateDaySaveRandom</samp>
+
** added <samp>WorldDate.Equals</samp> and <samp>GetHashCode</samp> implementations;
| Creates a <samp>Random</samp> instance using the most common seed (based on the save ID and total days played).
+
** added code docs;
|-
+
** <samp>TotalDays</samp> is no longer written to the save file.
| <samp>Utility.CreateRandom</samp><br /><samp>Utility.CreateRandomSeed</samp>
+
* 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>).
| Creates a <samp>Random</samp> (or seed for a <samp>Random</samp>) by combining the given seed values, which can be any numeric type.
+
* Fixed <samp>location.GetSeasonKey()</samp> not applying the greenhouse logic.
|-
  −
| <samp>Utility.TryCreateIntervalRandom</samp>
  −
| Get an RNG which produces identical results for all RNGs created with the same sync key during the given interval (one of <samp>tick</samp>, <samp>day</samp>, <samp>season</samp>, or <samp>year</samp>), including between players in multiplayer mode.
     −
For example, this will return the same number each time it's called until the in-game day changes:
+
====Time====
<syntaxhighlight lang="c#">
+
* 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.
public int GetDailyRandomNumber()
  −
{
  −
    Utility.TryCreateIntervalRandom("day", "example sync key", out Random random, out _);
  −
    return random.Next();
  −
}
  −
</syntaxhighlight>
  −
|-
  −
| <samp>Utility.TryGetRandom</samp>
  −
| Get a random entry from a dictionary.
  −
|-
  −
| <samp>random.Choose</samp>
  −
| Choose a random option from the values provided:
  −
<syntaxhighlight lang="c#">
  −
string npcName = Game1.random.Choose("Abigail", "Penny", "Sam");
  −
</syntaxhighlight>
  −
|-
  −
| <samp>random.ChooseFrom</samp>
  −
| Choose a random option from a list or array:
  −
<syntaxhighlight lang="c#">
  −
string[] names = new[] { "Abigail", "Penny", "Sam" };
  −
string npcName = Game1.random.ChooseFrom(names);
  −
</syntaxhighlight>
  −
|-
  −
| <samp>random.NextBool</samp>
  −
| Randomly choose <samp>true</samp> or <samp>false</samp>. For example:
  −
<syntaxhighlight lang="c#">
  −
bool flipSprite = Game1.random.NextBool();
  −
</syntaxhighlight>
  −
 
  −
You can optionally set the probability of <samp>true</samp>:
  −
<syntaxhighlight lang="c#">
  −
bool flipSprite = Game1.random.NextBool(0.8);
  −
</syntaxhighlight>
  −
|}
      
====Other====
 
====Other====
Here are some of the other new methods:
+
* Error stack traces on Linux/macOS now have line numbers.
 +
* All space-delimited fields now ignore extra spaces instead of crashing. This affects map/tile properties, data assets, event commands, game state queries, etc.
 +
* All players and NPCs now have <samp>Tile</samp> & <samp>TilePoint</samp> properties (their cached tile position) and a <samp>StandingPixel</samp> property (the cached pixel coordinate at the center of their bounding box). These [[#Other breaking API changes|replace various deleted methods]].
 +
* All terrain features now have <samp>Tile</samp> and <samp>Location</samp> properties, and their methods no longer have location/tile parameters in most cases.
 +
* All [[Modding:Modder Guide/Game Fundamentals#Net fields|net fields]] now have <samp>Name</samp> and <samp>Owner</samp> fields, which are used to show informative error messages when there's a sync issue and validate common mistakes (e.g. a net field not added to the <samp>NetFields</samp> collection).
 +
* The game now tracks the locations a player has visited. Mods can check the list in C# (via <samp>Game1.player.locationsVisited</samp>) or [[Modding:Game state queries|game state queries]] (via <samp>PLAYER_VISITED_LOCATION</samp>). For pre-existing saves, the list is retroactively populated based on accessible locations, events seen, mail flags set, etc.
 +
* Added menu queuing (via <samp>Game1.nextClickableMenu</samp> in C#). For example, this applies if you try to take an item from a mail letter when your inventory is full.
 +
* Added C# code docs in many places.
 +
* Added <samp>Id</samp> fields to simplify content pack edits in fish pond, movie concession, random bundle, and tailoring recipe data.
 +
* Added <samp>Game1.Multiplayer</samp> to get the game's low-level handler. (Most code should still use [[Modding:Modder Guide/APIs/Multiplayer|SMAPI's multiplayer API]] though.)
 +
* Added <samp>Game1.versionBuildNumber</samp> with the build number (like <samp>26039</samp>).
 +
* Added field-changed events to <samp>NetPosition</samp>.
 +
* Added <samp>LocalizedContentManager.CurrentLanguageString</samp>, which caches the language code like <samp>pt-BR</samp>).
 +
* The game now uses <samp>[XmlInclude]</samp> on its types more consistently. That means the default save serializer can handle more types (e.g. all monsters), and it's easier to create custom serializers.
 +
* Refactored many parts of the code to make it more moddable for C# mods. This includes marking all classes public, changing <samp>private</samp> members to <samp>protected</samp> or <samp>public</samp>, marking members <samp>virtual</samp>, rewriting or splitting code so it's easier to extend, etc.
 +
* The <samp>startup_preferences</samp> file is now formatted to simplify troubleshooting.
 +
* Fixed many cases where the game used <samp>Game1.player</samp> instead of the provided player.
 +
 
 +
==Breaking changes for C# mods==
 +
'''This section only describes how this update may break existing mods. See the ''what's new'' sections above for more info, including new functionality mods can use.'''
 +
 
 +
See also [[#Breaking changes for content packs|''Breaking changes for content packs'']], which affect C# mods too.
 +
 
 +
===.NET 6===
 +
: ''See also: [[#.NET 6|.NET 6]] under what's new.''
 +
 
 +
Stardew Valley 1.6 updates from .NET 5 to .NET 6. SMAPI can still load .NET 5 mods fine, but you'll get a build error when compiling them. To update a C# mod:
 +
<ol>
 +
<li>Make sure you have [https://visualstudio.microsoft.com/vs Visual Studio Community 2022] or later. (Compiling .NET 6 with earlier versions of Visual Studio isn't officially supported.)</li>
 +
<li>In Visual Studio, click ''Help > Check For Updates'' and install the latest version.</li>
 +
<li>Fully exit Visual Studio.</li>
 +
<li>Open each mod's <samp>.csproj</samp> file in a text editor, then find this line:
 +
<syntaxhighlight lang="xml">
 +
<TargetFramework>net5.0</TargetFramework>
 +
</syntaxhighlight>
 +
 
 +
And change it to this:
 +
<syntaxhighlight lang="xml">
 +
<TargetFramework>net6.0</TargetFramework>
 +
</syntaxhighlight>
 +
</li>
 +
<li>Delete your solution's hidden <samp>.vs</samp> folder, and every project's <samp>bin</samp> and <samp>obj</samp> folders.</li>
 +
<li>Reopen the solution in Visual Studio, click ''Build > Rebuild Solution'', and make sure it still loads into the game fine.</li>
 +
</ol>
 +
 
 +
===Item ID changes===
 +
: ''See also: [[#Custom items|custom items in what's new]].''
 +
 
 +
The [[#Custom items|main <samp>Item</samp> properties have changed]]. To migrate existing code:
 +
<ul>
 +
<li>Don't use <samp>ParentSheetIndex</samp> to compare items. For example, <samp>item.ParentSheetIndex == 0</samp> will match both [[weeds]] and any custom item whose sprite is the first one in its custom spritesheet. You should compare items using [[#Custom items|their new <samp>ItemId</samp> and <samp>QualifiedItemId</samp> properties]] instead. For example, here's how to migrate various common forms:
    
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! method
+
! old code
! effect
+
! new code
 
|-
 
|-
| <samp>Game1.getOfflineFarmhands()</samp>
  −
| Get all farmhands who aren't connected to the game.
   
|-
 
|-
| <samp>Game1.PerformActionWhenPlayerFree</samp>
+
| <samp>item.ParentSheetIndex == 848</samp>
| Calls the provided callback next time the player is free (e.g. no menu or event is up, not using a tool, etc). If the player is already free, it's run immediately.
+
| <samp>item.QualifiedItemId == "(O)848"</samp>
 
  −
For example, if you receive your first geode from a fishing chest, this is used to show the geode-received animation & animation when it closes.
   
|-
 
|-
| <samp>Game1.createRadialDebris_MoreNatural</samp>
+
| <samp>IsNormalObjectAtParentSheetIndex(item, 74)</samp>
| Scatter item debris around a position with a more randomized distribution than <samp>createRadialDebris</samp>.
+
| <samp>item.QualifiedItemId == "(O)74"</samp>
 
|-
 
|-
| <samp>Object.GetCategoryColor</samp><br /><samp>Object.GetCategoryDisplayName</samp>
+
| <samp>!item.bigCraftable && item.ParentSheetIndex == 128</samp>
| Get the color and display name for the given category number when it's shown in a tooltip.
+
| <samp>item.QualifiedItemId == "(O)128"</samp>
 
|-
 
|-
| <samp>Utility.distanceFromScreen</samp>
+
| <samp>item is Boots && item.ParentSheetIndex == 505</samp>
| Get the pixel distance between a position in the world and the player's screen viewport, where 0 is within the viewport.
+
| <samp>item.QualifiedItemId == "(B)505"</samp>
|-
+
|}</li>
| <samp>Utility.DrawErrorTexture</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>
| Draw the game's missing-texture image (🚫) to the screen, stretched to fit a given pixel area.
+
<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>Utility.DrawSquare</samp>
  −
| Draw a square to the screen with a background color and/or borders.
  −
|-
  −
| <samp>Utility.GetEnumOrDefault</samp>
  −
| Get an enum value if it's valid, else get a default value. This is mainly used to validate input from data files.
     −
For example:
   
<syntaxhighlight lang="c#">
 
<syntaxhighlight lang="c#">
NpcGender gender = (NPCGender)999999;
+
new Object("634", 1);                     // vanilla item
gender = Utility.GetEnumOrDefault(gender, Gender.Male); // returns Gender.Male since there's no enum constant with value 999999
+
new Object("Example.ModId_Watermelon", 1); // custom item
</syntaxhighlight>
  −
|-
  −
| <samp>Utility.getRandomNpcFromHomeRegion</samp>
  −
| Get a random social NPC based on their <samp>HomeRegion</samp> value in [[#Custom NPCs|<samp>Data/Characters</samp>]]. For example, this gets a random NPC for the <samp>Town</samp> home region:
  −
<syntaxhighlight lang="c#">
  −
NPC npc = Utility.getRandomNpcFromHomeRegion(NPC.region_town);
  −
</syntaxhighlight>
  −
|-
  −
| <samp>Utility.isFestivalDay</samp>
  −
| This method existed before 1.6, but you can now omit arguments to check today instead of a specific date:
  −
<syntaxhighlight lang="c#">
  −
bool festivalToday = Utility.isFestivalToday();
   
</syntaxhighlight>
 
</syntaxhighlight>
   −
Or check for a festival in specific location context:
+
You can also use the new <samp>ItemRegistry</samp> API to construct items from their <samp>QualifiedItemId</samp>:
<syntaxhighlight lang="c#">
  −
bool desertFestivalToday = Utility.isFestivalToday(LocationContexts.DesertId);
  −
</syntaxhighlight>
  −
|-
  −
| <samp>Utility.IsPassiveFestivalDay</samp>
  −
| This method existed before 1.6, but now can now omit arguments to check today instead of a specific date:
  −
<syntaxhighlight lang="c#">
  −
bool passiveFestivalToday = Utility.IsPassiveFestivalDay();
  −
</syntaxhighlight>
     −
Or check for a specific passive festival:
   
<syntaxhighlight lang="c#">
 
<syntaxhighlight lang="c#">
bool nightMarketToday = Utility.IsPassiveFestivalDay("NightMarket");
+
Item item = ItemRegistry.Create("(B)505"); // Rubber Boots
</syntaxhighlight>
+
</syntaxhighlight></li>
 +
</ul>
 +
 
 +
===Other ID changes===
 +
Many other things in the game now have unique string IDs too (including [[#Buff overhaul|buffs]], [[#String event IDs|events]], and fruit trees). To migrate existing code:
 +
 
 +
* When referencing numeric IDs, you usually just need to convert them into a string (like <code>Game1.player.hasBuff("1590166")</code> or <code>Game1.player.eventsSeen.Contains("1590166")</code>).
 +
* When creating buffs, see [[#Buff overhaul|buff overhaul]] for how to create buffs now.
 +
* For pre-existing content pack data, see migration steps in the ''[[#Unique string IDs|unique string IDs]]'' section.
 +
 
 +
===Building and animal changes===
 +
: ''See also: [[#Build anywhere|build anywhere in what's new]].''
 +
 
 +
* Since all locations now allow buildings and animals, mod code which handles <samp>BuildableGameLocation</samp> and <samp>IAnimalLocation</samp> won't detect all buildable locations. You can replace them with <samp>location.IsBuildableLocation()</samp> (or just access <samp>location.buildings</samp> directly) and <samp>location.animals.Any()</samp> instead. Mods should no longer have any reference at all to <samp>BuildableGameLocation</samp> and <samp>IAnimalLocation</samp>.
 +
* Since buildings can be built anywhere, you can no longer assume a building is on the farm. You can check the new <samp>building.buildingLocation</samp> field instead.
 +
* You should review direct references to the farm (like <code>Game1.getFarm()</code> or <code>Game1.getLocationFromName("Farm")</code>) to see if it needs to be rewritten to allow other locations.
 +
* <code>Utility.numSilos()</code> should no longer be used to calculate available hay, since it doesn't account for custom buildings with hay storage. Use <code>Game1.getFarm().GetHayCapacity()</code> instead.
 +
* The <samp>Cat</samp> and <samp>Dog</samp> classes are now unused; all pets are now <samp>Pet</samp> directly.
 +
 
 +
===Player changes===
 +
: ''See also: [[#Buff overhaul|buff overhaul in what's new]].''
 +
 
 +
<ul>
 +
<li>Several <samp>Game1.player</samp> / <samp>Farmer</samp> fields changed as part of the [[#Buff overhaul|buff overhaul]]:
 +
{| class="wikitable"
 
|-
 
|-
| <samp>Utility.TryGetPassiveFestivalData</samp><br /><samp>Utility.TryGetPassiveFestivalDataForDay</samp>
+
! old field
| Get the [[#Custom passive festivals|passive festival data]] for the given ID or date.
+
! how to migrate
 
|-
 
|-
| <samp>Utility.TryParseDirection</samp>
+
| <samp>appliedBuffs</samp><br /><samp>appliedSpecialBuffs</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]].
+
| Use <code>Game1.player.hasBuff(id)</code> instead.
 
|-
 
|-
| <samp>Utility.TryParseEnum</samp>
+
| <samp>attack</samp><br /><samp>immunity</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:
+
| Use <samp>Attack</samp> and <samp>Immunity</samp> instead.
<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>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>
| 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.
+
| Use equivalent properties under <samp>Game1.player.buffs</samp> instead (e.g. <samp>Game1.player.buffs.CombatLevel</code>).
 
|-
 
|-
| <samp>rectangle.GetPoints</samp><br /><samp>rectangle.GetVectors</samp>
+
| <samp>resilience</samp>
| Get all the integer coordinates within a given <samp>Rectangle</samp>. For example:
+
| Use <samp>buffs.Defense</samp> 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>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>
| ''(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.
+
| 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>Utility.WrapIndex</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>
| 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).
+
<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:
   −
For example:
+
{| class="wikitable"
<syntaxhighlight lang="c#">
+
|-
string[] values = new[] { "0", "1", "2" };
+
! method
int index = Utility.WrapIndex(-1, values.Length); // 2
+
! effect
</syntaxhighlight>
+
|-
 +
| <samp>CanSpawnCharacterHere</samp>
 +
| Get whether NPCs can be placed on the given tile (e.g. it's within the map bounds and tile is walkable), there's no placed object there, and the <samp>NoFurniture</samp> [[Modding:Maps|tile property]] isn't set.
 +
|-
 +
| <samp>CanItemBePlacedHere</samp>
 +
| Get whether items can be placed on the given tile in non-floating form (e.g. it's within the map bounds and not blocked by a non-walkable item), and the <samp>NoFurniture</samp> [[Modding:Maps|tile property]] isn't set.
 +
|-
 +
| <samp>isBuildable</samp>
 +
| Get whether buildings can be placed on the given tile.
 +
|-
 +
| <samp>IsTilePassable</samp>
 +
| Get whether the tile can be walked on (ignoring collisions with in-game objects, NPCs, etc).
 +
|-
 +
| <samp>IsTileOccupiedBy</samp>
 +
| Get whether the tile contains a player, object, NPC/monster/pet/etc, terrain feature, building, etc. You can choose which entities to check, and which ones to ignore if they don't block movement.
 +
|-
 +
| <samp>IsTileBlockedBy</samp>
 +
| Equivalent to calling both <samp>IsTilePassable</samp> and <samp>IsTileOccupiedBy</samp>.
 +
|-
 +
| <samp>IsLocationSpecificOccupantOnTile</samp><br /><samp>IsLocationSpecificPlacementRestriction</samp>
 +
| Generally shouldn't be used directly. Checks for location-specific collisions (e.g. ladders in [[The Mines|the mines]] or parrot platforms on [[Ginger Island]]).
 
|}
 
|}
   −
===Static delegate builder===
+
===Other breaking API changes===
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>]].
+
''(This section is meant as a quick reference if you have build errors; there's no need to read through it otherwise.)''
   −
For example, given a static method like this:
+
====Removed unused code====
<syntaxhighlight lang="c#">
+
1.6 removes a lot of unused code. That includes these classes:
public static bool OutputDeconstructor(Object machine, Item inputItem, bool probe, MachineItemOutput outputData, out int? overrideMinutesUntilReady) { ... }
+
{| class="wikitable"
</syntaxhighlight>
+
|-
 
+
! namespace
And a delegate which matches it:
+
! class name
<syntaxhighlight lang="c#">
+
|-
public delegate bool MachineOutputDelegate(Object machine, Item inputItem, bool probe, MachineItemOutput outputData, out int? overrideMinutesUntilReady);
+
| <samp>StardewValley</samp>
</syntaxhighlight>
+
| &#32;
 
+
* <samp>BuildingUpgrade</samp>
You can create an optimized delegate and call it like this:
+
* <samp>DisposableList</samp>
<syntaxhighlight lang="c#">
+
* <samp>FurniturePlacer</samp>
if (StaticDelegateBuilder.TryCreateDelegate("StardewValley.Object.OutputDeconstructor", out MachineOutputDelegate method, out string error))
+
* <samp>ListPool</samp>
    return method(this, inputItem, probe, outputData, out minutesUntilMorning);
+
* <samp>OneTimeRandom</samp>
else
  −
    Game1.log.Warn($"Machine {ItemId} has invalid output method: {error}");
  −
</syntaxhighlight>
  −
 
  −
The <samp>TryCreateDelegate</samp> method will cache created delegates, so calling it again will just return the same delegate instance.
  −
 
  −
===Game logging changes===
  −
The game now writes debug output through an internal <samp>Game1.log</samp> wrapper, instead of using <samp>Console.WriteLine</samp> directly. For example:
  −
<syntaxhighlight lang="c#">
  −
// old code
  −
Console.WriteLine("Error playing sound: " + ex);
  −
 
  −
// new code
  −
Game1.log.Error("Error playing sound.", ex);
  −
</syntaxhighlight>
  −
 
  −
This has a few benefits:
  −
* For vanilla players, the game no longer uses time & resources writing to a console that's not visible anyway.
  −
* For modded players, SMAPI can now...
  −
** distinguish between the game's debug/warn/error messages (so many warnings/errors that would previously appear as hidden <samp>TRACE</samp> messages will now be shown with the correct level);
  −
** apply its formatting rules to exceptions logged by the game too;
  −
** redirect game output much more efficiently without console interception.
  −
 
  −
===Other changes===
  −
====Audio====
  −
<ul>
  −
<li>Added <samp>Game1.sounds</samp>, which unifies the high-level sound effect logic (e.g. distance fading and multiplayer sync).</li>
  −
<li>Added <samp>silence</samp> [[Modding:Audio|audio cue]] for music. This is different from <samp>none</samp> in that it suppresses both town music and ambient sounds.</li>
  −
<li>Added <samp>Game1.soundBank.Exists(cueName)</samp> method to check if an audio cue exists.</li>
  −
<li>Added <samp>Game1.playSound</samp> overloads to get the audio cue being played.</li>
  −
<li>Added <samp>character.playNearbySoundAll</samp> and <samp>playNearbySoundAllLocal</samp> methods to play a sound for players near the player/character.</li>
  −
<li>Added position argument to <samp>DelayedAction.playSoundAfterDelay</samp>.</li>
  −
<li>Removed <samp>NetAudioCueManager</samp> and <samp>Game1.locationCues</samp> (unused).</li>
  −
<li>Unified the methods for playing normal/pitched/positional sounds (which also adds support for pitched non-synced & pitched positional sounds):
  −
{| class="wikitable"
   
|-
 
|-
! old methods
+
| <samp>StardewValley.Characters</samp>
! new method
+
| &#32;
 +
* <samp>BotchedNetBool</samp>
 +
* <samp>BotchedNetField</samp>
 +
* <samp>BotchedNetInt</samp>
 +
* <samp>BotchedNetLong</samp>
 
|-
 
|-
| <samp>Game1.playSound</samp><br /><samp>Game1.playSoundAt</samp><br /><samp>Game1.playSoundPitched</samp>
+
| <samp>StardewValley.Menus</samp>
| <samp>Game1.playSound</samp>
+
| &#32;
 +
* <samp>FarmInfoPage</samp>
 +
* <samp>MiniatureTerrainFeature</samp><!-- not a typo, it really was in StardewValley.Menus -->
 
|-
 
|-
| <samp>GameLocation.playSound</samp><br /><samp>GameLocation.playSoundAt</samp><br /><samp>GameLocation.playSoundPitched</samp>
+
| <samp>StardewValley.Monsters</samp>
| <samp>GameLocation.playSound</samp>
+
| &#32;
 +
* <samp>LavaCrab</samp>
 
|-
 
|-
| <samp>GameLocation.localSound</samp><br /><samp>GameLocation.localSoundAt</samp>
+
| <samp>StardewValley.Objects</samp>
| <samp>GameLocation.localSound</samp>
+
| &#32;
 +
* <samp>ObjectFactory</samp> (replaced by [[#Custom items|<samp>ItemRegistry</samp>]])
 
|-
 
|-
| <samp>NetAudio.Play</samp><br /><samp>NetAudio.PlayAt</samp><br /><samp>NetAudio.PlayPitched</samp>
+
| <samp>StardewValley.TerrainFeatures</samp>
| <samp>NetAudio.Play</samp>
+
| &#32;
 +
* <samp>Quartz</samp>
 
|-
 
|-
| <samp>NetAudio.PlayLocal</samp><br /><samp>NetAudio.PlayLocalAt</samp>
+
| <samp>StardewValley.Tools</samp>
| <samp>NetAudio.PlayLocal</samp>
+
| &#32;
|}</li>
+
* <samp>Blueprints</samp>
</ul>
+
* <samp>ToolFactory</samp> (replaced by [[#Custom items|<samp>ItemRegistry</samp>]])
 +
|}
   −
====Debug commands====
+
And these class members:
<ul>
  −
<li>All debug commands are now quote-aware, so you can pass spaces in arguments like <code>debug build "Junimo Hut"</code>.</li>
  −
<li>Added new [[Modding:Console commands|debug commands]]:
   
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! command
+
! type
! description
+
! members
 
|-
 
|-
| <samp>action {{t|action}}</samp>
+
| <samp>Axe</samp>
| Run a [[Modding:Trigger actions|trigger action string]], like <samp>action AddMoney 500</samp> to add {{price|500}} to the current player.
+
| &#32;
 +
* <samp>StumpStrength</samp>
 
|-
 
|-
| <samp>artifactSpots</samp>
+
| <samp>Bush</samp>
| Spawn an [[Artifact Spot|artifact spot]] in each empty tile around the player.
+
| &#32;
 +
* <samp>alpha</samp>
 +
* <samp>lastPlayerToHit</samp>
 
|-
 
|-
| <samp>endEvent</samp> / <samp>ee</samp>
+
| <samp>Chest</samp>
| Immediately end the current event or festival, applying the event's skip logic (if any). The event is marked seen, but you can rewatch it using the <samp>eventById</samp> command if needed.
+
| &#32;
 
+
* <samp>chestType</samp>
This replaces the pre-1.6 commands (<samp>ee</samp>, <samp>endEvent</samp>/<samp>leaveEvent</samp>, and <samp>eventOver</samp>) which worked in different ways and had side-effects like restarting the event or clearing the player's mail.
+
* <samp>coins</samp>
 +
|-
 +
| <samp>CosmeticPlant</samp>
 +
| &#32;
 +
* <samp>scale</samp>
 
|-
 
|-
| <samp>exportShops</samp>
+
| <samp>CraftingRecipe</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.
+
| &#32;
 +
* <samp>itemType</samp>
 
|-
 
|-
| <samp>filterLoadMenu</samp> / <samp>flm</samp>
+
| <samp>Critter</samp>
| ''Syntax: <samp>filterLoadMenu {{t|search text}}''
+
| &#32;
 
+
* <samp>InitShared()</samp>
Filter the current list of saves to those whose player name or farm name contains the given text.
   
|-
 
|-
| <samp>forcebuild</samp>
+
| <samp>Crop</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.
+
| &#32;
 +
* <samp>daysOfUnclutteredGrowth</samp>
 
|-
 
|-
| <samp>gamequery</samp> / <samp>gq</samp>
+
| <samp>Dialogue</samp>
| ''Syntax:'' <samp>gq {{t|query}}</samp>
+
| &#32;
 
+
* <samp>dialogueToBeKilled</samp>
Check whether the given [[Modding:Game state queries|game state query]] matches in the current context. For example:
  −
<pre>
  −
gq !SEASON Spring, WEATHER Here Sun
  −
> Result: true.
  −
</pre>
   
|-
 
|-
| <samp>itemquery</samp> / <samp>iq</samp>
+
| <samp>Farm</samp>
| ''Syntax:'' <samp>iq {{t|query}}</samp>
+
| &#32;
 
+
* <samp>GetSpouseOutdoorAreaSpritesheetIndex()</samp>
Open a shop menu with all the items matching an [[Modding:Item queries|item query]] (all items free). For example:
  −
* <samp>debug iq ALL_ITEMS</samp> shows all items;
  −
* <samp>debug iq ALL_ITEMS (W)</samp> shows all weapons;
  −
* <samp>debug iq (O)128</samp> shows a pufferfish (object 128);
  −
* <samp>debug iq FLAVORED_ITEM Wine (O)128</samp> shows Pufferfish Wine.
   
|-
 
|-
| <samp>logFile</samp>
+
| <samp>FarmAnimal</samp>
| Begin writing debug messages to a log file at <samp>%appdata%/StardewValley/ErrorLogs/game-latest.txt</samp> to simplify troubleshooting. You can also enter <samp>/logtext</samp> into the in-game chatbox to enable it.
+
| &#32;
 
+
* <samp>homeLocation</samp>
This does nothing if SMAPI is installed, since the debug messages are already saved to SMAPI's log.
   
|-
 
|-
| <samp>logSounds</samp>
+
| <samp>Farmer</samp>
| Log info about each sound effect played to the SMAPI console window.
+
| &#32;
|-
+
* <samp>barnUpgradeLevel</samp> and <samp>BarnUpgradeLevel</samp>
| <samp>movieSchedule {{o|year}}</samp>
+
* <samp>blueprints</samp>
| Lists the movies that will play in a given {{o|year}} (default this year), with the dates they'll play.
+
* <samp>coalPieces</samp> and <samp>CoalPieces</samp>
|-
+
* <samp>coopUpgradeLevel</samp> and <samp>CoopUpgradeLevel</samp>
| <samp>qualifiedid</samp>
+
* <samp>copperPieces</samp> and <samp>CopperPieces</samp>
| Print the held item's display name and [[#Custom items|qualified item ID]].
+
* <samp>eyeColor</samp>
|-
+
* <samp>feed</samp> and <samp>Feed</samp>
| <samp>search</samp>
+
* <samp>furnitureOwned</samp>
| ''Syntax:'' <samp>search {{o|term}}</samp>
+
* <samp>goldPieces</samp> and <samp>GoldPieces</samp>
 
+
* <samp>hasBusTicket</samp>
List all debug commands that match the given search term (or all debug commands if the search term is omitted). For example:
+
* <samp>hasGreenhouse</samp>
<pre>debug search backpack
+
* <samp>iridiumPieces</samp> and <samp>IridiumPieces</samp>
> Found 2 debug commands matching search term 'backpack':
+
* <samp>ironPieces</samp> and <samp>IronPieces</samp>
    - Backpack
+
* <samp>newSkillPointsToSpend</samp>
    - FillBackpack (fbp, fill, fillbp)</pre>
+
* <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>setFarmEvent</samp> / <samp>sfe</samp>
+
| <samp>Game1</samp>
| ''Syntax:'' <samp>setFarmEvent {{t|event id}}</samp>
+
| &#32;
 
+
* <samp>boardingBus</samp>
Queue an [[Random Events#Farm events|overnight farm event]] if one doesn't plan naturally instead. The {{t|event id}} can be one of...
+
* <samp>chanceToRainTomorrow</samp>
* <samp>dogs</samp>;
+
* <samp>checkForNewLevelPerks</samp>
* [[Random Events#Earthquake|<samp>earthquake</samp>]];
+
* <samp>cloud</samp>
* [[Random Events#The Crop Fairy|<samp>fairy</samp>]];
+
* <samp>coopDwellerBorn<samp>
* [[Random Events#Meteorite|<samp>meteorite</samp>]];
+
* <samp>cropsOfTheWeek</samp>
* [[Random Events#Stone Owl|<samp>owl</samp>]];
+
* <samp>currentBarnTexture</samp>
* [[Random Events#Strange Capsule|<samp>ufo</samp>]];
+
* <samp>currentBillboard</samp>
* [[Random Events#The Witch|<samp>witch</samp>]].
+
* <samp>currentCoopTexture</samp>
 
+
* <samp>currentFloor</samp>
Note that even if the farm event runs, it may exit without doing anything (e.g. rare events like <samp>ufo</samp> have extra condition checks when the start).
+
* <samp>currentHouseTexture</samp>
|-
+
* <samp>currentWallpaper</samp>
| <samp>shop</samp>
+
* <samp>dealerCalicoJackTotal</samp>
| ''Syntax:'' <samp>shop {{t|shop ID}} {{o|owner name}}</samp>
+
* <samp>FarmerFloor</samp>
 
+
* <samp>farmerWallpaper</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>fertilizer</samp>
|-
+
* <samp>floorPrice</samp>
| <samp>skinBuilding</samp> / <samp>bsm</samp>
+
* <samp>greenhouseTexture</samp>
| If the player is standing right under a building, open a menu to change the building appearance.
+
* <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>testwedding</samp>
+
| <samp>GameLocation</samp>
| Immediately play the [[Marriage#The Wedding|wedding]] event. This requires the player to be married first - to test specific NPCs, <samp>debug marry</samp> the NPC followed by this command.
+
| &#32;
 +
* <samp>boardBus(…)</samp>
 +
* <samp>checkForMapChanges()</samp>
 +
* <samp>getWallDecorItem(…)</samp>
 +
* <samp>removeBatch(…)</samp>
 +
* <samp>removeDirt(…)</samp>
 +
* <samp>removeStumpOrBoulder(…)</samp>
 +
* <samp>tryToBuyNewBackpack()</samp>
 
|-
 
|-
| <samp>thishouseupgrade</samp> / <samp>thishouse</samp> / <samp>thu</samp>
+
| <samp>GiantCrop</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.
+
| &#32;
 +
* <samp>forSale</samp>
 
|-
 
|-
| <samp>toggleCheats</samp>
+
| <samp>IClickableMenu</samp>
| Enable or disable entering debug commands into the in-game chat (prefixed with <samp>/</samp>).
+
| &#32;
 +
* <samp>currentRegion</samp>
 
|-
 
|-
| <samp>tokens</samp>
+
| <samp>MeleeWeapon</samp>
| ''Syntax:'' <samp>tokens {{t|tokenized string}}</samp>
+
| &#32;
 
+
* <samp>attackSwordCooldownTime</samp>
Parses a [[Modding:Tokenizable strings|tokenizable string]] and prints its output. For example:
+
* <samp>doStabbingSwordFunction(…)</samp>
<pre>
  −
tokens [LocalizedText Strings\StringsFromCSFiles:MapPage.cs.11064 [EscapedText [FarmName]]]
  −
> Result: "Lon Lon Farm"
  −
</pre>
   
|-
 
|-
| <samp>worldMapLines</samp>
+
| <samp>Monster</samp>
| Toggles the [[Modding:World map#Debug view|world map's debug view]].
+
| &#32;
|}</li>
+
* <samp>doHorizontalMovement(…)</samp>
<li>Improved existing debug commands:
+
* <samp>durationOfRandomMovements</samp>
{| class="wikitable"
+
* <samp>coinsToDrop</samp>
 
|-
 
|-
! command
+
| <samp>NPC</samp>
! changes
+
| &#32;
 +
* <samp>idForClones</samp>
 
|-
 
|-
| <samp>build</samp>
+
| <samp>Object</samp>
| Removed custom space handling; quote arguments with spaces instead of replacing them with 9 (e.g. <code>Junimo9Hut</code> <code>"Junimo Hut"</code>).
+
| &#32;
 +
* <samp>attachToSprinklerAttachment(…)</samp>
 +
* <samp>canBePlacedInWater()</samp>
 +
* <samp>consumeRecipe(…)</samp>
 +
* <samp>copperBar</samp>
 +
* <samp>goldBar</samp>
 +
* <samp>iridiumBar</samp>
 +
* <samp>ironBar</samp>
 +
* <samp>isHoeDirt</samp> and <samp>IsHoeDirt</samp>
 
|-
 
|-
| <samp>clearFurniture</samp>
+
| <samp>PathFindController</samp>
| Now works outside the farmhouse too.
+
| &#32;
 +
* <samp>CheckClearance(…)</samp>
 +
* <samp>limit</samp>
 
|-
 
|-
| <samp>dialogue</samp>
+
| <samp>SaveGame</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>).
+
| &#32;
 +
* <samp>cropsOfTheWeek</samp>
 +
* <samp>currentFloor</samp>
 +
* <samp>currentWallpaper</samp>
 +
* <samp>FarmerFloor</samp>
 +
* <samp>farmerWallpaper</samp>
 +
* <samp>shippingTax</samp>
 
|-
 
|-
| <samp>ebi</samp>
+
| <samp>Spiker</samp>
| Fixed event not played correctly if called from the same location as the event.
+
| &#32;
 +
* <samp>GetSpawnPosition</samp>
 
|-
 
|-
| <samp>fish</samp>
+
| <samp>Stats</samp>
| Fixed error if you're not holding a fishing rod. It now opens the fishing minigame with no tackle instead.
  −
|-
  −
| <samp>frameOffset</samp>
   
| &#32;
 
| &#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.
+
* <samp>barsSmelted</samp> and <samp>BarsSmelted</samp>
* Fixed command only taking the last digit in each number.
+
* <samp>coalFound</samp> and <samp>CoalFound</samp>
 +
* <samp>coinsFound</samp> and <samp>coinsFound</samp>
 +
* <samp>starLevelCropsShipped</samp> and <samp>starLevelCropsShipped</samp>
 
|-
 
|-
| <samp>getStat</samp><br /><samp>setStat</samp>
+
| <samp>Tool</samp>
| Added argument validation.
+
| &#32;
 +
* <samp>batteredSwordSpriteIndex</samp>
 +
* <samp>copperColor</samp>
 +
* <samp>GetSecondaryEnchantmentCount()</samp>
 +
* <samp>goldColor</samp>
 +
* <samp>iridiumColor</samp>
 +
* <samp>nonUpgradeable</samp>
 +
* <samp>parsnipSpriteIndex</samp>
 +
* <samp>Stackable</samp>
 +
* <samp>startOfNegativeWeaponIndex</samp>
 +
* <samp>steelColor</samp>
 
|-
 
|-
| <samp>grass</samp>
+
| <samp>Utility</samp>
| Now applies to the current location, instead of the farm.
+
| &#32;
 +
* <samp>buyFloor()</samp>
 +
* <samp>buyWallpaper()</samp>
 +
* <samp>cropsOfTheWeek()</samp>
 +
* <samp>facePlayerEndBehavior(…)</samp>
 +
* <samp>getRandomSlotCharacter()</samp>
 +
* <samp>plantCrops(…)</samp>
 +
* <samp>showLanternBar()</samp>
 +
|}
 +
 
 +
====Renamed classes====
 +
These classes were renamed in 1.6:
 +
{| class="wikitable"
 
|-
 
|-
| <samp>growAnimals</samp><br /><samp>growAnimalsFarm</samp>
+
! old name
| Merged into one <samp>growAnimals</samp> command that supports any location and doesn't reset the age of animals which are already adults.
+
! new name
 
|-
 
|-
| <samp>growCrops</samp>
+
| <samp>Game1.MusicContext</samp>
| Fixed error growing mixed seeds or giant crops.
+
| <samp>MusicContext</samp> (in <samp>StardewValley.GameData</samp>)
 
|-
 
|-
| <samp>itemNamed</samp>
+
| <samp>LocationContext</samp>
| Removed custom space handling; quote arguments with spaces instead of removing them (e.g. <code>EelRoe</code> → <code>"Eel Roe"</code>).
+
| <samp>LocationContexts</samp>
 
|-
 
|-
| <samp>junimoGoodbye</samp><br /><samp><samp>junimoStar</samp>
+
| <samp>SpecialOrder.QuestStatus</samp>
| Added validation to check that you're inside the community center.
+
| <samp>SpecialOrderStatus</samp> (in <samp>StardewValley.SpecialOrders</samp>)
 +
|}
 +
 
 +
And these were moved to a different namespace:
 +
{| class="wikitable"
 
|-
 
|-
| <samp>killAll</samp><br /><samp>killAllHorses</samp><br /><samp>killNpc</samp>
+
! type
| These now remove matching NPCs inside constructed buildings too.
+
! old namespace
 +
! new namespace
 
|-
 
|-
| <samp>killMonsterStat</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>
| Removed custom space handling; quote arguments with spaces instead of replacing them with 0 (e.g. <code>Dust0Spirit</code> <code>"Dust Spirit"</code>).
+
| <samp>StardewValley</samp>
 +
| <samp>StardewValley.Enchantments</samp>
 +
|-
 +
| <samp>Extensions</samp>
 +
| <samp>StardewValley</samp>
 +
| <samp>StardewValley.Extensions</samp>
 +
|-
 +
| <samp>ModDataDictionary</samp><br /><samp>ModHooks</samp>
 +
| <samp>StardewValley</samp>
 +
| <samp>StardewValley.Mods</samp>
 
|-
 
|-
| <samp>mailForTomorrow</samp>
+
| <samp>PathFindController</samp><br /><samp>PathNode</samp><br /><samp>PriorityQueue</samp><br /><samp>SchedulePathDescription</samp>
| Fixed zeros in the mail ID getting replaced with underscores.
+
| <samp>StardewValley</samp>
 +
| <samp>StardewValley.Pathfinding</samp>
 
|-
 
|-
| <samp>monster</samp>
+
| <samp>SpecialOrder</samp>
| Added validation for the monster name.
+
| <samp>StardewValley</samp>
 +
| <samp>StardewValley.SpecialOrders</samp>
 
|-
 
|-
| <samp>moveBuilding</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>
| Now applies to the current location, instead of the farm.
+
| <samp>StardewValley</samp>
 +
| <samp>StardewValley.SpecialOrders.Objectives</samp>
 
|-
 
|-
| <samp>movie</samp>
+
| <samp>FriendshipReward</samp><br /><samp>GemsReward</samp><br /><samp>MailReward</samp><br /><samp>MoneyReward</samp><br /><samp>OrderReward</samp><br /><samp>ResetEventReward</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.
+
| <samp>StardewValley</samp>
 +
| <samp>StardewValley.SpecialOrders.Rewards</samp>
 +
|}
   −
New usage:
+
====Other API changes====
: ''<samp>debug movie {{o|movie ID}} {{o|invite NPC name}}''
+
These class members changed in 1.6:
: ''<samp>debug movie current {{o|invite NPC name}}''
     −
The movie ID defaults to today's movie, and the NPC name can be omitted to watch the movie without an invitee. Specifying <samp>current</samp> as the movie uses the default value.
+
{| class="wikitable"
 
|-
 
|-
| <samp>panMode</samp>
+
! type
| 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>.
+
! member
 +
! migration
 
|-
 
|-
| <samp>paintBuilding</samp>
+
| <samp>BigSlime</samp>
| &#32;
+
| <samp>heldObject</samp>
* Now applies to the current location, instead of the farm.
+
| Replaced by <samp>heldItem</samp>, which allows non-object items too.
* Added validation for the target building.
   
|-
 
|-
| <samp>playSound</samp>
+
|rowspan="3"| <samp>Bush</samp>
| Added an optional pitch argument, like <samp>debug playSound barrelBreak 1200</samp>. The pitch is a value from 1 (low pitch) to 2400 (high pitch) inclusively.
+
| <samp>overrideSeason</samp>
 +
| Removed; use <code>bush.Location.GetSeason()</code> instead.
 
|-
 
|-
| <samp>question</samp>
+
| <samp>greenhouseBush</samp>
| You can now forget a selected answer (instead of adding it) by setting the second argument to false, like <samp>question {{t|id}} false</samp>.
+
| Removed; use <code>bush.IsSheltered()</code> or <code>bush.currentLocation.IsGreenhouse</code> instead.
 
|-
 
|-
| <samp>runTestEvent</samp>
+
| <samp>inBloom</samp>
| Fixed support for Unix line endings.
+
| Remove the arguments, like <code>bush.inBloom(Game1.currentSeason, Game1.dayOfMonth)</code> → <code>bush.inBloom()</code>.
 
|-
 
|-
| <samp>seenEvent</samp>
+
|rowspan="3"| <samp>Character</samp>
| You can now forget an event (instead of adding it) by setting the second argument to false, like <samp>seenEvent {{t|id}} false</samp>.
+
| <samp>getStandingX</samp><br /><samp>getStandingY</samp><br /><samp>getStandingXY</samp>
 +
| Removed; use <samp>character.StandingPixel</samp> instead.
 
|-
 
|-
| <samp>seenMail</samp>
+
| <samp>getTileLocation</samp><br /><samp>getTileX</samp><br /><samp>getTileY</samp><br />
| 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>.
+
| Removed; use <samp>character.Tile</samp> instead.
 
|-
 
|-
| <samp>skinBuilding</samp>
+
| <samp>getTileLocationPoint</samp>
| &#32;
+
| Removed; use <samp>character.TilePoint</samp> instead.
* Now applies to the current location, instead of the farm.
  −
* Added validation for the target building.
   
|-
 
|-
| <samp>skullGear</samp>
+
| <samp>Chest</samp>
| &#32;
+
| <samp>MoveToSafePosition</samp>
* Fixed command setting 32 slots instead of 36.
+
| Replaced by the simpler <samp>TryMoveToSafePosition</samp>
* Fixed command not adding empty inventory slots as expected by some game code.
   
|-
 
|-
| <Samp>setupFishPondFarm</samp>
+
|rowspan="2"| <samp>Dialogue</samp>
| Fixed error if the farm already has non-fish-pond buildings constructed.
+
| <samp>dialogues</samp>
 +
| Changed from <code>List&lt;string&gt;</code> to <code>List&lt;DialogueLine&gt;</code>. The <samp>Text</samp> field on each dialogue line is equivalent to the old value.
 
|-
 
|-
| <samp>speech</samp>
+
| <samp>isOnFinalDialogue()</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>).
+
| 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>spreadDirt</samp>
+
|rowspan="3"| <samp>Farmer</samp>
| Now applies to the current location, instead of the farm.
+
| <samp>changePants(…)</samp>
 +
| Renamed to <samp>changePantsColor(…)</samp> for consistency with <samp>change[Eye&#124;Hair&#124;Shoe]Color</samp>.
 
|-
 
|-
| <samp>spreadSeeds</samp>
+
| <samp>isMarried()</samp>
| Now applies to the current location, instead of the farm.
+
| Renamed to <samp>isMarriedOrRoommates()</samp> for clarity.
 
|-
 
|-
| <samp>thisHouseUpgrade</samp>
+
| <samp>visibleQuestCount</samp>
| Now applies to the current location, instead of the farm.
+
| Replaced by <samp>hasVisibleQuests</samp>.
 
|-
 
|-
| <samp>warpToPlayer</samp>
+
| <samp>Flooring</samp>
| Removed custom space handling; quote arguments with spaces instead of removing them (e.g. <code>JohnSmith</code> <code>"John Smith"</code>).
+
| <samp>GetFloorPathLookup</samp>
 +
| Use <samp>Game1.floorPathData</samp> instead.
 
|-
 
|-
| <samp>whereIs</samp>
+
| <samp>Forest</samp>
| &#32;
+
| <samp>log</samp>
* Now lists all matching NPCs instead of the first one.
+
| Moved into <samp>Forest.resourceClumps</samp>.
* Now searches the current event or festival, if any.
  −
|}</li>
  −
 
  −
<li>Removed some debug commands:
  −
{| class="wikitable"
   
|-
 
|-
! command
+
| <samp>FruitTree</samp>
! notes
+
| <samp>GreenHouseTree</samp>
 +
| Replaced by <samp>IgnoresSeasonsHere()</samp>.
 
|-
 
|-
| <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>
+
|rowspan="3"| <samp>Game1</samp>
| These are replaced by more general commands like <code>item (O)128</code> (spawn item by ID), <code>fuzzyItemNamed pufferfish</code> (spawn by item name), or <code>itemQuery FLAVORED_ITEM Wine (O)128</code> (spawn by [[Modding:Item queries|item query]]).
+
| <samp>bigCraftableInformation</samp>
 +
| Overhauled into [[#Custom big craftables|<samp>Game1.bigCraftableData</samp>]].
 
|-
 
|-
| <samp>addQuartz</samp><br /><samp>blueBook</samp><br /><samp>blueprint</samp><br /><samp>end</samp>
+
| <samp>clothingInformation</samp>
| These were part of unused features removed in 1.6.
+
| Overhauled into [[#Custom shirts|<samp>Game1.shirtData</samp>]] and [[#Custom pants|<samp>Game1.pantsData</samp>]].
 
|-
 
|-
| <samp>changeStat</samp>
+
| <samp>objectInformation</samp>
| Removed; use <samp>setStat</samp> instead.
+
| Overhauled into [[#Custom objects|<samp>Game1.objectData</samp>]].
 
|-
 
|-
| <samp>ee</samp><br /><samp>endEvent</samp>/<samp>leaveEvent</samp><br /><samp>eventOver</samp>
+
|rowspan="3"| <samp>GameLocation</samp>
| Replaced by the new <samp>endEvent</samp> command.
+
| <samp>getCharacters</samp>
 +
| Removed; use the <samp>characters</samp> field instead.
 
|-
 
|-
| <samp>oldMineGame</samp>
+
| <samp>GetMapPropertyPosition</samp>
| Removed along with the pre-1.4 [[Junimo Kart]] code.
+
| Replaced by <samp>TryGetMapPropertyAs</samp>, which supports multiple data types (not just <samp>Point</samp>).
 
|-
 
|-
| <samp>pathSpouseToMe</samp>/<samp>pstm</samp>
+
| <samp>isTileOccupied</samp><br /><samp>isTileOccupiedForPlacement</samp><br /><samp>isTileOccupiedIgnoreFloors</samp><br /><samp>isTileLocationOpenIgnoreFrontLayers</samp><br /><samp>isTileLocationTotallyClearAndPlaceable</samp><br /><samp>isTileLocationTotallyClearAndPlaceableIgnoreFloors</samp>
| Removed along with the unimplemented farm activities code.
+
| 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.
|}</li>
     −
<li>Added alternative names for some debug commands (new names in parentheses): <samp>bpm</samp> + <samp>bsm</samp> (<samp>paintBuilding</samp> + <samp>skinBuilding</samp>), <samp>craftingRecipe</samp> (</samp>addCraftingRecipe</samp>), <samp>db</samp> (</samp>speakTo</samp>), <samp>dialogue</samp> (</samp>addDialogue</samp>), <samp>pdb</samp> (</samp>printGemBirds</samp>), <samp>r</samp> (</samp>resetForPlayerEntry</samp>), <samp>removeLargeTf</samp> (</samp>removeLargeTerrainFeature</samp>), <samp>sb</samp> (</samp>showTextAboveHead</samp>), <samp>sl</samp> + <samp>sr</samp> (<samp>shiftToolbarLeft</samp> + </samp>shiftToolbarRight</samp>), <samp>sn</samp> (</samp>secretNote</samp>), and <samp>tls</samp> (</samp>toggleLightingScale</samp>).</li>
+
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.
<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>
+
{{collapse|expand for non-recommended code|content=<syntaxhighlight lang="c#">
</ul>
+
public static class GameLocationExtensions
 +
{
 +
    public static bool isTileOccupiedForPlacement(this GameLocation location, Vector2 tileLocation, Object toPlace = null)
 +
    {
 +
        return location.CanItemBePlacedHere(tileLocation, toPlace != null && toPlace.isPassable());
 +
    }
   −
====Location logic====
+
    public static bool isTileOccupied(this GameLocation location, Vector2 tileLocation, string characterToIgnore = "", bool ignoreAllCharacters = false)
* The [[desert]] no longer assumes the player arrived by bus unless their previous location was the [[Bus Stop|bus stop]].
+
    {
* The ticket price for the bus and Willy's boat can now be edited by C# mods via <samp>BusStop.TicketPrice</samp> and <samp>BoatTunnel.TicketPrice</samp> respectively.
+
        CollisionMask mask = ignoreAllCharacters ? CollisionMask.All & ~CollisionMask.Characters & ~CollisionMask.Farmers : CollisionMask.All;
 +
        return location.IsTileOccupiedBy(tileLocation, mask);
 +
    }
   −
====Menus & UI====
+
    public static bool isTileOccupiedIgnoreFloors(this GameLocation location, Vector2 tileLocation, string characterToIgnore = "")
* Rewrote calendar menu (<samp>Billboard</samp>) to simplify custom events & event types. C# mods can now edit <samp>billboard.calendarDayData</samp> or patch <samp>billboard.GetEventsForDay</samp> to add new events.
+
    {
* Added <samp>Game1.textShadowDarkerColor</samp> field for the colors previously hardcoded in <samp>Utility.drawTextWithShadow</samp>.
+
        return location.IsTileOccupiedBy(tileLocation, CollisionMask.Buildings | CollisionMask.Furniture | CollisionMask.Objects | CollisionMask.Characters | CollisionMask.TerrainFeatures, ignorePassables: CollisionMask.Flooring);
* Added <samp>MoneyDial.ShouldShakeMainMoneyBox</samp> field to simplify custom dials.
+
    }
* Partly de-hardcoded <samp>ShopMenu</samp> filter tabs. You can now change filter tabs by setting the <samp>shopMenu.tabButtons</samp> field with arbitrary <samp>Func&lt;ISalable, bool&gt; Filter</samp> values, or by using a predefined set of tabs like <samp>shopMenu.UseDresserTabs()</samp>.
  −
* The <samp>SpriteText</samp> methods now accept arbitrary <samp>Color</samp> tints instead of a few predefined color IDs.
  −
* The <samp>DiscreteColorPicker.getColorFromSelection</samp> methods are now static for reuse.
  −
* Fixed <samp>DiscreteColorPicker</samp> constructor ignoring the initial color argument, and added a constructor which takes a <samp>Color</samp> value.
  −
* Fixed an edge case where a custom language's fonts wouldn't be loaded when switching language.
     −
====[[Modding:Modder Guide/Game Fundamentals#Net fields|Net fields]]====
+
    public static bool isTileLocationOpenIgnoreFrontLayers(this GameLocation location, Location tile)
* Removed implicit conversion operators for most types due to their sometimes counter-intuitive behavior. The only ones left are <samp>NetBool</samp>, <samp>NetInt</samp>, and <samp>NetString</samp>; those are now marked obsolete and will raise build warnings on use.
+
    {
* <samp>NetLocationRef</samp> now has a public <samp>LocationName</samp> and <samp>IsStructure</samp>, and its <samp>Update</samp> method allows forcing an update.
+
        return location.map.RequireLayer("Buildings").Tiles[tile.X, tile.Y] == null && !location.isWaterTile(tile.X, tile.Y);
 +
    }
   −
====Quests====
+
    public static bool isTileLocationTotallyClearAndPlaceable(this GameLocation location, int x, int y)
* Quests now have string IDs, to simplify custom quest frameworks.
+
    {
* Added validation for quest data parsing.
+
        return location.isTileLocationTotallyClearAndPlaceable(new Vector2(x, y));
* In [[Modding:Special orders|<samp>Data/SpecialOrders</samp>]], the <samp>Duration</samp> and <samp>Repeatable</samp> fields are now strongly-typed and case-insensitive.
+
    }
* For C# mods, fixed <samp>DescriptionElement</samp> not allowing more than four translation token substitutions.
     −
====Dates & seasons====
+
    public static bool isTileLocationTotallyClearAndPlaceableIgnoreFloors(this GameLocation location, Vector2 v)
* Added a <samp>Season</samp> enum for strongly-typed, case-insensitive season checks (like <code>Game1.season == Season.Spring</code> instead of <code>Game1.currentSeason == "spring"</code>).
+
    {
* Added <samp>Game1.season</samp>, <samp>Game1.GetSeasonForLocation</samp>, <samp>Game1.WorldDate.Season</samp>, and <samp>location.GetSeason()</samp> to get the season enum.
+
        return location.isTileOnMap(v) && !location.isTileOccupiedIgnoreFloors(v) && location.isTilePassable(new Location((int)v.X, (int)v.Y), Game1.viewport) && location.isTilePlaceable(v);
* Added <samp>Utility.getSeasonKey</samp> to get the key form from a season enum.
+
    }
* Improved <samp>WorldDate</samp>:
  −
** added <samp>Now()</samp> to get a new instance matching the current date;
  −
** added <samp>WorldDate.Equals</samp> and <samp>GetHashCode</samp> implementations;
  −
** added code docs;
  −
** <samp>TotalDays</samp> is no longer written to the save file.
  −
* Renamed some members for clarity (<samp>Game1.GetSeasonForLocation</samp> → <samp>GetSeasonKeyForLocation</samp>, <samp>location.GetSeasonForLocation</samp> → <samp>GetSeasonKey</samp>, <samp>WorldDate.Season</samp> → <samp>SeasonKey</samp>).
  −
* Fixed <samp>location.GetSeasonKey()</samp> not applying the greenhouse logic.
     −
====Time====
+
    public static bool isTileLocationTotallyClearAndPlaceable(this GameLocation location, Vector2 v)
* 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.
+
    {
 +
        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;
 +
        }
   −
====Other====
+
        return location.isTileOnMap(v) && !location.isTileOccupied(v) && location.isTilePassable(new Location((int)v.X, (int)v.Y), Game1.viewport) && location.isTilePlaceable(v);
* Error stack traces on Linux/macOS now have line numbers.
+
    }
* All space-delimited fields now ignore extra spaces instead of crashing. This affects map/tile properties, data assets, event commands, game state queries, etc.
+
}
* All players and NPCs now have <samp>Tile</samp> & <samp>TilePoint</samp> properties (their cached tile position) and a <samp>StandingPixel</samp> property (the cached pixel coordinate at the center of their bounding box). These [[#Other breaking API changes|replace various deleted methods]].
+
</syntaxhighlight>
* All terrain features now have <samp>Tile</samp> and <samp>Location</samp> properties, and their methods no longer have location/tile parameters in most cases.
+
}}
* All [[Modding:Modder Guide/Game Fundamentals#Net fields|net fields]] now have <samp>Name</samp> and <samp>Owner</samp> fields, which are used to show informative error messages when there's a sync issue and validate common mistakes (e.g. a net field not added to the <samp>NetFields</samp> collection).
  −
* The game now tracks the locations a player has visited. Mods can check the list in C# (via <samp>Game1.player.locationsVisited</samp>) or [[Modding:Game state queries|game state queries]] (via <samp>PLAYER_VISITED_LOCATION</samp>). For pre-existing saves, the list is retroactively populated based on accessible locations, events seen, mail flags set, etc.
  −
* Added menu queuing (via <samp>Game1.nextClickableMenu</samp> in C#). For example, this applies if you try to take an item from a mail letter when your inventory is full.
  −
* Added C# code docs in many places.
  −
* Added <samp>Id</samp> fields to simplify content pack edits in fish pond, movie concession, random bundle, and tailoring recipe data.
  −
* Added <samp>Game1.Multiplayer</samp> to get the game's low-level handler. (Most code should still use [[Modding:Modder Guide/APIs/Multiplayer|SMAPI's multiplayer API]] though.)
  −
* Added <samp>Game1.versionBuildNumber</samp> with the build number (like <samp>26039</samp>).
  −
* Added field-changed events to <samp>NetPosition</samp>.
  −
* Added <samp>LocalizedContentManager.CurrentLanguageString</samp>, which caches the language code like <samp>pt-BR</samp>).
  −
* The game now uses <samp>[XmlInclude]</samp> on its types more consistently. That means the default save serializer can handle more types (e.g. all monsters), and it's easier to create custom serializers.
  −
* Refactored many parts of the code to make it more moddable for C# mods. This includes marking all classes public, changing <samp>private</samp> members to <samp>protected</samp> or <samp>public</samp>, marking members <samp>virtual</samp>, rewriting or splitting code so it's easier to extend, etc.
  −
* The <samp>startup_preferences</samp> file is now formatted to simplify troubleshooting.
  −
* Fixed many cases where the game used <samp>Game1.player</samp> instead of the provided player.
  −
 
  −
==Breaking changes for C# mods==
  −
'''This section only describes how this update may break existing mods. See the ''what's new'' sections above for more info, including new functionality mods can use.'''
  −
 
  −
See also [[#Breaking changes for content packs|''Breaking changes for content packs'']], which affect C# mods too.
  −
 
  −
===.NET 6===
  −
: ''See also: [[#.NET 6|.NET 6]] under what's new.''
  −
 
  −
Stardew Valley 1.6 updates from .NET 5 to .NET 6. SMAPI can still load .NET 5 mods fine, but you'll get a build error when compiling them. To update a C# mod:
  −
<ol>
  −
<li>Make sure you have [https://visualstudio.microsoft.com/vs Visual Studio Community 2022] or later. (Compiling .NET 6 with earlier versions of Visual Studio isn't officially supported.)</li>
  −
<li>In Visual Studio, click ''Help > Check For Updates'' and install the latest version.</li>
  −
<li>Fully exit Visual Studio.</li>
  −
<li>Open each mod's <samp>.csproj</samp> file in a text editor, then find this line:
  −
<syntaxhighlight lang="xml">
  −
<TargetFramework>net5.0</TargetFramework>
  −
</syntaxhighlight>
  −
 
  −
And change it to this:
  −
<syntaxhighlight lang="xml">
  −
<TargetFramework>net6.0</TargetFramework>
  −
</syntaxhighlight>
  −
</li>
  −
<li>Delete your solution's hidden <samp>.vs</samp> folder, and every project's <samp>bin</samp> and <samp>obj</samp> folders.</li>
  −
<li>Reopen the solution in Visual Studio, click ''Build > Rebuild Solution'', and make sure it still loads into the game fine.</li>
  −
</ol>
  −
 
  −
===Item ID changes===
  −
: ''See also: [[#Custom items|custom items in what's new]].''
  −
 
  −
The [[#Custom items|main <samp>Item</samp> properties have changed]]. To migrate existing code:
  −
<ul>
  −
<li>Don't use <samp>ParentSheetIndex</samp> to compare items. For example, <samp>item.ParentSheetIndex == 0</samp> will match both [[weeds]] and any custom item whose sprite is the first one in its custom spritesheet. You should compare items using [[#Custom items|their new <samp>ItemId</samp> and <samp>QualifiedItemId</samp> properties]] instead. For example, here's how to migrate various common forms:
  −
 
  −
{| class="wikitable"
   
|-
 
|-
! old code
+
| <samp>GiantCrop</samp>
! new code
+
| <samp>which</samp>
 +
| Replaced by <samp>itemId</samp>.
 
|-
 
|-
 +
| <samp>Item</samp>
 +
| <samp>SanitizeContextTag</samp>
 +
| Replaced by <samp>ItemContextTagManager.SanitizeContextTag</samp>.
 
|-
 
|-
| <samp>item.ParentSheetIndex == 848</samp>
+
| <samp>LocalizedContentManager</samp>
| <samp>item.QualifiedItemId == "(O)848"</samp>
+
| <samp>LanguageCodeString</samp>
 +
| Now static.
 
|-
 
|-
| <samp>IsNormalObjectAtParentSheetIndex(item, 74)</samp>
+
| <samp>LocationContextData</samp>
| <samp>item.QualifiedItemId == "(O)74"</samp>
+
| <samp>Name</samp>
 +
| Removed; use its dictionary key in <samp>Game1.locationContextData</samp> instead.
 
|-
 
|-
| <samp>!item.bigCraftable && item.ParentSheetIndex == 128</samp>
+
| <samp>NetFields</samp>
| <samp>item.QualifiedItemId == "(O)128"</samp>
+
| <samp>AddFields</samp>
|-
+
| Removed; use <samp>AddField</samp> instead. For example:
| <samp>item is Boots && item.ParentSheetIndex == 505</samp>
+
<syntaxhighlight lang="c#">
| <samp>item.QualifiedItemId == "(B)505"</samp>
+
// old code
|}</li>
+
NetFields.AddFields(textureName, spriteWidth, spriteHeight);
<li>Don't assume item sprites are in the vanilla spritesheets. For example, instead of rendering <samp>Game1.objectSpriteSheet</samp> for an object, call <code>ItemRegistry.GetMetadata(item.QualifiedItemId).GetTexture()</code> to get its texture.</li>
  −
<li>Creating items works just like before, except that you now specify the item's <samp>ItemId</samp> (''not'' <samp>QualifiedItemId</samp>) instead of its <samp>ParentSheetIndex</samp>. This is the same value for vanilla items. For example:
     −
<syntaxhighlight lang="c#">
+
// new code
new Object("634", 1);                      // vanilla item
+
NetFields
new Object("Example.ModId_Watermelon", 1); // custom item
+
    .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.
You can also use the new <samp>ItemRegistry</samp> API to construct items from their <samp>QualifiedItemId</samp>:
+
|-
 
+
|rowspan="7"| <samp>NPC</samp>
<syntaxhighlight lang="c#">
+
| <samp>canReceiveThisItemAsGift()</samp>
Item item = ItemRegistry.Create("(B)505"); // Rubber Boots
+
| 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>.
</syntaxhighlight></li>
+
|-
</ul>
+
| <samp>Gender</samp><br /><samp>female</samp><br /><samp>male</samp><br /><samp>undefined</samp>
 
+
| The <samp>Gender</samp> field now uses a <samp>Gender</samp> enum instead of numeric constants. For example, <code>npc.Gender == NPC.female</code> becomes <code>npc.Gender == Gender.Female</code> in 1.6.
===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:
+
| <samp>homeRegion</samp>
 
+
| Removed; use <samp>npc.GetData()?.HomeRegion</samp> instead. Change <samp>0</samp> to <samp>"Other"</samp> or <samp>NPC.region_other</samp>, <samp>1</samp> to <samp>"Desert"</samp> or <samp>NPC.region_desert</samp>, and <samp>2</samp> to <samp>"Town"</samp> or <samp>NPC.region_town</samp>.
* 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.
+
| <samp>isBirthday</samp>
* For pre-existing content pack data, see migration steps in the ''[[#Unique string IDs|unique string IDs]]'' section.
+
| Remove the arguments, like <code>npc.isBirthday(Game1.currentSeason, Game1.dayOfMonth)</code> → <code>npc.isBirthday()</code>.
 
  −
===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>isVillager()</samp>
! how to migrate
+
| Deprecated; use the <samp>character.IsVillager</samp> property instead.
 
|-
 
|-
| <samp>appliedBuffs</samp><br /><samp>appliedSpecialBuffs</samp>
+
| <samp>populateRoutesFromLocationToLocationList</samp>
| Use <code>Game1.player.hasBuff(id)</code> instead.
+
| Replaced by <samp>WarpPathfindingCache.PopulateCache</samp>.
 
|-
 
|-
| <samp>attack</samp><br /><samp>immunity</samp>
+
| <samp>Schedule</samp>
| Use <samp>Attack</samp> and <samp>Immunity</samp> instead.
+
| No longer assignable, use one of the <samp>TryLoadSchedule</samp> overloads instead.
 
|-
 
|-
| <samp>addedCombatLevel</samp><br /><samp>addedFarmingLevel</samp><br /><samp>addedFishingLevel</samp><br /><samp>addedForagingLevel</samp><br /><samp>addedLuckLevel</samp><br /><samp>addedMiningLevel</samp><br /><samp>attackIncreaseModifier</samp><br /><samp>critChanceModifier</samp><br /><samp>critPowerModifier</samp><br /><samp>knockbackModifier</samp><br /><samp>weaponPrecisionModifier</samp><br /><samp>weaponSpeedModifier</samp>
+
|rowspan="3"| <samp>Object</samp>
| Use equivalent properties under <samp>Game1.player.buffs</samp> instead (e.g. <samp>Game1.player.buffs.CombatLevel</code>).
+
| <samp>GetContextTagList()</samp>
 +
| Replaced by <samp>GetContextTags()</samp>, which returns a hash set instead of a list.
 
|-
 
|-
| <samp>resilience</samp>
+
| <samp>HasBeenPickedUpByPlayer</samp>
| Use <samp>buffs.Defense</samp> instead.
+
| Removed; use <samp>HasBeenInInventory</samp> instead.
 
|-
 
|-
| <samp>addedSpeed</samp><br /><samp>CombatLevel</samp><br /><samp>CraftingTime</samp><br /><samp>FarmingLevel</samp><br /><samp>FishingLevel</samp><br /><samp>ForagingLevel</samp><br /><samp>LuckLevel</samp><br /><samp>MagneticRadius</samp><br /><samp>MaxStamina</samp><br /><samp>MiningLevel</samp><br /><samp>Stamina</samp>
+
| <samp>isPotentialBasicShippedCategory</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.
+
| 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>).
|}</li>
  −
<li>Buffs are now recalculated automatically, and you can reset a buff by just reapplying it. See [[#Buff overhaul|buff overhaul]] for more info.</li>
  −
<li>Buff logic has been centralized into <samp>Game1.player.buffs</samp>. This replaces a number of former fields/methods like <samp>Game1.buffsDisplay</samp>.</li>
  −
</ul>
  −
 
  −
===Collision changes===
  −
The game's tile collision logic has been overhauled and merged into a simpler set of methods on <samp>GameLocation</samp> instances:
  −
 
  −
{| class="wikitable"
   
|-
 
|-
! method
+
|rowspan="9"| <samp>Utility</samp>
! effect
+
| <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>CanSpawnCharacterHere</samp>
+
| <samp>ForAllLocations</samp><br /><samp>iterateAllCrops</samp><br /><samp>iterateAllItems</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.
+
| Removed; use the equivalent <samp>Utility.ForEach*</samp> methods instead.
 
|-
 
|-
| <samp>CanItemBePlacedHere</samp>
+
| <samp>GetHorseWarpRestrictionsForFarmer</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.
+
| This now returns a flag enum instead of a list of integer values. The equivalent values are 1 → <samp>NoOwnedHorse</samp>, 2 → <samp>Indoors</samp>, 3 → <samp>NoRoom</samp>, and 4 → <samp>InUse</samp>.
 +
 
 +
For example:
 +
<syntaxhighlight lang="c#">
 +
// old code
 +
bool inUse = Utility.GetHorseWarpRestrictionsForFarmer(player).Any(p => p == 4);
 +
 
 +
// new code
 +
bool inUse = Utility.GetHorseWarpRestrictionsForFarmer(player).HasFlag(Utility.HorseWarpRestrictions.InUse);
 +
</syntaxhighlight>
 +
 
 +
Or to check if no restrictions apply:
 +
<syntaxhighlight lang="c#">
 +
bool canSummon = Utility.GetHorseWarpRestrictionsForFarmer(player) == Utility.HorseWarpRestrictions.None;
 +
</syntaxhighlight>
 +
 
 +
C# mods can patch <samp>Utility.GetHorseWarpErrorMessage</samp> if they need to add an error message for a custom restriction value.
 
|-
 
|-
| <samp>isBuildable</samp>
+
| <samp>getRandomTownNPC(…)</samp>
| Get whether buildings can be placed on the given tile.
+
| Replaced by either <code>Utility.GetRandomWinterStartParticipant(…)</code> or <code>Utility.getRandomNpcFromHomeRegion(NPC.region_town)</code>.
 
|-
 
|-
| <samp>IsTilePassable</samp>
+
| <samp>getTodaysBirthdayNPC</samp>
| Get whether the tile can be walked on (ignoring collisions with in-game objects, NPCs, etc).
+
| Remove the arguments, like <code>Utility.getTodaysBirthdayNPC(Game1.currentSeason, Game1.dayOfMonth)</code> → <code>Utility.getTodaysBirthdayNPC()</code>.
 
|-
 
|-
| <samp>IsTileOccupiedBy</samp>
+
| <samp>getPooledList</samp><br /><samp>returnPooledList</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 game no longer uses a list pool. In most cases you should use the [[#Iteration|<samp>Utility.ForEach*</samp> methods]] instead, which don't need it.
 
|-
 
|-
| <samp>IsTileBlockedBy</samp>
+
| <samp>numObelisksOnFarm</samp>
| Equivalent to calling both <samp>IsTilePassable</samp> and <samp>IsTileOccupiedBy</samp>.
+
| Renamed to <samp>GetObeliskTypesBuilt</samp>, which searches all locations.
 
|-
 
|-
| <samp>IsLocationSpecificOccupantOnTile</samp><br /><samp>IsLocationSpecificPlacementRestriction</samp>
+
| <samp>numSilos</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]]).
+
| Removed.
|}
     −
===Other breaking API changes===
+
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.
''(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====
+
If you actually need the number of silos, use <samp>location.getNumberBuildingsConstructed("Silo")</samp> (one location) or <samp>Game1.GetNumberBuildingsConstructed("Silo")</samp> (all locations).
1.6 removes a lot of unused code. That includes these classes:
+
|-
{| class="wikitable"
+
| <samp>removeThisCharacterFromAllLocations</samp>
 +
| Removed; use <samp>Game1.removeCharacterFromItsLocation</samp> instead.
 
|-
 
|-
! namespace
+
| <samp>ShopMenu</samp>
! class name
+
| <samp>storeContext</samp>
 +
| Replaced by <samp>ShopId</samp>.
 
|-
 
|-
| <samp>StardewValley</samp>
+
|rowspan="3"| <samp>Stats</samp>
| &#32;
+
| <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>
* <samp>BuildingUpgrade</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>DisposableList</samp>
  −
* <samp>FurniturePlacer</samp>
  −
* <samp>ListPool</samp>
  −
* <samp>OneTimeRandom</samp>
   
|-
 
|-
| <samp>StardewValley.Characters</samp>
+
| <samp>getStat(…)</samp><br /><samp>incrementStat(…)</samp>
| &#32;
+
| Replaced by <samp>Get(…)</samp> and <samp>Increment(…)</samp>. See [[#Stat changes for C# mods|stat changes for C# mods]].
* <samp>BotchedNetBool</samp>
  −
* <samp>BotchedNetField</samp>
  −
* <samp>BotchedNetInt</samp>
  −
* <samp>BotchedNetLong</samp>
   
|-
 
|-
| <samp>StardewValley.Menus</samp>
+
| <samp>stat_dictionary</samp>
| &#32;
+
| Renamed to <samp>Values</samp>. See [[#Stat changes for C# mods|stat changes for C# mods]].
* <samp>FarmInfoPage</samp>
  −
* <samp>MiniatureTerrainFeature</samp><!-- not a typo, it really was in StardewValley.Menus -->
   
|-
 
|-
| <samp>StardewValley.Monsters</samp>
+
| <samp>Woods</samp>
| &#32;
+
| <samp>stumps</samp>
* <samp>LavaCrab</samp>
+
| Moved into <samp>resourceClumps</samp>.
|-
  −
| <samp>StardewValley.Objects</samp>
  −
| &#32;
  −
* <samp>ObjectFactory</samp> (replaced by [[#Custom items|<samp>ItemRegistry</samp>]])
  −
|-
  −
| <samp>StardewValley.TerrainFeatures</samp>
  −
| &#32;
  −
* <samp>Quartz</samp>
  −
|-
  −
| <samp>StardewValley.Tools</samp>
  −
| &#32;
  −
* <samp>Blueprints</samp>
  −
* <samp>ToolFactory</samp> (replaced by [[#Custom items|<samp>ItemRegistry</samp>]])
   
|}
 
|}
   −
And these class members:
+
===Check for obsolete code===
 +
Perform a full rebuild of your mod (in Visual Studio, click ''Build > Rebuild Solution''), then check the Error List pane for any warnings like "'''X' is obsolete''". Anything from the vanilla game code which is marked obsolete won't work anymore and is only kept for save migrations. Usually the warning will include an explanation of what you should use instead.
 +
 
 +
==Breaking changes for content packs==
 +
'''This section only describes how this update may break existing mods. See the ''what's new'' sections above for more info, including new functionality mods can use.'''
 +
 
 +
===Standardized ID fields===
 +
Stardew Valley 1.6 adds an <samp>Id</samp> field to these assets. For Content Patcher content packs, these replace the previous synthetic ID:
 +
 
 
{| class="wikitable"
 
{| class="wikitable"
 
|-
 
|-
! type
+
! asset
! members
+
! old key
 +
! new key
 +
! migration steps
 
|-
 
|-
| <samp>Axe</samp>
+
| <samp>Data/ConcessionTastes</samp><br /><samp>Data/MovieReactions</samp><br /><samp>Data/RandomBundles</samp> (area)<br /><samp>Data/RandomBundles</samp> (bundle)
| &#32;
+
| <samp>Name</samp><br /><samp>NPCName</samp><br /><samp>AreaName</samp><br />''none''
* <samp>StumpStrength</samp>
+
|<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>Bush</samp>
+
| <samp>Data/FishPondData</samp><br /><samp>Data/RandomBundles</samp> (bundle set)
| &#32;
+
| <samp>RequiredTags</samp><br />''none''
* <samp>alpha</samp>
+
| <samp>Id</samp>
* <samp>lastPlayerToHit</samp>
+
| Use the new <samp>Id</samp> field to target an entry, and add it when creating a new entry. Required.
 
|-
 
|-
| <samp>Chest</samp>
+
| <samp>Data/TailoringRecipes</samp>
| &#32;
+
| <samp>FirstItemTags</samp> and <samp>SecondItemTags</samp>
* <samp>chestType</samp>
+
| <samp>Id</samp>
* <samp>coins</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.
|-
+
|}
| <samp>CosmeticPlant</samp>
+
 
| &#32;
+
For example, let's say you have a patch like this using Content Patcher:
* <samp>scale</samp>
+
{{#tag:syntaxhighlight|<nowiki>
|-
+
{
| <samp>CraftingRecipe</samp>
+
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
| &#32;
+
    "Changes": [
* <samp>itemType</samp>
+
        {
|-
+
            "Action": "EditData",
| <samp>Critter</samp>
+
            "Target": "Data/TailorRecipes",
| &#32;
+
            "Entries": {
* <samp>InitShared()</samp>
+
                "item_cloth|item_pufferchick": {
|-
+
                    "FirstItemTags": [ "item_cloth" ],
| <samp>Crop</samp>
+
                    "SecondItemTags": [ "item_pufferchick" ],
| &#32;
+
                    "CraftedItemId": "(S)1260"
* <samp>daysOfUnclutteredGrowth</samp>
+
                }
|-
+
            }
| <samp>Dialogue</samp>
+
        }
| &#32;
+
    ]
* <samp>dialogueToBeKilled</samp>
+
}</nowiki>|lang=javascript}}
|-
+
 
| <samp>Farm</samp>
+
When updating to Stardew Valley 1.6, replace the synthetic ID (<samp>item_cloth|item_pufferchick</samp>) with a real one:
| &#32;
+
* To edit an existing entry, unpack the asset and get its new <samp>Id</samp> value.
* <samp>GetSpouseOutdoorAreaSpritesheetIndex()</samp>
+
* To add a custom entry, use a [[Modding:Common data field types#Unique string ID|unique string ID]].
 +
 
 +
For example:
 +
{{#tag:syntaxhighlight|<nowiki>
 +
{
 +
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
 +
    "Changes": [
 +
        {
 +
            "Action": "EditData",
 +
            "Target": "Data/TailorRecipes",
 +
            "Entries": {
 +
                "ExampleAuthor.ModId_RainCoatFromPufferchick": {
 +
                    "Id": "ExampleAuthor.ModId_RainCoatFromPufferchick", // need to specify ID again when creating it
 +
                    "FirstItemTags": [ "item_cloth" ],
 +
                    "SecondItemTags": [ "item_pufferchick" ],
 +
                    "CraftedItemId": "(S)1260"
 +
                }
 +
            }
 +
        }
 +
    ]
 +
}</nowiki>|lang=javascript}}
 +
 
 +
===Event ID changes===
 +
{{/doc status|[[Modding:Event data]]|done=false}}
 +
 
 +
: ''See also: [[#String event IDs|string event IDs in what's new]].''
 +
 
 +
Events now have unique string IDs.
 +
 
 +
When creating an event:
 +
<ul>
 +
<li>New events should use a globally unique ID in the form <samp>Your.ModId_EventName</samp>. Existing events should be fine as-is, but it may be worth migrating them to avoid future conflicts.</li>
 +
<li>Every non-fork event '''must''' have a precondition in its key (even if it's empty). For example, change <code>"Your.ModId_EventName": "..."</code> to <code>"Your.ModId_EventName/": "..."</code>. This is needed for the game to distinguish between events and fork scripts.
 +
 
 +
<syntaxhighlight lang="js">
 +
"Example.ModId_EventName/": "...", // event: loaded automatically by the game
 +
"SomeFork": "..."                  // event fork: ignored unless it's loaded through an event script
 +
</syntaxhighlight></li>
 +
</ul>
 +
 
 +
===Monster eradication goal flag changes===
 +
{{/doc status|a new doc page|done=false}}
 +
 
 +
: ''See also: [[#Custom monster eradication goals|Custom monster eradication goals]].''
 +
 
 +
The game now tracks [[Adventurer's Guild]] monster eradication goal completion by the goal ID, instead of the produced item. You'll need to replace these mail flags if you check them:
 +
 
 +
{| class="wikitable"
 +
|-
 +
! old flag
 +
! new flag
 
|-
 
|-
| <samp>FarmAnimal</samp>
+
| <samp>Gil_Slime Charmer Ring</samp>
| &#32;
+
| <samp>Gil_Slimes</samp>
* <samp>homeLocation</samp>
   
|-
 
|-
| <samp>Farmer</samp>
+
| <samp>Gil_Savage Ring</samp>
| &#32;
+
| <samp>Gil_Shadows</samp>
* <samp>barnUpgradeLevel</samp> and <samp>BarnUpgradeLevel</samp>
+
|-
* <samp>blueprints</samp>
+
| <samp>Gil_Vampire Ring</samp>
* <samp>coalPieces</samp> and <samp>CoalPieces</samp>
+
| <samp>Gil_Bats</samp>
* <samp>coopUpgradeLevel</samp> and <samp>CoopUpgradeLevel</samp>
+
|-
* <samp>copperPieces</samp> and <samp>CopperPieces</samp>
+
| <samp>Gil_Skeleton Mask</samp>
* <samp>eyeColor</samp>
+
| <samp>Gil_Skeletons</samp>
* <samp>feed</samp> and <samp>Feed</samp>
+
|-
* <samp>furnitureOwned</samp>
+
| <samp>Gil_Insect Head</samp>
* <samp>goldPieces</samp> and <samp>GoldPieces</samp>
+
| <samp>Gil_Insects</samp>
* <samp>hasBusTicket</samp>
+
|-
* <samp>hasGreenhouse</samp>
+
| <samp>Gil_Hard Hat</samp>
* <samp>iridiumPieces</samp> and <samp>IridiumPieces</samp>
+
| <samp>Gil_Duggy</samp>
* <samp>ironPieces</samp> and <samp>IronPieces</samp>
+
|-
* <samp>newSkillPointsToSpend</samp>
+
| <samp>Gil_Burglar's Ring</samp>
* <samp>overallsColor</samp>
+
| <samp>Gil_DustSpirits</samp>
* <samp>ownsFurniture</samp>
+
|-
* <samp>quartzPieces</samp> and <samp>QuartzPieces</samp>
+
| <samp>Gil_Crabshell Ring</samp>
* <samp>shirtColor</samp>
+
| <samp>Gil_Crabs</samp>
* <samp>skinColor</samp>
  −
* <samp>stonePieces</samp> and <samp>StonePieces</samp>
  −
* <samp>theaterBuildDate</samp>
  −
* <samp>woodPieces</samp> and <samp>WoodPieces</samp>
   
|-
 
|-
| <samp>Game1</samp>
+
| <samp>Gil_Arcane Hat</samp>
| &#32;
+
| <samp>Gil_Mummies</samp>
* <samp>boardingBus</samp>
  −
* <samp>chanceToRainTomorrow</samp>
  −
* <samp>checkForNewLevelPerks</samp>
  −
* <samp>cloud</samp>
  −
* <samp>coopDwellerBorn<samp>
  −
* <samp>cropsOfTheWeek</samp>
  −
* <samp>currentBarnTexture</samp>
  −
* <samp>currentBillboard</samp>
  −
* <samp>currentCoopTexture</samp>
  −
* <samp>currentFloor</samp>
  −
* <samp>currentHouseTexture</samp>
  −
* <samp>currentWallpaper</samp>
  −
* <samp>dealerCalicoJackTotal</samp>
  −
* <samp>FarmerFloor</samp>
  −
* <samp>farmerWallpaper</samp>
  −
* <samp>fertilizer</samp>
  −
* <samp>floorPrice</samp>
  −
* <samp>greenhouseTexture</samp>
  −
* <samp>inMine<samp>
  −
* <samp>jukeboxPlaying</samp>
  −
* <samp>keyHelpString</samp>
  −
* <samp>listeningForKeyControlDefinitions<samp>
  −
* <samp>littleEffect</samp>
  −
* <samp>logoScreenTexture</samp>
  −
* <samp>mailboxTexture</samp>
  −
* <samp>menuChoice</samp>
  −
* <samp>menuUp<samp>
  −
* <samp>nameSelectUp<samp>
  −
* <samp>nameSelectType</samp>
  −
* <samp>numberOfSelectedItems</samp>
  −
* <samp>particleRaining<samp>
  −
* <samp>pickingTool</samp>
  −
* <samp>pickToolDelay</samp>
  −
* <samp>pickToolInterval</samp>
  −
* <samp>priceOfSelectedItem</samp>
  −
* <samp>progressBar</samp>
  −
* <samp>removeSquareDebrisFromTile(…)</samp>
  −
* <samp>selectedItemsType</samp>
  −
* <samp>shiny</samp>
  −
* <samp>shippingTax</samp>
  −
* <samp>showKeyHelp<samp>
  −
* <samp>slotResult</samp>
  −
* <samp>startedJukeboxMusic</samp>
  −
* <samp>tinyFontBorder</samp>
  −
* <samp>toolHeld</samp>
  −
* <samp>toolIconBox</samp>
  −
* <samp>tvStation</samp>
  −
* <samp>tvStationTexture</samp>
  −
* <samp>wallpaperPrice</samp>
   
|-
 
|-
| <samp>GameLocation</samp>
+
| <samp>Gil_Knight's Helmet</samp>
| &#32;
+
| <samp>Gil_Dinos</samp>
* <samp>boardBus(…)</samp>
  −
* <samp>checkForMapChanges()</samp>
  −
* <samp>getWallDecorItem(…)</samp>
  −
* <samp>removeBatch(…)</samp>
  −
* <samp>removeDirt(…)</samp>
  −
* <samp>removeStumpOrBoulder(…)</samp>
  −
* <samp>tryToBuyNewBackpack()</samp>
   
|-
 
|-
| <samp>GiantCrop</samp>
+
| <samp>Gil_Napalm Ring</samp>
| &#32;
+
| <samp>Gil_Serpents</samp>
* <samp>forSale</samp>
   
|-
 
|-
| <samp>IClickableMenu</samp>
+
| <samp>Gil_Telephone</samp>
| &#32;
+
| <samp>Gil_FlameSpirits</samp>
* <samp>currentRegion</samp>
+
|}
|-
+
 
| <samp>MeleeWeapon</samp>
+
===XNB impact===
| &#32;
+
====Overview====
* <samp>attackSwordCooldownTime</samp>
+
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.
* <samp>doStabbingSwordFunction()</samp>
+
 
 +
[[Modding:Using XNB mods|XNB mods]] are disproportionately affected, since...
 +
# they replace the entire file;
 +
# they're loaded through the MonoGame content pipeline which is less tolerant of format changes;
 +
# they don't benefit from the compatibility rewrites [[Modding:Content Patcher|Content Patcher]] provides for its content packs.
 +
 
 +
Content Patcher packs are typically unaffected (and Content Patcher will try to rewrite content packs automatically). However if a content pack replaces an entire asset instead of editing, it's more likely to be affected like an XNB mod.
 +
 
 +
====Changed assets====
 +
Compatibility is broadly grouped into four categories:
 +
* "'''✘ broken'''": mods will remove new content or significant changes, or the mod's intended changes will no longer work. Effects may range from display bugs to crashes, depending how the game uses that specific content.
 +
* "✘ will remove changes": mods will remove minor changes in 1.6 (e.g. typo fixes).
 +
* "✓ mostly unaffected": mods will only be affected if they replace the entire asset, or edit specific entries or fields.
 +
* Blank: no expected impact for the vast majority of mods.
 +
 
 +
{| class="wikitable"
 +
|-
 +
!rowspan="2"| content asset
 +
!rowspan="2"| changes in 1.6
 +
!colspan="2"| compatibility for pre-1.6 mods
 
|-
 
|-
| <samp>Monster</samp>
+
! XNB mods
| &#32;
+
! Content Patcher packs
* <samp>doHorizontalMovement(…)</samp>
  −
* <samp>durationOfRandomMovements</samp>
  −
* <samp>coinsToDrop</samp>
   
|-
 
|-
| <samp>NPC</samp>
+
| <samp>Buildings/houses</samp>
 
| &#32;
 
| &#32;
* <samp>idForClones</samp>
+
* fixed missing pixels
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>Object</samp>
+
| <samp>Characters/Dialogue/Abigail</samp><br /><samp>Characters/Dialogue/Alex</samp>
 
| &#32;
 
| &#32;
* <samp>attachToSprinklerAttachment(…)</samp>
+
* added [[#Dialogue changes|flower dance dialogue]]
* <samp>canBePlacedInWater()</samp>
+
* fixed typos
* <samp>consumeRecipe(…)</samp>
+
| '''✘ broken'''
* <samp>copperBar</samp>
+
| ✓ mostly unaffected
* <samp>goldBar</samp>
  −
* <samp>iridiumBar</samp>
  −
* <samp>ironBar</samp>
  −
* <samp>isHoeDirt</samp> and <samp>IsHoeDirt</samp>
   
|-
 
|-
| <samp>PathFindController</samp>
+
| <samp>Characters/Dialogue/Caroline</samp><br /><samp>Characters/Dialogue/Demetrius</samp>
 
| &#32;
 
| &#32;
* <samp>CheckClearance(…)</samp>
+
* fixed typos
* <samp>limit</samp>
+
| ✘ will remove changes
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>SaveGame</samp>
+
| <samp>Characters/Dialogue/Elliott</samp>
 +
| &#32;
 +
* added [[#Dialogue changes|flower dance dialogue]]
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 +
|-
 +
| <samp>Characters/Dialogue/Emily</samp>
 
| &#32;
 
| &#32;
* <samp>cropsOfTheWeek</samp>
+
* added [[#Dialogue changes|flower dance dialogue]]
* <samp>currentFloor</samp>
+
* fixed typos
* <samp>currentWallpaper</samp>
+
* updated <samp>%revealtaste</samp> format (backwards-compatible)
* <samp>FarmerFloor</samp>
+
| '''✘ broken'''
* <samp>farmerWallpaper</samp>
+
| ✓ mostly unaffected
* <samp>shippingTax</samp>
   
|-
 
|-
| <samp>Spiker</samp>
+
| <samp>Characters/Dialogue/George</samp>
 
| &#32;
 
| &#32;
* <samp>GetSpawnPosition</samp>
+
* added [[#Dialogue changes|Winter Star gift exchange dialogue]]
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>Stats</samp>
+
| <samp>Characters/Dialogue/Gus</samp>
 
| &#32;
 
| &#32;
* <samp>barsSmelted</samp> and <samp>BarsSmelted</samp>
+
* fixed typos
* <samp>coalFound</samp> and <samp>CoalFound</samp>
+
| ✘ will remove changes
* <samp>coinsFound</samp> and <samp>coinsFound</samp>
+
| ✓ mostly unaffected
* <samp>starLevelCropsShipped</samp> and <samp>starLevelCropsShipped</samp>
   
|-
 
|-
| <samp>Tool</samp>
+
| <samp>Characters/Dialogue/Haley</samp>
 
| &#32;
 
| &#32;
* <samp>batteredSwordSpriteIndex</samp>
+
* added [[#Dialogue changes|flower dance dialogue]]
* <samp>copperColor</samp>
+
* fixed typos
* <samp>GetSecondaryEnchantmentCount()</samp>
+
| '''✘ broken'''
* <samp>goldColor</samp>
+
| ✓ mostly unaffected
* <samp>iridiumColor</samp>
  −
* <samp>nonUpgradeable</samp>
  −
* <samp>parsnipSpriteIndex</samp>
  −
* <samp>Stackable</samp>
  −
* <samp>startOfNegativeWeaponIndex</samp>
  −
* <samp>steelColor</samp>
   
|-
 
|-
| <samp>Utility</samp>
+
| <samp>Characters/Dialogue/Harvey</samp>
 
| &#32;
 
| &#32;
* <samp>buyFloor()</samp>
+
* added [[#Dialogue changes|flower dance dialogue]]
* <samp>buyWallpaper()</samp>
+
| '''✘ broken'''
* <samp>cropsOfTheWeek()</samp>
+
| ✓ mostly unaffected
* <samp>facePlayerEndBehavior(…)</samp>
  −
* <samp>getRandomSlotCharacter()</samp>
  −
* <samp>plantCrops(…)</samp>
  −
* <samp>showLanternBar()</samp>
  −
|}
  −
 
  −
====Renamed classes====
  −
These classes were renamed in 1.6:
  −
{| class="wikitable"
   
|-
 
|-
! old name
+
| <samp>Characters/Dialogue/Jas</samp><br /><samp>Characters/Dialogue/Jodi</samp>
! new name
+
| &#32;
 +
* fixed typos
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>Game1.MusicContext</samp>
+
| <samp>Characters/Dialogue/Krobus</samp>
| <samp>MusicContext</samp> (in <samp>StardewValley.GameData</samp>)
+
| &#32;
 +
* added [[#Dialogue changes|roommate stardrop dialogue]]
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>LocationContext</samp>
+
| <samp>Characters/Dialogue/Leah</samp>
| <samp>LocationContexts</samp>
+
| &#32;
 +
* added [[#Dialogue changes|flower dance dialogue]]
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>SpecialOrder.QuestStatus</samp>
+
| <samp>Characters/Dialogue/Lewis</samp>
| <samp>SpecialOrderStatus</samp> (in <samp>StardewValley.SpecialOrders</samp>)
+
| &#32;
|}
+
* updated <samp>%revealtaste</samp> format (backwards-compatible)
 
+
|
And these were moved to a different namespace:
+
|
{| class="wikitable"
   
|-
 
|-
! type
+
| <samp>Characters/Dialogue/Linus</samp>
! old namespace
+
| &#32;
! new namespace
+
* added [[#Dialogue changes|dumpster dive dialogue]]
 +
* fixed typos
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
| <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>Characters/Dialogue/Marnie</samp>
| <samp>StardewValley</samp>
+
| &#32;
| <samp>StardewValley.Enchantments</samp>
+
* added [[#Dialogue changes|Stardew Valley Fair dialogue]]
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>Extensions</samp>
+
| <samp>Characters/Dialogue/MarriageDialogue</samp><br /><samp>Characters/Dialogue/MarriageDialogueAbigail</samp><br /><samp>Characters/Dialogue/MarriageDialogueElliott</samp>
| <samp>StardewValley</samp>
+
| &#32;
| <samp>StardewValley.Extensions</samp>
+
* fixed typos
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>ModDataDictionary</samp><br /><samp>ModHooks</samp>
+
| <samp>Characters/Dialogue/MarriageDialogueEmily</samp>
| <samp>StardewValley</samp>
+
| &#32;
| <samp>StardewValley.Mods</samp>
+
* changed <samp>spring_Maru</samp> key to <samp>spring_Emily</samp>
 +
* fixed typos
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>PathFindController</samp><br /><samp>PathNode</samp><br /><samp>PriorityQueue</samp><br /><samp>SchedulePathDescription</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>
| <samp>StardewValley</samp>
+
| &#32;
| <samp>StardewValley.Pathfinding</samp>
+
* fixed typos
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>SpecialOrder</samp>
+
| <samp>Characters/Dialogue/Maru</samp>
| <samp>StardewValley</samp>
+
| &#32;
| <samp>StardewValley.SpecialOrders</samp>
+
* added [[#Dialogue changes|flower dance dialogue]]
 +
* fixed typos
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
| <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>Characters/Dialogue/Penny</samp>
| <samp>StardewValley</samp>
+
| &#32;
| <samp>StardewValley.SpecialOrders.Objectives</samp>
+
* added [[#Dialogue changes|flower dance dialogue]]
 +
| '''✘ broken'''
 +
| ✓ 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>Characters/Dialogue/Pierre</samp>
| <samp>StardewValley</samp>
+
| &#32;
| <samp>StardewValley.SpecialOrders.Rewards</samp>
+
* added [[#Dialogue changes|Stardew Valley Fair dialogue]]
|}
+
* fixed typos
 
+
| '''✘ broken'''
====Other API changes====
+
| ✓ mostly unaffected
These class members changed in 1.6:
  −
 
  −
{| class="wikitable"
   
|-
 
|-
! type
+
| <samp>Characters/Dialogue/Robin</samp>
! member
+
| &#32;
! migration
+
* fixed typos
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>BigSlime</samp>
+
| <samp>Characters/Dialogue/Sam</samp>
| <samp>heldObject</samp>
+
| &#32;
| Replaced by <samp>heldItem</samp>, which allows non-object items too.
+
* added [[#Dialogue changes|flower dance dialogue]]
 +
* fixed typos
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
|rowspan="3"| <samp>Bush</samp>
+
| <samp>Characters/Dialogue/Sandy</samp>
| <samp>overrideSeason</samp>
+
| &#32;
| Removed; use <code>bush.Location.GetSeason()</code> instead.
+
* fixed typos
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>greenhouseBush</samp>
+
| <samp>Characters/Dialogue/Sebastian</samp>
| Removed; use <code>bush.IsSheltered()</code> or <code>bush.currentLocation.IsGreenhouse</code> instead.
+
| &#32;
 +
* added [[#Dialogue changes|flower dance dialogue]]
 +
* fixed typos
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>inBloom</samp>
+
| <samp>Characters/Dialogue/Willy</samp>
| Remove the arguments, like <code>bush.inBloom(Game1.currentSeason, Game1.dayOfMonth)</code> → <code>bush.inBloom()</code>.
+
| &#32;
 +
* added [[#Dialogue changes|Stardew Valley Fair dialogue]]
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
|rowspan="3"| <samp>Character</samp>
+
| <samp>Characters/Dialogue/Shane</samp>
| <samp>getStandingX</samp><br /><samp>getStandingY</samp><br /><samp>getStandingXY</samp>
+
| &#32;
| Removed; use <samp>character.StandingPixel</samp> instead.
+
* added [[#Dialogue changes|flower dance dialogue]]
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>getTileLocation</samp><br /><samp>getTileX</samp><br /><samp>getTileY</samp><br />
+
| <samp>Characters/Farmer/hats</samp>
| Removed; use <samp>character.Tile</samp> instead.
+
| &#32;
 +
* removed stray pixel on chicken mask
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>getTileLocationPoint</samp>
+
| <samp>Characters/schedules/Elliott</samp>
| Removed; use <samp>character.TilePoint</samp> instead.
+
| &#32;
 +
* fixed order of <samp>Fri_6</samp> and <samp>Fri</samp> entries
 +
| '''✘ broken'''
 +
|
 
|-
 
|-
| <samp>Chest</samp>
+
| <samp>Characters/schedules/Lewis</samp>
| <samp>MoveToSafePosition</samp>
+
| &#32;
| Replaced by the simpler <samp>TryMoveToSafePosition</samp>
+
* fixed <samp>winter_Sun</samp> schedule
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
|rowspan="2"| <samp>Dialogue</samp>
+
| <samp>Characters/schedules/Maru</samp>
| <samp>dialogues</samp>
+
| &#32;
| 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.
+
* fixed <samp>summer_Mon</samp> and <samp>summer_Sun</samp> schedules
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>isOnFinalDialogue()</samp>
+
| <samp>Characters/schedules/Penny</samp>
| This now indicates whether it's showing the last dialogue ''with message text''; there may still be entries in <samp>dialogues</samp> which apply side-effects without message text.
+
| &#32;
 +
* fixed <samp>summer_Sun</samp> schedule
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
|rowspan="3"| <samp>Farmer</samp>
+
| <samp>Characters/Schedules/Shane</samp>
| <samp>changePants(…)</samp>
+
| &#32;
| Renamed to <samp>changePantsColor(…)</samp> for consistency with <samp>change[Eye&#124;Hair&#124;Shoe]Color</samp>.
+
* fixed dialogue key
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>isMarried()</samp>
+
| <samp>Data/animationDescriptions</samp>
| Renamed to <samp>isMarriedOrRoommates()</samp> for clarity.
+
| &#32;
 +
* fixed frame in Lewis' Saloon drinking animation
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>visibleQuestCount</samp>
+
| <samp>Data/AquariumFish</samp>
| Replaced by <samp>hasVisibleQuests</samp>.
+
| &#32;
 +
* [[#Custom items|changed key type]]
 +
* added hat position for [[Sea Urchin]]
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>Flooring</samp>
+
| <samp>Data/BigCraftablesInformation</samp>
| <samp>GetFloorPathLookup</samp>
+
| &#32;
| Use <samp>Game1.floorPathData</samp> instead.
+
* 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>Forest</samp>
+
| <samp>Data/Blueprints</samp>
| <samp>log</samp>
+
| &#32;
| Moved into <samp>Forest.resourceClumps</samp>.
+
* asset replaced by [[#Custom buildings|<samp>Data/Buildings</samp>]]:
|-
+
** migrated to data model format
| <samp>FruitTree</samp>
+
** added new features
| <samp>GreenHouseTree</samp>
+
| '''✘ broken'''
| Replaced by <samp>IgnoresSeasonsHere()</samp>.
+
| ✓ mostly unaffected<br /><small>(covered by runtime migration)</small>
 
|-
 
|-
|rowspan="3"| <samp>Game1</samp>
+
| <samp>Data/Boots</samp>
| <samp>bigCraftableInformation</samp>
+
| &#32;
| Overhauled into [[#Custom big craftables|<samp>Game1.bigCraftableData</samp>]].
+
* [[#Custom items|changed key type]]
 +
* added display name
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected<br /><small>(covered by runtime migration)</small>
 
|-
 
|-
| <samp>clothingInformation</samp>
+
| <samp>Data/Bundles</samp>
| Overhauled into [[#Custom shirts|<samp>Game1.shirtData</samp>]] and [[#Custom pants|<samp>Game1.pantsData</samp>]].
+
| &#32;
 +
* can no longer omit empty fields before display name
 +
* added display name field in English
 +
* removed meat items in animal bundle
 +
| '''✘ broken'''
 +
| '''✘ likely broken'''
 
|-
 
|-
| <samp>objectInformation</samp>
+
| <samp>Data/ClothingInformation</samp>
| Overhauled into [[#Custom objects|<samp>Game1.objectData</samp>]].
+
| &#32;
 +
* asset replaced by [[#Custom pants|<samp>Data/Pants</samp>]] and [[#Custom shirts|<samp>Data/Shirts</samp>]]:
 +
** migrated to data model format
 +
** added new features
 +
| '''✘ broken'''
 +
| '''✘ likely broken'''
 
|-
 
|-
|rowspan="3"| <samp>GameLocation</samp>
+
| <samp>Data/Concessions</samp>
| <samp>getCharacters</samp>
+
| &#32;
| Removed; use the <samp>characters</samp> field instead.
+
* [[#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>GetMapPropertyPosition</samp>
+
| <samp>Data/ConcessionTastes</samp>
| Replaced by <samp>TryGetMapPropertyAs</samp>, which supports multiple data types (not just <samp>Point</samp>).
+
| &#32;
 +
* added automatic <samp>ID</samp> field
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>isTileOccupied</samp><br /><samp>isTileOccupiedForPlacement</samp><br /><samp>isTileOccupiedIgnoreFloors</samp><br /><samp>isTileLocationOpenIgnoreFrontLayers</samp><br /><samp>isTileLocationTotallyClearAndPlaceable</samp><br /><samp>isTileLocationTotallyClearAndPlaceableIgnoreFloors</samp>
+
| <samp>Data/CookingRecipes</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;
 
+
* replaced translations with [[Modding:Tokenizable strings|tokenizable strings]]
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.
+
* display names can now be omitted to use item name
{{collapse|expand for non-recommended code|content=<syntaxhighlight lang="c#">
+
| ✘ will remove changes
public static class GameLocationExtensions
+
| ✓ may remove unaffected
{
  −
    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>Data/CraftingRecipes</samp>
| <samp>which</samp>
+
| &#32;
| Replaced by <samp>itemId</samp>.
+
* replaced translations with [[Modding:Tokenizable strings|tokenizable strings]]
 +
* display names can now be omitted to use item name
 +
* added <samp>default</samp> unlock condition
 +
* fixed typo in Cookout Kit entry
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>Item</samp>
+
| <samp>Data/Crops</samp>
| <samp>SanitizeContextTag</samp>
+
| &#32;
| Replaced by <samp>ItemContextTagManager.SanitizeContextTag</samp>.
+
* [[#Custom crops|completely overhauled]]
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected<br /><small>(covered by runtime migration)</small>
 
|-
 
|-
| <samp>LocalizedContentManager</samp>
+
| <samp>Data/Events/AnimalShop</samp>
| <samp>LanguageCodeString</samp>
+
| &#32;
| Now static.
+
* updated command syntax (backwards-compatible)
 +
|
 +
|
 
|-
 
|-
| <samp>LocationContextData</samp>
+
| <samp>Data/Events/Farm</samp>
| <samp>Name</samp>
+
| &#32;
| Removed; use its dictionary key in <samp>Game1.locationContextData</samp> instead.
+
* 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>NetFields</samp>
+
| <samp>Data/Events/FishShop</samp>
| <samp>AddFields</samp>
+
| &#32;
| Removed; use <samp>AddField</samp> instead. For example:
+
* fixed typos
<syntaxhighlight lang="c#">
+
| ✘ will remove changes
// old code
+
| ✓ mostly unaffected
NetFields.AddFields(textureName, spriteWidth, spriteHeight);
  −
 
  −
// new code
  −
NetFields
  −
    .AddField(textureName)
  −
    .AddField(spriteWidth)
  −
    .AddField(spriteHeight);
  −
</syntaxhighlight>
  −
Note that the second argument (<samp>name</samp>) should usually be omitted, since it'll be auto-populated from the value passed to the first argument.
   
|-
 
|-
|rowspan="7"| <samp>NPC</samp>
+
| <samp>Data/Events/Forest</samp>
| <samp>canReceiveThisItemAsGift(…)</samp>
+
| &#32;
| 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>.
+
* fixed typos
 +
* updated Jas <samp>faceDirection</samp> command for sewer event
 +
| will remove changes
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>Gender</samp><br /><samp>female</samp><br /><samp>male</samp><br /><samp>undefined</samp>
+
| <samp>Data/Events/IslandHut</samp>
| The <samp>Gender</samp> field now uses a <samp>Gender</samp> enum instead of numeric constants. For example, <code>npc.Gender == NPC.female</code> becomes <code>npc.Gender == Gender.Female</code> in 1.6.
+
| &#32;
 +
* updated how Leo's name is translated
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>homeRegion</samp>
+
| <samp>Data/Events/IslandNorth</samp>
| Removed; use <samp>npc.GetData()?.HomeRegion</samp> instead. Change <samp>0</samp> to <samp>"Other"</samp> or <samp>NPC.region_other</samp>, <samp>1</samp> to <samp>"Desert"</samp> or <samp>NPC.region_desert</samp>, and <samp>2</samp> to <samp>"Town"</samp> or <samp>NPC.region_town</samp>.
+
| &#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>isBirthday</samp>
+
| <samp>Data/Events/IslandSouth</samp>
| Remove the arguments, like <code>npc.isBirthday(Game1.currentSeason, Game1.dayOfMonth)</code> → <code>npc.isBirthday()</code>.
+
| &#32;
 +
* fixed blank music field (backwards-compatible)
 +
* fixed typos
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>isVillager()</samp>
+
| <samp>Data/Events/JoshHouse</samp>
| Deprecated; use the <samp>character.IsVillager</samp> property instead.
+
| &#32;
 +
* fixed typos
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>populateRoutesFromLocationToLocationList</samp>
+
| <samp>Data/Events/LeahHouse</samp>
| Replaced by <samp>WarpPathfindingCache.PopulateCache</samp>.
+
| &#32;
 +
* fixed <samp>move</samp> command format in Leah's 2-heart event
 +
* fixed typos
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>Schedule</samp>
+
| <samp>Data/Events/Mountain</samp>
| No longer assignable, use one of the <samp>TryLoadSchedule</samp> overloads instead.
+
| &#32;
 +
* fixed skipped dialogue in Maru's 14-heart event
 +
* fixed typos
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 
|-
 
|-
|rowspan="3"| <samp>Object</samp>
+
| <samp>Data/Events/Saloon</samp><br /><samp>Data/Events/ScienceHouse</samp><br /><samp>Data/Events/SebastianRoom</samp>
| <samp>GetContextTagList()</samp>
+
| &#32;
| Replaced by <samp>GetContextTags()</samp>, which returns a hash set instead of a list.
+
* fixed typos
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>HasBeenPickedUpByPlayer</samp>
+
| <samp>Data/Events/Town</samp>
| Removed; use <samp>HasBeenInInventory</samp> instead.
+
| &#32;
 +
* fixed <samp>warp</samp> command format in community center completed event
 +
* fixed typos
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>isPotentialBasicShippedCategory</samp>
+
| <samp>Data/Events/WizardHouse</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>).
+
| &#32;
 +
* fixed typos
 +
| ✘ will remove changes
 +
| ✓ mostly unaffected
 
|-
 
|-
|rowspan="9"| <samp>Utility</samp>
+
| <samp>Data/ExtraDialogue</samp>
| <samp>doesItemWithThisIndexExistAnywhere</samp>
+
| &#32;
| Replace with <samp>Utility.doesItemExistAnywhere</samp>, which takes a string item ID. For example:
+
* split <samp>SummitEvent_Dialogue1_Spouse</samp> entry
* <code>Utility.doesItemWithThisIndexExistAnywhere(128)</code> &rarr; <code>Utility.doesItemExistAnywhere("(O)128")</code>;
+
* fixed event command formats in some summit dialogue
* <code>Utility.doesItemWithThisIndexExistAnywhere(128, true)</code> &rarr; <code>Utility.doesItemExistAnywhere("(BC)128")</code>.
+
* moved [[#Dialogue changes|dumpster dive dialogue into NPC files]]
 +
* removed unused entries
 +
* fixed typos
 +
| '''✘ broken'''
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>ForAllLocations</samp><br /><samp>iterateAllCrops</samp><br /><samp>iterateAllItems</samp>
+
| <samp>Data/FarmAnimals</samp>
| Removed; use the equivalent <samp>Utility.ForEach*</samp> methods instead.
+
| &#32;
 +
* [[#Custom farm animals|completely overhauled]]
 +
| '''✘ broken'''
 +
| '''✘ broken'''
 
|-
 
|-
| <samp>GetHorseWarpRestrictionsForFarmer</samp>
+
| <samp>Data/Festivals/fall16</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 command syntax (backwards-compatible)
For example:
+
* fixed typos
<syntaxhighlight lang="c#">
+
| ✘ will remove changes
// old code
+
| ✓ mostly unaffected
bool inUse = Utility.GetHorseWarpRestrictionsForFarmer(player).Any(p => p == 4);
  −
 
  −
// new code
  −
bool inUse = Utility.GetHorseWarpRestrictionsForFarmer(player).HasFlag(Utility.HorseWarpRestrictions.InUse);
  −
</syntaxhighlight>
  −
 
  −
Or to check if no restrictions apply:
  −
<syntaxhighlight lang="c#">
  −
bool canSummon = Utility.GetHorseWarpRestrictionsForFarmer(player) == Utility.HorseWarpRestrictions.None;
  −
</syntaxhighlight>
  −
 
  −
C# mods can patch <samp>Utility.GetHorseWarpErrorMessage</samp> if they need to add an error message for a custom restriction value.
   
|-
 
|-
| <samp>getRandomTownNPC(…)</samp>
+
| <samp>Data/Festivals/fall27</samp>
| Replaced by either <code>Utility.GetRandomWinterStartParticipant(…)</code> or <code>Utility.getRandomNpcFromHomeRegion(NPC.region_town)</code>.
+
| &#32;
 +
* removed <samp>shop</samp> field (moved into [[#Custom shops|<samp>Data/Shops</samp>]])
 +
| ✓ mostly unaffected
 +
| ✓ mostly unaffected
 
|-
 
|-
| <samp>getTodaysBirthdayNPC</samp>
+
| <samp>Data/Festivals/spring13</samp>
| Remove the arguments, like <code>Utility.getTodaysBirthdayNPC(Game1.currentSeason, Game1.dayOfMonth)</code> → <code>Utility.getTodaysBirthdayNPC()</code>.
+
| &#32;
|-
+
* migrated to new <samp>warpFarmers</samp> command
| <samp>getPooledList</samp><br /><samp>returnPooledList</samp>
+
* removed <samp>shop</samp> field (moved into [[#Custom shops|<samp>Data/Shops</samp>]])
| The game no longer uses a list pool. In most cases you should use the [[#Iteration|<samp>Utility.ForEach*</samp> methods]] instead, which don't need it.
  −
|-
  −
| <samp>numObelisksOnFarm</samp>
  −
| Renamed to <samp>GetObeliskTypesBuilt</samp>, which searches all locations.
  −
|-
  −
| <samp>numSilos</samp>
  −
| Removed.
  −
 
  −
If you're using this to calculate hay capacity, it's a bit more complicated in 1.6 since hay storage can be enabled for custom buildings and building construction can be enabled for any location. To get capacity for the current location, use <samp>Game1.currentLocation.GetHayCapacity()</samp> instead. To get total hay capacity in the world, use <samp>Utility.ForEachLocation</samp> to call it on every location.
  −
 
  −
If you actually need the number of silos, use <samp>location.getNumberBuildingsConstructed("Silo")</samp> (one location) or <samp>Game1.GetNumberBuildingsConstructed("Silo")</samp> (all locations).
  −
|-
  −
| <samp>removeThisCharacterFromAllLocations</samp>
  −
| Removed; use <samp>Game1.removeCharacterFromItsLocation</samp> instead.
  −
|-
  −
| <samp>ShopMenu</samp>
  −
| <samp>storeContext</samp>
  −
| Replaced by <samp>ShopId</samp>.
  −
|-
  −
|rowspan="3"| <samp>Stats</samp>
  −
| <samp>averageBedtime</samp><br /><samp>beveragesMade</samp><br /><samp>bouldersCracked</samp><br /><samp>caveCarrotsFound</samp><br /><samp>cheeseMade</samp><br /><samp>chickenEggsLayed</samp><br /><samp>copperFound</samp><br /><samp>cowMilkProduced</samp><br /><samp>cropsShipped</samp><br /><samp>daysPlayed</samp><br /><samp>diamondsFound</samp><br /><samp>dirtHoed</samp><br /><samp>duckEggsLayed</samp><br /><samp>fishCaught</samp><br /><samp>geodesCracked</samp><br /><samp>giftsGiven</samp><br /><samp>goatCheeseMade</samp><br /><samp>goatMilkProduced</samp><br /><samp>goldFound</samp><br /><samp>goodFriends</samp><br /><samp>individualMoneyEarned</samp><br /><samp>iridiumFound</samp><br /><samp>ironFound</samp><br /><samp>itemsCooked</samp><br /><samp>itemsCrafted</samp><br /><samp>itemsForaged</samp><br /><samp>itemsShipped</samp><br /><samp>monstersKilled</samp><br /><samp>mysticStonesCrushed</samp><br /><samp>notesFound</samp><br /><samp>otherPreciousGemsFound</samp><br /><samp>piecesOfTrashRecycled</samp><br /><samp>preservesMade</samp><br /><samp>prismaticShardsFound</samp><br /><samp>questsCompleted</samp><br /><samp>rabbitWoolProduced</samp><br /><samp>rocksCrushed</samp><br /><samp>seedsSown</samp><br /><samp>sheepWoolProduced</samp><br /><samp>slimesKilled</samp><br /><samp>stepsTaken</samp><br /><samp>stoneGathered</samp><br /><samp>stumpsChopped</samp><br /><samp>timesFished</samp><br /><samp>timesUnconscious</samp><br /><samp>totalMoneyGifted</samp><br /><samp>trufflesFound</samp><br /><samp>weedsEliminated</samp>
  −
| Removed; use the equivalent property or methods. For example, <code>Game1.stats.daysPlayed</code> can be replaced with <code>Game1.stats.DaysPlayed</code> or methods like <code>Game1.stats.Get(StatKeys.DaysPlayed)</code>. See [[#Stat changes for C# mods|stat changes for C# mods]].
  −
|-
  −
| <samp>getStat(…)</samp><br /><samp>incrementStat(…)</samp>
  −
| Replaced by <samp>Get(…)</samp> and <samp>Increment(…)</samp>. See [[#Stat changes for C# mods|stat changes for C# mods]].
  −
|-
  −
| <samp>stat_dictionary</samp>
  −
| Renamed to <samp>Values</samp>. See [[#Stat changes for C# mods|stat changes for C# mods]].
  −
|-
  −
| <samp>Woods</samp>
  −
| <samp>stumps</samp>
  −
| Moved into <samp>resourceClumps</samp>.
  −
|}
  −
 
  −
===Check for obsolete code===
  −
Perform a full rebuild of your mod (in Visual Studio, click ''Build > Rebuild Solution''), then check the Error List pane for any warnings like "'''X' is obsolete''". Anything from the vanilla game code which is marked obsolete won't work anymore and is only kept for save migrations. Usually the warning will include an explanation of what you should use instead.
  −
 
  −
==Breaking changes for content packs==
  −
'''This section only describes how this update may break existing mods. See the ''what's new'' sections above for more info, including new functionality mods can use.'''
  −
 
  −
===Standardized ID fields===
  −
Stardew Valley 1.6 adds an <samp>Id</samp> field to these assets. For Content Patcher content packs, these replace the previous synthetic ID:
  −
 
  −
{| class="wikitable"
  −
|-
  −
! asset
  −
! old key
  −
! new key
  −
! migration steps
  −
|-
  −
| <samp>Data/ConcessionTastes</samp><br /><samp>Data/MovieReactions</samp><br /><samp>Data/RandomBundles</samp> (area)<br /><samp>Data/RandomBundles</samp> (bundle)
  −
| <samp>Name</samp><br /><samp>NPCName</samp><br /><samp>AreaName</samp><br />''none''
  −
|<samp>Id</samp>
  −
| None. The <samp>Id</samp> field is set automatically to the same value (or <samp>Name</samp> for bundles), so there's no change for content packs. Omit the new field when creating a new entry.
  −
|-
  −
| <samp>Data/FishPondData</samp><br /><samp>Data/RandomBundles</samp> (bundle set)
  −
| <samp>RequiredTags</samp><br />''none''
  −
| <samp>Id</samp>
  −
| Use the new <samp>Id</samp> field to target an entry, and add it when creating a new entry. Required.
  −
|-
  −
| <samp>Data/TailoringRecipes</samp>
  −
| <samp>FirstItemTags</samp> and <samp>SecondItemTags</samp>
  −
| <samp>Id</samp>
  −
| Use the new <samp>Id</samp> field to target an entry, and add it when creating a new entry. Defaults to the <samp>CraftedItemIds</samp> (comma-delimited) or <samp>CraftedItemId</samp> value if omitted, but there's a high chance of conflicts so mods should always specify a unique ID.
  −
|}
  −
 
  −
For example, let's say you have a patch like this using Content Patcher:
  −
{{#tag:syntaxhighlight|<nowiki>
  −
{
  −
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
  −
    "Changes": [
  −
        {
  −
            "Action": "EditData",
  −
            "Target": "Data/TailorRecipes",
  −
            "Entries": {
  −
                "item_cloth|item_pufferchick": {
  −
                    "FirstItemTags": [ "item_cloth" ],
  −
                    "SecondItemTags": [ "item_pufferchick" ],
  −
                    "CraftedItemId": "(S)1260"
  −
                }
  −
            }
  −
        }
  −
    ]
  −
}</nowiki>|lang=javascript}}
  −
 
  −
When updating to Stardew Valley 1.6, replace the synthetic ID (<samp>item_cloth|item_pufferchick</samp>) with a real one:
  −
* To edit an existing entry, unpack the asset and get its new <samp>Id</samp> value.
  −
* To add a custom entry, use a [[Modding:Common data field types#Unique string ID|unique string ID]].
  −
 
  −
For example:
  −
{{#tag:syntaxhighlight|<nowiki>
  −
{
  −
    "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
  −
    "Changes": [
  −
        {
  −
            "Action": "EditData",
  −
            "Target": "Data/TailorRecipes",
  −
            "Entries": {
  −
                "ExampleAuthor.ModId_RainCoatFromPufferchick": {
  −
                    "Id": "ExampleAuthor.ModId_RainCoatFromPufferchick", // need to specify ID again when creating it
  −
                    "FirstItemTags": [ "item_cloth" ],
  −
                    "SecondItemTags": [ "item_pufferchick" ],
  −
                    "CraftedItemId": "(S)1260"
  −
                }
  −
            }
  −
        }
  −
    ]
  −
}</nowiki>|lang=javascript}}
  −
 
  −
===Event ID changes===
  −
: ''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
  −
! new flag
  −
|-
  −
| <samp>Gil_Slime Charmer Ring</samp>
  −
| <samp>Gil_Slimes</samp>
  −
|-
  −
| <samp>Gil_Savage Ring</samp>
  −
| <samp>Gil_Shadows</samp>
  −
|-
  −
| <samp>Gil_Vampire Ring</samp>
  −
| <samp>Gil_Bats</samp>
  −
|-
  −
| <samp>Gil_Skeleton Mask</samp>
  −
| <samp>Gil_Skeletons</samp>
  −
|-
  −
| <samp>Gil_Insect Head</samp>
  −
| <samp>Gil_Insects</samp>
  −
|-
  −
| <samp>Gil_Hard Hat</samp>
  −
| <samp>Gil_Duggy</samp>
  −
|-
  −
| <samp>Gil_Burglar's Ring</samp>
  −
| <samp>Gil_DustSpirits</samp>
  −
|-
  −
| <samp>Gil_Crabshell Ring</samp>
  −
| <samp>Gil_Crabs</samp>
  −
|-
  −
| <samp>Gil_Arcane Hat</samp>
  −
| <samp>Gil_Mummies</samp>
  −
|-
  −
| <samp>Gil_Knight's Helmet</samp>
  −
| <samp>Gil_Dinos</samp>
  −
|-
  −
| <samp>Gil_Napalm Ring</samp>
  −
| <samp>Gil_Serpents</samp>
  −
|-
  −
| <samp>Gil_Telephone</samp>
  −
| <samp>Gil_FlameSpirits</samp>
  −
|}
  −
 
  −
===XNB impact===
  −
====Overview====
  −
This section provides a summary of the XNB files which changed in Stardew Valley 1.6. This doesn't include new files (since they won't impact existing mods), or text changes in non-English files.
  −
 
  −
[[Modding:Using XNB mods|XNB mods]] are disproportionately affected, since...
  −
# they replace the entire file;
  −
# they're loaded through the MonoGame content pipeline which is less tolerant of format changes;
  −
# they don't benefit from the compatibility rewrites [[Modding:Content Patcher|Content Patcher]] provides for its content packs.
  −
 
  −
Content Patcher packs are typically unaffected (and Content Patcher will try to rewrite content packs automatically). However if a content pack replaces an entire asset instead of editing, it's more likely to be affected like an XNB mod.
  −
 
  −
====Changed assets====
  −
Compatibility is broadly grouped into four categories:
  −
* "'''✘ broken'''": mods will remove new content or significant changes, or the mod's intended changes will no longer work. Effects may range from display bugs to crashes, depending how the game uses that specific content.
  −
* "✘ will remove changes": mods will remove minor changes in 1.6 (e.g. typo fixes).
  −
* "✓ mostly unaffected": mods will only be affected if they replace the entire asset, or edit specific entries or fields.
  −
* Blank: no expected impact for the vast majority of mods.
  −
 
  −
{| class="wikitable"
  −
|-
  −
!rowspan="2"| content asset
  −
!rowspan="2"| changes in 1.6
  −
!colspan="2"| compatibility for pre-1.6 mods
  −
|-
  −
! XNB mods
  −
! Content Patcher packs
  −
|-
  −
| <samp>Buildings/houses</samp>
  −
| &#32;
  −
* fixed missing pixels
  −
| ✘ will remove changes
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Characters/Dialogue/Abigail</samp><br /><samp>Characters/Dialogue/Alex</samp>
  −
| &#32;
  −
* added [[#Dialogue changes|flower dance dialogue]]
  −
* fixed typos
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Characters/Dialogue/Caroline</samp><br /><samp>Characters/Dialogue/Demetrius</samp>
  −
| &#32;
  −
* fixed typos
  −
| ✘ will remove changes
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Characters/Dialogue/Elliott</samp>
  −
| &#32;
  −
* added [[#Dialogue changes|flower dance dialogue]]
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Characters/Dialogue/Emily</samp>
  −
| &#32;
  −
* added [[#Dialogue changes|flower dance dialogue]]
  −
* fixed typos
  −
* updated <samp>%revealtaste</samp> format (backwards-compatible)
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Characters/Dialogue/George</samp>
  −
| &#32;
  −
* added [[#Dialogue changes|Winter Star gift exchange dialogue]]
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Characters/Dialogue/Gus</samp>
  −
| &#32;
  −
* fixed typos
  −
| ✘ will remove changes
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Characters/Dialogue/Haley</samp>
  −
| &#32;
  −
* added [[#Dialogue changes|flower dance dialogue]]
  −
* fixed typos
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Characters/Dialogue/Harvey</samp>
  −
| &#32;
  −
* added [[#Dialogue changes|flower dance dialogue]]
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Characters/Dialogue/Jas</samp><br /><samp>Characters/Dialogue/Jodi</samp>
  −
| &#32;
  −
* fixed typos
  −
| ✘ will remove changes
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Characters/Dialogue/Krobus</samp>
  −
| &#32;
  −
* added [[#Dialogue changes|roommate stardrop dialogue]]
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Characters/Dialogue/Leah</samp>
  −
| &#32;
  −
* added [[#Dialogue changes|flower dance dialogue]]
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Characters/Dialogue/Lewis</samp>
  −
| &#32;
  −
* updated <samp>%revealtaste</samp> format (backwards-compatible)
  −
|
  −
|
  −
|-
  −
| <samp>Characters/Dialogue/Linus</samp>
  −
| &#32;
  −
* added [[#Dialogue changes|dumpster dive dialogue]]
  −
* fixed typos
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Characters/Dialogue/Marnie</samp>
  −
| &#32;
  −
* added [[#Dialogue changes|Stardew Valley Fair dialogue]]
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Characters/Dialogue/MarriageDialogue</samp><br /><samp>Characters/Dialogue/MarriageDialogueAbigail</samp><br /><samp>Characters/Dialogue/MarriageDialogueElliott</samp>
  −
| &#32;
  −
* fixed typos
  −
| ✘ will remove changes
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Characters/Dialogue/MarriageDialogueEmily</samp>
  −
| &#32;
  −
* changed <samp>spring_Maru</samp> key to <samp>spring_Emily</samp>
  −
* fixed typos
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Characters/Dialogue/MarriageDialogueKrobus</samp><br /><samp>Characters/Dialogue/MarriageDialogueLeah</samp><br /><samp>Characters/Dialogue/MarriageDialogueMaru</samp><br /><samp>Characters/Dialogue/MarriageDialoguePenny</samp><br /><samp>Characters/Dialogue/MarriageDialogueSam</samp>
  −
| &#32;
  −
* fixed typos
  −
| ✘ will remove changes
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Characters/Dialogue/Maru</samp>
  −
| &#32;
  −
* added [[#Dialogue changes|flower dance dialogue]]
  −
* fixed typos
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Characters/Dialogue/Penny</samp>
  −
| &#32;
  −
* added [[#Dialogue changes|flower dance dialogue]]
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Characters/Dialogue/Pierre</samp>
  −
| &#32;
  −
* added [[#Dialogue changes|Stardew Valley Fair dialogue]]
  −
* fixed typos
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Characters/Dialogue/Robin</samp>
  −
| &#32;
  −
* fixed typos
  −
| ✘ will remove changes
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Characters/Dialogue/Sam</samp>
  −
| &#32;
  −
* added [[#Dialogue changes|flower dance dialogue]]
  −
* fixed typos
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Characters/Dialogue/Sandy</samp>
  −
| &#32;
  −
* fixed typos
  −
| ✘ will remove changes
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Characters/Dialogue/Sebastian</samp>
  −
| &#32;
  −
* added [[#Dialogue changes|flower dance dialogue]]
  −
* fixed typos
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Characters/Dialogue/Willy</samp>
  −
| &#32;
  −
* added [[#Dialogue changes|Stardew Valley Fair dialogue]]
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Characters/Dialogue/Shane</samp>
  −
| &#32;
  −
* added [[#Dialogue changes|flower dance dialogue]]
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Characters/Farmer/hats</samp>
  −
| &#32;
  −
* removed stray pixel on chicken mask
  −
| ✘ will remove changes
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Characters/schedules/Elliott</samp>
  −
| &#32;
  −
* fixed order of <samp>Fri_6</samp> and <samp>Fri</samp> entries
  −
| '''✘ broken'''
  −
|
  −
|-
  −
| <samp>Characters/schedules/Lewis</samp>
  −
| &#32;
  −
* fixed <samp>winter_Sun</samp> schedule
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Characters/schedules/Maru</samp>
  −
| &#32;
  −
* fixed <samp>summer_Mon</samp> and <samp>summer_Sun</samp> schedules
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Characters/schedules/Penny</samp>
  −
| &#32;
  −
* fixed <samp>summer_Sun</samp> schedule
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Characters/Schedules/Shane</samp>
  −
| &#32;
  −
* fixed dialogue key
  −
| ✘ will remove changes
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Data/animationDescriptions</samp>
  −
| &#32;
  −
* fixed frame in Lewis' Saloon drinking animation
  −
| ✘ will remove changes
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Data/AquariumFish</samp>
  −
| &#32;
  −
* [[#Custom items|changed key type]]
  −
* added hat position for [[Sea Urchin]]
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Data/BigCraftablesInformation</samp>
  −
| &#32;
  −
* asset replaced by [[#Custom big craftables|<samp>Data/BigCraftables</samp>]]:
  −
** migrated to data model format
  −
** added new features
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected<br /><small>(covered by runtime migration)</small>
  −
|-
  −
| <samp>Data/Blueprints</samp>
  −
| &#32;
  −
* asset replaced by [[#Custom buildings|<samp>Data/Buildings</samp>]]:
  −
** migrated to data model format
  −
** added new features
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected<br /><small>(covered by runtime migration)</small>
  −
|-
  −
| <samp>Data/Boots</samp>
  −
| &#32;
  −
* [[#Custom items|changed key type]]
  −
* added display name
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected<br /><small>(covered by runtime migration)</small>
  −
|-
  −
| <samp>Data/Bundles</samp>
  −
| &#32;
  −
* can no longer omit empty fields before display name
  −
* added display name field in English
  −
* removed meat items in animal bundle
  −
| '''✘ broken'''
  −
| '''✘ likely broken'''
  −
|-
  −
| <samp>Data/ClothingInformation</samp>
  −
| &#32;
  −
* asset replaced by [[#Custom pants|<samp>Data/Pants</samp>]] and [[#Custom shirts|<samp>Data/Shirts</samp>]]:
  −
** migrated to data model format
  −
** added new features
  −
| '''✘ broken'''
  −
| '''✘ likely broken'''
  −
|-
  −
| <samp>Data/Concessions</samp>
  −
| &#32;
  −
* [[#Custom movie concessions|added new required fields (<samp>Texture</samp> and <samp>SpriteIndex</samp>)]]
  −
* replaced translations with [[Modding:Tokenizable strings|tokenizable strings]]
  −
* changed IDs to strings
  −
| '''✘ broken'''
  −
| '''✘ likely broken'''
  −
|-
  −
| <samp>Data/ConcessionTastes</samp>
  −
| &#32;
  −
* added automatic <samp>ID</samp> field
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Data/CookingRecipes</samp>
  −
| &#32;
  −
* replaced translations with [[Modding:Tokenizable strings|tokenizable strings]]
  −
* display names can now be omitted to use item name
  −
| ✘ will remove changes
  −
| ✓ may remove unaffected
  −
|-
  −
| <samp>Data/CraftingRecipes</samp>
  −
| &#32;
  −
* replaced translations with [[Modding:Tokenizable strings|tokenizable strings]]
  −
* display names can now be omitted to use item name
  −
* added <samp>default</samp> unlock condition
  −
* fixed typo in Cookout Kit entry
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Data/Crops</samp>
  −
| &#32;
  −
* [[#Custom crops|completely overhauled]]
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected<br /><small>(covered by runtime migration)</small>
  −
|-
  −
| <samp>Data/Events/AnimalShop</samp>
  −
| &#32;
  −
* updated command syntax (backwards-compatible)
  −
|
  −
|
  −
|-
  −
| <samp>Data/Events/Farm</samp>
  −
| &#32;
  −
* replaced send-mail events with [[Modding:Trigger actions|trigger actions]]
  −
* updated pet event to support custom pet types
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected<br /><small>(✘ may cause duplicate mail if they edit<br />send-mail events)</small>
  −
|-
  −
| <samp>Data/Events/FishShop</samp>
  −
| &#32;
  −
* fixed typos
  −
| ✘ will remove changes
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Data/Events/Forest</samp>
  −
| &#32;
  −
* fixed typos
  −
* updated Jas <samp>faceDirection</samp> command for sewer event
  −
| ✘ will remove changes
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Data/Events/IslandHut</samp>
  −
| &#32;
  −
* updated how Leo's name is translated
  −
| ✘ will remove changes
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Data/Events/IslandNorth</samp>
  −
| &#32;
  −
* updated quote format
  −
* fixed blank music field (backwards-compatible)
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected<br /><small>(✘ likely broken if they edit the <samp>6497421</samp> event)</small>
  −
|-
  −
| <samp>Data/Events/IslandSouth</samp>
  −
| &#32;
  −
* fixed blank music field (backwards-compatible)
  −
* fixed typos
  −
| ✘ will remove changes
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Data/Events/JoshHouse</samp>
  −
| &#32;
  −
* fixed typos
  −
| ✘ will remove changes
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Data/Events/LeahHouse</samp>
  −
| &#32;
  −
* fixed <samp>move</samp> command format in Leah's 2-heart event
  −
* fixed typos
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Data/Events/Mountain</samp>
  −
| &#32;
  −
* fixed skipped dialogue in Maru's 14-heart event
  −
* fixed typos
  −
| ✘ will remove changes
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Data/Events/Saloon</samp><br /><samp>Data/Events/ScienceHouse</samp><br /><samp>Data/Events/SebastianRoom</samp>
  −
| &#32;
  −
* fixed typos
  −
| ✘ will remove changes
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Data/Events/Town</samp>
  −
| &#32;
  −
* fixed <samp>warp</samp> command format in community center completed event
  −
* fixed typos
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Data/Events/WizardHouse</samp>
  −
| &#32;
  −
* fixed typos
  −
| ✘ will remove changes
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Data/ExtraDialogue</samp>
  −
| &#32;
  −
* split <samp>SummitEvent_Dialogue1_Spouse</samp> entry
  −
* fixed event command formats in some summit dialogue
  −
* moved [[#Dialogue changes|dumpster dive dialogue into NPC files]]
  −
* removed unused entries
  −
* fixed typos
  −
| '''✘ broken'''
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Data/FarmAnimals</samp>
  −
| &#32;
  −
* [[#Custom farm animals|completely overhauled]]
  −
| '''✘ broken'''
  −
| '''✘ broken'''
  −
|-
  −
| <samp>Data/Festivals/fall16</samp>
  −
| &#32;
  −
* updated command syntax (backwards-compatible)
  −
* fixed typos
  −
| ✘ will remove changes
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Data/Festivals/fall27</samp>
  −
| &#32;
  −
* removed <samp>shop</samp> field (moved into [[#Custom shops|<samp>Data/Shops</samp>]])
  −
| ✓ mostly unaffected
  −
| ✓ mostly unaffected
  −
|-
  −
| <samp>Data/Festivals/spring13</samp>
  −
| &#32;
  −
* migrated to new <samp>warpFarmers</samp> command
  −
* removed <samp>shop</samp> field (moved into [[#Custom shops|<samp>Data/Shops</samp>]])
   
* updated <samp>faceDirection</samp> syntax
 
* updated <samp>faceDirection</samp> syntax
 
* fixed typos
 
* fixed typos
Line 9,514: Line 9,162:  
* can no longer omit empty fields before display name
 
* can no longer omit empty fields before display name
 
| '''✘ broken'''
 
| '''✘ broken'''
| '''✘ likely broken'''
+
| ✓ mostly unaffected<br /><small>(covered by runtime migration)</small>
 
|-
 
|-
 
| <samp>Data/hats</samp>
 
| <samp>Data/hats</samp>
5

edits