Spaces:
Runtime error
Runtime error
| const BlockType = require('../../extension-support/block-type'); | |
| const ArgumentType = require('../../extension-support/argument-type'); | |
| const Cast = require('../../util/cast'); | |
| class TailgatingExtension { | |
| constructor(runtime) { | |
| /** | |
| * The runtime instantiating this block package. | |
| * @type {Runtime} | |
| */ | |
| this.runtime = runtime; | |
| this.trackers = Object.create(null); | |
| this.maxSaving = Object.create(null); | |
| this.positions = Object.create(null); | |
| const shouldSaveNewPosition = (positionsList, tracker) => { | |
| const firstPos = positionsList[0]; | |
| if (typeof firstPos !== "object") return true; | |
| if (firstPos.x !== tracker.x || firstPos.y !== tracker.y) { | |
| return true; | |
| } | |
| return false; | |
| }; | |
| this.runtime.on('RUNTIME_STEP_START', () => { | |
| for (const trackerName in this.trackers) { | |
| const tracker = this.trackers[trackerName]; | |
| // happens when sprite is deleted or clone is deleted | |
| if (tracker.isDisposed) { | |
| this.stopTrackingSprite({ NAME: trackerName }); | |
| continue; | |
| } | |
| // 0 positions should be saved, so just dont make them at all | |
| const positions = this.positions[trackerName]; | |
| const maxPositions = this.maxSaving[trackerName]; | |
| if (maxPositions <= 0) continue; | |
| // only track new positions when they have changed | |
| // we have no reason to track the same position multiple times (that would make this ext useless) | |
| if (shouldSaveNewPosition(positions, tracker)) { | |
| // console.log('saved new pos for', trackerName); | |
| positions.unshift({ x: tracker.x, y: tracker.y }); | |
| } | |
| this.positions[trackerName] = positions.slice(0, maxPositions); | |
| } | |
| }); | |
| } | |
| getInfo() { | |
| return { | |
| id: "jgTailgating", | |
| name: "Tailgating", | |
| blocks: [ | |
| { | |
| opcode: "startTrackingSprite", | |
| blockType: BlockType.COMMAND, | |
| text: "start tracking [SPRITE] as [NAME]", | |
| arguments: { | |
| SPRITE: { | |
| type: ArgumentType.STRING, | |
| menu: "spriteMenu", | |
| }, | |
| NAME: { | |
| type: ArgumentType.STRING, | |
| defaultValue: "leader", | |
| } | |
| }, | |
| }, | |
| { | |
| opcode: "stopTrackingSprite", | |
| blockType: BlockType.COMMAND, | |
| text: "stop tracking [NAME]", | |
| arguments: { | |
| NAME: { | |
| type: ArgumentType.STRING, | |
| defaultValue: "leader", | |
| } | |
| }, | |
| }, | |
| '---', | |
| { | |
| opcode: "followSprite", | |
| blockType: BlockType.COMMAND, | |
| text: "follow [INDEX] positions behind [NAME]", | |
| arguments: { | |
| INDEX: { | |
| type: ArgumentType.NUMBER, | |
| defaultValue: 20, | |
| }, | |
| NAME: { | |
| type: ArgumentType.STRING, | |
| defaultValue: "leader", | |
| } | |
| }, | |
| }, | |
| { | |
| opcode: "savePositionsBehindSprite", | |
| blockType: BlockType.COMMAND, | |
| text: "set max saved positions behind [NAME] to [MAX]", | |
| arguments: { | |
| MAX: { | |
| type: ArgumentType.NUMBER, | |
| defaultValue: 20, | |
| }, | |
| NAME: { | |
| type: ArgumentType.STRING, | |
| defaultValue: "leader", | |
| } | |
| }, | |
| }, | |
| { | |
| opcode: "getSpriteFollowPos", | |
| blockType: BlockType.REPORTER, | |
| disableMonitor: true, | |
| text: "get position [INDEX] behind [NAME]", | |
| arguments: { | |
| INDEX: { | |
| type: ArgumentType.NUMBER, | |
| defaultValue: 20, | |
| }, | |
| NAME: { | |
| type: ArgumentType.STRING, | |
| defaultValue: "leader", | |
| } | |
| }, | |
| }, | |
| ], | |
| menus: { | |
| spriteMenu: '_getSpriteMenu' | |
| }, | |
| }; | |
| } | |
| // menus | |
| _getSpriteMenu() { | |
| const emptyMenu = [{ text: '', value: '' }]; | |
| const sprites = []; | |
| if (this.runtime.vm.editingTarget && !this.runtime.vm.editingTarget.isStage) { | |
| sprites.push({ text: 'this sprite', value: '_myself_' }); | |
| } | |
| for (const target of this.runtime.targets) { | |
| if (!target.isOriginal) continue; | |
| if (target.isStage) continue; | |
| if (this.runtime.vm.editingTarget && this.runtime.vm.editingTarget.id === target.id) continue; | |
| const name = target.getName(); | |
| sprites.push({ | |
| text: name, | |
| value: name | |
| }); | |
| } | |
| return sprites.length > 0 ? sprites : emptyMenu; | |
| } | |
| // blocks | |
| startTrackingSprite(args, util) { | |
| const spriteName = Cast.toString(args.SPRITE); | |
| const trackerName = Cast.toString(args.NAME); | |
| const pickedSprite = spriteName === '_myself_' ? util.target : this.runtime.getSpriteTargetByName(spriteName); | |
| if (!pickedSprite) return; | |
| this.trackers[trackerName] = pickedSprite; | |
| this.positions[trackerName] = []; | |
| if (!(trackerName in this.maxSaving)) { | |
| this.maxSaving[trackerName] = 20; | |
| } | |
| } | |
| stopTrackingSprite(args) { | |
| const trackerName = Cast.toString(args.NAME); | |
| delete this.trackers[trackerName]; | |
| this.positions[trackerName] = []; | |
| } | |
| followSprite(args, util) { | |
| const trackerName = Cast.toString(args.NAME); | |
| const index = Cast.toNumber(args.INDEX); | |
| const spritePositions = this.positions[trackerName]; | |
| if (!spritePositions) return; | |
| let position = spritePositions[index]; | |
| if (typeof position !== "object") { | |
| // this index position was not found | |
| // use the last one in the list instead | |
| // if there is nothing in the list, dont do anything | |
| if (spritePositions.length <= 0) return; | |
| position = spritePositions[spritePositions.length - 1]; | |
| } | |
| util.target.setXY(position.x, position.y); | |
| } | |
| getSpriteFollowPos(args) { | |
| const trackerName = Cast.toString(args.NAME); | |
| const index = Cast.toNumber(args.INDEX); | |
| const spritePositions = this.positions[trackerName]; | |
| if (!spritePositions) return '{}'; | |
| let position = spritePositions[index]; | |
| if (typeof position !== "object") { | |
| // this index position was not found | |
| // use the last one in the list instead | |
| // if there is nothing in the list, dont do anything | |
| if (spritePositions.length <= 0) return '{}'; | |
| position = spritePositions[spritePositions.length - 1]; | |
| } | |
| return JSON.stringify({ | |
| x: position.x, | |
| y: position.y | |
| }); | |
| } | |
| savePositionsBehindSprite(args, util) { | |
| const trackerName = Cast.toString(args.NAME); | |
| const maxPositions = Cast.toNumber(args.MAX); | |
| let max = Math.round(maxPositions); | |
| if (max <= 0) { | |
| max = 0; | |
| } | |
| if (max > 0) { | |
| max++; | |
| } | |
| this.maxSaving[trackerName] = max; | |
| } | |
| } | |
| module.exports = TailgatingExtension; |