Skip to content

Latest commit

 

History

History
1998 lines (1587 loc) · 55.4 KB

File metadata and controls

1998 lines (1587 loc) · 55.4 KB

author guide

This document lists the tokens available in Content Patcher packs.

See the main README for other info.

Contents

Introduction

Overview

A token is a named container which has predefined values.

For example, season (the token) may contain spring, summer, fall, or winter (the value). Here's a dialogue which includes the current season name:

"Entries": {
   "fri": "It's a beautiful {{season}} day!" // It's a beautiful Spring day!
}

Tokens can be used as placeholders in text (like the above example) or as patch conditions. You can use player config, global token values, and dynamic token values as tokens.

Placeholders

You can use tokens in text by putting two curly brackets around the token name, which will be replaced with the actual value automatically.

Token placeholders can be used in most fields (the documentation for each field will specify), and they're not case-sensitive (so {{season}} and {{SEASON}} are the same thing). Patches will be disabled automatically if a token they use isn't currently available.

For example, this gives the farmhouse a different appearance in each season:

{
    "Action": "EditImage",
    "Target": "Buildings/houses",
    "FromFile": "assets/{{season}}_house.png" // assets/spring_house.png, assets/summer_house.png, etc
}

Tokens which return a single value (like {{season}}) are most useful in placeholders, but multi-value tokens will work too (they'll show a comma-delimited list).

Conditions

You can make a patch conditional by adding a When field, which can list any number of conditions. Each condition has...

  • A key containing a token without the outer curly braces, like Season or HasValue:{{spouse}}. The key is not case-sensitive.
  • A value containing the comma-separated values to match, like spring, summer. If the key token returns any of these values, the condition matches. This field supports tokens and is not case-sensitive.

For example, this changes the house texture only in spring or summer in the first year:

{
    "Action": "EditImage",
    "Target": "Buildings/houses",
    "FromFile": "assets/{{season}}_house.png",
    "When": {
        "Season": "spring, summer",
        "Year": "1"
    }
}

Each condition is true if any of its values match, and the patch is applied if all of its conditions match.

Input arguments

An input argument or input is a value you give to the token within the {{...}} braces. Input can be positional (an unnamed list of values) or named. Argument values are comma-separated, and named arguments are pipe-separated.

For example, {{Random: a, b, c |key=some, value |example }} has five arguments: three positional values a, b, c; a named key argument with values some and value; and a named example argument with an empty value.

Some tokens recognise input arguments to change their output, which are documented in the sections below. For example, the Uppercase token makes its input uppercase:

"Entries": {
   "fri": "It's a beautiful {{uppercase: {{season}}}} day!" // It's a beautiful SPRING day!
}

There are also global input arguments which are handled by Content Patcher, so they work with any token.

Global tokens

Global token values are defined by Content Patcher, so you can use them without doing anything else.

Date and weather

condition purpose  
Day The day of month. Possible values: any integer from 1 through 28. #
DayEvent

The festival or wedding happening today. Possible values:

  • wedding (current player is getting married);
  • dance of the moonlight jellies;
  • egg festival;
  • feast of the winter star;
  • festival of ice;
  • flower dance;
  • luau;
  • stardew valley fair;
  • spirit's eve;
  • a custom festival name.
#
DayOfWeek

The day of week. Possible values: Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, and Sunday.

#
DaysPlayed The total number of in-game days played for the current save (starting from one when the first day starts). #
Season

The season name. Possible values: Spring, Summer, Fall, and Winter.

#
Time

The in-game time of day, as a numeric value between 0600 (6am) and 2600 (2am before sleeping). This can also be used with range tokens:

"When": {
   "Time": "{{Range: 0600, 2600}}"
}

ℹ See update rate before using this token.

#
Weather

The weather type in the current world area (or the area specified with a LocationContext argument). Possible values:

value meaning
Sun The weather is sunny (including festival/wedding days). This is the default weather if no other value applies.
Rain Normal rain is falling, but without lightning.
Storm Normal rain is falling with lightning.
GreenRain Green rain is falling.
Snow Snow is falling.
Wind The wind is blowing with visible debris (e.g. flower petals in spring and leaves in fall).
custom For custom weathers defined by a mod, the weather ID.

ℹ See update rate before using this token without specifying a location context.

#
Year

The year number (like 1 or 2).

#

Player

condition purpose  
DailyLuck

The daily luck for the current or specified player.

This is a decimal value usually between -0.1 and 0.1. This cannot be compared using the {{Range}} token, which produces a range of integer values. The value can only be safely compared using query expressions. For example:

"When": {
   "Query: {{DailyLuck}} < 0": true // spirits unhappy today
}
#
FarmhouseUpgrade

The farmhouse upgrade level for the current or specified player. The normal values are 0 (initial farmhouse), 1 (adds kitchen), 2 (add children's bedroom), and 3 (adds cellar). Mods may add upgrade levels beyond that.

#
HasActiveQuest

The active quest IDs in the current or specified player's quest list. See Modding:Quest data on the wiki for valid quest IDs.

#
HasCaughtFish

The fish IDs caught by the current or specified player. See object IDs on the wiki.

#
HasConversationTopic

The active conversation topics for the current or specified player.

#
HasCookingRecipe

The cooking recipes known by the current or specified player.

#
HasCraftingRecipe

The crafting recipes known by the current or specified player.

#
HasDialogueAnswer

The response IDs for answers to question dialogues by the current or specified player.

#
HasFlag

The flags set for the current or specified player. That includes...

  • letter IDs sent to the player (including letters they haven't read, or those added to the mailbox for tomorrow);
  • non-letter mail flags (used to track game info);
  • world state IDs.

See useful flags on the wiki.

#
HasProfession

The professions learned by the current or specified player.

Possible values:

  • Combat skill: Acrobat, Brute, Defender, Desperado, Fighter, Scout.
  • Farming skill: Agriculturist, Artisan, Coopmaster, Rancher, Shepherd, Tiller.
  • Fishing skill: Angler, Fisher, Mariner, Pirate, Luremaster, Trapper.
  • Foraging skill: Botanist, Forester, Gatherer, Lumberjack, Tapper, Tracker.
  • Mining skill: Blacksmith, Excavator, Gemologist, Geologist, Miner, Prospector.

Custom professions added by a mod are represented by their integer profession ID.

#
HasReadLetter

The letter IDs opened by the current or specified player. A letter is considered 'opened' if the letter UI was shown.

#
HasSeenEvent

The event IDs seen by the current or specified player, matching IDs in the Data/Events files.

You can use Debug Mode to see event IDs in-game.

#
HasVisitedLocation

The location internal names which the current or specified player have previously visited, matching IDs in the Data/Locations file.

You can use Debug Mode to see location names in-game.

#
HasWalletItem

The special wallet items for the current player.

Possible values:

flag meaning
DwarvishTranslationGuide Unlocks speaking to the Dwarf.
RustyKey Unlocks the sewers.
ClubCard Unlocks the desert casino.
KeyToTheTown Allows access to all buildings in town, at any time of day.
SpecialCharm Permanently increases daily luck.
SkullKey Unlocks the Skull Cavern and the Saloon's Junimo Kart machine.
MagnifyingGlass Unlocks the ability to find secret notes.
DarkTalisman Unlocks the Witch's Swamp.
MagicInk Unlocks magical buildings and dark shrines.
BearsKnowledge Increases sell price of blackberries and salmonberries.
SpringOnionMastery Increases sell price of spring onions.
#
IsMainPlayer

Whether the current or specified player is the main player. Possible values: true, false.

#
IsOutdoors

Whether the current or specified player is outdoors. Possible values: true, false.

ℹ See update rate before using this token.

#
LocationContext

The general world area recognized by the game containing the current or specified player.

Possible values:

ℹ See update rate before using this token.

#
LocationName
LocationUniqueName

The internal name of the current or specified player's current location, like FarmHouse or Town. You can see the name for the current location using Debug Mode or patch summary.

Notes:

  • Temporary festival maps always have the location name "Temp".
  • LocationName and LocationUniqueName are identical except inside constructed buildings, cabins, and farmhand cellars. For example, a coop might have LocationName "Deluxe Coop" and LocationUniqueName "Coop7379e3db-1c12-4963-bb93-23a1323a25f7". The LocationUniqueName can be used as the target location for warp properties.

ℹ See update rate before using this token.

#
LocationOwnerId

The unique ID of the player who owns the current or specified player's location, if applicable.

This works for these locations:

location owner
farmhouse main player
island house main player
cabin linked farmhand
cellar same as the cabin/farmhouse it's linked to
farm building player who constructed it

This can be used to get other info for the owner, like {{PlayerName: {{LocationOwnerId}}}}.

ℹ See update rate before using this token.

#
PlayerGender

The current or specified player's gender. Possible values: Female, Male.

#
PlayerName

The current or specified player's name.

#
PreferredPet

The current player's preferred pet. Possible values: Cat, Dog.

#
SkillLevel

The current player's skill levels. You can specify the skill level as an input argument like this:

"When": {
   "SkillLevel:Combat": "1, 2, 3" // combat level 1, 2, or 3
}

The valid skills are Combat, Farming, Fishing, Foraging, Luck (unused in the base game), and Mining.

#

Relationships

condition purpose  
ChildNames
ChildGenders

The names and genders (Female or Male) for the current or specified player's children.

These are listed in order of birth for use with the valueAt argument. For example, {{ChildNames |valueAt=0}} and {{ChildGenders |valueAt=0}} is the name and gender of the oldest child.

#
Hearts

The player's heart level with a given NPC. You can specify the character name as an input argument (using their English name regardless of translations), like this:

"When": {
   "Hearts:Abigail": "10, 11, 12, 13"
}
#
Relationship

The player's relationship with a given NPC or player. You can specify the character name as part of the key (using their English name regardless of translations), like this:

"When": {
   "Relationship:Abigail": "Married"
}

The valid relationship types are...

value meaning
Unmet The player hasn't talked to the NPC yet.
Friendly The player talked to the NPC at least once, but hasn't reached one of the other stages yet.
Dating The player gave them a bouquet.
Engaged The player gave them a mermaid's pendant, but the marriage hasn't happened yet.
Married The player married them.
Divorced The player married and then divorced them.
#
Roommate

The name of the current or specified player's NPC roommate (using their English name regardless of translations).

#
Spouse

The name of the current or specified player's NPC spouse (using their English name regardless of translations).

#

World

condition purpose  
FarmCave

The farm cave type. Possible values: None, Bats, Mushrooms.

#
FarmMapAsset

The farm type's map asset name relative to the game's Content/Maps folder.

This is usually one of:

farm type value
Standard Farm
Beach Farm_Island
Forest Farm_Foraging
Four Corners Farm_FourCorners
Hill-top Farm_Mining
Meadowlands Farm_Ranching
Riverland Farm_Fishing
Wilderness Farm_Combat
custom type The MapName value in Data/AdditionalFarms.
invalid type Farm
#
FarmName The name of the current farm. #
FarmType

The farm type. This will be one of...

value description
Standard
Beach
FourCorners
Forest
Hilltop
Riverland
Wilderness
A farm type from the base game.
custom farm ID A custom farm type, using the ID value from the mod's farm data.
Custom (rare) A custom farm type from mods using an old approach for custom farm types.
#
IsCommunityCenterComplete

Whether all bundles in the community center are completed. Possible values: true, false.

#
IsJojaMartComplete

Whether the player bought a Joja membership and completed all Joja bundles. Possible values: true false.

#
HavingChild

The names of players and NPCs whose relationship has an active pregnancy or adoption. Player names are prefixed with @ to avoid ambiguity with NPC names. For example, to check if the current player is having a child:

"When": {
    "HavingChild": "{{spouse}}"
}

Usage notes:

  • "HavingChild": "@{{playerName}}" and "HavingChild": "{{spouse}}" are equivalent for this token.
  • See also the Pregnant token.
#
Pregnant

The players or NPCs who are currently pregnant. This is a subset of HavingChild that only applies to the female partner in heterosexual relationships. (Same-sex partners adopt a child instead.)

#

Number manipulation

condition purpose  
Count

Get the number of values currently contained by a token. For example, {{Count:{{HasActiveQuest}}}} is the number of currently active quests.

#
Query

Evaluate arbitrary arithmetic and logical operations; see query expressions for more info.

#
Range

A list of integers between the specified min/max integers (inclusive). This is mainly meant for comparing values; for example:

"When": {
   "Hearts:Abigail": "{{Range: 6, 14}}" // equivalent to "6, 7, 8, 9, 10, 11, 12, 13, 14"
}

You can use tokens for the individual numbers (like {{Range:6, {{MaxHearts}}}}) or both (like {{Range:{{FriendshipRange}}}}), as long as the final parsed input has the form min, max.

To minimise the possible performance impact, the range can't exceed 5000 numbers and should be much smaller if possible.

#
Round

An approximation of the input number with fewer fractional digits.

In its default form, this just rounds to the nearest whole number. For example, {{Round: 2.1 }} results in 2, and {{Round: 2.5555 }} results in 3.

The token takes optional arguments to change the rounding logic:

usage result description
Round(2.5555) 3 Round to the nearest whole number.
Round(2.5555, 2) 2.56 Round to the nearest value with the given number of fractional digits.
Round(2.5555, 2, down) 2.55 Round up or down (defaults to half rounded to even if not specified).

This is mainly useful in combination with query expressions. For example, monster HP must be a whole number, so this rounds the result of a calculation to the nearest whole number:

{
  "Action": "EditData",
  "Target": "Data/Monsters",
  "Fields": {
    "Green Slime": {
      "0": "{{Round: {{Query: {{multiplier}} * 2.5 }} }}",
    }
  }
}

You can use tokens in the individual fields (like {{Round: {{value}}, 2}}) or for multiple fields at once (like {{Round: {{Settings}}}} where {{Settings}} = 2.5, 3, up), as long as the final parsed input matches one of the above forms.

#

String manipulation

condition purpose  
Lowercase
Uppercase

Convert the input text to a different letter case:

Lowercase

Change to all small letters.
Example: {{Lowercase:It's a warm {{Season}} day!}}it's a warm summer day!

Uppercase

Change to all capital letters.
Example: {{Uppercase:It's a warm {{Season}} day!}}IT'S A WARM SUMMER DAY!

#
Merge

Combine any number of input values into one token. This can be used to search multiple tokens in a When block:

"When": {
   "Merge: {{Roommate}}, {{Spouse}}": "Krobus"
}

Or combined with valueAt to get the first non-empty value from a list of tokens:

"{{Merge: {{TokenA}}, {{TokenB}}, {{TokenC}} |valueAt=0 }}"

Note that you can also add literal values to the list, like {{Merge: {{Roommate}}, Krobus, Abigail }}.

#
PathPart

Get part of a file/asset path, in the form {{PathPart: <path>, <part to get>}}. For example:

{
   "Action": "Load",
   "Target": "Portraits/Abigail",
   "FromFile": "assets/{{PathPart: {{Target}}, Filename}}.png" // assets/Abigail.png
}

Given the path assets/portraits/Abigail.png, you can specify...

  • A fragment type:

    part value description example
    DirectoryPath The path without the file name. assets/portraits
    FileName The file name (including the extension, if any). Abigail.png
    FileNameWithoutExtension The file name (excluding the extension). Abigail
  • Or an index position from the left:

    part value example
    0 assets
    1 portraits
    2 Abigail.png
    3 empty value
  • Or a negative index to search from the right:

    part value example
    -1 Abigail.png
    -2 portraits
    -3 assets
    -4 empty value

See also TargetPathOnly and TargetWithoutPath, which simplify a very common version of this.

#
Render

Get the string representation of the input argument. This is mainly useful in When blocks to compare the rendered value directly (instead of comparing token set values):

"When": {
   "Render:{{season}} {{day}}": "spring 14"
}

This isn't needed in other contexts, where you can use token placeholders directly. For example, these two entries are equivalent:

"Entries": {
   "Mon": "It's a lovely {{season}} {{day}}!",
   "Mon": "It's a lovely {{Render: {{season}} {{day}} }}!",
}
#

Metadata

These tokens provide meta info about tokens, content pack files, installed mods, and the game state.

condition purpose  
FirstValidFile

Get the first path which matches a file in the content pack folder, given a list of file paths. You can specify any number of files.

Each file path must be relative to the content pack's main folder, and can't contain ../.

For example:

// from `assets/<language>.json` if it exists, otherwise `assets/default.json`
"FromFile": "{{FirstValidFile: assets/{{language}}.json, assets/default.json }}"
#
HasMod

The installed mod IDs (matching the UniqueID field in their manifest.json).

#
HasFile

Whether a file exists in the content pack folder given its path. Returns true or false.

The file path must be relative to the content pack's main folder, and can't contain ../.

For example:

"When": {
  "HasFile:assets/{{season}}.png": "true"
}

If the input has commas like HasFile: a, b.png, they're treated as part of the filename.

#
HasValue

Whether the input argument is non-blank. For example, to check if the player is married to anyone:

"When": {
  "HasValue:{{spouse}}": "true"
}

This isn't limited to a single token. You can pass in any tokenized string, and HasValue will return true if the resulting string is non-blank:

"When": {
  "HasValue:{{spouse}}{{LocationName}}": "true"
}
#
i18n

Get text from the content pack's i18n translation files. See the translation documentation for more info.

#
Language

The game's current language. Possible values:

code meaning
de German
en English
es Spanish
fr French
hu Hungarian
it Italian
ja Japanese
ko Korean
pt Portuguese
ru Russian
tr Turkish
zh Chinese

For custom languages added via Data/AdditionalLanguages, the token will contain their LanguageCode value.

#
ModId

The current content pack's unique ID (from the UniqueID field in its manifest.json).

This is typically used to build unique string IDs. For example:

"Id": "{{ModId}}_ExampleItem"
#

Field references

These tokens contain field values for the current patch. For example, {{FromFile}} is the current value of the FromFile patch field.

These have some restrictions:

  • They're only available in a patch block directly (e.g. they won't work in dynamic tokens).
  • They can't be used in their source field. For example, you can't use {{Target}} in the Target field.
  • You can't create circular references. For example, you can use {{FromFile}} in the Target field and {{Target}} in the FromFile field, but not both at once.
condition purpose  
FromFile

The patch's FromFile field value for the current asset. Path separators are normalized for the OS. This is mainly useful for checking if the path exists:

{
   "Action": "EditImage",
   "Target": "Characters/Abigail",
   "FromFile": "assets/{{Season}}_abigail.png",
   "When": {
      "HasFile:{{FromFile}}": true
   }
}
#
Target
TargetPathOnly
TargetWithoutPath

The patch's Target field value for the current asset. Path separators are normalized for the OS. This is mainly useful for patches which specify multiple targets:

{
   "Action": "EditImage",
   "Target": "Characters/Abigail, Characters/Sam",
   "FromFile": "assets/{{TargetWithoutPath}}.png" // assets/Abigail.png *or* assets/Sam.png
}

The difference between the three tokens is the part they return. For example, given the target value Characters/Dialogue/Abigail:

token part returned example
Target The full path. Characters/Dialogue/Abigail
TargetPathOnly The part before the last separator. Characters/Dialogue
TargetWithoutPath The part after the last separator. Abigail

See also PathPart for more advanced scenarios.

#

Specialized

These are advanced tokens meant to support some specific situations.

condition purpose  
AbsoluteFilePath

Get the absolute path for a file in your content pack's folder, given its path relative to the content pack's main folder (which can't contain ../).

For example, for a player with a default Windows Steam install, {{AbsoluteFilePath: assets/portraits.png}} will return a value similar to C:\Program Files (x86)\Steam\steamapps\common\Stardew Valley\Mods\[CP] YourMod\assets\portraits.png.

#
FormatAssetName

Normalize an asset name into the form expected by the game. For example, {{FormatAssetName: Data/\\///Achievements/}} returns a value like Data/Achievements.

This has one optional argument:

argument effect
separator The folder separator to use in the asset name instead of the default /. This is only needed when adding the path to a /-delimited field, like `{{FormatAssetName: {{assetKey}}

There's no need to use this in Target fields, which are normalized automatically.

#
InternalAssetKey

Get a special asset key which lets the game load a file directly from your content pack, without needing to Load it into a new Content asset.

For example, you can use this to provide the textures for a custom farm type:

{
    "Format": "2.4.0",
    "Changes": [
        {
            "Action": "EditData",
            "Target": "Data/AdditionalFarms",
            "Entries": {
                "{{ModId}}_FarmId": {
                    "IconTexture": "{{InternalAssetKey: assets/icon.png}}",}
            }
        }
    ]
}

Note that other content packs can't target an internal asset key (which is why it's internal). If you need to let other content packs edit it, you can use Action: Load to create a new asset for it, then use that asset name instead. When doing this, using the unique string ID convention is strongly recommended to avoid conflicts. For example:

{
    "Format": "2.4.0",
    "Changes": [
        {
            "Action": "EditData",
            "Target": "Data/AdditionalFarms",
            "Entries": {
                "{{ModId}}_FarmId": {
                    "IconTexture": "Mods/{{ModId}}/FarmIcon",}
            }
        },
        {
            "Action": "Load",
            "Target": "Mods/{{ModId}}/FarmIcon",
            "FromFile": "assets/icon.png"
        }
    ]
}
#

Global input arguments

Global input arguments are handled by Content Patcher itself, so they work with all tokens (including mod-provided tokens). If you use multiple input arguments, they're applied sequentially in left-to-right order.

contains

The contains argument lets you search a token's values. It returns true or false depending on whether the token contains any of the given values. This is mainly useful for logic in conditions:

// player has blacksmith OR gemologist
"When": {
   "HasProfession": "Blacksmith, Gemologist"
}

// player has blacksmith AND gemologist
"When": {
   "HasProfession |contains=Blacksmith": "true",
   "HasProfession |contains=Gemologist": "true"
}

// NOT year 1
"When": {
   "Year |contains=1": "false"
}

This can also be used in placeholders. For example, this will load a different file depending on whether the player has the Gemologist profession:

{
    "Action": "EditImage",
    "Target": "Buildings/houses",
    "FromFile": "assets/gems-{{HasProfession |contains=Gemologist}}.png" // assets/gems-true.png
}

You can specify multiple values, in which case it returns whether any of them match:

// player has blacksmith OR gemologist
"When": {
   "HasProfession |contains=Blacksmith, Gemologist": "true"
}

// player has neither blacksmith NOR gemologist
"When": {
   "HasProfession |contains=Blacksmith, Gemologist": "false"
}

valueAt

The valueAt argument gets one value from a token at the given position (starting at zero for the first value). If the index is outside the list, this returns an empty list.

This depends on the token's order, which you can check with the patch summary unsorted console command. Some tokens like ChildNames have a consistent order (which will be documented in the info for each token); most others like HasFlag are listed in the order they're defined in the game data, which may change from one save to the next.

For example:

token value
{{ChildNames}} Angus, Bob, Carrie
{{ChildNames |valueAt=0}} Angus
{{ChildNames |valueAt=1}} Bob
{{ChildNames |valueAt=2}} Carrie
{{ChildNames |valueAt=3}} empty list

You can use a negative index to get a value starting from the end of the list, where -1 is the last item. For example:

token value
{{ChildNames}} Angus, Bob, Carrie
{{ChildNames |valueAt=-1}} Carrie
{{ChildNames |valueAt=-2}} Bob
{{ChildNames |valueAt=-3}} Angus
{{ChildNames |valueAt=-4}} empty list

Custom input value separator

By default input arguments are comma-separated, but sometimes it's useful to allow commas in the input values. You can use the inputSeparator argument to use a different separator (which can be one or multiple characters).

For example, this can allow commas in random dialogue:

"Entries": {
   "fri": "{{Random: Hey, how are you? @@ Hey, what's up? |inputSeparator=@@}}"

Note: you should avoid the {}|=: characters in separators, even if they're technically valid. The behavior when separators conflict with token syntax depends on implementation details that may change from one Content Patcher version to the next.

Player config

You can let players configure your mod using a config.json file. If the player has Generic Mod Config Menu installed, they'll also be able to configure the mod through an in-game options menu.

For example, you can use config values as tokens and conditions:

{
    "Format": "2.4.0",
    "ConfigSchema": {
        "EnableJohn": {
            "AllowValues": "true, false",
            "Default": true
        }
    },
    "Changes": [
        {
            "Action": "Include",
            "FromFile": "assets/john.json",
            "When": {
                "EnableJohn": true
            }
        }
    ]
}

See the player config documentation for more info.

Randomization

Overview

You can randomize values using the Random token:

{
   "Action": "Load",
   "Target": "Characters/Abigail",
   "FromFile": "assets/abigail-{{Random:hood, jacket, raincoat}}.png"
}

And you can optionally use pinned keys to keep multiple Random tokens in sync (see below for more info):

{
   "Action": "Load",
   "Target": "Characters/Abigail",
   "FromFile": "assets/abigail-{{Random:hood, jacket, raincoat |key=outfit}}.png",
   "When": {
      "HasFile:assets/abigail-{{Random:hood, jacket, raincoat |key=outfit}}.png": true
   }
}

This token is dynamic and may behave in unexpected ways; see below to avoid surprises.

Unique properties

Random tokens are...

  1. Dynamic. Random tokens rechoose when they're evaluated, generally when a new day starts. The randomness is seeded with the game seed + in-game date + input string, so reloading the save won't change which choices were made.

  2. Independent. Each Random token changes separately. In particular:

    • If a patch has multiple Target values, Random may have a different value for each target.
    • If a FromFile field has a Random token, you can't just copy its value into a HasFile field to check if the file exists, since Random may return a different choice in each field.

    To keep multiple Random tokens in sync, see pinned keys below.

  3. Fair. Each option has an equal chance of being chosen. To load the dice, just specify a value multiple times. For example, 'red' is twice as likely as 'blue' in this patch:

    {
       "Action": "Load",
       "Target": "Characters/Abigail",
       "FromFile": "assets/abigail-{{Random:red, red, blue}}.png"
    }
  4. Bounded if the choices don't contain tokens. For example, you can use it in true/false contexts if all the choices are 'true' or 'false', or numeric contexts if all the choices are numbers.

  5. Update rate

    A Random token changes its choices on day start by default. If you want randomization to change within a day, you need to make two changes:

    • Specify a patch update rate so the patch itself updates more often.
    • Use a pinned key to set the seed to a value which changes more often. For example, this would change every time the in-game time changes:
      {{Random: a, b, c |key={{Time}} }}
      
      Note that {{Random}} tokens with the same key will synchronize their values. You can make the key unique to avoid that:
      {{Random: a, b, c |key=Abigail portraits {{Time}} }}
      

    Pinned keys

    Basic pinned keys:

    If you need multiple Random tokens to make the same choices (e.g. to keep an NPC's portrait and sprite in sync), you can specify a 'pinned key'. This is like a name for the random; every Random token with the same pinned key will make the same choice. (Note that list order does matter.)

    For example, this keeps Abigail's sprite and portrait in sync using abigail-outfit as the pinned key:

    {
       "Action": "Load",
       "Target": "Characters/Abigail, Portraits/Abigail",
       "FromFile": "assets/{{Target}}-{{Random:hood, jacket, raincoat |key=abigail-outfit}}.png"
    }

    You can use tokens in a pinned key. For example, this synchronizes values separately for each NPC:

    {
       "Action": "Load",
       "Target": "Characters/Abigail, Portraits/Abigail, Characters/Haley, Portraits/Haley",
       "FromFile": "assets/{{Target}}-{{Random:hood, jacket, raincoat |key={{TargetWithoutPath}}-outfit}}.png"
    }
    Advanced pinned keys:

    The pinned key affects the internal random number used to make a choice, not the choice itself. You can use it with Random tokens containing different values (even different numbers of values) for more interesting features.

    For example, this gives Abigail and Haley random outfits but ensures they never wear the same one:

    {
       "Action": "Load",
       "Target": "Characters/Abigail, Portraits/Abigail",
       "FromFile": "assets/{{Target}}-{{Random:hood, jacket, raincoat |key=outfit}}.png"
    },
    {
       "Action": "Load",
       "Target": "Characters/Haley, Portraits/Haley",
       "FromFile": "assets/{{Target}}-{{Random:jacket, raincoat, hood |key=outfit}}.png"
    }
    Okay, I'm confused. What the heck are pinned keys?

    Without pinned keys, each token will randomly choose its own value:

    {{Random: hood, jacket, raincoat}} = raincoat
    {{Random: hood, jacket, raincoat}} = hood
    {{Random: hood, jacket, raincoat}} = jacket

    If they have the same pinned key, they'll always be in sync:

    {{Random: hood, jacket, raincoat |key=outfit}} = hood
    {{Random: hood, jacket, raincoat |key=outfit}} = hood
    {{Random: hood, jacket, raincoat |key=outfit}} = hood

    For basic cases, you just need to know that same options + same key = same value.

    If you want to get fancy, then the way it works under the hood comes into play. Setting a pinned key doesn't sync the choice, it syncs the internal number used to make that choice:

    {{Random: hood, jacket, raincoat |key=outfit}} = 217437 modulo 3 choices = index 0 = hood
    {{Random: hood, jacket, raincoat |key=outfit}} = 217437 modulo 3 choices = index 0 = hood
    {{Random: hood, jacket, raincoat |key=outfit}} = 217437 modulo 3 choices = index 0 = hood

    You can use that in interesting ways. For example, shifting the values guarantees they'll never choose the same value (since same index = different value):

    {{Random: hood, jacket, raincoat |key=outfit}} = 217437 modulo 3 choices = index 0 = hood
    {{Random: jacket, raincoat, hood |key=outfit}} = 217437 modulo 3 choices = index 0 = jacket

    Advanced

    Dynamic tokens

    Dynamic tokens are defined in a DynamicTokens section of your content.json (see example below). Each block in this section defines the value for a token using these fields:

    field purpose
    Name The name of the token to use for tokens & condition.
    Value The value(s) to set. This can be a comma-delimited value to give it multiple values. This field supports tokens, including dynamic tokens defined before this entry.
    When (optional) Only set the value if the given conditions match. If not specified, always matches.

    Some usage notes:

    • You can list any number of dynamic token blocks.
    • If you list multiple blocks for the same token name, the last one whose conditions match will be used.
    • You can use tokens in the Value and When fields. That includes dynamic tokens if they're defined earlier in the list (in which case the last applicable value defined before this block will be used). Using a token in the value implicitly adds a When condition (so the block is skipped if the token is unavailable, like {{season}} when a save isn't loaded).
    • Dynamic tokens can't have the same name as an existing global token or player config field.

    For example, this content.json defines a custom {{style}} token and uses it to load different crop sprites depending on the weather:

    {
       "Format": "2.4.0",
       "DynamicTokens": [
          {
             "Name": "Style",
             "Value": "dry"
          },
          {
             "Name": "Style",
             "Value": "wet",
             "When": {
                "Weather": "rain, storm"
             }
          }
       ],
       "Changes": [
          {
             "Action": "Load",
             "Target": "TileSheets/crops",
             "FromFile": "assets/crop-{{style}}.png"
          }
       ]
    }

    Query expressions

    A query expression is an arbitrary set of arithmetic and logical expressions which can be evaluated into a number, true/false value, or text.

    Usage

    Query expressions are evaluated using the Query token. It can be used as a placeholder or condition, and can include nested tokens. Here's an example which includes all of those:

    {
       "Format": "2.4.0",
       "Changes": [
          {
             "Action": "EditData",
             "Target": "Characters/Dialogue/Abigail",
             "Entries": {
                "Mon": "Hard to imagine you only arrived {{query: {{DaysPlayed}} / 28}} months ago!"
             },
             "When": {
                "query: {{Hearts:Abigail}} >= 10": true
             }
          }
       ]
    }

    You can use text values in expressions if they're single-quoted (including tokens which return text):

    "Query: '{{Season}}' = 'spring'": true

    Expressions are case-insensitive, including when comparing text values.

    Caveats

    Query expressions are very powerful, but you should be aware of the caveats:

    • Query expressions have very little validation. An invalid expression generally won't show warnings ahead of time, it'll just fail when the patch is applied. Make sure to carefully test any content pack features which use expressions, and check new or edited expressions with patch parse.
    • Query expressions evaluate the expanded text. For example, if the player name contains a single-quote like D'Artagnan, then this expression will fail due to a syntax error:
      "Query: '{{PlayerName}}' LIKE 'D*'": true // 'D'Artagnan' LIKE 'D*'
    • Query expressions may return obscure or technical error messages when invalid.
    • Query expressions may make your content pack harder to read and understand.

    Consider using non-expression features instead where possible. For example:

    With query expression Without query expression
    "When": {
       "Query: {{Time}} >= 0600 AND {{Time}} <= 1200": true
    }
    "When": {
       "Time": "{{Range: 0600, 1200}}"
    }

    Operators

    The supported operators are listed below.

    • Perform arithmetic on numeric values (like 5 + 5):

      operator effect
      + addition
      - subtraction
      * multiplication
      / division
      % modulus
      () grouping
    • Compare two values (like 5 < 10):

      operator effect
      < less than
      <= less than or equal
      > more than
      >= more than or equal
      = equal
      <> not equal
    • Combine expressions using logical operators:

      operator effect
      AND both expressions are true, like {{Time}} >= 0600 AND {{Time}} <= 1200.
      OR one or both expressions are true, like {{Time}} <= 1200 OR {{Time}} >= 2400.
      NOT negate the following expression, like NOT {{Time}} > 1200.
    • Group sub-expressions using () to avoid an ambiguous order of operations:

      "{{Query}}: ({{Time}} >= 0600 AND {{Time}} <= 1200) OR {{Time}} > 2400": true
    • Check whether a value is IN or NOT IN a list:

      "Query: '{{spouse}}' IN ('Abigail', 'Leah', 'Maru')": true
    • Check text against a prefix/postfix using the LIKE or NOT LIKE operator. The wildcard * can only be at the start/end of the string, and it can only be used with quoted text (e.g. LIKE '1' will work but LIKE 1 will return an error).

      "Query: '{{spouse}}' LIKE 'Abig*'": true

    Mod-provided tokens

    SMAPI mods can add new tokens for content packs to use (see extensibility for modders), which work just like normal Content Patcher tokens. For example, this patch uses a token from Json Assets:

    {
       "Format": "2.4.0",
       "Changes": [
          {
             "Action": "EditData",
             "Target": "Data/NpcGiftTastes",
             "Entries": {
                "Universal_Love": "74 446 797 373 {{spacechase0.jsonAssets/ObjectId:item name}}",
             }
          }
       ]
    }

    To use a mod-provided token, at least one of these must be true:

    • The mod which provides the token is a required dependency of your content pack.
    • Or the patch using the token has an immutable (i.e. not using any tokens) HasMod condition which lists the mod:
      {
         "Format": "2.4.0",
         "Changes": [
            {
               "Action": "EditData",
               "Target": "Data/NpcGiftTastes",
               "Entries": {
                  "Universal_Love": "74 446 797 373 {{spacechase0.jsonAssets/ObjectId:item name}}",
               },
               "When": {
                  "HasMod": "spacechase0.jsonAssets"
               }
            }
         ]
      }

    Aliases

    An alias adds an optional alternate name for an existing token. This only affects your content pack, and you can use both the alias name and the original token name. This is mostly useful for custom tokens provided by other mods, which often have longer names.

    Aliases are defined by the AliasTokenNames field in content.json, where each key is the alternate name and the value is the original token name. For example:

    {
        "Format": "2.4.0",
        "AliasTokenNames": {
            "ItemID": "spacechase0.jsonAssets/ObjectId",
            "ItemSprite": "spacechase0.jsonAssets/ObjectSpriteSheetIndex"
        },
        "Changes": [
            {
                "Action": "EditData",
                "Target": "Data/NpcGiftTastes",
                "Entries": {
                    "Universal_Love": "74 446 797 373 {{ItemID: pufferchick}}"
                }
            }
        ]
    }

    When using Include patches, aliases automatically work in the included files too.

    The alias name can't match a global token or config token.

    Note: this aliases the token name, but you can alias the token value by using a dynamic token:

    {
        "Format": "2.4.0",
        "DynamicTokens": [
            {
                "Name": "PufferchickId",
                "Value": "{{spacechase0.jsonAssets/ObjectId: pufferchick}}"
            }
        ],
        "Changes": [
            {
                "Action": "EditData",
                "Target": "Data/NpcGiftTastes",
                "Entries": {
                    "Universal_Love": "74 446 797 373 {{PufferchickId}}"
                }
            }
        ]
    }

    Common values

    These are predefined values used in tokens, linked from the token documentation above as needed.

    Location context

    Some tokens let you choose which world area to get info for using an input argument like this:

    example meaning
    {{Weather}}
    {{Weather: current}}
    Get weather for the current location.
    {{Weather: island}} Get the weather on Ginger Island.
    {{Weather: valley}} Get the weather in the valley.

    The possible contexts are:

    value meaning
    current The context the current player is in. This is the default and doesn't need to be specified.
    island Locations on the Ginger Island.
    valley Any other location.

    Target player

    Some tokens let you choose which player's info to get using an input argument like this:

    example meaning
    {{HasFlag}}
    {{HasFlag: currentPlayer}}
    Get flags for the current player.
    {{HasFlag: hostPlayer}} Get flags for the host player.
    {{HasFlag: currentPlayer, hostPlayer}} Get flags for the current and host player(s).
    {{HasFlag: anyPlayer}} Get flags which any one or more players have.
    {{HasFlag: 3864039824286870457}} Get flags for the player with the unique multiplayer ID 3864039824286870457.

    The possible player types are:

    value meaning
    currentPlayer The current player who has the mod installed.
    hostPlayer The player hosting the multiplayer world. This is the same as currentPlayer in single-player or if the current player is hosting.
    anyPlayer The combined values for all players, regardless of whether they're online.
    player ID The unique multiplayer ID for a specific player, like 3864039824286870457.

    See also