const Cast = require('../util/cast'); class Scratch3EventBlocks { constructor (runtime) { /** * The runtime instantiating this block package. * @type {Runtime} */ this.runtime = runtime; this.runtime.on('KEY_PRESSED', key => { this.runtime.startHats('event_whenkeypressed', { KEY_OPTION: key }); this.runtime.startHats('event_whenkeypressed', { KEY_OPTION: 'any' }); }); } /** * Retrieve the block primitives implemented by this package. * @return {object.} Mapping of opcode to Function. */ getPrimitives () { return { event_whentouchingobject: this.touchingObject, event_broadcast: this.broadcast, event_broadcastandwait: this.broadcastAndWait, event_whengreaterthan: this.hatGreaterThanPredicate }; } getHats () { return { event_whenflagclicked: { restartExistingThreads: true }, event_whenkeypressed: { restartExistingThreads: false }, event_whenthisspriteclicked: { restartExistingThreads: true }, event_whentouchingobject: { restartExistingThreads: false, edgeActivated: true }, event_whenstageclicked: { restartExistingThreads: true }, event_whenbackdropswitchesto: { restartExistingThreads: true }, event_whengreaterthan: { restartExistingThreads: false, edgeActivated: true }, event_whenbroadcastreceived: { restartExistingThreads: true } }; } touchingObject (args, util) { const requestedObject = args.TOUCHINGOBJECTMENU; if (requestedObject === '_mouse_') { const mouseX = util.ioQuery('mouse', 'getClientX'); const mouseY = util.ioQuery('mouse', 'getClientY'); return util.target.isTouchingPoint(mouseX, mouseY); } else if (requestedObject === '_edge_') { return util.target.isTouchingEdge(); } return util.target.isTouchingSprite(requestedObject); } hatGreaterThanPredicate (args, util) { const option = Cast.toString(args.WHENGREATERTHANMENU).toLowerCase(); const value = Cast.toNumber(args.VALUE); // @todo: Other cases :) if (option === 'timer') { return util.ioQuery('clock', 'projectTimer') > value; } return false; } broadcast (args, util) { const broadcastVar = util.runtime.getTargetForStage().lookupBroadcastMsg( args.BROADCAST_OPTION.id, args.BROADCAST_OPTION.name); if (broadcastVar) { const broadcastOption = broadcastVar.name; util.startHats('event_whenbroadcastreceived', { BROADCAST_OPTION: broadcastOption }); } } broadcastAndWait (args, util) { const broadcastVar = util.runtime.getTargetForStage().lookupBroadcastMsg( args.BROADCAST_OPTION.id, args.BROADCAST_OPTION.name); if (broadcastVar) { const broadcastOption = broadcastVar.name; // Have we run before, starting threads? if (!util.stackFrame.startedThreads) { // No - start hats for this broadcast. util.stackFrame.startedThreads = util.startHats( 'event_whenbroadcastreceived', { BROADCAST_OPTION: broadcastOption } ); if (util.stackFrame.startedThreads.length === 0) { // Nothing was started. return; } } // We've run before; check if the wait is still going on. const instance = this; const waiting = util.stackFrame.startedThreads.some(thread => instance.runtime.isActiveThread(thread)); if (waiting) { util.yield(); } } } } module.exports = Scratch3EventBlocks;