import { CreateAssetCommand, DeleteAssetCommand, DuplicateAssetCommand, MakeProjectAssetCommand, RenameAssetCommand, ResetAssetPropertyCommand, SetAssetPropertyCommand, SetMachineScopeCommand, SetMachineStartCommand, SetStartSceneCommand, SetVariablesPersistentCommand, SetVariablesScopeCommand, } from '../../../core/commands/assetCommands'; import { ASSET_TYPES, type AssetType } from '../../../core/model/AssetTypes'; import type { PropertyBag, PropertyValue } from '../../../core/model/Properties'; import type { Scope, SharedScope } from '../../../core/model/Scope'; import { ASSET, anyValue, type CatalogCommand, flag, id, madeAsset, object, oneOf, text, theAsset, } from './shared'; /** Assets the agent cannot make: each needs a file, and there is no upload for agents. */ const FILE_TYPES: readonly AssetType[] = ['texture', 'font', 'sound', 'video']; export const ASSET_COMMANDS: readonly CatalogCommand[] = [ { name: 'create_asset', description: 'Makes a new asset. A scene is where objects are placed; a sprite, text or camera is placed into one; ' + "a behavior is a graph of nodes that runs on the object it is placed under. Textures, fonts, sounds and videos need a file and can't be made here.", args: object( { type: { type: 'string', enum: ASSET_TYPES.filter((type) => !FILE_TYPES.includes(type)), description: 'The kind of asset.', }, name: { type: 'string', minLength: 1, description: 'Its name in the asset list.' }, props: { type: 'object', description: "Starting values of its properties by key (see catalog topic 'asset_types').", }, }, ['type', 'name'], ), build: (args) => { const command = new CreateAssetCommand( text(args, 'type') as AssetType, text(args, 'name'), (args.props ?? {}) as PropertyBag, ); return { command, made: { id: command.asset.id } }; }, shows: madeAsset, }, { name: 'rename_asset', description: 'Renames an asset.', args: object({ asset: ASSET, name: { type: 'string', minLength: 1 } }, ['asset', 'name']), build: (args) => ({ command: new RenameAssetCommand(text(args, 'asset'), text(args, 'name')) }), shows: theAsset, }, { name: 'duplicate_asset', description: 'Copies an asset; the copy comes right behind it in the list.', args: object({ asset: ASSET }, ['asset']), build: (args) => { const command = new DuplicateAssetCommand(text(args, 'asset')); return { command, made: { id: command.copyId } }; }, shows: madeAsset, }, { name: 'delete_asset', description: 'Deletes an asset and what depends on it (placed copies of it, for one). The user is asked first and may say no.', args: object({ asset: ASSET }, ['asset']), confirms: true, build: (args) => ({ command: new DeleteAssetCommand(text(args, 'asset')) }), }, { name: 'set_asset_property', description: "Sets a property of an asset by its key (see get_asset, or catalog topic 'asset_types').", args: object({ asset: ASSET, key: id('Key of the property.'), value: anyValue }, [ 'asset', 'key', 'value', ]), build: (args) => ({ command: new SetAssetPropertyCommand( text(args, 'asset'), text(args, 'key'), args.value as PropertyValue, ), }), shows: theAsset, }, { name: 'reset_asset_property', description: 'Puts a property of an asset back to what a new asset starts with.', args: object({ asset: ASSET, key: id('Key of the property.') }, ['asset', 'key']), build: (args) => ({ command: new ResetAssetPropertyCommand(text(args, 'asset'), text(args, 'key')) }), shows: theAsset, }, { name: 'set_start_scene', description: 'Makes a scene the one the game starts in; an empty scene id takes that back.', args: object({ scene: { type: 'string', description: 'Id of the scene, or "".' } }, ['scene']), build: (args) => ({ command: new SetStartSceneCommand(text(args, 'scene')) }), }, { name: 'set_machine_scope', description: 'How many current states a state machine keeps: local, one per behavior running it; global, one for the ' + 'whole run; scene, one that starts over with every scene.', args: object({ asset: ASSET, scope: oneOf(['local', 'global', 'scene'], 'The scope.') }, [ 'asset', 'scope', ]), build: (args) => ({ command: new SetMachineScopeCommand(text(args, 'asset'), text(args, 'scope') as Scope), }), shows: theAsset, }, { name: 'set_machine_start', description: 'Makes a state node the state a machine starts in; an empty node id takes the mark off.', args: object({ asset: ASSET, node: { type: 'string', description: 'Id of the state node, or "".' } }, [ 'asset', 'node', ]), build: (args) => ({ command: new SetMachineStartCommand(text(args, 'asset'), text(args, 'node')) }), shows: theAsset, }, { name: 'set_variables_scope', description: 'How long the values of a Variables asset live: global, the whole run; scene, built again with every scene ' + '(which also switches persistent off).', args: object({ asset: ASSET, scope: oneOf(['global', 'scene'], 'The scope.') }, ['asset', 'scope']), build: (args) => ({ command: new SetVariablesScopeCommand(text(args, 'asset'), text(args, 'scope') as SharedScope), }), shows: theAsset, }, { name: 'set_variables_persistent', description: 'Whether a Variables asset keeps its values past the end of the run, saved in the browser.', args: object({ asset: ASSET, persistent: flag('Keep them.') }, ['asset', 'persistent']), build: (args) => ({ command: new SetVariablesPersistentCommand(text(args, 'asset'), args.persistent as boolean), }), shows: theAsset, }, { name: 'make_project_asset', description: "Makes an asset a song keeps to itself (it has an owner in list_assets) one of the project's own, shown in the lists.", args: object({ asset: ASSET }, ['asset']), build: (args) => ({ command: new MakeProjectAssetCommand(text(args, 'asset')) }), shows: theAsset, }, ];