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_add_npc_races(*races)
Add races to NPC_RACES, keeping whatever is already listed.
The NPC twin of :func:settings_add_playable_races - same semantics, same ordering
caveat. Separate from the playable list on purpose: the races a player may BE and the
races that raid them are different questions.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*races
|
race names, as separate arguments, a comma-separated string, or a list. |
()
|
Returns:
| Name | Type | Description |
|---|---|---|
list |
the names actually added, in order. |
settings_add_playable_races(*races)
Add races to PLAYABLE_RACES, keeping whatever is already listed.
The call a MOD that ships player-flyable hulls should make. Accepts names as separate arguments, one comma-separated string, or a list::
settings_add_playable_races("Federation", "Klingon")
settings_add_playable_races("Federation, Klingon")
ADD rather than replace, so a mod can put a Galaxy alongside a TSN crew instead of taking the mission's own races away. A total conversion stays a MISSION's choice - it sets the setting to its own races alone - rather than something installing a mastlib does to you.
WHY NOT settings_set_mod_default. That is the right tier for "a value the library
ships and the mission did not override", and it deliberately returns False once the
mission has spoken (_explicit_keys). Adding a race is not overriding a choice, it is
widening a list, and it has to work even when the mission named the key - a mission
that lists TSN, Ximni has said nothing at all about the Federation. So this edits the
live settings dict, which is what every mod doing this had to hand-roll.
ORDER MATTERS, and this is the one sharp edge. Addons decide which floor plans and
fleet ladders to load by READING these settings at load time, and addon load order is
non-deterministic. Adding a race the mod supplies hulls for is safe, because the mod's
own addon merges those. Adding a race to unlock ANOTHER addon's content is a race with
that addon's own load - call this as early as possible (the first line of the mod's
__init__.mast) and do not rely on it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*races
|
race names, as separate arguments, a comma-separated string, or a list. |
()
|
Returns:
| Name | Type | Description |
|---|---|---|
list |
the names actually added, in order. Empty when every one was already listed. |
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. |