/** * How long a shared value lives. `local` is one per behavior instance, `global` one for the whole * run, `scene` one per scene: rebuilt from the declarations whenever a scene is loaded, so what a * level counts is gone with the level while a score is not (#164). * * Everything was `local` before scopes existed, so a missing field means `local` and old projects * load unchanged. Variables are shared by living on a Variables asset instead (#91) – that asset is * shared by its nature, so a missing field means `global` there (see `sharedScopeOf`). */ export type Scope = 'local' | 'global' | 'scene'; /** The scopes of something that is shared either way: a Variables asset has no `local`. */ export type SharedScope = 'global' | 'scene'; export interface Scoped { scope?: Scope; } export function scopeOf(owner: Scoped): Scope { if (owner.scope === 'global') return 'global'; return owner.scope === 'scene' ? 'scene' : 'local'; } /** Whether the value is shared at all: both `global` and `scene` are one value for many instances. */ export function isShared(owner: Scoped): boolean { return owner.scope === 'global' || owner.scope === 'scene'; } /** Whether a scene swap rebuilds the value instead of handing it over. */ export function isPerScene(owner: Scoped): boolean { return owner.scope === 'scene'; } /** Reads a scope out of loaded data, where anything but the two known words means `local`. */ export function readScope(raw: unknown): Scope { if (raw === 'global') return 'global'; return raw === 'scene' ? 'scene' : 'local'; } /** Keeps `local` out of the document: the field is present only when it says more than that. */ export function setScope(owner: Scoped, scope: Scope): void { if (scope === 'local') delete owner.scope; else owner.scope = scope; } /** The scope of something shared by nature, where a missing field is `global` rather than `local`. */ export function sharedScopeOf(owner: Scoped): SharedScope { return owner.scope === 'scene' ? 'scene' : 'global'; } /** Reads the scope of something shared by nature out of loaded data. */ export function readSharedScope(raw: unknown): SharedScope { return raw === 'scene' ? 'scene' : 'global'; } /** Keeps the default out of the document the other way round: only `scene` is written. */ export function setSharedScope(owner: Scoped, scope: SharedScope): void { if (scope === 'scene') owner.scope = 'scene'; else delete owner.scope; }