This document lists the tokens available in Content Patcher packs.
See the main README for other info.
- Introduction
- Global tokens
- Global input arguments
- Player config
- Randomization
- Advanced
- Common values
- See also
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.
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).
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
orHasValue:{{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.
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 token values are defined by Content Patcher, so you can use them without doing anything else.
condition | purpose | |||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Day | The day of month. Possible values: any integer from 1 through 28. | # | ||||||||||||||||
DayEvent |
The festival or wedding happening today. Possible values:
|
# | ||||||||||||||||
DayOfWeek |
The day of week. Possible values: |
# | ||||||||||||||||
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: |
# | ||||||||||||||||
Time |
The in-game time of day, as a numeric value between "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
ℹ See update rate before using this token without specifying a location context. |
# | ||||||||||||||||
Year |
The year number (like |
# |
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
"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...
|
# | ||||||||||||||||||||||||
HasProfession |
The professions learned by the current or specified player. Possible values:
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
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 You can use Debug Mode to see location names in-game. |
# | ||||||||||||||||||||||||
HasWalletItem |
The special wallet items for the current player. Possible values:
|
# | ||||||||||||||||||||||||
IsMainPlayer |
Whether the current or specified player is the main player. Possible values:
|
# | ||||||||||||||||||||||||
IsOutdoors |
Whether the current or specified player is outdoors. Possible values: ℹ 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
Notes:
ℹ 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:
This can be used to get other info for the owner, like ℹ See update rate before using this token. |
# | ||||||||||||||||||||||||
PlayerGender |
The current or specified player's gender. Possible values: |
# | ||||||||||||||||||||||||
PlayerName |
The current or specified player's name. |
# | ||||||||||||||||||||||||
PreferredPet |
The current player's preferred pet. Possible values: |
# | ||||||||||||||||||||||||
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 |
# |
condition | purpose | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
ChildNames ChildGenders |
The names and genders ( These are listed in order of birth for use with the |
# | ||||||||||||||
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...
|
# | ||||||||||||||
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). |
# |
condition | purpose | |||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
FarmCave |
The farm cave type. Possible values: |
# | ||||||||||||||||||||||
FarmMapAsset |
The farm type's map asset name relative to the game's This is usually one of:
|
# | ||||||||||||||||||||||
FarmName | The name of the current farm. | # | ||||||||||||||||||||||
FarmType |
The farm type. This will be one of...
|
# | ||||||||||||||||||||||
IsCommunityCenterComplete |
Whether all bundles in the community center are completed. Possible values: |
# | ||||||||||||||||||||||
IsJojaMartComplete |
Whether the player bought a Joja membership and completed all Joja bundles. Possible values: |
# | ||||||||||||||||||||||
HavingChild |
The names of players and NPCs whose relationship has an active pregnancy or adoption. Player names
are prefixed with "When": {
"HavingChild": "{{spouse}}"
} Usage notes:
|
# | ||||||||||||||||||||||
Pregnant |
The players or NPCs who are currently pregnant. This is a subset of |
# |
condition | purpose | |||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Count |
Get the number of values currently contained by a token. For example, |
# | ||||||||||||
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 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,
The token takes optional arguments to change the rounding logic:
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 |
# |
condition | purpose | |||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Lowercase Uppercase |
Convert the input text to a different letter case:
|
# | ||||||||||||||||||||||||||||||||
Merge |
Combine any number of input values into one token. This can be used to search multiple tokens in a
"When": {
"Merge: {{Roommate}}, {{Spouse}}": "Krobus"
} Or combined with "{{Merge: {{TokenA}}, {{TokenB}}, {{TokenC}} |valueAt=0 }}" Note that you can also add literal values to the list, like |
# | ||||||||||||||||||||||||||||||||
PathPart |
Get part of a file/asset path, in the form {
"Action": "Load",
"Target": "Portraits/Abigail",
"FromFile": "assets/{{PathPart: {{Target}}, Filename}}.png" // assets/Abigail.png
} Given the path
See also |
# | ||||||||||||||||||||||||||||||||
Render |
Get the string representation of the input argument. This is mainly useful in "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}} }}!",
} |
# |
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 |
# | ||||||||||||||||||||||||||
HasFile |
Whether a file exists in the content pack folder given its path. Returns 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 |
# | ||||||||||||||||||||||||||
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 "When": {
"HasValue:{{spouse}}{{LocationName}}": "true"
} |
# | ||||||||||||||||||||||||||
i18n |
Get text from the content pack's |
# | ||||||||||||||||||||||||||
Language |
The game's current language. Possible values:
For custom languages added via |
# | ||||||||||||||||||||||||||
ModId |
The current content pack's unique ID (from the This is typically used to build unique string IDs. For example: "Id": "{{ModId}}_ExampleItem" |
# |
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 theTarget
field. - You can't create circular references. For example, you can use
{{FromFile}}
in theTarget
field and{{Target}}
in theFromFile
field, but not both at once.
condition | purpose | |||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
FromFile |
The patch's {
"Action": "EditImage",
"Target": "Characters/Abigail",
"FromFile": "assets/{{Season}}_abigail.png",
"When": {
"HasFile:{{FromFile}}": true
}
} |
# | ||||||||||||
Target TargetPathOnly TargetWithoutPath |
The patch's {
"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
See also |
# |
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, |
# | ||||
FormatAssetName |
Normalize an asset name into the form expected by the game. For example,
This has one optional argument:
There's no need to use this in |
# | ||||
InternalAssetKey |
Get a special asset key which lets the game load a file directly from your content pack, without
needing to 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 {
"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 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.
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"
}
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 |
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.
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.
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.
Random
tokens are...
-
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.
-
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 aRandom
token, you can't just copy its value into aHasFile
field to check if the file exists, sinceRandom
may return a different choice in each field.
To keep multiple
Random
tokens in sync, see pinned keys below. - If a patch has multiple
-
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" }
-
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.
- 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:
Note that
{{Random: a, b, c |key={{Time}} }}
{{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}} }}
- 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; everyRandom
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
- 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
andWhen
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 aWhen
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.
- 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.
-
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
orNOT IN
a list:"Query: '{{spouse}}' IN ('Abigail', 'Leah', 'Maru')": true
-
Check text against a prefix/postfix using the
LIKE
orNOT 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 butLIKE 1
will return an error)."Query: '{{spouse}}' LIKE 'Abig*'": 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" } } ] }
- Author guide for other actions and options
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:
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:
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"
}
]
}
A query expression is an arbitrary set of arithmetic and logical expressions which can be
evaluated into a number, true
/false
value, or text.
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.
Query expressions are very powerful, but you should be aware of the caveats:
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}}"
} |
The supported operators are listed below.
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:
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}}"
}
}
]
}
These are predefined values used in tokens, linked from the token documentation above as needed.
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. |
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 . |