Cambios

Página creada con «←Índice {{Modder compatibility header}} {{Traducir}} Este página explica cómo actualizar tus mods para que sean compatibles con {{version|1.5.5|S…»
←[[Modding:Índice|Índice]]

{{Modder compatibility header}}
{{Traducir}}

Este página explica cómo actualizar tus mods para que sean compatibles con {{version|1.5.5|Stardew Valley 1.5.5}}, y documenta algunos de los cambios y nuevas funciones.

==Cambios para mods SMAPI==
===64-bit MonoGame y .NET 5===
Stardew Valley 1.5.5 migra a 64-bit MonoGame y .NET 5 en todas las plataformas. SMAPI re-escribe mods, por lo que deberían funcionar en su mayoría, pero se recomienda actualizarlos para evitar problemas.

Para actualizar tu código de C#:
<ol>
<li>[[Modding:Migrar a 64-bit en Windows#¿Cómo actualizo código para 64-bit?|Activa compatibilidad 64-bit]] si no lo haz hecho aún. (A menos que cambiaras la configuración explícitamente, los mods son 64-bit por defecto.)</li>
<li>Migra tus archivos <samp>.csproj</samp> al formato nuevo:<ol>
<li>Reemplaza tus archivos <samp>.csproj</samp> con esto:
<syntaxhighlight lang="xml">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AssemblyName>EXAMPLE_MOD_NAME</AssemblyName>
<RootNamespace>EXAMPLE_MOD_NAME</RootNamespace>
<Version>1.0.0</Version>
<TargetFramework>net5.0</TargetFramework>
<LangVersion>Latest</LangVersion>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Pathoschild.Stardew.ModBuildConfig" Version="4.1.1" />
</ItemGroup>
</Project>
</syntaxhighlight>
</li>
<li>Si el mod usa [[Modding:Modder Guide/APIs/Harmony|Harmony]], agrega <code><nowiki><EnableHarmony>true</EnableHarmony></nowiki></code> al grupo de propiedades (PropertyGroup).</li>
<li>Actualiza las etiquetas de <samp>AssemblyName</samp>, <samp>RootNamespace</samp>, y <samp>Version</samp>. (Puedes eliminar <samp>AssemblyName</samp> y <samp>RootNamespace</samp> si son el mismo nombre del proyecto.)</li>
<li>Add any other NuGet packages you used, if any.</li>
</ol>

Si ya estás usando el formato simplificado, sólo debes actualizar el número de versión en el archivo .csproj:
<ol>
<li>Reemplaza <code><nowiki><TargetFramework>net452</TargetFramework></nowiki></code> con <code><nowiki><TargetFramework>net5.0</TargetFramework></nowiki></code>.</li>
<li>Reemplaza <code><nowiki><PackageReference Include="Pathoschild.Stardew.ModBuildConfig" Version="3.3.0" /></nowiki></code> con <code><nowiki><PackageReference Include="Pathoschild.Stardew.ModBuildConfig" Version="4.1.1" /></nowiki></code></li>
</ol>
</li>
<li>Elimina el archivo <samp>Properties/AssemblyInfo.cs</samp>, la carpeta <samp>packages</samp>, y el archivo <samp>packages.config</samp> (si están presentes).</li>
<li>Sal de Visual Studio.</li>
<li>En tu solución, elimina la carpeta invisible <samp>.vs</samp>, y en todos los proyectos las carpetas <samp>bin</samp> y <samp>obj</samp></li>
<li>Reabre la solución en Visual Studio, haz click en ''Compilar > Recompilar Solución'', arregla cualquier error, y prueba el mod en el juego.</li>
</ol>

Cosas que revisar:
* [[Modding:Guía del Modder/APIs/Utilidades#Constantes|<code>Constants.GameFramework</code>]] siempre devuelve <samp>MonoGame</samp>. Cualquier código que revise <samp>Xna</samp> puede removerse o reescribirse.

Si necesitas ayuda, siéntete libre de preguntar en [[Modding:Comunidad#Discord|#making-mods en el servidor de Stardew Valley]]!

===Cambio al formato de nombre de archivos===
Some background first:
* An ''asset name'' identifies an asset you can load through a content API like <code><nowiki>Game1.content.Load<T>("asset name")</nowiki></code>. For example: <code>Characters/Abigail</code>.
* A ''file path'' identifies a physical file on the computer. For example: <code>C:\Program Files (x86)\Steam\steamapps\common\Stardew Valley\Content\Characters\Abigail.xnb</code>.

Stardew Valley 1.5.5 makes that distinction more important, since MonoGame uses Linux-style separators in asset names on all platforms. That means '''asset names no longer match path conventions on Windows'''.

You should review all code in your mods that creates/compares paths, check whether it's actually creating/comparing asset names, y if so migrate it to the equivalent methods:

{| class="wikitable"
|-
! code for file paths
! code for asset names
|-
| <code>PathUtilities.NormalizePath("a/b")</code>
| <code>PathUtilities.NormalizeAssetName("a/b")</code>
|-
| <code>Path.Combine("a", "b")</code>
| <code>PathUtilities.NormalizeAssetName("a/b")</code>
|-
| <code>Path.DirectorySeparatorChar</code>
| <code>PathUtilities.AssetDirectorySeparator</code>
|}

===Game compatibility branch===
{{main article|Modding:Player Guide/Troubleshooting#SMAPI doesn't work with compatibility branch}}

Stardew Valley 1.5.5 is available in two branches on each OS: the ''main branch'' which is installed by default, y an optional [https://www.stardewvalley.net/compatibility''compatibility branch'' for older systems]. These have identical content for players, but use different frameworks:

{| class="wikitable"
|-
! branch
! OS
! game framework
! runtime
|- style="color: #090;"
|rowspan="2"| main
| Linux/macOS
| MonoGame 3.8
| 64-bit .NET 5
|- style="color: #090;"
| Windows
| MonoGame 3.8
| 64-bit .NET 5
|- style="color: #900;"
|rowspan="2"| compatibility
| Linux/macOS
| MonoGame 3.5.1
| 64-bit Mono 4.5
|- style="color: #900;"
| Windows
| XNA Framework 4.0
| 32-bit .NET Framework 4.5
|}

Unfortunately '''SMAPI only supports the main branch of the game currently.''' There are formidable difficulties across all mods in supporting all three variations, 32-bit imposes significant restrictions on what mods can do, y the [https://store.steampowered.com/hwsurvey Steam hardware stats] show that ≈99.69% of players have 64-bit.

Having two versions of SMAPI (like we do for Linux/macOS vs Windows compatibility) wouldn't be enough in this case. Every C# mod author would need to manually port two versions of every update of every mod forever, which is prohibitively unfeasible. It's possible that in the future we'll either figure out how SMAPI can automatically rewrite mods for the compatibility branch, or some modders may port SMAPI y individual mods to the compatibility branch.

===Game assembly name===
Previously the game assembly was <code>Stardew Valley</code> on Windows, y <code>StardewValley</code> on Linux y macOS. The assembly is now named <code>Stardew Valley</code> on all platforms. Most mods shouldn't be affected once you update the mod build package.

===New assembly reference model===
If your mod references a <samp>.dll</samp> file manually, note that assembly references are handled differently in .NET 5. Custom assemblies are no longer copied into your mod's folder by default, which may break your mod. In that case you need to explicitly enable assembly bundling in your project file; see <code>BundleExtraAssemblies</code> in the [https://smapi.io/package mod build package] documentation for details.

==Breaking changes for Content Patcher packs==
===XNB impact===
Here's a summary of the XNB files which changed in Stardew Valley 1.5.5.

Notes:
* This ignores text changes in non-English files for simplicity.
* New content files aren't listed, since they won't impact existing mods.
* XNB mods are disproportionately affected, since they replace the entire file. Content Patcher packs are typically unaffected unless they replace the entire file (in which case see the XNB mod column).

Shorthand:
* 'roto' means removing new content or potentially important changes, or potentially causing significant display bugs. This is a broad category — the game may work fine without it or crash, depending how it uses that specific content.
* 'mayoritariamente intacto' means mods will only be affected if they edit specific entries or fields.
* Blank means no expected impact for the vast majority of mods.

{| class="wikitable"
|-
! content file
! changes
! XNB
! Content Patcher
|-
| <samp>Data/TV/TipChannel</samp>
| arreglo de error
| ✘ se removerán los cambios
| ✓ mayoritariamente intacto
|-
| <samp>Effects/BloomCombine</samp><br /><samp>Effects/BloomExtract</samp><br /><samp>Effects/GaussianBlur</samp>
| deleted
|
|
|-
| <samp>Fonts/*</samp>
| sin cambios<br />([[Modding:Editing XNB files#unpack|unpacked format]] may differ on Windows due to [[#64-bit MonoGame y .NET 5|MonoGame]])
|
|
|-
| <samp>LooseSprites/Cursors2</samp>
| nuevo sprite en área vacía
| '''✘ roto'''
| ✓ mayoritariamente intacto
|-
| <samp>Maps/Desert</samp>
| arreglos cosméticos
| ✘ se removerán los cambios
| ✓ mayoritariamente intacto
|-
| <samp>Maps/ElliottHouse</samp>
| arreglos menores
| ✘ se removerán los cambios
| ✓ mayoritariamente intacto
|-
| <samp>Maps/Farm</samp><br /><samp>Maps/Farm_Combat</samp><br /><samp>Maps/Farm_Fishing</samp><br /><samp>Maps/Farm_Foraging</samp><br /><samp>Maps/Farm_FourCorners</samp><br /><samp>Maps/Farm_Island</samp><br /><samp>Maps/Farm_Mining</samp>
| cave y shipping areas now use tile properties to disable building, instead of being hardcoded
| ✘ will remove those build restrictions
| ✘ may remove those build restrictions
|-
| <samp>Maps/FarmHouse</samp><br /><samp>Maps/FarmHouse1</samp><br /><samp>Maps/FarmHouse1_marriage</samp><br /><samp>Maps/FarmHouse2</samp><br /><samp>Maps/FarmHouse2_marriage</samp><br /><samp>Maps/Farmhouse_*</samp> renovation maps<br /><samp>Maps/IslandFarmHouse</samp><br /><samp>Maps/Shed</samp><br /><samp>Maps/Shed2</samp>
| added new [[#Custom floors/walls|wall/flooring properties]]
| '''✘ roto''' (will disable most floor/walls when renovations applied)
| ✘ may disable some floor/walls when renovations applied
|-
| <samp>Maps/spouseRooms</samp>
| added [[#Custom spouse rooms|spouse standing spots]] (defaults to old offset if not set)
| ✓ mayoritariamente intacto
| ✓ mayoritariamente intacto
|-
| <samp>Strings/Locations</samp>
| changed <samp>ManorHouse_DivorceBook_*</samp> entries to support [[#Non-Krobus roommates|Non-Krobus roommates]]
| '''✘ roto'''
| ✓ mayoritariamente intacto
|}

==New features for SMAPI mods==
: ''See also [[#New features for Content Patcher packs|new features for Content Patcher packs]], which apply for C# mods too.

===Scarecrow changes===
You can now patch <code>Object.IsScarecrow()</code> and/or <code>Object.GetRadiusForScarecrow()</code> (or add [[#Custom scarecrows|context tags]]) to support custom scarecrows or custom ranges.

===Horse footstep changes===
You can now override the footstep logic for a horse by setting its <samp>onFootstepAction</samp> field. For example:
<syntaxhighlight lang="c#">
Horse horse = ...; // get the horse instance you want to change
horse.onFootstepAction = (string tileType) =>
{
// play custom audio, etc
};
</syntaxhighlight>

==New features for Content Patcher packs==
Stardew Valley 1.5.5 has no known breaking changes for content packs. All content packs should work fine once the framework mod that loads them is updated.

===Custom farm types===
You can now add custom farm types by editing the <samp>Data/AdditionalFarms</samp> asset. Each entry consists of an object with these fields:

{| class="wikitable"
|-
! field
! description
|-
| <samp>ID</samp>
| A unique ID value. This must be '''globally''' unique across all mods, so you should prefix your mod ID (''e.g.,'' <samp>Example.PineapplesAnywhere/PineappleFarm</samp>). You should avoid commas for compatibility with Content Patcher packs checking the <samp><nowiki>{{FarmType}}</nowiki></samp> token. This is not shown in-game.
|-
| <samp>TooltipStringPath</samp>
| Where to get the translatable farm name y description. This must be a key in the form <samp>{{t|asset name}}:{{t|key}}</samp>; for example, <samp>Strings/UI:Farm_Description</samp> will get it from the <samp>Farm_Description</samp> entry in the <samp>Strings/UI</samp> file. The translated text must be in the form "<samp>{{t|name}}_{{t|description}}</samp>", like "Pineapple Farm_A farm shaped like a pineapple".
|-
| <samp>MapName</samp>
| The map asset name relative to the <samp>Maps</samp> folder. For example, <samp>Farm_Pineapple</samp> would load <samp>Maps/Farm_Pineapple</samp>.
|-
| <samp>IconTexture</samp>
| ''(optional)'' The asset name for a 22x20 pixel icon texture, shown on the 'New Game' y co-op join screens.
|-
| <samp>WorldMapTexture</samp>
| ''(optional)'' The asset name for a 131x61 pixel texture that's drawn over the farm area in the in-game world map.
|-
| <samp>ModData</samp>
| ''(optional)'' A string→string dictionary of mod-specific metadata for the farm, which can be accessed in C# code via <samp>Game1.GetFarmTypeModData(key)</samp>.
|}

For example, this Content Patcher pack would create a 'pineapple' farm:
{{#tag:syntaxhighlight|
{
"Format": "{{Content Patcher version}}",
"Changes": [
// add farm type
{
"Action": "EditData",
"Target": "Data/AdditionalFarms",
"Entries": {
"ExampleAuthor.PineappleFarm/PineappleFarm": { // for technical reasons, you need to specify the ID here *and* in the "ID" field
"ID": "ExampleAuthor.PineappleFarm/PineappleFarm",
"TooltipStringPath": "Strings/UI:ExampleAuthor_PineappleFarm",
"MapName": "ExampleAuthor_PineappleFarm",
"IconTexture": "Mods/ExampleAuthor.PineappleFarm/Icon",
"WorldMapTexture": "Mods/ExampleAuthor.PineappleFarm/WorldMap"
}
}
},

// add farm name + description
{
"Action": "EditData",
"Target": "Strings/UI",
"Entries": {
"ExampleAuthor_PineappleFarm": "Pineapple Farm_A farm shaped like a pineapple!" // tip: use <nowiki>{{i18n}}</nowiki> to translate it
}
},

// load map
{
"Action": "Load",
"Target": "Maps/ExampleAuthor_PineappleFarm",
"FromFile": "assets/map.tmx"
},

// load icon
{
"Action": "Load",
"Target": "Mods/ExampleAuthor.PineappleFarm/Icon, Mods/ExampleAuthor.PineappleFarm/WorldMap",
"FromFile": "assets/<nowiki>{{TargetWithoutPath}}</nowiki>.png"
}
]
}|lang=javascript}}

===Custom languages===
{{main article|Modding:Custom languages}}

You can now add custom languages by editing the <samp>Data/AdditionalLanguages</samp> asset. Each entry consists of an object with these fields:

{| class="wikitable"
|-
! field
! description
|-
| <samp>ID</samp>
| A unique ID value. This is not shown in-game.
|-
| <samp>LanguageCode</samp>
| The language code for this localization. This should ideally be a [[wikipedia:List of ISO 639-1 codes|ISO 639-1 code]]. You should avoid commas for compatibility with Content Patcher packs checking the <samp><nowiki>{{Language}}</nowiki></samp> token.
|-
| <samp>ButtonTexture</samp>
| The asset name for a 174x78 pixel texture containing the button of the language for language selection menu. The top half of the sprite is the default state, while the bottom half is the hover state.
|-
| <samp>UseLatinFont</samp>
| Whether the language uses the same Latin character font as English. If set to <samp>false</samp>, you must set the <samp>FontFile</samp> field.
|-
| <samp>TimeFormat</samp>
| A string which describes the in-game time format, with tokens replaced by in-game values. For example, <code>[HOURS_12]:[MINUTES] [AM_PM]</code> would show <code>12:00 PM</code> at noon.

The valid tokens are:
* <code>[HOURS_12]</code>: hours in 12-hour format, where midnight y noon are both "12".
* <code>[HOURS_12_0]</code>: hours in 12-hour format, where midnight y noon are both "0".
* <code>[HOURS_24]</code>: hours in 24-hour format, where midnight is "0" y noon is "12".
* <code>[HOURS_24_00]</code>: hours in 24-hour format with zero-padding, where midnight is "00" y noon is "12".
* <code>[MINUTES]</code>: minutes with zero-padding.
* <code>[AM_PM]</code>: the localized text for "am" or "pm" (taken from <code>Strings\\StringsFromCSFiles:DayTimeMoneyBox.cs.10370</code> y <code>DayTimeMoneyBox.cs.10371</code> respectively). The game shows "pm" between noon y 11:59pm inclusively; it shows "am" otherwise.
|-
| <samp>ClockTimeFormat</samp>
| A string which describes the in-game time format. Equivalent to <samp>TimeFormat</samp>, but used for the in-game clock.
|-
| <samp>ClockDateFormat</samp>
| A string which describes the in-game date format as shown in the in-game clock, with tokens replaced by in-game values. For example, <code>[DAY_OF_WEEK]. [DAY_OF_MONTH]</code> would show <code>Mon. 1</code>.

The valid tokens are:
* <code>[DAY_OF_WEEK]</code>: the abbreviated day of week as returned by <code>Game1.shortDayDisplayNameFromDayOfSeason</code> (like <samp>Mon</samp> for Monday).
* <code>[DAY_OF_MONTH]</code>: the numerical day of the month.
|-
| <samp>FontFile</samp>
| ''(optional)'' The asset name for the font file to use (if <samp>UseLatinFont</samp> is <samp>false</samp>).
|-
| <samp>FontPixelZoom</samp>
| ''(optional)'' A factor by while to multiply the font size.
|-
| <samp>FontApplyYOffset</samp>
| ''(optional)'' Whether to shift the font up by four pixels (multiplied by the <samp>FontPixelZoom</samp>), to better align languages with larger characters like Chinese y Japanese.
|-
| <samp>NumberComma</samp>
| ''(optional)'' The string to use as the thousands separator (''e.g.,'' <code>","</code> for <code>5,000,000</code>). Defaults to a comma.
|-
| <samp>SmallFontLineSpacing</samp>
| ''(optional)'' The line spacing value used by <samp>smallFont</samp>. Defaults to 26.
|-
| <samp>UseGenderedCharacterTranslations</samp>
| ''(optional)'' Whether the social tab y gift log will use gender-specific translations (like the vanilla Portuguese language). Defaults to false.

Specifically, this affects the <samp>Strings\StringsFromCSFiles:SocialPage.cs.11635</samp> translation ("''(Single)''"). When enabled, it can contain male y female translations separated by <code>/</code>, like the vanilla Portuguese translation: "''(solteiro)/(solteira)''".
|}

For example, this Content Patcher pack would add Esperanto to the game:
{{#tag:syntaxhighlight|
{
"Format": "{{Content Patcher version}}",
"Changes": [
// define language
{
"Action": "EditData",
"Target": "Data/AdditionalLanguages",
"Entries": {
"ExampleAuthor.Esperanto": { // for technical reasons, you need to specify the ID here *and* in the "ID" field
"ID": "ExampleAuthor.Esperanto",
"LanguageCode": "eo",
"ButtonTexture": "Mods/ExampleAuthor.Esperanto/Button",
"UseLatinFont": true,
"TimeFormat": "[HOURS_24_00]:[MINUTES]",
"ClockTimeFormat": "[HOURS_24_00]:[MINUTES]",
"ClockDateFormat": "[DAY_OF_WEEK] [DAY_OF_MONTH]"
}
}
},

// load button texture
{
"Action": "Load",
"Target": "Mods/ExampleAuthor.Esperanto/Button",
"FromFile": "assets/button.png"
}
]
}|lang=javascript}}

Once the language is defined, you can add translations to the game by patching game assets like usual, y use the language code you specified above. For example:
<syntaxhighlight lang="javascript">
{
"Action": "EditData",
"Target": "Strings/StringsFromCSFiles",
"Entries": {
"Game1.cs.3043": "Lundo",
"Game1.cs.3044": "Mardo",
...
},
"When": {
"Language": "eo"
}
}
</syntaxhighlight>

===Custom festival location names===
The location name in the festival-started message (''e.g.,'' "''The Luau has begun on the beach''") was previously hardcoded, so it would always show the internal name for non-vanilla festival locations. You can now add a <samp>locationDisplayName</samp> field in the <samp>Data/Festivals/*</samp> file to set the display name.

===Custom spouse rooms===
Adding spouse rooms for custom NPCs is now much easier.
<ul>
<li>You can edit the <samp>Data/SpouseRooms</samp> asset to add the spouse room info in this format: <code>"{{t|NPC name}}": "{{t|map name}}/{{t|map index}}"</code>.

{| class="wikitable"
|-
! field
! effect
|-
| <code>{{t|NPC name}}</code>
| The internal name of the NPC (''i.e.,'' their key in <samp>Data/NPCDispositions</samp>).
|-
| <code>{{t|map name}}</code>
| The asset name of the map in the game's <samp>Content/Maps</samp> folder. This can be a custom map loaded through Content Patcher's <samp>Load</samp> action or SMAPI's <samp>IAssetLoader</samp> API.
|-
| <code>{{t|map index}}</code>
| The index of the spouse room within the map file, to allow multiple spouse rooms in the same file. Each spouse room is 6 tiles across by 9 tiles down, starting with index 0 in the top-left corner. You can have any number of rows y columns (the index will wrap at the end of the row), as long as they fit an integer number of spouse rooms.
|}</li>
<li>You can mark where the spouse stands in their spouse room by placing the red circle path tile (tile index 7) on [[Modding:Maps#Paths layer|the <samp>Paths</samp> layer]].</li>
<li>The spouse room maps are now applied using the game's newer map override system, so tile properties y custom tilesheets in the spouse room map are copied over automatically.</li>
<li>Some of the game's spouse room code (''e.g.,'' positions for Sebastian's 14-heart frog terrarium) was updated to potentially allow moving spouse rooms around. However, some things like event positions are still hardcoded y will need to be fixed to fully support this feature.</li>
</ul>

For example, this Content Patcher pack would add a spouse room for a new Akila NPC:
{{#tag:syntaxhighlight|
{
"Format": "{{Content Patcher version}}",
"Changes": [
// register spouse room
{
"Action": "EditData",
"Target": "Data/SpouseRooms",
"Entries": {
"Akila": "ExampleAuthor_ExampleAkilaMod_SpouseRoom/0"
}
},

// load spouse room map
{
"Action": "Load",
"Target": "Maps/ExampleAuthor_ExampleAkilaMod_SpouseRoom",
"FromFile": "assets/spouse-room.tmx"
}
]
}|lang=javascript}}

===Custom spouse outside areas===
You can now customize the [[Marriage#Spouse Outside Area|spouse outside area]] for any NPC by editing <samp>Data/SpousePatios</samp>, which has four slash-delimited fields:
{| class="wikitable"
|-
! field
! effect
|-
| <samp>map asset name</samp>
| The asset name relative to the <samp>Content/Maps</samp> folder which contains the spouse area map. The map must contain one or more 4x4 tile areas, with any number of rows y columns.
|-
| <samp>index</samp>
| The index (starting at zero) within the map for the 4x4 area to use as the outdoor area.
|-
| <samp>NPC animation frames</samp>
| ''(Optional)'' The spouse's animation frames, as a sequence of space-delimited frame indexes in their sprite's spritesheet each lasting 100 milliseconds. If not set, vanilla spouses will use their hardcoded animations y custom spouses won't be animated.
|-
| <samp>{{t|NPC offset X}} {{t|NPC offset Y}}</samp>
| ''(Optional)'' A pixel X y Y offset applied to the NPC's position when they're in their outdoor area.
|}

You can mark where the spouse stands in their spouse area by placing the red circle path tile (tile index 7) on [[Modding:Maps#Paths layer|the <samp>Paths</samp> layer]].

For example, this Content Patcher pack would add the outside area for a new Akila NPC. When in the outside area, their sprite would cycle through spritesheet indexes 16&ndash;19 for 300 milliseconds each, y be offset by 1 pixel to the right y 5 pixels down.
{{#tag:syntaxhighlight|
{
"Format": "{{Content Patcher version}}",
"Changes": [
// register outside area
{
"Action": "EditData",
"Target": "Data/SpousePatios",
"Entries": {
"Akila": "ExampleAuthor_ExampleAkilaMod_OutsideArea/0/16 16 16 17 17 17 18 18 18 19 19 19/1 5"
}
},

// load spouse map
{
"Action": "Load",
"Target": "Maps/ExampleAuthor_ExampleAkilaMod_OutsideArea",
"FromFile": "assets/outside-area.tmx"
}
]
}|lang=javascript}}

===Custom farmhouse renovations===
You can now add custom [[Farmhouse#Upgrades|farmhouse renovations]] that will be applied automatically when the specified [[Modding:Mail data#Mail flags|mail flag]] is set. This is based on a new map property in the farmhouse map:

{| class="wikitable"
|-
! valid in
! map property
! usage
|-
| farmhouse
| <samp>AdditionalRenovations {{t|renovation}}+</samp>
| A comma-separated list of renovations to apply, each in the form <samp>{{t|map patch ID}} {{t|required mail flag}} {{t|map asset if active}} {{t|map asset if inactive}} {{o|area rectangle}}</samp>. Fields:
{| class="wikitable"
|-
! field
! effect
|-
| <samp>map patch ID</samp>
| A unique ID for the patch being applied. This is usually similar to the renovation name, but can be any unique value. If a renovation applies multiple map patches, each one must have unique ID.
|-
| <samp>required mail flag</samp>
| The [[Modding:Mail data#Mail flags|mail flag]] that is checked on the house's owner to decide whether the patch should be applied.
|-
| <samp>map asset if active</samp>
| The asset name for the map applied when the mail flag is set, relative to the <samp>Maps</samp> folder.
|-
| <samp>map asset if inactive</samp>
| The asset name for the map applied when the mail flag is not set, relative to the <samp>Maps</samp> folder.
|-
| <samp>area rectangle</samp>
| ''(Optional)'' The tile area in the map to patch, specified as <samp>{{t|X}} {{t|Y}} {{t|width}} {{t|height}}</samp>. If {{t|X}} isn't set, this defaults to the top-left corner of the map. If it is, you must specify all four values.
|}
|}

For example, this Content Patcher pack would add a renovation to the fully-upgraded farmhouse based on a custom <samp>ExampleAuthor_PineapplesEverywhere_HasRenovation</samp> flag. Note that <samp>TextOperations</samp> is used to avoid overwriting any renovations added by another mod, y <samp>ExampleAuthor_PineapplesEverywhere_</samp> is a unique prefix for the hypothetical mod to avoid conflicts with other mods.
{{#tag:syntaxhighlight|
{
"Format": "{{Content Patcher version}}",
"Changes": [
// add renovation
{
"Action": "EditMap",
"Target": "Maps/FarmHouse2, Maps/FarmHouse2_marriage",
"TextOperations": [
{
"Operation": "Append",
"Target": [ "MapProperties", "AdditionalRenovations" ],
"Value": "ExampleAuthor_PineapplesEverywhere_KitchenUpgrade ExampleAuthor_PineapplesEverywhere_HasRenovation ExampleAuthor_PineapplesEverywhere_Kitchen ExampleAuthor_PineapplesEverywhere_Empty 0 19 3 3",
"Delimiter": "," // if there are already renovations, add a comma before this one
}
]
},

// load renovation map patch
{
"Action": "Load",
"Target": "Maps/ExampleAuthor_PineapplesEverywhere_Kitchen",
"FromFile": "assets/kitchen-upgrade.tmx"
},

// load empty map (applied if renovation is inactive)
{
"Action": "Load",
"Target": "Maps/ExampleAuthor_PineapplesEverywhere_Empty",
"FromFile": "assets/kitchen-upgrade-empty.tmx"
}
]
}|lang=javascript}}

===Custom floors/walls===
====In decoratable locations====
You can now change the walls/floors for decoratable locations (like farmhouses, cabins, or sheds) for flooring/painting/wallpaper placement just by editing map/tile properties.

First, you can define distinct areas using two new map properties:

{| class="wikitable"
|-
! valid in
! map property
! usage
|-
| ''decoratable locations''
| <samp>FloorIDs {{o|area}}+</samp><br /><samp>WallIDs {{o|area}}+</samp><br />
| A comma-separated list of the distinct areas which have flooring or walls. The <samp>FloorIDs</samp> y <samp>WallIDs</samp> don't need to match. Each area has the form <code>{{t|area ID}} {{o|default flooring/wallpaper ID}}</code>, where:
* <samp>{{t|area ID}}</samp> uniquely identifies the area or room.
* <samp>{{o|default flooring/wallpaper ID}}</samp> (optional) sets the initial flooring/wallpaper ID if that area hasn't been customized by the player yet. This can be defined in three forms:
** <code>{{t|index}}</code>: get the floor/wallpaper matching that index in the vanilla <samp>Maps/walls_and_floors</samp> tilesheet.
** <code>{{t|tilesheet}}:{{t|index}}</code>: add <samp>Maps/{{t|tilesheet}}</samp> to the map, y match the index in that tilesheet.
** <code>{{t|area ID}}</code>: inherit the default floor/wallpaper from the named area. For example, <samp>Hallway_Bedroom Bedroom</samp> applies the bedroom wallpaper to the hallway between the bedroom y living room when the farmhouse is first upgraded.
** If omitted, the default will be flooring/wallpaper #0.

For example: <pre>FloorIDs: Kitchen 22, LivingRoom Bedroom, Hallway_Bedroom Bedroom, Bedroom
WallIDs: LivingRoom, Hallway_Bedroom Bedroom, Bedroom</pre>

You don't need to add every area to the <samp>FloorIDs</samp>/<samp>WallIDs</samp> list; assigning a flooring/wall to an unlisted value will be handled correctly. You only really need to add an area to <samp>FloorIDs</samp>/<samp>WallIDs</samp> to set the default flooring/wallpaper value, or for cases where the order of the walls/floors is important (for backwards compatibility with code that sets wallpaper/flooring by an integer room index, as is the case with the floors/walls in the vanilla farmhouse).
|}

Then you can add individual tiles to each area with two new tile properties:

{| class="wikitable"
|-
! layer
! property
! effect
|-
| <samp>Back</samp>
| <samp>WallID {{t|area ID}}</samp><br /><samp>FloorID {{t|area ID}}</samp>
| Adds this tile to the given floor/wall area. Each floor tile should have the <samp>FloorID</samp> property, but only the top edge of the wall should have <samp>WallID</samp>.
|}

====In the furniture catalogue====
You can also add new flooring/wallpaper options to the furniture catalogue by adding it to <samp>Data/AdditionalWallpaperFlooring</samp>. Each entry consists of an object with these fields:

{| class="wikitable"
|-
! field
! description
|-
| <samp>ID</samp>
| A unique ID value. This is not shown in-game.
|-
| <samp>Texture</samp>
| The asset name which contains 32x32 pixel (flooring) or 16x48 pixel (wallpaper) sprites. The tilesheet must be 256 pixels wide, but can have any number of flooring/wallpaper rows.
|-
| <samp>IsFlooring</samp>
| Whether this is a flooring tilesheet; else it's a wallpaper tilesheet.
|-
| <samp>Count</samp>
| The number of flooring or wallpaper sprites in the tilesheet.
|}

For example, this Content Patcher pack would add three new wallpapers to the game:
{{#tag:syntaxhighlight|
{
"Format": "{{Content Patcher version}}",
"Changes": [
// define wallpaper
{
"Action": "EditData",
"Target": "Data/AdditionalWallpaperFlooring",
"Entries": {
"ExampleAuthor.CustomWallpapers": { // for technical reasons, you need to specify the ID here *and* in the "ID" field
"ID": "ExampleAuthor.CustomWallpapers",
"Texture": "Mods/ExampleAuthor.CustomWallpapers/Wallpapers",
"IsFlooring": false,
"Count": 3
}
}
},

// load wallpaper tilesheet
{
"Action": "Load",
"Target": "Mods/ExampleAuthor.CustomWallpapers/Wallpapers",
"FromFile": "assets/wallpapers.png"
}
]
}|lang=javascript}}

===Map property changes===
{{main article|Modding:Maps#Known_properties}}
Stardew Valley 1.5.5 adds several map properties (in addition to those listed in their own sections):

{| class="wikitable"
|-
! valid in
! map property
! usage
|-
| ''any''
| <samp>AllowGrassGrowInWinter T</samp>
| Allows [[grass]] to spread in winter.
|-
| ''any''
| <samp>AllowGrassSurviveInWinter T</samp>
| Allows [[grass]] that's alive on the last day of fall to survive through to winter.
|-
| ''any''
| <samp>ClearEmptyDirtOnNewMonth T</samp>
| Destroy most tilled dirt that doesn't contain crops when a new year starts.
|-
| ''any''
| <samp>EnableGrassSpread T</samp>
| Gives [[grass]] in the location a chance to spread each day.
|-
| ''any''
| <samp>ForceAllowTreePlanting T</samp>
| Allows planting trees (both wild y fruit) in this location, even if it normally wouldn't be allowed.
|-
| ''any''
| <samp>IsFarm T</samp>
| Marks the location as a farm. This only affects generic location/interaction logic which checks the in-code <code>location.IsFarm</code> property; logic hardcoded into the game's <code>Farm</code> class (''e.g.,'' farm animals, pets, crows/scarecrows, greenhouse, farm buildings, etc) is still limited to the actual farm.
|-
| ''any''
| <samp>IsGreenhouse T</samp>
| Marks the location as a greenhouse.
|-
| ''any''
| <samp>SpawnGrassFromPathsOnNewYear T</samp>
| Spawns grass on every tile with index 22 on the <samp>Paths</samp> layer when a new year starts. See also <samp>SpawnRandomGrassOnNewYear</samp>.
|-
| ''any''
| <samp>SpawnDebrisOnNewMonth T</samp><br /><samp>SpawnDebrisOnNewYear T</samp>
| Spawns weeds, stones, or twigs at random positions when a new month/year starts (subject to their usual spawn rules).
|-
| ''any''
| <samp>SpawnRandomGrassOnNewYear T</samp>
| Spawns grass at random positions when a new year starts (subject to its usual spawn rules). See also <samp>SpawnGrassFromPathsOnNewYear</samp>.
|-
| farm
| <samp>FarmFishLocationOverride {{t|location name}} {{t|chance}}</samp>
| Adds an alternative location name when catching fish, where the {{t|chance}} is a decimal value between 0 (never happens) y 1 (always happens). For example, <samp>FarmFishLocationOverride Mountain 0.5</samp> adds a 50% chance of catching mountain fish instead of the normal fish for that location. The location name is case-sensitive, y matches those shown by the {{nexus mod|679|Debug Mode mod}}.
|-
| farm
| <samp>FarmHouseFurniture [{{t|furniture ID}} {{t|tile X}} {{t|tile Y}} {{t|rotations}}]+</samp>
| Spawns initial furniture in the farmhouse when creating a new save. If you add multiple furniture to the same tile, the first one will be placed on the ground y the last one will be placed on the first one.<br />This is also required to enable the <samp>FarmHouseWallpaper</samp>, <samp>FarmHouseFlooring</samp>, y <samp>FarmHouseStarterSeedsPosition</samp> properties. You can enable it without spawning any furniture with <samp>FarmHouseFurniture -1 0 0 0</samp>.
|-
| farm
| <samp>FarmHouseFlooring {{t|flooring id}}</samp>
| Sets the initial farmhouse floor to the given ID when creating a new save. These are mapped to the 4x4 tile areas in the <samp>Maps/walls_and_floors</samp> tilesheet starting at tile index 336 (where index 0 is mapped to the top-left square).<br />This is only enabled if <samp>FarmHouseFurniture</samp> is set.
|-
| farm
| <samp>FarmHouseWallpaper {{t|wallpaper id}}</samp>
| Sets the initial farmhouse wallpaper to the given ID when creating a new save. These are mapped to the 1x4 tile areas in the <samp>Maps/walls_and_floors</samp> tilesheet starting from the top-left.<br />This is only enabled if <samp>FarmHouseFurniture</samp> is set.
|-
| farm
| <samp>FarmHouseStarterSeedsPosition {{t|tile X}} {{t|tile Y}}</samp>
| Sets the tile position in the farmhouse where the seed package is placed when creating a new save.<br />This is only enabled if <samp>FarmHouseFurniture</samp> is set.
|-
| farm
| <samp>FarmOceanCrabPotOverride T</samp>
| Causes crab pots on the farm should catch ocean fish.
|-
| farm
| <samp>SpawnBeachFarmForage T</samp>
| Randomly spawns beach forage y [[Supply Crate|supply crates]] on the farm (like the [[Farm Maps|vanilla beach farm]]). Forage y crates will only appear on tiles which have the <samp>BeachSpawn T</samp> property on the <samp>Back</samp> layer, are clear for placement, y don't have a tile on the <samp>AlwaysFront</samp> layer.
|-
| farm
| <samp>SpawnForestFarmForage T</samp>
| Randomly spawns forest forage on the farm (like the [[Farm Maps|vanilla forest farm]]). Forage will only spawn on tiles which have the <samp>Type Grass</samp> tile property, are clear for placement, y don't have a tile on the <samp>AlwaysFront</samp> layer.
|-
| farm
| <samp>SpawnMountainFarmOreRect {{t|tile X}} {{t|tile Y}} {{t|tile width}} {{t|tile height}}</samp>
| The tile area on the farm map where ores should randomly spawn (like the [[Farm Maps|vanilla hilltop farm]]). Ores will only spawn on tiles which have the <samp>Type Dirt</samp> tile property y are clear for object placement.
|-
| farmhouse
| <samp>EntryLocation {{t|tile X}} {{t|tile Y}}</samp>
| Sets the tile on which the player appears when they warp into the farmhouse.
|}

And one new tile property:

{| class="wikitable"
|-
! layer
! property
! effect
|-
| <samp>Back</samp>
| <samp>TouchAction Warp {{t|area}} {{t|x}} {{t|y}} {{o|string prerequisite}}</samp>
| Adds a player-only warp on the tile to the specified location name y position. This is exactly equivalent to <samp>TouchAction MagicWarp</samp>, but without the magic sound/visual effect.
|}

It also changes one tile property:
{| class="wikitable"
|-
! layer
! property
! effect
|-
| <samp>Back</samp>
| <samp>Water</samp>
| Setting the value to <samp>I</samp> (uppercase i) will make the tile behave like normal water, but won't render the water animation overlay for it.
|}

===Non-Krobus roommates===
The game's [[marriage]] logic previously had hardcoded exceptions to treat [[Krobus]] as a roommate instead. That logic has been reworked so it can be applied to any NPC (including custom NPCs).

Specifically:
<ul>
<li>Items with the "<samp>propose_roommate_{{t|NPC name}}</samp>" [[Modding:Items#Context tags|context tag]] will trigger a roommate proposal when given to the named NPC. The NPC name must be lowercase with underscores instead of spaces (''e.g.,'' <samp>propose_roommate_dwarf</samp>).</li>
<li>These [[Modding:Dialogue|dialogue keys]] apply before they move in:
{| class="wikitable"
|-
! content file
! key
! effect
|-
| <samp>Strings/StringsFromCSFiles</samp>
| <samp>{{t|NPC name}}_EngagedRoommate</samp>
| The NPC's roommate proposal accept dialogue.<br />⚠ Ignored if you don't specify <samp>Data/EngagementDialogue:{{t|NPC name}}Roommate0</samp>.<br />For example: ''A Void Ghost pendant! How did you...?$3#$b#Oh, wow.$7#$b#@... yes, I'll come live with you, if you like. But we have to keep it secret from everyone.#$b#I'll be at your house in a few days... okay?$h''
|-
| <samp>Strings/Characters</samp>
| <samp>MovieInvite_NoTheater</samp>
| The NPC's roommate proposal rejection text when you don't meet the requirements (''i.e.,'' min friendship + house upgrade level, y not already having a roommate/spouse). This is the same dialogue used when you can't invite someone to the movies.
|-
| <samp>Data/EngagementDialogue</samp>
| <samp>{{t|NPC name}}Roommate0</samp><br /><samp>{{t|NPC name}}Roommate1</samp>
| The NPC's normal dialogue after accepting the proposal, but before moving in. The <samp>Roommate0</samp> variant is always used on the day the NPC accepted; on subsequent days the NPC randomly chooses <samp>Roommate0</samp> or <samp>Roommate1</samp>. If the <samp>Roommate0</samp> variant isn't defined, the NPC will use the normal <samp>{{t|NPC Name}}0</samp> y <samp>{{t|NPC Name}}1</samp> keys. If the <samp>Roommate0</samp> variant is defined, <samp>Roommate1</samp> must be set too to avoid errors.<br />For example: ''@... I'm afraid we'll have to keep this a secret... Neither my people nor yours would accept us living together.''
|}

And after they move in:
{| class="wikitable"
|-
! content file
! key
! effect
|-
| <samp>Characters/Dialogue/MarriageDialogue{{t|NPC name}}Roommate</samp>
| ''all keys''
| Equivalent to <samp>Characters/Dialogue/MarriageDialogue{{t|NPC name}}</samp>, but only applies if the NPC is a roommate. If the file exists, it completely replaces the spouse version; otherwise the game defaults to the spouse version.
|-
| <samp>Characters/Dialogue/MarriageDialogue</samp>
| <samp>*Roommate</samp>
| Keys with the <samp>Roommate</samp> suffix take priority if they exist (only in this file, not the <samp>MarriageDialogue{{t|NPC name}}</samp> files).
|-
| <samp>Data/Festivals/*</samp>
| <samp>{{t|NPC name}}_roommate</samp>
| The NPC's normal dialogue at the festival if they're a roommate. If the key isn't defined, they'll use <samp>{{t|NPC name}}_spouse</samp> instead.
|}

And for other NPCs:
{| class="wikitable"
|-
! content file
! key
! effect
|-
| <samp>Characters/Dialogue/*</samp>
| <samp>*_roommate_*</samp>
| Equivalent to the <samp>*_inlaw_*</samp> infix in [[Modding:Dialogue#Generic dialogue|generic dialogue]], used if you're a roommate with the NPC. If not defined, the game will fallback to the non-infixed dialogue (it won't use the <samp>*_inlaw_*</samp> variant).
|}</li>
<li>Roommates will sleep in a [[Single Bed]] if one is available y unused in the house; otherwise they'll use a double bed like a normal spouse. (Krobus is an exception, since he doesn't sleep in a bed.)</li>
<li>Added [[Modding:Event data#Event preconditions|event preconditions]] to check whether the local player has a roommate (<samp>R</samp>) or doesn't have a roommate (<samp>Rf</samp>). This can be combined with <samp>O {{t|NPC name}}</samp> to check for a specific roommate, like <samp>R/O Abigail</samp>.</li>
</ul>

===Custom mail formatting===
You can now customize [[Modding:Mail data|mail]] y [[Secret Notes|secret notes]] by including three custom commands in the letter text (including the <samp>[]</samp> characters):
{| class="wikitable"
|-
! command
! effect
|-
| <samp>[letterbg {{t|index}}]</samp>
| Changes the default letter background to a vanilla background from <samp>LooseSprites/letterBG</samp>. The index can be 0 (default letter), 1 (Sandy's lined paper), 2 (Wizard style), or 3 (Krobus style). This will also set the default text color for that style, unless overridden by <samp>textcolor</samp>.
|-
| <samp>[letterbg {{t|asset name}} {{t|index}}]</samp>
| Changes the default letter background to the given texture. The asset name should match a texture containing two rows: one with 320x180 pixel letter background images, y one with 24x24 pixel button backgrounds shown behind attached items. The index is the sprite to use from those rows, starting at 0 for the first one.
|-
| <samp>[textcolor {{t|color}}]</samp>
| Changes the letter text color. The valid colors are <samp>black</samp>, <samp>blue</samp>, <samp>cyan</samp>, <samp>gray</samp>, <samp>green</samp>, <samp>orange</samp>, <samp>purple</samp>, <samp>red</samp>, y <samp>white</samp>.
|}

===Custom scarecrows===
You can now mark any placeable item as a [[scarecrow]] with two new [[Modding:Items#Context tags|context tags]]:

{| class="wikitable"
|-
! context tag
! effect
|-
| <samp>crow_scare</samp>
| Sets the item as a placeable scarecrow. If not set, the item is considered a scarecrow if its default name contains the substring <code>arecrow</code> (like before).
|-
| <samp>crow_scare_radius_{{t|radius}}</samp>
| If the item is a scarecrow, sets the radius that it covers. If not set, the scarecrow defaults to 17 if the default name contains the substring <code>Deluxe</code> y 9 otherwise.
|}

===Improved map seats===
{{main article|Modding:Maps#Sentarse en sillas que no sean muebles}}

Al definir asientos de mapa en <samp>Data\ChairTiles</samp> (ve [[Modding:Migrate to Stardew Valley 1.5#Sentarse en sillas que no sean muebles|la guía de migración]]), puedes poner el campo de tipo como <samp>custom {{t|separación_x}} {{t|separación_y}} {{t|extra_altura}}</samp> para sobrepasar los valores de altura y separación del código. Los tres valores se miden en baldosas (''e.j.,'' una separación X de 0.5 movería el lugar de asiento por media baldosa).

==See also==
* [[User:Pathoschild/Modding wishlist/Completed#Done in Stardew Valley 1.5.5|Modding wishlist items done in Stardew Valley 1.5.5]]

[[Category:Modding]]

[[zh:模组:迁移至游戏本体1.5.5]]
48

ediciones