Modularize client item type definitions by item module
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
// Maintainer-controlled web client version.
|
// Maintainer-controlled web client version.
|
||||||
// Format: YYYY.MM.DD Rn (example: 2026.02.20 R2)
|
// Format: YYYY.MM.DD Rn (example: 2026.02.20 R2)
|
||||||
window.CHGRID_WEB_VERSION = "2026.02.23 R223";
|
window.CHGRID_WEB_VERSION = "2026.02.24 R224";
|
||||||
// Optional display timezone for timestamps. Falls back to America/Detroit if unset/invalid.
|
// Optional display timezone for timestamps. Falls back to America/Detroit if unset/invalid.
|
||||||
window.CHGRID_TIME_ZONE = "America/Detroit";
|
window.CHGRID_TIME_ZONE = "America/Detroit";
|
||||||
|
|||||||
@@ -1,82 +1,6 @@
|
|||||||
import { EFFECT_SEQUENCE } from '../audio/effects';
|
|
||||||
import { RADIO_CHANNEL_OPTIONS } from '../audio/radioStationRuntime';
|
|
||||||
import { type ItemType, type WorldItem } from '../state/gameState';
|
import { type ItemType, type WorldItem } from '../state/gameState';
|
||||||
|
import { CLOCK_TIME_ZONE_OPTIONS } from './types/clock';
|
||||||
const DEFAULT_CLOCK_TIME_ZONE_OPTIONS = [
|
import { DEFAULT_ITEM_TYPE_DEFINITIONS, DEFAULT_ITEM_TYPE_SEQUENCE } from './types';
|
||||||
'America/Anchorage',
|
|
||||||
'America/Argentina/Buenos_Aires',
|
|
||||||
'America/Chicago',
|
|
||||||
'America/Detroit',
|
|
||||||
'America/Halifax',
|
|
||||||
'America/Indiana/Indianapolis',
|
|
||||||
'America/Kentucky/Louisville',
|
|
||||||
'America/Los_Angeles',
|
|
||||||
'America/St_Johns',
|
|
||||||
'Asia/Bangkok',
|
|
||||||
'Asia/Dhaka',
|
|
||||||
'Asia/Dubai',
|
|
||||||
'Asia/Hong_Kong',
|
|
||||||
'Asia/Kabul',
|
|
||||||
'Asia/Karachi',
|
|
||||||
'Asia/Kathmandu',
|
|
||||||
'Asia/Kolkata',
|
|
||||||
'Asia/Seoul',
|
|
||||||
'Asia/Singapore',
|
|
||||||
'Asia/Tehran',
|
|
||||||
'Asia/Tokyo',
|
|
||||||
'Asia/Yangon',
|
|
||||||
'Atlantic/Azores',
|
|
||||||
'Atlantic/South_Georgia',
|
|
||||||
'Australia/Brisbane',
|
|
||||||
'Australia/Darwin',
|
|
||||||
'Australia/Eucla',
|
|
||||||
'Australia/Lord_Howe',
|
|
||||||
'Europe/Berlin',
|
|
||||||
'Europe/Helsinki',
|
|
||||||
'Europe/London',
|
|
||||||
'Europe/Moscow',
|
|
||||||
'Pacific/Apia',
|
|
||||||
'Pacific/Auckland',
|
|
||||||
'Pacific/Chatham',
|
|
||||||
'Pacific/Honolulu',
|
|
||||||
'Pacific/Kiritimati',
|
|
||||||
'Pacific/Noumea',
|
|
||||||
'Pacific/Pago_Pago',
|
|
||||||
'UTC',
|
|
||||||
] as const;
|
|
||||||
|
|
||||||
const DEFAULT_ITEM_TYPE_SEQUENCE: ItemType[] = ['clock', 'dice', 'piano', 'radio_station', 'wheel', 'widget'];
|
|
||||||
const DEFAULT_PIANO_INSTRUMENT_OPTIONS = [
|
|
||||||
'piano',
|
|
||||||
'electric_piano',
|
|
||||||
'guitar',
|
|
||||||
'organ',
|
|
||||||
'bass',
|
|
||||||
'violin',
|
|
||||||
'synth_lead',
|
|
||||||
'brass',
|
|
||||||
'nintendo',
|
|
||||||
'drum_kit',
|
|
||||||
] as const;
|
|
||||||
const DEFAULT_PIANO_VOICE_MODE_OPTIONS = ['poly', 'mono'] as const;
|
|
||||||
|
|
||||||
const DEFAULT_ITEM_TYPE_EDITABLE_PROPERTIES: Record<ItemType, string[]> = {
|
|
||||||
radio_station: ['title', 'streamUrl', 'enabled', 'mediaVolume', 'mediaChannel', 'mediaEffect', 'mediaEffectValue', 'facing', 'emitRange'],
|
|
||||||
dice: ['title', 'sides', 'number'],
|
|
||||||
piano: ['title', 'instrument', 'voiceMode', 'octave', 'attack', 'decay', 'release', 'brightness', 'emitRange'],
|
|
||||||
wheel: ['title', 'spaces'],
|
|
||||||
clock: ['title', 'timeZone', 'use24Hour'],
|
|
||||||
widget: ['title', 'enabled', 'directional', 'facing', 'emitRange', 'emitVolume', 'emitSoundSpeed', 'emitSoundTempo', 'emitEffect', 'emitEffectValue', 'useSound', 'emitSound'],
|
|
||||||
};
|
|
||||||
|
|
||||||
const DEFAULT_ITEM_TYPE_GLOBAL_PROPERTIES: Record<ItemType, Record<string, string | number | boolean>> = {
|
|
||||||
radio_station: { useSound: 'none', emitSound: 'none', useCooldownMs: 1000, emitRange: 20, directional: true, emitSoundSpeed: 50, emitSoundTempo: 50 },
|
|
||||||
dice: { useSound: 'sounds/roll.ogg', emitSound: 'none', useCooldownMs: 1000, emitRange: 15, directional: false, emitSoundSpeed: 50, emitSoundTempo: 50 },
|
|
||||||
piano: { useSound: 'none', emitSound: 'none', useCooldownMs: 1000, emitRange: 15, directional: false, emitSoundSpeed: 50, emitSoundTempo: 50 },
|
|
||||||
wheel: { useSound: 'sounds/spin.ogg', emitSound: 'none', useCooldownMs: 4000, emitRange: 15, directional: false, emitSoundSpeed: 50, emitSoundTempo: 50 },
|
|
||||||
clock: { useSound: 'none', emitSound: 'sounds/clock.ogg', useCooldownMs: 1000, emitRange: 10, directional: false, emitSoundSpeed: 50, emitSoundTempo: 50 },
|
|
||||||
widget: { useSound: 'none', emitSound: 'none', useCooldownMs: 1000, emitRange: 15, directional: false, emitSoundSpeed: 50, emitSoundTempo: 50 },
|
|
||||||
};
|
|
||||||
|
|
||||||
export type ItemPropertyValueType = 'boolean' | 'text' | 'number' | 'list' | 'sound';
|
export type ItemPropertyValueType = 'boolean' | 'text' | 'number' | 'list' | 'sound';
|
||||||
|
|
||||||
@@ -105,41 +29,33 @@ type UiDefinitionsPayload = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let itemTypeSequence: ItemType[] = [...DEFAULT_ITEM_TYPE_SEQUENCE];
|
let itemTypeSequence: ItemType[] = [...DEFAULT_ITEM_TYPE_SEQUENCE];
|
||||||
let itemTypeLabels: Record<ItemType, string> = {
|
let itemTypeLabels: Record<ItemType, string> = {} as Record<ItemType, string>;
|
||||||
radio_station: 'radio',
|
|
||||||
dice: 'dice',
|
|
||||||
piano: 'piano',
|
|
||||||
wheel: 'wheel',
|
|
||||||
clock: 'clock',
|
|
||||||
widget: 'widget',
|
|
||||||
};
|
|
||||||
let itemTypeTooltips: Partial<Record<ItemType, string>> = {};
|
let itemTypeTooltips: Partial<Record<ItemType, string>> = {};
|
||||||
let itemTypeEditableProperties: Record<ItemType, string[]> = {
|
let itemTypeEditableProperties: Record<ItemType, string[]> = {} as Record<ItemType, string[]>;
|
||||||
radio_station: [...DEFAULT_ITEM_TYPE_EDITABLE_PROPERTIES.radio_station],
|
let itemTypeGlobalProperties: Record<ItemType, Record<string, string | number | boolean>> = {} as Record<
|
||||||
dice: [...DEFAULT_ITEM_TYPE_EDITABLE_PROPERTIES.dice],
|
ItemType,
|
||||||
piano: [...DEFAULT_ITEM_TYPE_EDITABLE_PROPERTIES.piano],
|
Record<string, string | number | boolean>
|
||||||
wheel: [...DEFAULT_ITEM_TYPE_EDITABLE_PROPERTIES.wheel],
|
>;
|
||||||
clock: [...DEFAULT_ITEM_TYPE_EDITABLE_PROPERTIES.clock],
|
let optionItemPropertyValues: Partial<Record<string, string[]>> = {};
|
||||||
widget: [...DEFAULT_ITEM_TYPE_EDITABLE_PROPERTIES.widget],
|
|
||||||
};
|
|
||||||
let itemTypeGlobalProperties: Record<ItemType, Record<string, string | number | boolean>> = {
|
|
||||||
radio_station: { ...DEFAULT_ITEM_TYPE_GLOBAL_PROPERTIES.radio_station },
|
|
||||||
dice: { ...DEFAULT_ITEM_TYPE_GLOBAL_PROPERTIES.dice },
|
|
||||||
piano: { ...DEFAULT_ITEM_TYPE_GLOBAL_PROPERTIES.piano },
|
|
||||||
wheel: { ...DEFAULT_ITEM_TYPE_GLOBAL_PROPERTIES.wheel },
|
|
||||||
clock: { ...DEFAULT_ITEM_TYPE_GLOBAL_PROPERTIES.clock },
|
|
||||||
widget: { ...DEFAULT_ITEM_TYPE_GLOBAL_PROPERTIES.widget },
|
|
||||||
};
|
|
||||||
let optionItemPropertyValues: Partial<Record<string, string[]>> = {
|
|
||||||
mediaEffect: EFFECT_SEQUENCE.map((effect) => effect.id),
|
|
||||||
emitEffect: EFFECT_SEQUENCE.map((effect) => effect.id),
|
|
||||||
mediaChannel: [...RADIO_CHANNEL_OPTIONS],
|
|
||||||
instrument: [...DEFAULT_PIANO_INSTRUMENT_OPTIONS],
|
|
||||||
voiceMode: [...DEFAULT_PIANO_VOICE_MODE_OPTIONS],
|
|
||||||
timeZone: [...DEFAULT_CLOCK_TIME_ZONE_OPTIONS],
|
|
||||||
};
|
|
||||||
let itemTypePropertyMetadata: Partial<Record<ItemType, Record<string, ItemPropertyMetadata>>> = {};
|
let itemTypePropertyMetadata: Partial<Record<ItemType, Record<string, ItemPropertyMetadata>>> = {};
|
||||||
|
|
||||||
|
for (const definition of DEFAULT_ITEM_TYPE_DEFINITIONS) {
|
||||||
|
itemTypeLabels[definition.type] = definition.label;
|
||||||
|
if (definition.tooltip) {
|
||||||
|
itemTypeTooltips[definition.type] = definition.tooltip;
|
||||||
|
}
|
||||||
|
itemTypeEditableProperties[definition.type] = [...definition.editableProperties];
|
||||||
|
itemTypeGlobalProperties[definition.type] = { ...definition.globalProperties };
|
||||||
|
if (definition.propertyMetadata) {
|
||||||
|
itemTypePropertyMetadata[definition.type] = { ...definition.propertyMetadata };
|
||||||
|
}
|
||||||
|
if (definition.propertyOptions) {
|
||||||
|
for (const [key, values] of Object.entries(definition.propertyOptions)) {
|
||||||
|
optionItemPropertyValues[key] = [...values];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export let EDITABLE_ITEM_PROPERTY_KEYS = new Set<string>(
|
export let EDITABLE_ITEM_PROPERTY_KEYS = new Set<string>(
|
||||||
Object.values(itemTypeEditableProperties).flatMap((keys) => keys),
|
Object.values(itemTypeEditableProperties).flatMap((keys) => keys),
|
||||||
);
|
);
|
||||||
@@ -190,7 +106,7 @@ function normalizePropertyMetadataRecord(raw: Record<string, unknown> | undefine
|
|||||||
|
|
||||||
/** Returns current timezone option list used by clock item properties. */
|
/** Returns current timezone option list used by clock item properties. */
|
||||||
export function getClockTimeZoneOptions(): string[] {
|
export function getClockTimeZoneOptions(): string[] {
|
||||||
return [...(optionItemPropertyValues.timeZone ?? DEFAULT_CLOCK_TIME_ZONE_OPTIONS)];
|
return [...(optionItemPropertyValues.timeZone ?? CLOCK_TIME_ZONE_OPTIONS)];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns default timezone used by clock items when no override is set. */
|
/** Returns default timezone used by clock items when no override is set. */
|
||||||
|
|||||||
64
client/src/items/types/clock.ts
Normal file
64
client/src/items/types/clock.ts
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
import { type ItemTypeClientDefinition } from './shared';
|
||||||
|
|
||||||
|
export const CLOCK_TIME_ZONE_OPTIONS = [
|
||||||
|
'America/Anchorage',
|
||||||
|
'America/Argentina/Buenos_Aires',
|
||||||
|
'America/Chicago',
|
||||||
|
'America/Detroit',
|
||||||
|
'America/Halifax',
|
||||||
|
'America/Indiana/Indianapolis',
|
||||||
|
'America/Kentucky/Louisville',
|
||||||
|
'America/Los_Angeles',
|
||||||
|
'America/St_Johns',
|
||||||
|
'Asia/Bangkok',
|
||||||
|
'Asia/Dhaka',
|
||||||
|
'Asia/Dubai',
|
||||||
|
'Asia/Hong_Kong',
|
||||||
|
'Asia/Kabul',
|
||||||
|
'Asia/Karachi',
|
||||||
|
'Asia/Kathmandu',
|
||||||
|
'Asia/Kolkata',
|
||||||
|
'Asia/Seoul',
|
||||||
|
'Asia/Singapore',
|
||||||
|
'Asia/Tehran',
|
||||||
|
'Asia/Tokyo',
|
||||||
|
'Asia/Yangon',
|
||||||
|
'Atlantic/Azores',
|
||||||
|
'Atlantic/South_Georgia',
|
||||||
|
'Australia/Brisbane',
|
||||||
|
'Australia/Darwin',
|
||||||
|
'Australia/Eucla',
|
||||||
|
'Australia/Lord_Howe',
|
||||||
|
'Europe/Berlin',
|
||||||
|
'Europe/Helsinki',
|
||||||
|
'Europe/London',
|
||||||
|
'Europe/Moscow',
|
||||||
|
'Pacific/Apia',
|
||||||
|
'Pacific/Auckland',
|
||||||
|
'Pacific/Chatham',
|
||||||
|
'Pacific/Honolulu',
|
||||||
|
'Pacific/Kiritimati',
|
||||||
|
'Pacific/Noumea',
|
||||||
|
'Pacific/Pago_Pago',
|
||||||
|
'UTC',
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
/** Default client-side UI definition for clock items. */
|
||||||
|
export const clockDefinition: ItemTypeClientDefinition = {
|
||||||
|
type: 'clock',
|
||||||
|
label: 'clock',
|
||||||
|
editableProperties: ['title', 'timeZone', 'use24Hour'],
|
||||||
|
globalProperties: {
|
||||||
|
useSound: 'none',
|
||||||
|
emitSound: 'sounds/clock.ogg',
|
||||||
|
useCooldownMs: 1000,
|
||||||
|
emitRange: 10,
|
||||||
|
directional: false,
|
||||||
|
emitSoundSpeed: 50,
|
||||||
|
emitSoundTempo: 50,
|
||||||
|
},
|
||||||
|
propertyOptions: {
|
||||||
|
timeZone: [...CLOCK_TIME_ZONE_OPTIONS],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
18
client/src/items/types/dice.ts
Normal file
18
client/src/items/types/dice.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { type ItemTypeClientDefinition } from './shared';
|
||||||
|
|
||||||
|
/** Default client-side UI definition for dice items. */
|
||||||
|
export const diceDefinition: ItemTypeClientDefinition = {
|
||||||
|
type: 'dice',
|
||||||
|
label: 'dice',
|
||||||
|
editableProperties: ['title', 'sides', 'number'],
|
||||||
|
globalProperties: {
|
||||||
|
useSound: 'sounds/roll.ogg',
|
||||||
|
emitSound: 'none',
|
||||||
|
useCooldownMs: 1000,
|
||||||
|
emitRange: 15,
|
||||||
|
directional: false,
|
||||||
|
emitSoundSpeed: 50,
|
||||||
|
emitSoundTempo: 50,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
22
client/src/items/types/index.ts
Normal file
22
client/src/items/types/index.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import { type ItemType } from '../../state/gameState';
|
||||||
|
import { clockDefinition } from './clock';
|
||||||
|
import { diceDefinition } from './dice';
|
||||||
|
import { pianoDefinition } from './piano';
|
||||||
|
import { radioStationDefinition } from './radioStation';
|
||||||
|
import { wheelDefinition } from './wheel';
|
||||||
|
import { widgetDefinition } from './widget';
|
||||||
|
import { type ItemTypeClientDefinition } from './shared';
|
||||||
|
|
||||||
|
/** Ordered default client item definitions used before server UI definitions arrive. */
|
||||||
|
export const DEFAULT_ITEM_TYPE_DEFINITIONS: ItemTypeClientDefinition[] = [
|
||||||
|
clockDefinition,
|
||||||
|
diceDefinition,
|
||||||
|
pianoDefinition,
|
||||||
|
radioStationDefinition,
|
||||||
|
wheelDefinition,
|
||||||
|
widgetDefinition,
|
||||||
|
];
|
||||||
|
|
||||||
|
/** Default add-item menu ordering derived from local item definitions. */
|
||||||
|
export const DEFAULT_ITEM_TYPE_SEQUENCE: ItemType[] = DEFAULT_ITEM_TYPE_DEFINITIONS.map((definition) => definition.type);
|
||||||
|
|
||||||
23
client/src/items/types/piano.ts
Normal file
23
client/src/items/types/piano.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import { PIANO_INSTRUMENT_OPTIONS } from '../../audio/pianoSynth';
|
||||||
|
import { type ItemTypeClientDefinition } from './shared';
|
||||||
|
|
||||||
|
/** Default client-side UI definition for piano items. */
|
||||||
|
export const pianoDefinition: ItemTypeClientDefinition = {
|
||||||
|
type: 'piano',
|
||||||
|
label: 'piano',
|
||||||
|
editableProperties: ['title', 'instrument', 'voiceMode', 'octave', 'attack', 'decay', 'release', 'brightness', 'emitRange'],
|
||||||
|
globalProperties: {
|
||||||
|
useSound: 'none',
|
||||||
|
emitSound: 'none',
|
||||||
|
useCooldownMs: 1000,
|
||||||
|
emitRange: 15,
|
||||||
|
directional: false,
|
||||||
|
emitSoundSpeed: 50,
|
||||||
|
emitSoundTempo: 50,
|
||||||
|
},
|
||||||
|
propertyOptions: {
|
||||||
|
instrument: [...PIANO_INSTRUMENT_OPTIONS],
|
||||||
|
voiceMode: ['poly', 'mono'],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
24
client/src/items/types/radioStation.ts
Normal file
24
client/src/items/types/radioStation.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { RADIO_CHANNEL_OPTIONS } from '../../audio/radioStationRuntime';
|
||||||
|
import { EFFECT_SEQUENCE } from '../../audio/effects';
|
||||||
|
import { type ItemTypeClientDefinition } from './shared';
|
||||||
|
|
||||||
|
/** Default client-side UI definition for radio_station items. */
|
||||||
|
export const radioStationDefinition: ItemTypeClientDefinition = {
|
||||||
|
type: 'radio_station',
|
||||||
|
label: 'radio',
|
||||||
|
editableProperties: ['title', 'streamUrl', 'enabled', 'mediaVolume', 'mediaChannel', 'mediaEffect', 'mediaEffectValue', 'facing', 'emitRange'],
|
||||||
|
globalProperties: {
|
||||||
|
useSound: 'none',
|
||||||
|
emitSound: 'none',
|
||||||
|
useCooldownMs: 1000,
|
||||||
|
emitRange: 20,
|
||||||
|
directional: true,
|
||||||
|
emitSoundSpeed: 50,
|
||||||
|
emitSoundTempo: 50,
|
||||||
|
},
|
||||||
|
propertyOptions: {
|
||||||
|
mediaEffect: EFFECT_SEQUENCE.map((effect) => effect.id),
|
||||||
|
mediaChannel: [...RADIO_CHANNEL_OPTIONS],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
14
client/src/items/types/shared.ts
Normal file
14
client/src/items/types/shared.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { type ItemType } from '../../state/gameState';
|
||||||
|
import { type ItemPropertyMetadata } from '../itemRegistry';
|
||||||
|
|
||||||
|
/** Static client-side definition for one item type's UI/config defaults. */
|
||||||
|
export type ItemTypeClientDefinition = {
|
||||||
|
type: ItemType;
|
||||||
|
label: string;
|
||||||
|
tooltip?: string;
|
||||||
|
editableProperties: string[];
|
||||||
|
globalProperties: Record<string, string | number | boolean>;
|
||||||
|
propertyOptions?: Record<string, string[]>;
|
||||||
|
propertyMetadata?: Record<string, ItemPropertyMetadata>;
|
||||||
|
};
|
||||||
|
|
||||||
18
client/src/items/types/wheel.ts
Normal file
18
client/src/items/types/wheel.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { type ItemTypeClientDefinition } from './shared';
|
||||||
|
|
||||||
|
/** Default client-side UI definition for wheel items. */
|
||||||
|
export const wheelDefinition: ItemTypeClientDefinition = {
|
||||||
|
type: 'wheel',
|
||||||
|
label: 'wheel',
|
||||||
|
editableProperties: ['title', 'spaces'],
|
||||||
|
globalProperties: {
|
||||||
|
useSound: 'sounds/spin.ogg',
|
||||||
|
emitSound: 'none',
|
||||||
|
useCooldownMs: 4000,
|
||||||
|
emitRange: 15,
|
||||||
|
directional: false,
|
||||||
|
emitSoundSpeed: 50,
|
||||||
|
emitSoundTempo: 50,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
35
client/src/items/types/widget.ts
Normal file
35
client/src/items/types/widget.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import { EFFECT_SEQUENCE } from '../../audio/effects';
|
||||||
|
import { type ItemTypeClientDefinition } from './shared';
|
||||||
|
|
||||||
|
/** Default client-side UI definition for widget items. */
|
||||||
|
export const widgetDefinition: ItemTypeClientDefinition = {
|
||||||
|
type: 'widget',
|
||||||
|
label: 'widget',
|
||||||
|
editableProperties: [
|
||||||
|
'title',
|
||||||
|
'enabled',
|
||||||
|
'directional',
|
||||||
|
'facing',
|
||||||
|
'emitRange',
|
||||||
|
'emitVolume',
|
||||||
|
'emitSoundSpeed',
|
||||||
|
'emitSoundTempo',
|
||||||
|
'emitEffect',
|
||||||
|
'emitEffectValue',
|
||||||
|
'useSound',
|
||||||
|
'emitSound',
|
||||||
|
],
|
||||||
|
globalProperties: {
|
||||||
|
useSound: 'none',
|
||||||
|
emitSound: 'none',
|
||||||
|
useCooldownMs: 1000,
|
||||||
|
emitRange: 15,
|
||||||
|
directional: false,
|
||||||
|
emitSoundSpeed: 50,
|
||||||
|
emitSoundTempo: 50,
|
||||||
|
},
|
||||||
|
propertyOptions: {
|
||||||
|
emitEffect: EFFECT_SEQUENCE.map((effect) => effect.id),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
Reference in New Issue
Block a user