Tutorial: Adding Seasonal Outfits via Appearances

From Stardew Modding Wiki
Jump to navigation Jump to search

If you want to add seasonal outfits for your NPC, there's two ways you can do this: the token way or the Appearances way. Appearances is a new code structure added in SDV 1.6, so if you're looking at an older NPC's code for reference, they'll most likely be using the token way. The main difference between the two is that the token way is simpler to code as long as you only want a basic set of outfits, while the Appearance way is more complicated but also _much_ more versatile and allows for specific outfits with specific conditions.

If you only want a basic seasonal set of one outfit per season, you can use the default Content Patcher {{Season}} token along with a single code block to handle all of your outfit changes:

{
	"LogName": Seasonal Portraits",
	"Action": "EditImage",
	"Target": "Portraits/NPCName",
	"FromFile": "assets/images/npcname_{{Season}}.png",
},

As long as your files are named "npcname_Spring.png", "npcname_Summer.png", etc., Content Patcher will automatically select the appropriate portrait when you're in that season. Easy, right?

Say you want something more complicated though. Maybe you want the character to change outfits depending on whether they're inside or outside, or you want special outfits for festivals, or you want a unique outfit for a specific heart event. To do this, you can use the Appearances system.

This is a basic Appearances code block:

{
	"Action": "EditData",
	"Target": "Data/Characters",
	"TargetField": ["NPCName", "Appearance"],
	"Entries":
	{
		"{{ModID}}.NPCName.Outfit1":
		{
			"Id": "{{ModId}}_NPCName_Outfit1",
			"Season": "spring",
			"Portrait": "Portraits/NPCName_Outfit1",
			"Sprite": "Characters/NPCName_Outfit1",
			"Indoors": true,
			"Outdoors": true,
			"IsIslandAttire": false,
			"Condition": "TRUE",
			"Precedence": 0,
			"Weight": 1
		},
	}
}

The Action, Target, and Entries fields should be familiar to you by now, but TargetField might be new. It can be a bit confusing to use but in a nutshell, it tells Content Patcher to only add to or edit the specific field (in this case, the Appearance field within the NPC's entry in Data/Characters). As far as seasonal outfits go though, all we need is to copy the TargetField from the example and replace NPCName with your character's disposition name, same as you would with the token example.

Let's go through the lines below that:

"{{ModID}}.NPCName.Outfit1,"

This line between Entries and the entry block is an ID of sorts. You can name it whatever you like, but for clarity, naming it similarly to the ID in the following entry block is helpful. {{ModID}} is a default Content Patcher token that will automatically fill in the unique ID from your manifest. For Outfit1, use something that references what the specific entry block is for, eg. Indoor, Spring, or EggFestival.

"Id": "{{ModId}}_NPCName_Outfit1",

As above, this is to identify the unique Appearance block so that the game is able to differentiate between multiple Appearances for your NPC. This is also the only mandatory line in an Appearance block.

"Season": "spring",

This line is optional and determines which season the outfit should be used in. Only one season can be listed, so if you want to use the same Appearance for multiple seasons, either leave this line out (for outfits that apply in all seasons) or duplicate the Appearance block (for outfits that apply in only two or three seasons).

"Portrait": "Portraits/NPCName_Outfit1", "Sprite": "Characters/NPCName_Outfit1",

These two lines define the portraits and character sprites for the Appearance. If you only need a portrait _or_ a sprite instead of both for an Appearance, you can remove the appropriate line. These should be treated like a Target field - the NPCName_Outfit1 doesn't have to match your filename because you'll create a Load code block later on that defines where the assets for these are drawn from.

"Indoors": true, "Outdoors": true,

These two determine whether an outfit is used inside buildings, outside buildings, or in any location. Both lines default to true if omitted, so if your Appearance doesn't have indoor/outdoor variations, you can remove these lines. This is also one of the main advantages of using the Appearances system, as it has a _much_ smaller performance impact compared to using the IsOutdoors CP token and "Update": "OnLocationChange".

"IsIslandAttire": false,

This is used to set an outfit as Ginger Island resort attire, much like loading NPCName_Beach portraits and sprites. If set to true, the NPC will _only_ wear this at the resort and won't wear it any other time.

"Condition": "TRUE",

This line is used to set particular conditions where the outfit should be used, which is the other main advantage of using the Appearances system. Conditions are updated whenever the NPC changes locations and are set via game state queries (GSQs), which can check a wide variety of different things. CP When conditions and dynamic tokens can also be used as GSQs as long as they're formatted as a token (see example below). If you only need outfits to change by season or indoor/outdoor checks, you can remove this line. A few commonly-used conditions for custom outfits are:

IS_EVENT (event ID}: Used during an event (see List of Vanilla Events IDs for a quick reference) or festival. Festivals use the format festival_(season)(day), e.g. the Egg Festival would be festival_spring13.

WEATHER TARGET (weather type): Used for weather-specific outfits. TARGET refers to the NPC's location, so NPCs on Ginger Island, Calico Desert, or a custom location with different weather will match their weather-specific outfits to the weather in their location rather than Pelican Town.

LOCATION_NAME TARGET (map name): Used for location-specific outfits. As with the previous, TARGET refers to the NPC's location, so their outfit won't change if the player is in that location but the NPC isn't.

One thing to note is that the TIME GSQ doesn't work for Appearances unless you also have a C# mod forcing a time-specific check, which has the same performance impact as using Content Patcher's Time When condition and "Update": "OnTimeChange".

"Precedence": 0,

If you have two or more Appearance blocks that meet the same conditions (for example, a spring outfit and a spring rain outfit), the Precedence line determines which one will take priority. Lower values take priority over higher numbers and negative numbers can be used. For reference, vanilla outfit changes such as Shane's Joja uniform and Maru's hospital uniform are set to "Precedence": -1000,. If none of your outfits have overlapping conditions, you can remove this line.

"Weight": 1

This is used when randomly selecting between two Appearances with the same conditions and the same precedence to determine the randomisation odds. For example, if you have two spring outfits but want one to only be used rarely, you could set "Weight": 5 for the common one and "Weight": 1 for the rare one, which would give them 5/6 and 1/6 odds respectively.

To put these together, here's a few example Appearances from Diverse Stardew Valley's Abigail:

	"DSV.Abigail.Indoor":
	{
		"Id": "{{ModId}}_Abigail_Outdoor",
		"Portrait": "Portraits/Abigail_Outdoor",
		"Sprite": "Characters/Abigail_Outdoor",
		"Indoors": false,
		"Outdoors": true,
		"Precedence": -110
	},
	"DSV.Abigail.EggFestival":
	{
		"Id": "{{ModId}}_Abigail_EggFestival",
		"Portrait": "Portraits/Abigail_EggFestival",
		"Sprite": "Characters/Abigail_EggFestival",
		"Indoors": false,
		"Condition": "IS_EVENT festival_spring13",
		"Precedence": -200
	},
	"DSV.Abigail.Maternity":
	{
		"Id": "{{ModId}}_Abigail_Maternity",
		"Portrait": "Portraits/Abigail_Maternity",
		"Sprite": "Characters/Abigail_Maternity",
		"Condition": "{{Pregnant |contains= Abigail}}, {{DSV.Core/ConfigValue:MaternitySprites |contains= True}}",
		"Precedence": -250
	},
	"DSV.Abigail.Swim":
	{
		"Id": "{{ModId}}_Abigail_Swim",
		"Portrait": "Portraits/Abigail_Swim",
		"Sprite": "Characters/Abigail_Swim",
		"Condition": "ANY \"LOCATION_NAME Target BathHouse_Pool BathHouse_MensLocker BathHouse_WomensLocker\" \"IS_EVENT festival_summer5, {{HasMod |contains= spacechase0.SurfingFestival}}\"",
		"Precedence": -150
	},

The first two are fairly straightforward - the Outdoor Appearance sets an outfit to be used when Abigail is outdoors but not indoors and the EggFestival Appearance sets an outfit to be used when Abigail is at the Egg Festival, with a higher precedence in order to take priority over the Outdoor Appearance. The second two get more complicated with conditions though. The Maternity Appearance sets an outfit to be used when Abigail is pregnant, using the default CP Pregnant token and one of DSV's custom C# tokens to check its MaternitySprites configuration option, and has a higher priority than all other Appearances. The Swim Appearance sets an outfit to be used if Abigail is either in the bathhouse or locker rooms OR if the player has Surfing Festival installed and Abigail is at the Surfing Festival.

The final part of Appearances is to Load any portraits or sprites set in an Appearance block. Don't forget this step! If your assets aren't Loaded, none of your Appearances will work. This is done in the same way that you Load your NPC's base portraits and sprites:

{
	"LogName": Seasonal Portraits - Appearance Load",
	"Action": "Load",
	"Target": "Portraits/NPCName_Outfit1",
	"FromFile": "assets/images/NPCName_Outfit1.png",
},

The Appearance assets can then be edited via EditImage just like any other portrait or sprite, which opens up further customisation possibilities. It can be confusing at first, but Appearances are much more flexible and versatile once you get the hang of them.