HammeriteAudioBrushProperties

Audio. Inherits RefCounted

The acoustic character of a room, authored on the air brush that carves it.

In the subtractive world an air brush IS a room and the compiler already derives which rooms exist and which openings join them. What it cannot derive is intent: whether a courtyard should be treated as open sky, how much weather gets into a covered alley, whether a chamber should ring like stone or be deadened like a carpeted study. Those are authoring decisions, and before this schema existed there was nowhere on a brush to put them - which is why acoustics needed a parallel world of hand-placed zone entities to hold them. So: hammerite-audio declares them, core stores them sparsely on the brush, and the audio graph reads them off the cells. Core never learns what a reverb preset is. Every property AUTO-derives by default, so an author who places nothing and touches nothing still gets a working graph - the overrides exist for the cases derivation gets wrong.

Methods

ReturnsMethod
voidregister() static
boolis_excluded(map: HammeriteMap, cell: HammeriteCell) static
intzone_type_for_cell(map: HammeriteMap, cell: HammeriteCell) static
intpreset_id_for_cell(map: HammeriteMap, cell: HammeriteCell) static
intget_preset(brush: HammeriteBrush) static
boolset_preset(brush: HammeriteBrush, preset_id: int) static
floatweather_exposure_for_cell(map: HammeriteMap, cell: HammeriteCell) static

Enumerations

enum ZoneTypeChoice

ValueNameDescription
0AUTOExterior when the room is open to the sky itself (HammeriteMap.cell_is_open_to_sky()), else interior.
1INTERIORWeather is heard only through the openings that lead outdoors.
2EXTERIOROutdoors: weather is heard all round.
3SEMI_EXTERIORCovered outdoors, weather scaled by KEY_WEATHER_EXPOSURE. Never derived.

Constants

SCHEMA_ID

const SCHEMA_ID = &"audio"

Schema id, and therefore the namespace of every key below.

KEY_ZONE_TYPE

const KEY_ZONE_TYPE = &"audio/zone_type"

Brush property holding a ZoneTypeChoice; read it through zone_type_for_cell().

KEY_PRESET

const KEY_PRESET = &"audio/reverb_preset"

Brush property holding a reverb preset by its id, PRESET_AUTO for "pick one from what the room is built of". Read it through preset_id_for_cell() or get_preset(), write it through set_preset().

KEY_WEATHER_EXPOSURE

const KEY_WEATHER_EXPOSURE = &"audio/weather_exposure"

Brush property, 0..1: how much weather reaches a semi-exterior room. See weather_exposure_for_cell().

KEY_EXCLUDE

const KEY_EXCLUDE = &"audio/exclude"

Brush property: true leaves the room out of the audio graph. See is_excluded().

KEY_AMBIENT

const KEY_AMBIENT = &"audio/ambient"

Brush property: the game's id for the room's ambient bed, resolved through HammeriteAudioRuntime.ambient_resolver. Empty is silence.

KEY_AMBIENT_VOLUME

const KEY_AMBIENT_VOLUME = &"audio/ambient_volume"

Brush property: the room's ambience level, in dB.

PRESET_AUTO

const PRESET_AUTO = -1

The KEY_PRESET value meaning "pick the preset from what the room is built of" - sample the boundary materials rather than take an authored answer. Not a real preset id, and deliberately outside their range, so that every other value stored IS the id. It used to be 0 with the ids offset by one above it, which made set_property(KEY_PRESET, HammeriteAudioPreset.Kind.STONE_HALL_LARGE) - id 0 - mean Auto, and every other preset come out one off (#242).

Method descriptions

register()

static func register() -> void

Declare the acoustic schema with HammeriteBrushPropertyRegistry. Called from the HammeriteAudio autoload rather than from the editor plugin, because the registry is what supplies DEFAULTS at read time: a shipped game with no editor still has to resolve every property an author never overrode. Idempotent - registering twice replaces the schema rather than stacking a second copy.

is_excluded()

static func is_excluded(map: HammeriteMap, cell: HammeriteCell) -> bool

Is cell's room excluded from the audio graph?

zone_type_for_cell()

static func zone_type_for_cell(map: HammeriteMap, cell: HammeriteCell) -> int

The HammeriteAudioZone.ZoneType for cell, resolving AUTO through the compiled graph: a room that is open to the sky ITSELF is exterior, anything else is interior. Note this asks HammeriteMap.cell_is_open_to_sky(), not HammeriteMap.cell_reaches_sky(). Those differ exactly where it matters here: a room with a window onto a courtyard REACHES the sky, and the lightmapper rightly lets daylight in through the window - but the room is not outdoors, and its weather should arrive through that window rather than falling on the listener's head. Using reachability made every room with a window read as open air, which is the wrong answer for every one of them. Semi-exterior is never derived - a covered space looks exactly like an open one to either test - so it is the one answer an author has to give.

preset_id_for_cell()

static func preset_id_for_cell(map: HammeriteMap, cell: HammeriteCell) -> int

The authored preset id for cell, or -1 when the author left it on Auto and the caller should derive one from the room's materials instead.

get_preset()

static func get_preset(brush: HammeriteBrush) -> int

The reverb preset brush's room is authored to, or PRESET_AUTO for one derived from what it is built of.

set_preset()

static func set_preset(brush: HammeriteBrush, preset_id: int) -> bool

Author brush's room to reverb preset preset_id, or to PRESET_AUTO for one derived from its materials. False for a preset no table defines. The value stored IS the id, so this and HammeriteBrush.set_property() agree - which they did not when the property held the id plus one (#242).

weather_exposure_for_cell()

static func weather_exposure_for_cell(map: HammeriteMap, cell: HammeriteCell) -> float

Weather exposure for cell (0 sheltered .. 1 open). Only a semi-exterior room has a partial answer; the other two are decided by what they are, and returning their implied value here keeps callers from having to special-case the zone type.

Hammerite 1.0 · built from a6dd634, 2026-10-10