import { pauseAnimation, playAnimation, stopAnimation } from '../../../model/animation'; import type { NodeDef, PortDef } from '../../NodeRegistry'; import { asBoolean, asEntity, asNumber, asString } from '../../values'; import { bool, exec, num, obj, withDefault } from '../shared'; /** * The `animation` input of the animation nodes; unconnected it shows the animation picker, the * way `soundPort` shows the sound picker. An `Animation` literal or a list item is what feeds it. */ export const animationPort = (): PortDef => ({ key: 'animation', label: 'animation', type: 'string', field: { key: 'animation', label: 'Animation', kind: 'animation', default: '' }, }); export const PlayAnimation: NodeDef = { type: 'PlayAnimation', label: 'Play animation', category: 'action', description: 'Plays an animation on an object: its rows reach the object and what is placed inside it, so every ' + 'instance plays on its own. A paused one runs on from where it stands; one already running keeps its ' + 'frame but wins again over the others on the object. Blend fades numbers and colors over that many ' + 'seconds from what they held when it took over; everything else switches at once. Blend out is for ' + 'Once (reset): when its frames run out it fades back to where it started over that many seconds. ' + 'Restart starts one already running or paused over from its first frame – blended in from where it ' + 'stands when Blend is set.', inputs: [ exec(), obj('object'), animationPort(), withDefault(num('blend', 'blend (s)'), 0), withDefault(num('blendOut', 'blend out (s)'), 0), withDefault(bool('restart'), false), ], outputs: [exec()], params: [], run: (ctx, inputs) => { const target = asEntity(inputs.object); const animation = asString(inputs.animation); if (target && animation) playAnimation( target, animation, Math.max(0, asNumber(inputs.blend)), Math.max(0, asNumber(inputs.blendOut)), asBoolean(inputs.restart), ctx.self, ); return { next: 'exec' }; }, }; export const StopAnimation: NodeDef = { type: 'StopAnimation', label: 'Stop animation', category: 'action', description: 'Ends an animation on an object where it stands – the values it set stay. With a blend it fades out ' + 'over that many seconds instead, back to what another animation sets there or else to what the ' + 'values were when it started. Leave Animation at None to end every one.', inputs: [exec(), obj('object'), animationPort(), withDefault(num('blend', 'blend (s)'), 0)], outputs: [exec()], params: [], run: (_ctx, inputs) => { const target = asEntity(inputs.object); if (target) stopAnimation(target, asString(inputs.animation), Math.max(0, asNumber(inputs.blend))); return { next: 'exec' }; }, }; export const PauseAnimation: NodeDef = { type: 'PauseAnimation', label: 'Pause animation', category: 'action', description: 'Holds an animation on an object at its frame until Play animation lets it run on. Leave Animation at None to hold every one.', inputs: [exec(), obj('object'), animationPort()], outputs: [exec()], params: [], run: (_ctx, inputs) => { const target = asEntity(inputs.object); if (target) pauseAnimation(target, asString(inputs.animation)); return { next: 'exec' }; }, };