Dynamic modding

Version

Please help with verifying or updating older sections of this article. At least some were last verified for version 3.5.

This article is for the PC version of Stellaris only.

This page is about the abstract but super flexible modding features, namely effects and conditions as well as scripted localization and scripted variables.

## Effects

Effects are statements to be executed and affect game status. Many game objects and event modding use this for dynamic effects. Head to effects for full list of effect statements.

Effects must be executed under a scope. Head to scopes for details.

### Scripted effects

There are more than singular statements of effects to be used for an effect. Scripted effects are moddable blocks of effect statements to be used as an effect. They are defined at "`common/scripted_effects/xyz.txt`".

#### How to use

A scripted effect consists a block of effect statements and/or other scripted effects. That’s it:

```
example_scripted_effect = {
	shift_ethic = ethic_materialist
	…
}

```

Defined scripted effects can be used as though they were effects. For instance, "example\_scripted\_effect" can be called with `example_scripted_effect = yes`.

#### Parameters

Scripted effects can have parameters. All parameters are strings and will be dynamically inserted into the scripted effects.

For example, a scripted effect can be like this, so the empire will have their ethic shifted to materialist:

```
 # definition
 example\_scripted\_effect = {
 shift\_ethic = ethic\_$ETHIC$
 }

 # calling
 example\_scripted\_effect = { ETHIC = materialist }

```

Or even like this, so the empire will have their ethic shifted to materialist twice:

```
 # definition
 example\_scripted\_effect = {
 while = {
 count = $COUNT$
 shift\_ethic = ethic\_$ETHIC$
 }
 }

 # calling
 example\_scripted\_effect = { ETHIC = materialist COUNT = 2 }

```

#### Parameter conditions

*Documentation file:* Stellaris/common/scripted\_effects/99\_advanced\_documentation.txt

You can also write a condition block for parameters with "double" square brackets, making the stuff within it only called if the parameter (here $homeworld$) is passed through in the effect call.

```
[[homeworld] <<<STUFF HERE>>>]

```

Example:

```
 last\_created\_species = {
 save\_global\_event\_target\_as = vaadwaurSpecies
 [[homeworld]set\_species\_homeworld = event\_target:tempHomeworld]
 }

```

Putting an exclamation mark at the beginning of the parameter will cause the block to only be called if the parameters *isn't* passed, or is set to no:

```
[[!homeworld] <<<STUFF HERE>>>]

```

You can also declare a fallback value in the parameter itself using the pipe symbol, e.g.:

```
 has\_global\_flag = crisis\_stage\_$STAGE|1$

```

The vanilla game (2.6) does not yet use much of this scripted syntax feature (introduced in patch 2.3). Only few examples can be found in:

```
common/scripted_effects/archaeology_event_effects.txt
common/scripted_triggers/00_scripted_triggers.txt

```

Instead, Star Trek mods like "New Civilisations" use this feature a little more often.

#### Inline math

Scripted effects and scripted triggers can also have `@\[ ... ]`, a simple inline math statement.

```
 inline\_math\_example = {
 add\_monthly\_resource\_mult = {
 resource = unity
 value = $COUNT|1$
 min = @\[ $COUNT|1$ \* 10 ]
 max = 99999999
 }
 }

```

This scripted effect will give the scoped empire X times their monthly unity income (up to 99,999,999 and down to X \* 10), where X is the parameter given as COUNT.

For example, `inline_math_example = { COUNT = 10 }` gives the scoped empire 10 times their monthly unity income (up to 99,999,999 and down to 100).

Inline math has a drawback. Only the **FIRST** `@\[ ... ]` statement in a scripted effect / trigger is correctly recognized and evaluated. If multiple inline math statements is needed anyway, create multiple scripted effects that call each other.

To the authoring of this entry there are 4 known functional operators for inline math statements:

“+”
Adds the number on the right to the number on the left.
“-”
Subtracts the number on the right from the number on the left.
“\*”
Multiplies the number on the left by the number on the right.
“/”
Divides the number on the left by the number on the right.
Any other attempted operator such as a `=` or `^` will result in the joining of the two sides. For example, if the statement `@\[ 4 = 2 ]` is ran, the resultant will be 42 to the effect.

```
 # If <condition A> is true, give the scoped empire twice the monthly unity income, otherwise once the monthly unity income.
 # If <condition B> is true, unity gained this way is reduced by -25%.
 inline\_math\_drawback = {
 if = {
 limit = { <condition A> }
 inline\_math\_drawback\_step\_2 = { COUNT = 2 }
 }
 else = {
 inline\_math\_drawback\_step\_2 = { COUNT = 1 }
 }
 }

 inline\_math\_drawback\_step\_2 = {
 if = {
 limit = { <condition B> }
 inline\_math\_drawback\_step\_3 = { COUNT = $COUNT$ MULT = 0.75 }
 }
 else = {
 inline\_math\_drawback\_step\_3 = { COUNT = $COUNT$ MULT = 1.0 }
 }
 }

 inline\_math\_drawback\_step\_3 = {
 inline\_math\_drawback\_step\_4 = {
 RESOURCE = unity
 COUNT = @\[ $COUNT$ \* $MULT$ ]
 }
 }

 inline\_math\_drawback\_step\_4 = {
 add\_monthly\_resource\_mult = {
 resource = $RESOURCE$
 value = $COUNT$
 min = @\[ $COUNT$ \* 100 ]
 max = 100000000
 }
 }

```

It should be noted however that if multiple inline math statements are required for your code you will have to execute them in a manner of one per scripted effect call. It is however possible to send an inline math statement as a parameter by wrapping it in a pair of quotations `"@\[ ... ]"`. Wrapping an inline math statement will allow for a scripted event to use multiple inline statements so long as the statements are a parameter to another effect, although it cannot send more than one statement as a parameter to an effect.

```
 # If <condition A> is true, give the scoped empire twice the unity income, otherwise once a static unity income.
 # If <condition B> is true, unity gained this way is reduced by -25%.
 inline\_math\_effect = {
 if = {
 limit = { <condition A> }
 inline\_math\_drawback\_step\_2 = { COUNT = 2 }
 }
 else = {
 inline\_math\_drawback\_step\_2 = { COUNT = 1 }
 }
 }

 # These inline statements won't run here allowing us to pick and chose which one we want, but it will autofill the $COUNT$ parameter in this statement.
 inline\_math\_drawback\_step\_2 = {
 if = {
 limit = { <condition B> }
 inline\_math\_drawback\_step\_3 = { Resource = unity Value = "@\[ $COUNT$ \* 0.75 \* 500]" }
 }
 else = {
 inline\_math\_drawback\_step\_3 = { Resource = unity Value = "@\[ $COUNT$ \* 500]" }
 }
 }

 inline\_math\_drawback\_step\_3 = {
 add\_resource = {
 $Resource$ = $Value$
 }
 }

```

#### Bracket Localisations

Scripted effects change how bracket localisations need to be formatted. As of 3.4, names that use bracket localisations need to be formatted as follows for `set_name` or a `name` property:

```
 name = {
 	key = "NAME\_Imperial\_Origin\_Empire"
 	variable\_string = "[origin\_imperial\_species.GetAdj]" # brackets optional inside a variable\_string
 	# use one variable\_string = "scope.GetX" per bracket command in the localisation string identified by the key
 }

```

However, when using bracket localisations in scripted effects, you need to either include two backslashes before the variable string, as follows:

```
 name = {
 	key = "NAME\_Imperial\_Origin\_Empire"
 	variable\_string = "\\[origin\_imperial\_species.GetAdj]" # use double slashes before the opening bracket, or omit brackets
 }

```

Or omit the brackets in the `variable_string`. Nothing else needs to be changed. Not doing the above will result in the bracket localisation simply not appearing.

## Conditions

Conditions are statements to be evaluated for a yes or no. Many game objects and event modding use this for dynamic conditions. Head to conditions for full list of condition statements.

Conditions must be checked on a scope. Head to scopes for details.

### Scripted triggers

Similarly, there are more than singular statements of conditions to be used for a condition. Scripted triggers are moddable blocks of condition statements to be used as a condition. They are defined at "`common/scripted_triggers/xyz.txt`".

#### How to use

Like scripted effects, a scripted trigger is a block of condition statements and/or other scripted triggers.

```
example_scripted_trigger = {
	has_ethic = ethic_materialist
	has_ethic = ethic_fanatic_materialist
	…
}

```

Defined scripted triggers can be used as though they were Conditions. For instance, "example\_scripted\_trigger" can be called with `example_scripted_trigger = <yes/no>`.

#### Parameters

Scripted triggers do also have parameters.

```
 # definition
 example\_scripted\_trigger = {
 has\_ethic = ethic\_$ETHIC$
 has\_ethic = ethic\_fanatic\_$ETHIC$
 }

 # calling
 example\_scripted\_trigger = { ETHIC = materialist }

```

A scripted trigger with parameters can't be called in `xyz = no` form, but can be called in `NOT = { … }` block.

## Scripted localization

Scripted localizations are defined at "`common/scripted_loc/xyz.txt`".

### How to use

First, define an instance.

```
defined_text = {
	name = GetAuthorityName
	text = {
		trigger = { has_authority = auth_democratic }
		localization_key = auth_democratic
	}
	text = {
		trigger = { has_authority = auth_oligarchic }
		localization_key = auth_oligarchic
	}
	…
}

```

Then go to the localisation files and just use `[<scope>.GetAuthorityName]` to call this scripted loc. This instance of scripted loc is designated to be called from country scopes, but there is actually no scope type limitations on scripted loc itself.

## Scripted variables

Scripted variables are defined at "`common/scripted_variables/xyz.txt`".

A scripted variable file **must** end in a blank or commented line.

### How to use

Scripted variables are no game objects. They are only `@` variables to be used from other game files. A game file can have its own `@` variables defined but those variables can't be used by other game files. However, scripted variables are shared through all game files.

For example, we can define a scripted variable like this:

```
@example = 2

```

And use it like this:

```
 example\_scripted\_effect = {
 	while = {
 		count = @example
 		shift\_ethic = ethic\_$ETHIC$
 	}
 }

```

Or this:

```
 example\_scripted\_effect = {
 while = {
 count = $COUNT$
 shift\_ethic = ethic\_$ETHIC$
 }
 }

```

```
 example\_scripted\_effect = { ETHIC = materialist COUNT = @example }

```

Modifiers can also have `@` variables for their numeric values.

## Modifiers

Since patch 3.0 there is a modifiers `multiplier` parameter for `add_modifier`, were you can multiply numeric values.

```
 effect = {
 add\_modifier = {
 modifier = soul\_diet1
 multiplier = 6
 days = 360
 }
 }

```

### Scripted Modifiers

*Documentation file:* Stellaris/common/scripted\_modifiers/00\_scripted\_modifiers.txt (introduced with patch 3.4)

You can create new scripted modifiers in `common/scripted_modifiers`. There are various settings available which will affect how it displays in tooltips.

Note that any modifier created there will do nothing by default. You need to manually give it effects. E.g. by putting '`mult = modifier:my_modifier`' in certain triggered modifiers or resource tables. See `01_ruler_jobs.txt/head_researcher` and `04_species_traits.txt/trait_charismatic` for examples.

#### How to use

Settings

`icon`: Name of file in `gfx\interface\icons\modifiers` (without the .dds). Default is "`mod_`" + key
`percentage`: Show as a % or not. Default: no
`min_mult`: Sets the minimum this modifier can be when used as a multiplier in the source code (so probably not relevant since this modifier will not be applied in the source code – but you could theoretically overwrite a code-generated modifier here). Default 0
`max_decimals`: Default 2
`good`: Sets if it registers as "good" (i.e. a positive number is green, a negative red). Default no.
`neutral`: Sets if no value is either good or bad (all is yellow). Default no.
`hidden`: Probably hides it in tooltips? Needs testing. Default no.
`no_diff`: not sure what this does either. Default no
`cap_zero_to_one`: ditto. Default no
`localize_with_value_key`: Expects you to put `$VALUE$` in the loc key (the number will be printed there). Default no
`category`: Sets the modifier category, which is sometimes used to determine whether it is applied to a certain object (so make sure this is set to what you want).
In other words, this is referring to the object that the modifier is read from. I.e. where you could get its value via check\_modifier\_value, for instance.
It should be set to the lowest possible place in the hierarchy, where country is the top, then planet would be in the middle, and pop would be at the bottom.
Possible values: all, pop, ship, station, fleet, country, army, leader, planet, component, pop\_faction (currently unused, do not use), deposit, megastructure, habitability, starbase, economic\_unit, system, trade, federation, espionage
Example:

```
pop\_job\_trade\_mult = {
 icon = mod\_trade\_value\_mult
 percentage = yes
 good = yes
 category = pop
}

```

## Flags

Flags are **boolean values** (flag is either present or not), which can be attached to the following scopes: leader, planet, country (first\_contact), fleet, ship, species, pop (pop\_faction), federation, galactic\_object (ambient\_object), megastructure, espionage\_operation or global.

The command to set or clear a flag are:

* `set_<scope>_flag = <flag_name>`
* `set_timed_<scope>_flag = { flag = <flag_name> days = <int> }`
* `remove_<scope>_flag = <flag_name>`

Flags can be checked via conditions, for the flag presence ~~or the duration since the flag has been set~~ (not yet implemented):

* `has_<scope>_flag = <flag_name>`
* ~~`had_<scope>_flag = { flag = <flag_name> days = <duration> }`~~

Note that modifiers are somewhat similar to flags, but in addition they alter the statistics of the scope they are attached to.

### Dynamic flags

The flag name may be dynamic, by appending `@` and a scope (leader, country or title):

It only affects how the actual flag name is created, but doesn't change how the flag is checked.

`from = { set_leader_flag = is_friend_of_@root }`

#### How to use

For example, if a leader has a leader ID of 140, the saved leader flag will be `is_friend_of_140`.

They can also be used in triggers: `has_leader_flag = is_friend_of_@from`

Use of dynamic flags is currently only supported for set|remove\_*scope*\_flag commands and has\_*scope*\_flag conditions. They cannot be used in the flag line of the create\_leader command (flags used in instances other than those listed previously must be static).

Note that scopes saved as variables in event targets can be used in dynamic flags as well.

## Script values

*Documentation file:* Stellaris/common/script\_values/00\_script\_values.txt (introduced with patch 3.3)

**Script values** provides the ability to dynamically get numbers like ai\_weight versions of scripted triggers, with the capabilities of advanced script math on the fly. Basically, the gist of what made them powerful is being able to substitute a value for a key which would run a series of calculations on demand.

#### How to use

To use one of them, create a txt-file in the "`common/script_values`" folder and refer to them elsewhere in script via key "`value:<value>`" e.g. `value:example_value` to get a number.

**Important note:** Be mindful of performance when using these in triggers that are checked often!

```
example\_value = {
	base = 10 # default: 0
	# List of valid mathematical operations:
	# Numerical (modifying by a number):
	# - set/weight (both do the same, replaces the current result with this value)
	# - add
	# - subtract
	# - factor/mult/multiply ("multiply" fits the name scheme of the rest better, but the other two were kept for historical reasons)
	# - divide
	# - modulo
	# - round\_to (rounds to nearest of that value, e.g. 10.7 round\_to 5 gives you 10)
	# - max (sets to specified value if currently above it)
	# - min (sets to specified value if currently below it)
	# - pow (value is multiplied by itself to the power of x; be careful, you can get overflows if you are not careful)
	# Simple (do not need a number, but just "yes", e.g. "round = yes")
	# - round (sets to nearest full number)
	# - ceiling (rounds up)
	# - floor (rounds down)
	# - abs (multiply by -1 if negative)
	# - square (multiply by itself)
	# - square\_root
	# All mathematical operations except weight and factor can be used inline e.g.
	add = 100
	multiply = value:some\_other\_script\_value
	round = yes
	# (Note: weight and factor will instead overwrite the base value - use set, mult or multiply instead)
	# They can also be used in modifier = {} fields, which lets you only apply them if triggers are true
	modifier = {
		max = owner.max\_example\_variable 					# Variable set by set\_variable
		owner = { is\_variable\_set = max\_example\_variable }	# Only applied if this trigger is true
	}
	# What works for right hand side values of mathematical operations? See events/00\_how\_to\_use\_variables for full list.
	complex\_trigger\_modifier = { 	# This lets you get the value of a trigger that you can't use in one-liners because it uses {}
		trigger = count\_owned\_planet
		trigger\_scope = owner 		# Lets you get the result of the trigger on a different scope. Default is "this"
		parameters = { 				# Stick any further information necessary in here, like you'd do within the {} of the trigger normally
			limit = { num\_pops > 10 }
		}
		mode = add 					# Allows all numerical operations
		mult = 5 					# Multiplies the outcome by this. In this example, this means adding 5 for each planet with more than 10 pops
	}
}

```

## Inline scripts

*Documentation file:* Stellaris/common/inline\_scripts/00\_README.txt (introduced with patch 3.5)

**Inline scripts** gives you the ability to write a block of script in one file and then include that block of script into other scripts as if it would have been written directly in those other scripts. This can prevent a huge amount of copy paste. It is especially useful when you may want to update something inside of the block of script since updating the inline\_script will automatically update all scripts that are using that inline\_script, while otherwise you would need to go through all those scripts yourself and update them one by one.

This is very similar to how scripted effects and scripted triggers work. But inline scripts can be used for modularization or things that are not effect or trigger blocks (e.g. see vanilla Curators dialog).

#### How to use

Create a txt file in the "`common/inline_scripts`" folder with the script that you want to inline into other scripts. Note that you can only have one inline script per file and that the file name will be used when inlining the script into other scripts. You can organize the inline scripts by putting them inside subfolders.

Example at `common/inline_scripts/edicts/upkeep_low.txt`:

```
resources = {
 category = edicts
 upkeep = {
 unity = 10
 multiplier = value:edict\_size\_effect
 }
}

```

Then use `inline_script = <file_name_without_extension>` to inline it. Example at `00_edicts.txt`:

```
fortify\_the\_border = {
	length = @EdictPerpetual
	icon = "GFX\_edict\_type\_policy"
	inline\_script = "edicts/upkeep\_low" # Game replaces this statement with the contents of common/inline\_scripts/edicts/upkeep\_low.txt
	modifier = {
		starbase\_upgrade\_speed\_mult = 0.50
		country\_starbase\_capacity\_add = 2

```

#### Parameters

You can use parameters to change parts of the inline script.

E.g. as `common/inline_scripts/test_basic_policy.txt`:

```
$KEY$ = {
	option = {
		name = "$KEY$\_a"
		on\_enabled = {
			add\_modifier = { modifier = $MODIFIER\_A$ days = 360 }
		}
	}
	option = {
		name = "$KEY$\_b"
		on\_enabled = {
			add\_modifier = { modifier = $MODIFIER\_B$ days = 360 }
		}
	}
}

```

E.g. as `common/policies/00_policies.txt`:

```
inline\_script = {
 script = test\_basic\_policy
 KEY = test\_1
 MODIFIER\_A = evermore\_science
 MODIFIER\_B = fumongus\_authoritarian
}

```

Inline script parameters accept strings so it’s possible to swap in a full statement or even several statements by enclosing it in "".

```
inline\_script = {
 script = just\_an\_example
 MODIFIER = "num\_tech\_alternatives\_add = 1 scientist\_skill\_levels = 2" # <--- like this
}

```

#### Good to know

Support for inline\_script hasn't been added everywhere, so if you get an error that inline\_script is an unexpected token or that inline\_script is encountered before init then it’s likely that you can't use inline\_scripts there. You also can't use inline scripts within a list of items such as `examples = { abc test2 test3 object }`.

## See also

* Dynamic event targets

**Modding**

1. ↑ A bit earlier, but not documented.
2. ↑ Forum: [Dev Team] 3.4.2 'Cepheus’ Patch Released (checksum 7836), 2022-05-12
3. ↑ forum:774248/page-20#post-20109979
4. ↑ forum:589686/page-1707#post-24382261
5. ↑ forum:589686/page-1633#post-23624865
6. ↑ Forum: 3.3.1 "Libra" Update Now Available!, 2022-02-23.
7. ↑ Forum: Dev Diary #240 – Scripting Improvements in 3.3, 2022-02-03.
8. ↑ Dev Diary #267 – 3.5 'Fornax’ Patch Notes