The settings system
Mission configuration defaults loaded from settings.yaml (or legacy setup.json).
Overview
settings_get_defaults() returns a dict of built-in defaults merged with mission-specific overrides from settings.yaml in the mission directory. The result is cached after the first call, so all modules that read settings see a consistent snapshot.
Common use-cases:
- Reading built-in settings like
DIFFICULTY,PLAYER_COUNT,WORLD_SELECT, or operator-mode config. - Adding module-specific defaults with
settings_add_defaultsso that a module's settings are visible insettings_get_defaults()even when the author hasn't created asettings.yaml.
Quick example
== setup ==
settings = settings_get_defaults()
difficulty = settings.get("DIFFICULTY", 5)
log(f"Difficulty is {difficulty}")
from sbs_utils.procedural.settings import settings_get_defaults, settings_add_defaults
# Read built-in settings
settings = settings_get_defaults()
difficulty = settings.get("DIFFICULTY", 5)
player_count = settings.get("PLAYER_COUNT", 1)
# Register module-specific defaults (won't override settings.yaml values)
settings_add_defaults({
"ENEMY_COUNT": 10,
"BOSS_ENABLED": False,
})
Built-in settings keys
| Key | Default | Notes |
|---|---|---|
DIFFICULTY |
5 | Mission difficulty 1–10 |
PLAYER_COUNT |
1 | Expected number of player ships |
WORLD_SELECT |
"siege" |
World generation preset |
TERRAIN_SELECT |
"some" |
Terrain density |
LETHAL_SELECT |
"none" |
Lethal NPC density |
FRIENDLY_SELECT |
"few" |
Friendly NPC density |
UPGRADE_SELECT |
"max" |
Available upgrades |
AUTO_START |
False |
Skip lobby and start immediately |
GAME_STARTED |
False |
Set by the game engine at start |
GAME_ENDED |
False |
Set by mission when over |
GRID_THEME |
0 | Engineering grid color theme index |
PLAYER_LIST |
list of 8 ships | Player ship definitions |
API
settings_add_defaults(additions)
Merge additional keys into the global settings defaults.
additions acts as a fallback — existing values from settings.yaml
or setup.json take precedence, so this only fills gaps.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
additions
|
dict
|
Default key-value pairs to add if not already present. |
required |
settings_get_defaults()
Return the merged default settings dict, loading settings.yaml or setup.json if present.
Results are cached after the first call. Mission-specific values from the YAML/JSON file override the built-in defaults.
Returns:
| Name | Type | Description |
|---|---|---|
dict |
The default settings mapping. |
settings_get_profile()
The selected profile file, PARSED - not merged.
settings_get_defaults() folds a profile's settings keys into the settings dict and
then forgets the file, which is all a setting ever needed. A profile that also selects
ADD-ONS has to be read as a document, by the compiler, before any settings exist to
merge into - so the parse is cached here and both callers share it.
Returns:
| Name | Type | Description |
|---|---|---|
dict |
the profile, or an empty dict when none was named or it did not load. |
settings_npc_races()
The races that can appear as NPCs, lowercased, from NPC_RACES.
settings_playable_races()
The races a player ship may be, lowercased, from PLAYABLE_RACES.
settings_profile_addons()
The profile's addons: include/exclude, by addon FOLDER name.
settings_profile_media()
The profile's media: include/exclude, by media pack name.
settings_profile_reset()
Forget the parsed profile. Called from reset_mission_state - a reused
interpreter can be pointed at a different mission, and its profile.
settings_race_is_npc(race)
Whether a race can appear as an NPC.
Used by the race_* addons to skip loading a fleet ladder for a race this mission
never spawns. As with :func:settings_race_is_playable, matching ignores case and
spacing, and an EMPTY setting means no restriction rather than no races.
settings_race_is_playable(race)
Whether a race may be flown as a player ship.
Used by the interiors_* addons to skip loading floor plans for a race no player
can be, since an interior is only ever built for a player ship.
An EMPTY or missing PLAYABLE_RACES means "no restriction" rather than "nothing is
playable" - a mission that clears the setting should get every race, not a game where
no ship has an interior.
settings_seed_apply(value=None)
Seed the global RNG so a run is reproducible.
Every random draw in sbs_utils flows through Python's single global
random.Random instance -- both module-level random.* calls and the
from random import ... bindings (scatter, vec) resolve to it -- so one
seed here makes terrain scatter, fleet-race weights, dialogue %
selection, faces, and names all reproducible.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
int | None
|
explicit seed. If |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
int |
the seed actually applied. |
settings_set_mod_default(key, value)
Set a setting on behalf of a MOD - unless the mission already spoke for it.
The tier that was missing. There are two kinds of "default" and the existing
:func:settings_add_defaults only expresses the weaker one: it does
additions | setting_defaults, so anything already in the built-ins wins, and a mod
can therefore only fill a key sbs_utils has never heard of. For a key the library ships
a value for - MUSIC_SELECT, PLAYABLE_RACES - a mod had no way to be heard at all.
So the precedence is now, strongest first::
var.NAME= (command line) > COSMOS_SETTINGS > profiles/<name>.yaml
> settings.yaml / setup.json
> settings_set_mod_default <- this
> the library built-in
which is the order an author would expect: a mod re-skins the game, and anything the mission or the operator actually typed still beats it.
Last mod loaded wins between two mods, and load order is non-deterministic - so two mods claiming the same key is a genuine conflict, not something to paper over. Use a key the mod owns.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
the setting name. |
required |
value
|
the value. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
bool |
whether it applied. False means the mission (or the launch) had already set it. |