/** * Picking an object of the same scene for an object variable (#258), with the real mouse: the * placed behavior offers None and the scene's objects, the pick is stored as the object's id and a * run reads the object itself. Removing that object drops the reference; undo brings it back. On the * behavior asset there is no scene, so the row still says "(null)". * * Everything it adds carries an `or57` id and goes again at the end. */ import { MAKE_OBJECT } from './lib/scaffold.mjs'; export async function objectReferences(t) { const { check, json, evaluate, mutate, click, press, sleep, shot, select, undo, stop } = t; const press_ = async (at, what) => { if (!at) throw new Error(`nothing to click: ${what}`); await click(at.x, at.y); await sleep(150); }; const target = () => json("__gm.state.activeScene.objects.find((o) => o.id === 'or57-obj')?.overrides.target ?? null"); // On start the behavior logs the object its `target` names. const graph = { nodes: [ { id: 'or57-start', type: 'OnStart', x: 0, y: 0, params: {} }, { id: 'or57-vars', type: 'Variables', x: 0, y: 200, params: {}, ports: [{ key: 'target', kind: 'object' }], }, { id: 'or57-log', type: 'Log', x: 320, y: 0, params: {} }, ], edges: [ { id: 'or57-e1', from: { node: 'or57-start', port: 'exec' }, to: { node: 'or57-log', port: 'exec' } }, { id: 'or57-e2', from: { node: 'or57-vars', port: 'target' }, to: { node: 'or57-log', port: 'message' }, }, ], }; await mutate(` const p = __gm.state.project; const scene = __gm.state.activeScene; p.assets.push({ id: 'or57-aim', type: 'behavior', name: 'Aim 57', props: { enabled: true, runInEditor: false, target: { $object: '' } }, variables: [{ key: 'target', label: 'target', kind: 'object', default: { $object: '' } }], graph: ${JSON.stringify(graph)}, }); ${MAKE_OBJECT} const sprite = p.assets.find((a) => a.type === 'sprite'); scene.objects.push(make('or57-obj', 'or57-aim', '', 400, 'Aim 57')); scene.objects.push(make('or57-crate', sprite.id, '', 450, 'Crate 57')); `); const sceneId = await json('__gm.state.activeScene.id'); // 57a. The behavior asset has no scene: its object variable only says "(null)". await select({ kind: 'asset', assetId: 'or57-aim' }); await sleep(200); check( 'on the behavior asset the object variable says (null)', (await json("__gm.locate('(null)')")) !== null, ); // 57b. On the placed object the row is a dropdown: None, the object itself and the Crate. A click // on the Crate stores its id. await select({ kind: 'object', holderId: sceneId, objectId: 'or57-obj' }); await sleep(200); await press_(await json("__gm.inspectorField('target')"), 'the target field'); const offered = (await json('__gm.overlayTexts()')) ?? []; await shot('01-menu'); check( 'the placed object offers None, itself and the other objects of the scene', ['None', 'Aim 57', 'Crate 57'].every((label) => offered.includes(label)), JSON.stringify(offered), ); await press_(await json("__gm.locate('Crate 57', true)"), 'Crate 57 in the menu'); const picked = await target(); check( 'picking the Crate stores its id and the row shows its name', JSON.stringify(picked) === JSON.stringify({ $object: 'or57-crate' }) && (await json("__gm.locate('Crate 57')")) !== null, JSON.stringify(picked), ); await shot('02-picked'); // 57c. A run reads the object itself. await evaluate('__gm.state.select(null)'); const logFrom = t.consoleLog.length; await t.play(); await sleep(600); await stop(); const logged = t.consoleLog .slice(logFrom) .filter((line) => line.startsWith('[behavior Aim 57]')) .map((line) => line.split(']').pop().trim()); check('in a run the variable is the picked object', logged.includes('Crate 57'), JSON.stringify(logged)); // 57d. Removing the Crate drops the reference with it; one undo brings both back. await select({ kind: 'object', holderId: sceneId, objectId: 'or57-crate' }); await sleep(150); await press('Delete'); await sleep(150); const dropped = await target(); await undo(); const back = await target(); check( 'removing the picked object drops the reference, undo brings it back', JSON.stringify(dropped) === JSON.stringify({ $object: '' }) && JSON.stringify(back) === JSON.stringify({ $object: 'or57-crate' }), JSON.stringify({ dropped, back }), ); // Clean up. await evaluate('__gm.state.select(null)'); await mutate(` const p = __gm.state.project; const scene = __gm.state.activeScene; scene.objects = scene.objects.filter((o) => !o.id.startsWith('or57-')); p.assets = p.assets.filter((a) => a.id !== 'or57-aim'); `); }