fvtt-types
Version:
TypeScript type definitions for Foundry VTT
346 lines (289 loc) • 11.7 kB
text/typescript
import type { IntentionalPartial, InexactPartial, NullishProps, HandleEmptyObject, Identity } from "#utils";
import type { Canvas } from "#client/canvas/_module.d.mts";
import type { PlaceablesLayer } from "./_module.d.mts";
import type { AmbientSound } from "#client/canvas/placeables/_module.d.mts";
declare module "#configuration" {
namespace Hooks {
interface PlaceablesLayerConfig {
SoundsLayer: SoundsLayer.Any;
}
}
}
/**
* This Canvas Layer provides a container for AmbientSound objects.
*/
declare class SoundsLayer extends PlaceablesLayer<"AmbientSound"> {
/**
* @privateRemarks This is not overridden in foundry but reflects the real behavior.
*/
static get instance(): Canvas["sounds"];
/**
* Track whether to actively preview ambient sounds with mouse cursor movements
* @defaultValue `false`
*/
livePreview: boolean;
/**
* A mapping of ambient audio sources which are active within the rendered Scene
* @defaultValue `new foundry.utils.Collection()`
*/
sources: Collection<foundry.canvas.sources.PointSoundSource.Internal.Any>;
/**
* @privateRemarks This is not overridden in foundry but reflects the real behavior.
*/
override options: SoundsLayer.LayerOptions;
/**
* @defaultValue
* ```
* foundry.utils.mergeObject(super.layerOptions, {
* name: "sounds",
* zIndex: 900
* })
* ```
*/
static override get layerOptions(): SoundsLayer.LayerOptions;
static override documentName: "AmbientSound";
override get hookName(): "SoundsLayer";
protected override _draw(options: HandleEmptyObject<SoundsLayer.DrawOptions>): Promise<void>;
protected override _tearDown(options: HandleEmptyObject<SoundsLayer.TearDownOptions>): Promise<void>;
protected override _activate(): void;
/**
* Initialize all AmbientSound sources which are present on this layer
*/
initializeSources(): void;
/**
* Update all AmbientSound effects in the layer by toggling their playback status.
* Sync audio for the positions of tokens which are capable of hearing.
* @param options - Additional options forwarded to AmbientSound synchronization
* (defaultValue: `{}`)
* @remarks Probably meant to be treated as always `void`; the `number` return is from an `Array#push` call, not anything meaningful
*/
refresh(options?: SoundsLayer.RefreshOptions): number | void;
/**
* Preview ambient audio for a given mouse cursor position
* @param position - The cursor position to preview
*/
previewSound(position: Canvas.Point): void;
/**
* Terminate playback of all ambient audio sources
*/
stopAll(): void;
/**
* Get an array of listener positions for Tokens which are able to hear environmental sound.
* @remarks Returns an array of `token.center`s, so actual `PIXI.Point`s for once
*/
getListenerPositions(): PIXI.Point[];
/**
* Sync the playing state and volume of all AmbientSound objects based on the position of listener points
* @param listeners - Locations of listeners which have the capability to hear
* @param options - Additional options forwarded to AmbientSound synchronization
* (defaultValue: `{}`)
*/
protected _syncPositions(listeners: PIXI.Point[], options?: SoundsLayer.SyncPositionsOptions | null): void;
/**
* Configure playback by assigning the muffled state and final playback volume for the sound.
* This method should mutate the config object by assigning the volume and muffled properties.
* @param config - A playback configuration object
*/
protected _configurePlayback(config: SoundsLayer.AmbientSoundPlaybackConfig): void;
/**
* Actions to take when the darkness level of the Scene is changed
* @param event - The darkness-changing event
*/
protected _onDarknessChange(event: Canvas.Event.DarknessChange): void;
/**
* Play a one-shot Sound originating from a predefined point on the canvas.
* The sound plays locally for the current client only.
* To play a sound for all connected clients use SoundsLayer#emitAtPosition.
* @param src - The sound source path to play
* @param origin - The canvas coordinates from which the sound originates
* @param radius - The radius of effect in distance units
* @param options - Additional options which configure playback
* @returns A Promise which resolves to the played Sound, or null
*
* @example Play the sound of a trap springing
* ```js
* const src = "modules/my-module/sounds/spring-trap.ogg";
* const origin = {x: 5200, y: 3700}; // The origin point for the sound
* const radius = 30; // Audible in a 30-foot radius
* await canvas.sounds.playAtPosition(src, origin, radius);
* ```
*
* @example A Token casts a spell
* ```js
* const src = "modules/my-module/sounds/spells-sprite.ogg";
* const origin = token.center; // The origin point for the sound
* const radius = 60; // Audible in a 60-foot radius
* await canvas.sounds.playAtPosition(src, origin, radius, {
* walls: false, // Not constrained by walls with a lowpass muffled effect
* muffledEffect: {type: "lowpass", intensity: 6},
* sourceData: {
* angle: 120, // Sound emitted at a limited angle
* rotation: 270 // Configure the direction of sound emission
* }
* playbackOptions: {
* loopStart: 12, // Audio sprite timing
* loopEnd: 16,
* fade: 300, // Fade-in 300ms
* onended: () => console.log("Do something after the spell sound has played")
* }
* });
* ```
*/
playAtPosition(
src: string,
/** @privateRemarks The examples in the docs show passing a simple `{x, y}` object here, so unlike other places in this layer `Canvas.Point` is appropriate */
origin: Canvas.Point,
radius: number,
options?: SoundsLayer.PlayAtPositionOptions, // not:null (destructured)
): Promise<foundry.audio.Sound | null>;
/**
* Emit playback to other connected clients to occur at a specified position.
* @param args - Arguments passed to SoundsLayer#playAtPosition
* @returns A Promise which resolves once playback for the initiating client has completed
*/
emitAtPosition(...args: Parameters<this["playAtPosition"]>): ReturnType<this["playAtPosition"]>;
/**
* Handle mouse cursor movements which may cause ambient audio previews to occur
*/
protected _onMouseMove(): void;
protected override _onDragLeftStart(event: Canvas.Event.Pointer): void;
protected override _onDragLeftMove(event: Canvas.Event.Pointer): void;
protected override _onDragLeftDrop(event: Canvas.Event.Pointer): void;
protected override _onDragLeftCancel(event: Canvas.Event.Pointer): void;
/**
* Handle PlaylistSound document drop data.
* @param event - The drag drop event
* @param data - The dropped transfer data.
*/
protected _onDropData(event: DragEvent, data: SoundsLayer.DropData): Promise<AmbientSound.Implementation | false>;
}
declare namespace SoundsLayer {
interface Any extends AnySoundsLayer {}
interface AnyConstructor extends Identity<typeof AnySoundsLayer> {}
interface DrawOptions extends PlaceablesLayer.DrawOptions {}
interface TearDownOptions extends PlaceablesLayer.TearDownOptions {}
interface LayerOptions extends PlaceablesLayer.LayerOptions<AmbientSound.ImplementationClass> {
name: "sounds";
zIndex: 900;
}
interface DropData extends Canvas.DropPosition {
type: "PlaylistSound";
uuid: string;
}
/** @internal */
type _Fade = NullishProps<{
/**
* A duration in milliseconds to fade volume transition
* @defaultValue `250`
* @remarks The above is only a parameter default; `null` is treated as `0`
*/
fade: number;
}>;
interface RefreshOptions extends _Fade {}
interface SyncPositionsOptions extends _Fade {}
/** @internal */
type _PlayAtPositionOptions = NullishProps<{
/**
* Should volume be attenuated by distance?
* @defaultValue `true`
*/
easing: boolean;
/**
* Should the sound always be played for GM users regardless of actively controlled tokens?
* @defaultValue `true`
*/
gmAlways: boolean;
/** A base sound effect to apply to playback */
baseEffect: AmbientSoundDocument.Effect;
/** A muffled sound effect to apply to playback, a sound may only be muffled if it is not constrained by walls */
muffledEffect: AmbientSoundDocument.Effect;
/**
* Additional data passed to the SoundSource constructor
* @remarks `IntentionalPartial` because this is spread into an object with existing `x`, `y`, `radius`, and `walls` keys
*/
sourceData: IntentionalPartial<PointSourceData>;
/**
* Additional options passed to Sound#play
* @remarks The `loop` and `volume` keys will be overwritten
*/
playbackOptions: foundry.audio.Sound.PlaybackOptions;
}> &
InexactPartial<{
/**
* The maximum volume at which the effect should be played
* @defaultValue `1`
* @remarks Can't be `null` because it only has a parameter default
*/
volume: number;
/**
* Should the sound be constrained by walls?
* @defaultValue `true`
* @remarks Can't be `null` as it gets passed to `PointSoundSource.ConfiguredInstance#initialize`
*/
walls: boolean;
}>;
interface PlayAtPositionOptions extends _PlayAtPositionOptions {}
/** @internal */
type _AmbientSoundPlaybackConfig = NullishProps<{
/**
* Is playback constrained or muffled by walls?
* @remarks Falsey is *possibly* muffled, truthy is definitely constrained
*/
walls: boolean;
/**
* The coordinates of the closest listener or undefined if there is none
* @remarks If falsey, `volume` is set to `0`
*
* One of the rare times Foundry actually wants a `PIXI.Point`, as it calls `listener#equals(source)`
*/
listener: PIXI.Point;
}>;
/** @privateRemarks The only place this is used outside of variables entirely internal to function bodies in Foundry code is as a parameter for `#_configurePlayback` */
interface AmbientSoundPlaybackConfig extends _AmbientSoundPlaybackConfig {
/**
* The Sound node which should be controlled for playback
*/
sound?: foundry.audio.Sound;
/**
* The SoundSource which defines the area of effect for the sound
*/
source: foundry.canvas.sources.PointSoundSource.Implementation;
/**
* An AmbientSound object responsible for the sound, or undefined
*/
object?: AmbientSound.Implementation;
/**
* The minimum distance between a listener and the AmbientSound origin
* @remarks Entirely unused in 12.331
*/
distance?: number;
/**
* Is the closest listener muffled
* @remarks Always overwritten in `#_configurePlayback`, never required to be passed
*/
muffled?: boolean;
/**
* The final volume at which the Sound should be played
*/
volume?: number;
}
}
export default SoundsLayer;
/**
* @privateRemarks This is the only place in v12 (and v13 as of 332) where this v11 type is still used
*/
interface PointSourceData {
x: number;
y: number;
elevation: number;
z: number | null;
radius: number;
externalRadius: number;
rotation: number;
angle: number;
walls: boolean;
disabled: boolean;
}
declare abstract class AnySoundsLayer extends SoundsLayer {
constructor(...args: never);
}