Spaces:
Runtime error
Runtime error
| const BlockType = require('../../extension-support/block-type') | |
| const BlockShape = require('../../extension-support/block-shape') | |
| const ArgumentType = require('../../extension-support/argument-type') | |
| const TargetType = require('../../extension-support/target-type') | |
| const Cast = require('../../util/cast') | |
| function span(text) { | |
| let el = document.createElement('span') | |
| el.innerHTML = text | |
| el.style.display = 'hidden' | |
| el.style.whiteSpace = 'nowrap' | |
| el.style.width = '100%' | |
| el.style.textAlign = 'center' | |
| return el | |
| } | |
| class jwTargetType { | |
| customId = "jwTargets" | |
| targetId = "" | |
| constructor(targetId) { | |
| this.targetId = targetId | |
| } | |
| static toTarget(x) { | |
| if (x instanceof jwTargetType) return x | |
| if (typeof x == "string") return new jwTargetType(x) | |
| return new jwTargetType("") | |
| } | |
| jwArrayHandler() { | |
| try { | |
| return `Target<${this.target.sprite.name}>` | |
| } catch { | |
| return `Target` | |
| } | |
| } | |
| toString() { | |
| return this.targetId | |
| } | |
| toMonitorContent = () => span(this.toString()) | |
| toReporterContent() { | |
| try { | |
| let target = this.target | |
| let name = target.sprite.name | |
| let isClone = !target.isOriginal | |
| let costumeURI = target.getCostumes()[target.currentCostume].asset.encodeDataURI() | |
| let root = document.createElement('div') | |
| root.style.display = 'flex' | |
| root.style.flexDirection = 'column' | |
| root.style.justifyContent = 'center' | |
| let img = document.createElement('img') | |
| img.src = costumeURI | |
| img.style.maxWidth = '150px' | |
| img.style.maxHeight = '150px' | |
| root.appendChild(img) | |
| root.appendChild(span(`${name}${isClone ? ' (clone)' : ''}`)) | |
| return root | |
| } catch { | |
| return span("Unknown") | |
| } | |
| } | |
| get target() { | |
| return vm.runtime.getTargetById(this.targetId) | |
| } | |
| } | |
| const Target = { | |
| Type: jwTargetType, | |
| Block: { | |
| blockType: BlockType.REPORTER, | |
| forceOutputType: "Target", | |
| disableMonitor: true | |
| }, | |
| Argument: { | |
| check: ["Target"] | |
| } | |
| } | |
| let jwArray = { | |
| Type: class {}, | |
| Block: {}, | |
| Argument: {} | |
| } | |
| class Extension { | |
| constructor() { | |
| vm.jwTargets = Target | |
| vm.runtime.registerSerializer( | |
| "jwTargets", | |
| v => v.targetId, | |
| v => new Target.Type(v) | |
| ); | |
| if (!vm.jwArray) vm.extensionManager.loadExtensionIdSync('jwArray') | |
| jwArray = vm.jwArray | |
| } | |
| getInfo() { | |
| return { | |
| id: "jwTargets", | |
| name: "Targets", | |
| color1: "#4254f5", | |
| menuIconURI: "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyMCAyMCIgeG1sbnM6Yng9Imh0dHBzOi8vYm94eS1zdmcuY29tIj4KICA8Y2lyY2xlIHN0eWxlPSJzdHJva2Utd2lkdGg6IDJweDsgcGFpbnQtb3JkZXI6IHN0cm9rZTsgZmlsbDogcmdiKDY2LCA4NCwgMjQ1KTsgc3Ryb2tlOiByZ2IoNDAsIDU1LCAxOTkpOyIgY3g9IjEwIiBjeT0iMTAiIHI9IjkiPjwvY2lyY2xlPgogIDxwYXRoIGQ9Ik0gMTAgMy4yMjIgQyA0Ljc4MyAzLjIyMiAxLjUyMyA4Ljg3IDQuMTMgMTMuMzg5IEMgNS4zNCAxNS40ODUgNy41OCAxNi43NzggMTAgMTYuNzc4IEMgMTUuMjE4IDE2Ljc3OCAxOC40OCAxMS4xMyAxNS44NjkgNi42MTEgQyAxNC42NjEgNC41MTUgMTIuNDIyIDMuMjIyIDEwIDMuMjIyIE0gMTAgNS40ODEgQyAxMy40NzkgNS40ODEgMTUuNjUzIDkuMjQ4IDEzLjkxMyAxMi4yNTkgQyAxMy4xMDYgMTMuNjU4IDExLjYxNiAxNC41MTkgMTAgMTQuNTE5IEMgNi41MjIgMTQuNTE5IDQuMzUgMTAuNzUyIDYuMDg3IDcuNzQxIEMgNi44OTUgNi4zNDIgOC4zODUgNS40ODEgMTAgNS40ODEgTSAxMCA3Ljc0MSBDIDguMjYyIDcuNzQxIDcuMTczIDkuNjIyIDguMDQ0IDExLjEzIEMgOC40NDggMTEuODI4IDkuMTkzIDEyLjI1OSAxMCAxMi4yNTkgQyAxMS43NCAxMi4yNTkgMTIuODI3IDEwLjM3OCAxMS45NTYgOC44NyBDIDExLjU1MyA4LjE3MiAxMC44MDggNy43NDEgMTAgNy43NDEiIGZpbGw9IiNmZmYiIHN0eWxlPSIiPjwvcGF0aD4KPC9zdmc+", | |
| blocks: [ | |
| { | |
| opcode: 'this', | |
| text: 'this target', | |
| hideFromPalette: true, | |
| ...Target.Block | |
| }, | |
| { | |
| opcode: 'stage', | |
| text: 'stage target', | |
| hideFromPalette: true, | |
| ...Target.Block | |
| }, | |
| { | |
| opcode: 'fromName', | |
| text: '[SPRITE] target', | |
| arguments: { | |
| SPRITE: { | |
| menu: "sprite" | |
| } | |
| }, | |
| ...Target.Block | |
| }, | |
| { | |
| opcode: 'cloneOrigin', | |
| text: 'origin of [TARGET]', | |
| arguments: { | |
| TARGET: Target.Argument | |
| }, | |
| ...Target.Block | |
| }, | |
| '---', | |
| { | |
| opcode: 'get', | |
| text: '[TARGET] [MENU]', | |
| blockType: BlockType.REPORTER, | |
| arguments: { | |
| TARGET: Target.Argument, | |
| MENU: { | |
| menu: "targetProperty", | |
| defaultValue: "name" | |
| } | |
| } | |
| }, | |
| { | |
| opcode: 'set', | |
| text: 'set [TARGET] [MENU] to [VALUE]', | |
| blockType: BlockType.COMMAND, | |
| arguments: { | |
| TARGET: Target.Argument, | |
| MENU: { | |
| menu: "targetPropertySet", | |
| defaultValue: "x" | |
| }, | |
| VALUE: { | |
| type: ArgumentType.STRING, | |
| exemptFromNormalization: true | |
| } | |
| } | |
| }, | |
| '---', | |
| { | |
| opcode: 'isClone', | |
| text: 'is [TARGET] a clone', | |
| blockType: BlockType.BOOLEAN, | |
| arguments: { | |
| TARGET: Target.Argument | |
| } | |
| }, | |
| { | |
| opcode: 'isTouching', | |
| text: 'is [A] touching [B]', | |
| blockType: BlockType.BOOLEAN, | |
| arguments: { | |
| A: Target.Argument, | |
| B: Target.Argument | |
| } | |
| }, | |
| '---', | |
| { | |
| opcode: 'getVar', | |
| text: 'var [NAME] of [TARGET]', | |
| blockType: BlockType.REPORTER, | |
| allowDropAnywhere: true, | |
| arguments: { | |
| TARGET: Target.Argument, | |
| NAME: { | |
| type: ArgumentType.STRING | |
| } | |
| } | |
| }, | |
| { | |
| opcode: 'setVar', | |
| text: 'set var [NAME] of [TARGET] to [VALUE]', | |
| blockType: BlockType.COMMAND, | |
| arguments: { | |
| TARGET: Target.Argument, | |
| NAME: { | |
| type: ArgumentType.STRING | |
| }, | |
| VALUE: { | |
| type: ArgumentType.STRING, | |
| exemptFromNormalization: true | |
| } | |
| } | |
| }, | |
| '---', | |
| { | |
| opcode: 'clone', | |
| text: 'create clone of [TARGET]', | |
| blockType: BlockType.COMMAND, | |
| arguments: { | |
| TARGET: Target.Argument | |
| } | |
| }, | |
| { | |
| opcode: 'cloneR', | |
| text: 'create clone of [TARGET]', | |
| arguments: { | |
| TARGET: Target.Argument | |
| }, | |
| ...Target.Block | |
| }, | |
| '---', | |
| { | |
| opcode: 'all', | |
| text: 'all targets', | |
| ...jwArray.Block | |
| }, | |
| { | |
| opcode: 'touching', | |
| text: 'targets touching [TARGET]', | |
| arguments: { | |
| TARGET: Target.Argument | |
| }, | |
| ...jwArray.Block | |
| }, | |
| { | |
| opcode: 'clones', | |
| text: 'clones of [TARGET]', | |
| arguments: { | |
| TARGET: Target.Argument | |
| }, | |
| ...jwArray.Block | |
| }, | |
| { | |
| opcode: 'arrayHasTarget', | |
| text: '[ARRAY] has clone of [TARGET]', | |
| blockType: BlockType.BOOLEAN, | |
| arguments: { | |
| ARRAY: jwArray.Argument, | |
| TARGET: Target.Argument | |
| } | |
| }, | |
| '---', | |
| { | |
| blockType: BlockType.XML, | |
| xml: `<block type="control_run_as_sprite" />` | |
| } | |
| ], | |
| menus: { | |
| sprite: { | |
| acceptReporters: true, | |
| items: 'getSpriteMenu' | |
| }, | |
| targetProperty: { | |
| acceptReporters: true, | |
| items: [ | |
| "name", | |
| "x", | |
| "y", | |
| "direction", | |
| "size", | |
| "stretch x", | |
| "stretch y", | |
| "costume #", | |
| "costume name", | |
| ] | |
| }, | |
| targetPropertySet: { | |
| acceptReporters: true, | |
| items: [ | |
| "x", | |
| "y", | |
| "direction", | |
| "size", | |
| "stretch x", | |
| "stretch y", | |
| "costume #", | |
| "costume name", | |
| ] | |
| } | |
| } | |
| }; | |
| } | |
| getSpriteMenu({}) { | |
| let sprites = ["this", "stage"] | |
| for (let target of vm.runtime.targets.filter(v => v !== vm.runtime._stageTarget)) { | |
| if (!sprites.includes(target.sprite.name)) sprites.push(target.sprite.name) | |
| } | |
| return sprites | |
| } | |
| this({}, util) { | |
| return new Target.Type(util.target.id) | |
| } | |
| stage() { | |
| return new Target.Type(vm.runtime._stageTarget.id) | |
| } | |
| fromName({SPRITE}, util) { | |
| SPRITE = Cast.toString(SPRITE) | |
| if (SPRITE == "this") return this.this({}, util) | |
| if (SPRITE == "stage") return this.stage() | |
| let target = vm.runtime.getSpriteTargetByName(SPRITE) | |
| return new Target.Type(target ? target.id : "") | |
| } | |
| cloneOrigin({TARGET}, util) { | |
| TARGET = Target.Type.toTarget(TARGET) | |
| if (!TARGET.target) return "" | |
| return this.fromName({SPRITE: TARGET.target.sprite.name}, util) | |
| } | |
| get({TARGET, MENU}) { | |
| TARGET = Target.Type.toTarget(TARGET) | |
| MENU = Cast.toString(MENU) | |
| if (!TARGET.target) return "" | |
| switch(MENU) { | |
| case "x": return TARGET.target.x | |
| case "y": return TARGET.target.y | |
| case "direction": return TARGET.target.direction | |
| case "size": return TARGET.target.size | |
| case "name": return TARGET.target.sprite.name | |
| case "stretch x": return TARGET.target.stretch[0] | |
| case "stretch y": return TARGET.target.stretch[1] | |
| case "costume #": return TARGET.target.currentCostume + 1 | |
| case "costume name": return TARGET.target.getCurrentCostume().name | |
| } | |
| return "" | |
| } | |
| set({TARGET, MENU, VALUE}) { | |
| TARGET = Target.Type.toTarget(TARGET) | |
| MENU = Cast.toString(MENU) | |
| if (!TARGET.target) return | |
| switch(MENU) { | |
| case "x": | |
| TARGET.target.setXY(Cast.toNumber(VALUE), TARGET.target.y) | |
| break | |
| case "y": | |
| TARGET.target.setXY(TARGET.target.x, Cast.toNumber(VALUE)) | |
| break | |
| case "direction": | |
| TARGET.target.setDirection(Cast.toNumber(VALUE)) | |
| break | |
| case "size": | |
| TARGET.target.setSize(Cast.toNumber(VALUE)) | |
| break | |
| case "stretch x": | |
| TARGET.target.setStretch(Cast.toNumber(VALUE), TARGET.target.stretch[1]) | |
| break | |
| case "stretch y": | |
| TARGET.target.setStretch(TARGET.target.stretch[0], Cast.toNumber(VALUE)) | |
| break | |
| case "costume #": | |
| TARGET.target.setCostume(Cast.toNumber(VALUE) - 1) | |
| break | |
| case "costume name": | |
| let index = TARGET.target.getCostumes().indexOf(TARGET.target.getCostumes().find(v => v.name === Cast.toString(VALUE))) | |
| TARGET.target.setCostume(index) | |
| break | |
| } | |
| } | |
| isClone({TARGET}) { | |
| TARGET = Target.Type.toTarget(TARGET) | |
| if (!TARGET.target) return false | |
| return !TARGET.target.isOriginal | |
| } | |
| isTouching({A, B}) { | |
| A = Target.Type.toTarget(A) | |
| B = Target.Type.toTarget(B) | |
| if (!A.target) return | |
| return A.target.isTouchingTarget(B.targetId) | |
| } | |
| getVar({TARGET, NAME}) { | |
| TARGET = Target.Type.toTarget(TARGET) | |
| NAME = Cast.toString(NAME) | |
| if (!TARGET.target) return "" | |
| let variable = Object.values(TARGET.target.variables).find(v => v.name == NAME) | |
| if (!variable) return "" | |
| return variable.value | |
| } | |
| setVar({TARGET, NAME, VALUE}) { | |
| TARGET = Target.Type.toTarget(TARGET) | |
| NAME = Cast.toString(NAME) | |
| if (!TARGET.target) return | |
| let variable = Object.values(TARGET.target.variables).find(v => v.name == NAME) | |
| if (!variable) return | |
| variable.value = VALUE | |
| } | |
| clone(args) { | |
| this.cloneR(args) | |
| } | |
| cloneR({TARGET}) { | |
| TARGET = Target.Type.toTarget(TARGET) | |
| if (!TARGET.target) return | |
| let origin = TARGET.target | |
| let clone = origin.makeClone() | |
| if (clone) { | |
| vm.runtime.addTarget(clone) | |
| clone.goBehindOther(origin) //mimick clone making from control category | |
| } | |
| return new Target.Type(clone ? clone.id : "") | |
| } | |
| all() { | |
| return new jwArray.Type(vm.runtime.targets.map(v => new Target.Type(v.id))) | |
| } | |
| touching({TARGET}) { | |
| TARGET = Target.Type.toTarget(TARGET) | |
| if (!TARGET.target) return new jwArray.Type | |
| let targets = vm.runtime.targets | |
| targets = targets.filter(v => v !== TARGET && !v.isStage) | |
| targets = targets.filter(v => v.isTouchingTarget(TARGET.targetId)) | |
| return new jwArray.Type(targets.map(v => new Target.Type(v.id))) | |
| } | |
| clones({TARGET}) { | |
| TARGET = Target.Type.toTarget(TARGET) | |
| if (TARGET.target) { | |
| return new jwArray.Type(TARGET.target.sprite.clones.filter(v => !v.isOriginal).map(v => new Target.Type(v.id))) | |
| } | |
| return new jwArray.Type() | |
| } | |
| arrayHasTarget({ARRAY, TARGET}) { | |
| ARRAY = jwArray.Type.toArray(ARRAY) | |
| TARGET = Target.Type.toTarget(TARGET) | |
| if (!TARGET.target) return false | |
| return ARRAY.array.find(v => { | |
| let target = Target.Type.toTarget(v) | |
| if (!target.target) return false | |
| return target.target.sprite == TARGET.target.sprite | |
| }) !== undefined | |
| } | |
| } | |
| module.exports = Extension |