diff --git a/README.md b/README.md index 0b7ccef..9330902 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # desynced-tools + Tools for working with behaviors and blueprints from Desynced. # Getting started @@ -10,6 +11,7 @@ Try online at https://desynced-behavior-editor.web.app/ or for command line tool # Tools ## ds-disas + Usage: `ds-disas filename.txt` Converts a Desynced blueprint or behavior string to assembly language. @@ -17,18 +19,19 @@ The output filename will be the input with ".asm" added. To produce the input file, copy a behavior or blueprint in the game and then paste that into a plain text file. ## ds-as + Usage: `ds-as filename.asm` Convert from assembly language back into a Desynced clipboard string. The output filename will be the input with ".txt" added. ## js2ds + Usage: `js2ds filename.js` or `js2ds filename.ts` Convert from JavaScript or TypeScript to desynced-tools assembly language. The output filename will be the input with ".asm" added. - # Development Checkout out the code from https://github.com/ribrdb/desynced-tools @@ -36,7 +39,9 @@ Checkout out the code from https://github.com/ribrdb/desynced-tools First run `npm install` to install dependencies, then run `npm run generate` to generate required code. ## Web demo + To build the web demo: - - `npm run esbuild` - - Extract the monaco 0.45.0 distribution into website/monaco-editor-0.45.0/ - https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.45.0.tgz + +- `npm run esbuild` +- Extract the monaco 0.45.0 distribution into website/monaco-editor-0.45.0/ + https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.45.0.tgz diff --git a/TODO.md b/TODO.md index 9aca850..5bc4e69 100644 --- a/TODO.md +++ b/TODO.md @@ -6,4 +6,4 @@ easier syntax for setting them. - Review instructions to see if more should have JS overrides. - Figure out how to support mods? -- Write a vscode extension. \ No newline at end of file +- Write a vscode extension. diff --git a/as.ts b/as.ts index 65ddfae..48cec1e 100644 --- a/as.ts +++ b/as.ts @@ -1,17 +1,14 @@ #!/usr/bin/env node -import * as fs from "fs"; -import { ObjectToDesyncedString } from "./dsconvert"; import { assemble } from "./assembler"; +import { ObjectToDesyncedString } from "./dsconvert"; +import * as fs from "fs"; const code = fs.readFileSync(process.argv[2], "utf8"); const obj = assemble(code); -let typ = 'C' -if ('frame' in obj) { - typ = 'B'; +let typ = "C"; +if ("frame" in obj) { + typ = "B"; } const str = ObjectToDesyncedString(obj, typ); fs.writeFileSync(process.argv[2] + ".txt", str); -fs.writeFileSync( - process.argv[2] + ".json", - JSON.stringify(obj, undefined, 2) -); +fs.writeFileSync(process.argv[2] + ".json", JSON.stringify(obj, undefined, 2)); diff --git a/asm.monarch.js b/asm.monarch.js index a1b63e2..a6d5767 100644 --- a/asm.monarch.js +++ b/asm.monarch.js @@ -6,52 +6,59 @@ export const asmSyntax = { // defaultToken: 'invalid', keywords: [ - 'nil', 'true', 'false', 'self', 'signal', 'visual', 'goto', 'store' + "nil", + "true", + "false", + "self", + "signal", + "visual", + "goto", + "store", ], - // this came from an example, not sure if it really matches json escapes. - escapes: /\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/, + escapes: + /\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/, // The main tokenizer for our languages tokenizer: { root: [ // identifiers and keywords - - [/\w+:|:\w+/, 'type.identifier' ], // to show labels nicely - [/p\d+|[A-Z]/, 'variable'], - [/\$\w+(?==)/, 'attribute.name'], - [/[a-z_]\w+/, {cases:{ - '@keywords': 'keyword', - '@default': 'identifier' }} ], + + [/\w+:|:\w+/, "type.identifier"], // to show labels nicely + [/p\d+|[A-Z]/, "variable"], + [/\$\w+(?==)/, "attribute.name"], + [ + /[a-z_]\w+/, + { + cases: { + "@keywords": "keyword", + "@default": "identifier", + }, + }, + ], // whitespace - { include: '@whitespace' }, + { include: "@whitespace" }, // numbers - [/\d+/, 'number'], - + [/\d+/, "number"], // strings - [/"([^"\\]|\\.)*$/, 'string.invalid' ], // non-teminated string - [/"/, { token: 'string.quote', bracket: '@open', next: '@string' } ], - - - + [/"([^"\\]|\\.)*$/, "string.invalid"], // non-teminated string + [/"/, { token: "string.quote", bracket: "@open", next: "@string" }], ], - - string: [ - [/[^\\"]+/, 'string'], - [/@escapes/, 'string.escape'], - [/\\./, 'string.escape.invalid'], - [/"/, { token: 'string.quote', bracket: '@close', next: '@pop' } ] + [/[^\\"]+/, "string"], + [/@escapes/, "string.escape"], + [/\\./, "string.escape.invalid"], + [/"/, { token: "string.quote", bracket: "@close", next: "@pop" }], ], whitespace: [ - [/[ \t\r\n]+/, 'white'], - [/;.*$/, 'comment'], + [/[ \t\r\n]+/, "white"], + [/;.*$/, "comment"], ], }, }; diff --git a/assembler.ts b/assembler.ts index f442256..1de10e8 100644 --- a/assembler.ts +++ b/assembler.ts @@ -1,11 +1,10 @@ // Copyright 2023 Ryan Brown - -import { instructions } from "./decompile/dsinstr"; import { RawBehavior } from "./decompile/RawBehavior"; import { RawBlueprint } from "./decompile/RawBlueprint"; import { RawInstruction } from "./decompile/RawInstruction"; -import { binaryInsert } from "binary-insert"; -import binarySearch from "binary-search"; +import { instructions } from "./decompile/dsinstr"; +import { Behavior, splitProgram } from "./ir/behavior"; +import { Code, Pass, reversePass } from "./ir/code"; import { Arg, FALSE, @@ -20,9 +19,9 @@ import { STOP, TRUE, } from "./ir/instruction"; -import { Code, Pass, reversePass } from "./ir/code"; import { MethodInfo, ops } from "./methods"; -import { Behavior, splitProgram } from "./ir/behavior"; +import { binaryInsert } from "binary-insert"; +import binarySearch from "binary-search"; interface SubInfo { label: number; @@ -54,7 +53,7 @@ const numberLiteralPattern = String.raw`-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d const numberLiteralExactPattern = new RegExp(`^${numberLiteralPattern}$`); const itemNumPattern = new RegExp(`^(\\w+)@(${numberLiteralPattern})$`); const coordPattern = new RegExp( - `^(${numberLiteralPattern})\\s+(${numberLiteralPattern})$` + `^(${numberLiteralPattern})\\s+(${numberLiteralPattern})$`, ); function parseAssembly(code: string): Code { @@ -73,7 +72,7 @@ function parseAssembly(code: string): Code { let key = `$s${strings.size}`; strings.set(key, JSON.parse(s)); return key; - } + }, ); const commentStart = line.indexOf(";"); if (commentStart >= 0) { @@ -112,9 +111,7 @@ function parseAssembly(code: string): Code { return code1; } -export function assemble( - code: string -): RawBehavior | RawBlueprint { +export function assemble(code: string): RawBehavior | RawBlueprint { let instructions = parseAssembly(code); const program: Behavior = splitProgram(instructions); @@ -137,7 +134,7 @@ class Assembler { const frame = this.program.main.code[0].args[0]; if (frame?.type !== "value" || frame.value.id == null) { throw new Error( - `Blueprint frame must be a string at line ${this.program.main[0].lineno}` + `Blueprint frame must be a string at line ${this.program.main[0].lineno}`, ); } const bp: RawBlueprint = { @@ -164,7 +161,7 @@ class Assembler { const regNo = num(inst, inst.args[0]); if (inst.args[1]?.type !== "value") { throw new Error( - `Register value must be a value at line ${inst.lineno}` + `Register value must be a value at line ${inst.lineno}`, ); } bp.regs[regNo] = inst.args[1].value; @@ -188,16 +185,18 @@ class Assembler { const [index, id, code] = inst.args; const ctype = str(inst, id); if (code?.type === "label") { - const behavior = this.program.others.get(code.label) ?? this.program.subs.get(code.label); + const behavior = + this.program.others.get(code.label) ?? + this.program.subs.get(code.label); if (!behavior) { throw new Error( - `Behavior ${code.label} not found at line ${inst.lineno}` + `Behavior ${code.label} not found at line ${inst.lineno}`, ); } const p = new Assembler({ ...this.program, main: behavior, - mainLabel: code.label + mainLabel: code.label, }).assembleBehavior(); bp.components.push([ctype, num(inst, index), p]); } else { @@ -218,10 +217,16 @@ class Assembler { const behaviors: Map = new Map(); // Assemble subroutines in reverse call order so parameter rw flags can be propagated for (const sub of Array.from(this.subs.values()).reverse()) { - behaviors.set(sub.label, this.assembleSub(sub.instructions.clone(), behaviors)); + behaviors.set( + sub.label, + this.assembleSub(sub.instructions.clone(), behaviors), + ); } - const main: RawBehavior = this.assembleSub(this.program.main.clone(), behaviors); + const main: RawBehavior = this.assembleSub( + this.program.main.clone(), + behaviors, + ); if (behaviors.size > 0) { // Reverse back to original call order main.subs = Array.from(behaviors.values()).reverse(); @@ -251,7 +256,7 @@ class Assembler { behavior: result, labelInfo, resolveSub: this.resolveSub.bind(this), - resolveBehavior: label => behaviors.get(label), + resolveBehavior: (label) => behaviors.get(label), resolveBp: this.resolveBp.bind(this), }); sub.apply(resolver); @@ -276,7 +281,8 @@ class Assembler { resolveBp(bpName: string) { const prog = { ...this.program, - main: (this.program.bps.get(bpName) ?? (this.program.mainLabel === bpName ? this.program.main : undefined))!, + main: (this.program.bps.get(bpName) ?? + (this.program.mainLabel === bpName ? this.program.main : undefined))!, mainLabel: bpName, }; if (!prog.main) { @@ -289,7 +295,7 @@ class Assembler { function findReferencedSubs(program: Behavior): Map { const callgraph = {}; - const pass: (name: string) => Pass = (name) => { + const pass: (name: string) => Pass = (name) => { callgraph[name] ??= []; return (inst) => { @@ -306,33 +312,33 @@ function findReferencedSubs(program: Behavior): Map { if (!sub) { throw new Error(`Sub ${subName} not found at line ${inst.lineno}`); } - if(!(subName in callgraph)) { + if (!(subName in callgraph)) { sub.apply(pass(subName)); } } - } + }; }; const mainLabel = program.mainLabel ?? ""; program.main.apply(pass(mainLabel)); - + // Sort the subroutines in call order const sortedSubNames = bfsSort(callgraph, mainLabel); const result = new Map(); for (const subName of sortedSubNames) { - if(subName === mainLabel) continue; + if (subName === mainLabel) continue; const sub = program.subs.get(subName); - if(!sub) { + if (!sub) { throw new Error(`Sub ${subName} not found`); } result.set(subName, { name: subName, instructions: sub, - label: result.size + 1 + label: result.size + 1, }); } @@ -347,11 +353,11 @@ function bfsSort(graph: { [key: string]: string[] }, rootNode: string) { while (queue.length) { const next = queue.shift(); - if(next == null) continue; + if (next == null) continue; result.push(next); for (const edge of graph[next]) { - if(!visited.has(edge)) { + if (!visited.has(edge)) { visited.add(edge); queue.push(edge); } @@ -370,7 +376,7 @@ function parseArg( arg: string, methodInfo: MethodInfo | undefined, strings: Map, - skipPush = false + skipPush = false, ): Arg | undefined { arg = arg.trim(); let keyMatch = arg.match(/^\$(sub|txt|c|nx|ny|bp|next)=(.+)/); @@ -426,7 +432,7 @@ function setKey(inst: Instruction, key: string, value: Arg) { case "next": if (value.type !== "label") { throw new Error( - `Invalid ${key}: ${JSON.stringify(value)} at line ${inst.lineno}` + `Invalid ${key}: ${JSON.stringify(value)} at line ${inst.lineno}`, ); } inst[key] = value; @@ -437,7 +443,7 @@ function setKey(inst: Instruction, key: string, value: Arg) { return; } throw new Error( - `Invalid txt: ${JSON.stringify(value)} at line ${inst.lineno}` + `Invalid txt: ${JSON.stringify(value)} at line ${inst.lineno}`, ); case "c": if (value.type === "value" && value.value.num != null) { @@ -445,7 +451,7 @@ function setKey(inst: Instruction, key: string, value: Arg) { return; } throw new Error( - `Invalid c: ${JSON.stringify(value)} at line ${inst.lineno}` + `Invalid c: ${JSON.stringify(value)} at line ${inst.lineno}`, ); case "nx": case "ny": @@ -455,7 +461,7 @@ function setKey(inst: Instruction, key: string, value: Arg) { } } throw new Error( - `Invalid ${key}: ${JSON.stringify(value)} at line ${inst.lineno}` + `Invalid ${key}: ${JSON.stringify(value)} at line ${inst.lineno}`, ); } @@ -464,7 +470,7 @@ function str(inst: Instruction, a: Arg | undefined) { return a.stringValue()!; } throw new Error( - `Expected string: ${JSON.stringify(a)} at line ${inst.lineno}` + `Expected string: ${JSON.stringify(a)} at line ${inst.lineno}`, ); } @@ -473,7 +479,7 @@ function num(inst: Instruction, a: Arg | undefined): number { return a.value.num; } throw new Error( - `Expected number: ${JSON.stringify(a)} at line ${inst.lineno}` + `Expected number: ${JSON.stringify(a)} at line ${inst.lineno}`, ); } @@ -516,7 +522,7 @@ function pseudoPass(behavior: RawBehavior, labelInfo: LabelInfo): Pass { reg.reg < 1 ) { throw new Error( - `Unknown parameter register ${reg} at line ${instr.lineno}` + `Unknown parameter register ${reg} at line ${instr.lineno}`, ); } behavior.pnames ??= []; @@ -531,7 +537,7 @@ function pseudoPass(behavior: RawBehavior, labelInfo: LabelInfo): Pass { reg.reg < 1 ) { throw new Error( - `Unknown parameter register ${reg} at line ${instr.lineno}` + `Unknown parameter register ${reg} at line ${instr.lineno}`, ); } behavior.parameters ??= []; @@ -541,12 +547,12 @@ function pseudoPass(behavior: RawBehavior, labelInfo: LabelInfo): Pass { default: throw new Error( - `Unknown pseudo instruction ${instr.op} at line ${instr.lineno}` + `Unknown pseudo instruction ${instr.op} at line ${instr.lineno}`, ); } if (instr.next?.type === "nodeRef") { throw new Error( - `Unexpected type of "instr.next". Labels should not be resolved` + `Unexpected type of "instr.next". Labels should not be resolved`, ); } if (instr.next !== undefined) { @@ -564,7 +570,7 @@ function pseudoPass(behavior: RawBehavior, labelInfo: LabelInfo): Pass { function replaceJump(code: Code, ip: number, target: Label | Stop | NodeRef) { if (target.type === "nodeRef") { throw new Error( - `Unexpected type of "target". Labels should not be resolved` + `Unexpected type of "target". Labels should not be resolved`, ); } if (ip == 0) { @@ -593,7 +599,7 @@ function removeNopPass(labelInfo: LabelInfo): Pass { if (instr.next !== undefined) { if (instr.next.type === "nodeRef") { throw new Error( - `Unexpected type of "instr.next". Labels should not be resolved` + `Unexpected type of "instr.next". Labels should not be resolved`, ); } const next: Label | Stop = instr.next; @@ -698,7 +704,7 @@ function removeDeadCode(code: Code, labelInfo: LabelInfo) { code.code.splice(i, 1); codeIsStable = false; } - }) + }), ); } } @@ -730,24 +736,23 @@ function reorderCode(code: Code, labelInfo: LabelInfo) { code.code = [...newOrder].map((i) => code.code[i]); - function add (n: number) { + function add(n: number) { if (unprocessed.has(n)) { binaryInsert(toProcess, n, (a, b) => b - a); unprocessed.delete(n); } - }; + } function addLast(n: number) { toProcess.push(n); unprocessed.delete(n); - }; + } function controlFlow() { - while (toProcess.length > 0) { const i = toProcess.pop()!; if (newOrder.has(i)) continue; newOrder.add(i); - + const resolve = (a: Arg | undefined): number | undefined => { if (a === undefined) return i + 1; if (a.type === "nodeRef") return a.nodeIndex; @@ -760,18 +765,18 @@ function reorderCode(code: Code, labelInfo: LabelInfo) { return labelIPs.get(label); } }; - + const instr = code.code[i]; const info = instructions[instr.op]; instr.forArgs(info?.execArgs, (arg) => { const resolved = resolve(arg); if (resolved != null) add(resolved); }); - + if (info?.terminates) { continue; } - + const next = resolve(instr.next); if (next != null) { if (next == i + 1) { @@ -791,14 +796,14 @@ function resolveLabelsPass( behavior, resolveBp, resolveSub, - resolveBehavior + resolveBehavior, }: { labelInfo: LabelInfo; behavior: RawBehavior; resolveBp: (s: string) => RawBlueprint | undefined; resolveSub: (s: string) => ResolvedSub | undefined; resolveBehavior: (label: number) => RawBehavior | undefined; - } + }, ): Pass { const labelMap = new Map(); code.apply((instr, i) => { @@ -829,7 +834,7 @@ function resolveLabelsPass( const resolved = labelMap.get(instr.next.label); if (resolved == null) { throw new Error( - `Unknown label ${instr.next} at line ${instr.lineno}` + `Unknown label ${instr.next} at line ${instr.lineno}`, ); } if (resolved != i + 2) { @@ -883,13 +888,16 @@ function resolveLabelsPass( value = v.reg; const method = ops[instr.op]; - if(value > 0) { + if (value > 0) { let isWrite; if (instr.resolvedSub) { const behavior = resolveBehavior(instr.resolvedSub.index); isWrite = behavior?.parameters?.[vi] ?? false; } else { - isWrite = typeof method.out === "number" ? method.out === vi : method.out?.includes(vi) ?? false; + isWrite = + typeof method.out === "number" + ? method.out === vi + : method.out?.includes(vi) ?? false; } behavior.parameters ??= []; behavior.parameters[value - 1] ||= isWrite; @@ -911,7 +919,7 @@ function addSpecialOptions( instr: Instruction, ds: RawInstruction, resolveSub: (s: string) => ResolvedSub | undefined, - resolveBp: (s: string) => RawBlueprint | undefined + resolveBp: (s: string) => RawBlueprint | undefined, ) { if (instr.comment) { ds.cmt = instr.comment; diff --git a/compile.ts b/compile.ts index 187d8aa..4df1177 100755 --- a/compile.ts +++ b/compile.ts @@ -1,9 +1,8 @@ // Copyright 2023 Ryan Brown - -import * as ts from "typescript"; -import * as tsApiUtils from "ts-api-utils"; -import {MethodInfo, methods} from "./methods"; -import {Code} from "./ir/code"; +import { CompilerOptions } from "./compiler_options"; +import { gameData, SocketSize } from "./data"; +import { generateAsm } from "./decompile/disasm"; +import { Code } from "./ir/code"; import { Arg, Instruction, @@ -17,10 +16,11 @@ import { TRUE, FALSE, } from "./ir/instruction"; -import {generateAsm} from "./decompile/disasm"; -import {gameData, SocketSize} from "./data"; -import {CompilerOptions} from "./compiler_options" -export {CompilerOptions} +import { MethodInfo, methods } from "./methods"; +import * as tsApiUtils from "ts-api-utils"; +import * as ts from "typescript"; + +export { CompilerOptions }; // Some arbitrary things to use for dynamic jump labels const dynamicLabels = [ @@ -59,24 +59,36 @@ const dynamicLabels = [ "v_idle", ]; -function findParent(n: ts.Node, predicate: (n: ts.Node) => n is N): N | undefined { +function findParent( + n: ts.Node, + predicate: (n: ts.Node) => n is N, +): N | undefined { let parent = n.parent; - while(parent != null && !predicate(parent)) { + while (parent != null && !predicate(parent)) { parent = parent.parent; } return parent as N; } -function compileFile(mainFileName: string, sourceFiles: ts.SourceFile[]): string { +function compileFile( + mainFileName: string, + sourceFiles: ts.SourceFile[], +): string { const c = new Compiler(); - sourceFiles.forEach(f => c.addSourceFile(f)); + sourceFiles.forEach((f) => c.addSourceFile(f)); - let main: { sub: ts.FunctionDeclaration } | { blueprint: BlueprintDeclaration } | null = null; + let main: + | { sub: ts.FunctionDeclaration } + | { blueprint: BlueprintDeclaration } + | null = null; for (const sub of c.subs.values()) { - if (isExported(sub) && findParent(sub, ts.isSourceFile)?.fileName === mainFileName) { + if ( + isExported(sub) && + findParent(sub, ts.isSourceFile)?.fileName === mainFileName + ) { if (main == null) { - main = {sub}; + main = { sub }; } else { throw new Error("Only one declaration may be exported"); } @@ -84,9 +96,13 @@ function compileFile(mainFileName: string, sourceFiles: ts.SourceFile[]): string } for (const blueprint of c.blueprints.values()) { - if (isExported(blueprint.statement) && findParent(blueprint.statement, ts.isSourceFile)?.fileName === mainFileName) { + if ( + isExported(blueprint.statement) && + findParent(blueprint.statement, ts.isSourceFile)?.fileName === + mainFileName + ) { if (main == null) { - main = {blueprint}; + main = { blueprint }; } else { throw new Error("Only one declaration may be exported"); } @@ -97,20 +113,20 @@ function compileFile(mainFileName: string, sourceFiles: ts.SourceFile[]): string throw new Error("One declaration must be exported"); } - if ('sub' in main) { + if ("sub" in main) { c.compileBehavior(main.sub, true); - } else if ('blueprint' in main) { + } else if ("blueprint" in main) { c.compileBlueprint(main.blueprint, true); } for (const sub of c.subs.values()) { - if (!('sub' in main) || main.sub !== sub) { + if (!("sub" in main) || main.sub !== sub) { c.compileBehavior(sub, false); } } for (const blueprint of c.blueprints.values()) { - if (!('blueprint' in main) || main.blueprint !== blueprint) { + if (!("blueprint" in main) || main.blueprint !== blueprint) { c.compileBlueprint(blueprint, false); } } @@ -200,7 +216,7 @@ class VariableScope { this.children.forEach((scope) => { chidrenNewParametersCount = Math.max( chidrenNewParametersCount, - scope.allocate(currentAvailables, paramCounter + newParametersCount) + scope.allocate(currentAvailables, paramCounter + newParametersCount), ); }); return newParametersCount + chidrenNewParametersCount; @@ -261,10 +277,10 @@ function isExported(f: { modifiers?: ts.NodeArray }): boolean { } type BlueprintDeclaration = { - name: string, - frame: string, - statement: ts.VariableStatement, - initializer: ts.CallExpression + name: string; + frame: string; + statement: ts.VariableStatement; + initializer: ts.CallExpression; }; class Compiler { @@ -287,7 +303,7 @@ class Compiler { } else if (ts.isVariableStatement(n)) { if (n.declarationList.declarations.length > 0) { for (const declaration of n.declarationList.declarations) { - if(this.#extractBlueprint(n, declaration)) { + if (this.#extractBlueprint(n, declaration)) { continue; } @@ -304,7 +320,10 @@ class Compiler { }); } - #extractBlueprint(statement: ts.VariableStatement, declaration: ts.VariableDeclaration): boolean { + #extractBlueprint( + statement: ts.VariableStatement, + declaration: ts.VariableDeclaration, + ): boolean { if (!ts.isIdentifier(declaration.name)) { return false; } @@ -313,7 +332,10 @@ class Compiler { return false; } - if (!ts.isCallExpression(declaration.initializer) || !ts.isPropertyAccessExpression(declaration.initializer.expression)) { + if ( + !ts.isCallExpression(declaration.initializer) || + !ts.isPropertyAccessExpression(declaration.initializer.expression) + ) { return false; } @@ -328,15 +350,18 @@ class Compiler { const frame = gameData.framesByJsName.get(frameName); if (frame == null) { - this.#error(`Unknown frame: ${frameName}`, declaration.initializer.expression.name); + this.#error( + `Unknown frame: ${frameName}`, + declaration.initializer.expression.name, + ); } this.blueprints.set(blueprintName, { name: blueprintName, statement: statement, frame: frame.id, - initializer: declaration.initializer - }) + initializer: declaration.initializer, + }); return true; } @@ -375,48 +400,59 @@ class Compiler { const blueprintArg = blueprint.initializer.arguments[0]; if (!ts.isObjectLiteralExpression(blueprintArg)) { - this.#error(`Unsupported blueprint argument 1: ${ts.SyntaxKind[blueprintArg.kind]}`, blueprintArg) + this.#error( + `Unsupported blueprint argument 1: ${ts.SyntaxKind[blueprintArg.kind]}`, + blueprintArg, + ); } - const frame = gameData.frames.get(blueprint.frame) ?? gameData.frames.get(`f_${blueprint.frame}`); + const frame = + gameData.frames.get(blueprint.frame) ?? + gameData.frames.get(`f_${blueprint.frame}`); if (frame == null || frame.visual == null) { this.#error(`Unknown frame: ${blueprint.frame}`, blueprint.initializer); } const visual = gameData.visuals.get(frame.visual); if (visual == null) { - this.#error(`Unknown visual ${frame.visual} of frame: ${frame.id}`, blueprint.initializer.arguments[0]); + this.#error( + `Unknown visual ${frame.visual} of frame: ${frame.id}`, + blueprint.initializer.arguments[0], + ); } - this.#rawEmit(".blueprint", new LiteralValue({id: frame.id})); + this.#rawEmit(".blueprint", new LiteralValue({ id: frame.id })); const parsedBlueprint: { - name?: ParsedLiteral, - power?: ParsedLiteral, - connected?: ParsedLiteral, - channels?: ParsedLiteral, - transportRoute?: ParsedLiteral, - requester?: ParsedLiteral, - supplier?: ParsedLiteral, - deliver?: ParsedLiteral, - itemTransporterOnly?: ParsedLiteral, - highPriority?: ParsedLiteral, - construction?: ParsedLiteral, - signal?: ParsedLiteral, - visual?: ParsedLiteral, - store?: ParsedLiteral, - goto?: ParsedLiteral, - internal?: ParsedLiteral, - small?: ParsedLiteral, - medium?: ParsedLiteral, - large?: ParsedLiteral, - locks?: ParsedLiteral + name?: ParsedLiteral; + power?: ParsedLiteral; + connected?: ParsedLiteral; + channels?: ParsedLiteral; + transportRoute?: ParsedLiteral; + requester?: ParsedLiteral; + supplier?: ParsedLiteral; + deliver?: ParsedLiteral; + itemTransporterOnly?: ParsedLiteral; + highPriority?: ParsedLiteral; + construction?: ParsedLiteral; + signal?: ParsedLiteral; + visual?: ParsedLiteral; + store?: ParsedLiteral; + goto?: ParsedLiteral; + internal?: ParsedLiteral; + small?: ParsedLiteral; + medium?: ParsedLiteral; + large?: ParsedLiteral; + locks?: ParsedLiteral; } = this.parseBlueprint(blueprintArg) as any; - if (parsedBlueprint == null || typeof parsedBlueprint !== 'object') { - this.#error(`Unsupported blueprint argument 1: ${parsedBlueprint}`, blueprintArg); + if (parsedBlueprint == null || typeof parsedBlueprint !== "object") { + this.#error( + `Unsupported blueprint argument 1: ${parsedBlueprint}`, + blueprintArg, + ); } - if (typeof parsedBlueprint.name?.value === 'string') { + if (typeof parsedBlueprint.name?.value === "string") { this.#rawEmit(".name", new StringLiteral(parsedBlueprint.name.value)); } @@ -430,24 +466,40 @@ class Compiler { if (parsedBlueprint?.channels?.value != null) { if (!Array.isArray(parsedBlueprint.channels.value)) { - this.#error("Blueprint logistics channels must be array", parsedBlueprint.channels.node); + this.#error( + "Blueprint logistics channels must be array", + parsedBlueprint.channels.node, + ); } - const logisticChannels = parsedBlueprint.channels.value.map(v => v.value); + const logisticChannels = parsedBlueprint.channels.value.map( + (v) => v.value, + ); for (let i = 1; i <= 4; i++) { - this.#rawEmit(".logistics", new StringLiteral(`channel_${i}`), logisticChannels.includes(i) ? TRUE : FALSE); + this.#rawEmit( + ".logistics", + new StringLiteral(`channel_${i}`), + logisticChannels.includes(i) ? TRUE : FALSE, + ); } } const processLogisticsBoolean = (key: string, name: string = key) => { if (parsedBlueprint?.[key]?.value != null) { if (typeof parsedBlueprint[key].value !== "boolean") { - this.#error(`Blueprint ${key} must be boolean`, parsedBlueprint[key].node); + this.#error( + `Blueprint ${key} must be boolean`, + parsedBlueprint[key].node, + ); } - this.#rawEmit(".logistics", new StringLiteral(name), parsedBlueprint[key].value ? TRUE : FALSE); + this.#rawEmit( + ".logistics", + new StringLiteral(name), + parsedBlueprint[key].value ? TRUE : FALSE, + ); } - } + }; processLogisticsBoolean("transportRoute", "transport_route"); processLogisticsBoolean("requester"); @@ -457,62 +509,81 @@ class Compiler { processLogisticsBoolean("highPriority", "high_priority"); processLogisticsBoolean("construction", "can_construction"); - const allSockets = (visual.sockets ?? []).map(socket => { - return socket[1] as SocketSize + const allSockets = (visual.sockets ?? []).map((socket) => { + return socket[1] as SocketSize; }); - const registerLinks: Array<{ from: number, to: string | number, node: ts.Node }> = []; + const registerLinks: Array<{ + from: number; + to: string | number; + node: ts.Node; + }> = []; const registerNames: Map = new Map(); const duplicateBehaviorControllerParameterNames: Set = new Set(); const behaviorControllerParameterNames: Map = new Map(); const registerValues: Record = {}; - const updateLinks = (registerNum: number, item: ParsedLiteral | undefined) => { + const updateLinks = ( + registerNum: number, + item: ParsedLiteral | undefined, + ) => { if (!item) return; const linkAsArray = Array.isArray(item.value) ? item.value : [item]; for (const link of linkAsArray) { if (link.value == null) continue; - if (typeof link.value === 'string') { - registerValues[registerNum] = new LiteralValue({id: link.value}); - } else if (typeof link.value === 'number') { - registerValues[registerNum] = new LiteralValue({num: link.value}); + if (typeof link.value === "string") { + registerValues[registerNum] = new LiteralValue({ id: link.value }); + } else if (typeof link.value === "number") { + registerValues[registerNum] = new LiteralValue({ num: link.value }); } else if (typeof link.value != "object") { - this.#error(`Invalid link type: ${ts.SyntaxKind[link.node.kind]}`, link.node); - } else if ('id' in link.value || 'num' in link.value) { + this.#error( + `Invalid link type: ${ts.SyntaxKind[link.node.kind]}`, + link.node, + ); + } else if ("id" in link.value || "num" in link.value) { registerValues[registerNum] = new LiteralValue(link.value); } else { - const name: ParsedLiteral = link.value['name']; - if(name != null) { - if(typeof name.value !== 'string') { + const name: ParsedLiteral = link.value["name"]; + if (name != null) { + if (typeof name.value !== "string") { this.#error("name must be string", name.node); } - if(registerNames.has(name.value)) { + if (registerNames.has(name.value)) { this.#error(`Duplicate register name: ${name}`, name.node); } registerNames.set(name.value, registerNum); } - const value = link.value['value']; - if(value != null) { - if(typeof value.value === 'string') { - registerValues[registerNum] = new LiteralValue({id: value.value}); - } else if (typeof value.value === 'number') { - registerValues[registerNum] = new LiteralValue({num: value.value}); - } else if ('id' in value.value || 'num' in value.value) { + const value = link.value["value"]; + if (value != null) { + if (typeof value.value === "string") { + registerValues[registerNum] = new LiteralValue({ + id: value.value, + }); + } else if (typeof value.value === "number") { + registerValues[registerNum] = new LiteralValue({ + num: value.value, + }); + } else if ("id" in value.value || "num" in value.value) { registerValues[registerNum] = new LiteralValue(value.value); } else { this.#error("Invalid link value type", value.node); } } - const to = link.value['to']; - if(to != null) { - const tos: ParsedLiteral[] = Array.isArray(to.value) ? to.value : [to]; - for(const to of tos) { - if(typeof to.value !== "string" && typeof to.value !== "number") { + const to = link.value["to"]; + if (to != null) { + const tos: ParsedLiteral[] = Array.isArray(to.value) + ? to.value + : [to]; + for (const to of tos) { + if ( + typeof to.value !== "string" && + typeof to.value !== "number" + ) { this.#error("Invalid to link type", to.node); } @@ -525,12 +596,12 @@ class Compiler { } } } - } + }; - updateLinks(Math.abs(regNums.signal), parsedBlueprint.signal) - updateLinks(Math.abs(regNums.visual), parsedBlueprint.visual) - updateLinks(Math.abs(regNums.store), parsedBlueprint.store) - updateLinks(Math.abs(regNums.goto), parsedBlueprint.goto) + updateLinks(Math.abs(regNums.signal), parsedBlueprint.signal); + updateLinks(Math.abs(regNums.visual), parsedBlueprint.visual); + updateLinks(Math.abs(regNums.store), parsedBlueprint.store); + updateLinks(Math.abs(regNums.goto), parsedBlueprint.goto); let registerIndex = 5; @@ -555,12 +626,12 @@ class Compiler { continue; } - if (typeof component.value !== 'object') { + if (typeof component.value !== "object") { this.#error(`${socketType} socket must be object`, component.node); } - const id = component.value['id'] as ParsedLiteral; - if (id == null || typeof id.value !== 'string') { + const id = component.value["id"] as ParsedLiteral; + if (id == null || typeof id.value !== "string") { this.#error(`${socketType} socket id must be string`, id.node); } @@ -569,18 +640,28 @@ class Compiler { this.#error(`Unknown component: ${id.value}`, id.node); } - const behavior = component.value['behavior'] as ParsedLiteral; + const behavior = component.value["behavior"] as ParsedLiteral; let componentRegisters: Array<{}>; const componentRegisterNames: Map = new Map(); if (behavior != null) { // If the component has a behavior then look up the subroutine to get register (parameter) count - if ((typeof behavior.value !== 'string' || !this.subs.has(behavior.value))) { - this.#error(`${socketType} socket behavior must be reference to function`, behavior.node); + if ( + typeof behavior.value !== "string" || + !this.subs.has(behavior.value) + ) { + this.#error( + `${socketType} socket behavior must be reference to function`, + behavior.node, + ); } const sub = this.subs.get(behavior.value)!; - componentRegisters = sub.parameters.map(p => ({})); - for (let parameterIndex = 0; parameterIndex < sub.parameters.length; parameterIndex++) { + componentRegisters = sub.parameters.map((p) => ({})); + for ( + let parameterIndex = 0; + parameterIndex < sub.parameters.length; + parameterIndex++ + ) { const parameter = sub.parameters[parameterIndex]; if (!ts.isIdentifier(parameter.name)) { this.#error("Parameter name must be identifier", parameter); @@ -593,7 +674,10 @@ class Compiler { behaviorControllerParameterNames.delete(parameterName); duplicateBehaviorControllerParameterNames.add(parameterName); } else { - behaviorControllerParameterNames.set(parameterName, registerIndex + parameterIndex); + behaviorControllerParameterNames.set( + parameterName, + registerIndex + parameterIndex, + ); } } } @@ -602,50 +686,64 @@ class Compiler { componentRegisters = componentData.registers ?? []; } - const links = component.value['links'] as ParsedLiteral; + const links = component.value["links"] as ParsedLiteral; if (links != null) { if (Array.isArray(links.value)) { for (let linkIndex = 0; linkIndex < links.value.length; linkIndex++) { const item = links.value[linkIndex]; const registerNum = registerIndex + linkIndex; if (linkIndex >= componentRegisters.length) { - this.#error(`Component only has ${componentRegisters.length} registers`, item.node) + this.#error( + `Component only has ${componentRegisters.length} registers`, + item.node, + ); } updateLinks(registerNum, item); } - } else if (typeof links.value === 'object') { + } else if (typeof links.value === "object") { for (const key in links.value) { const item = links.value[key]; const linkIndex = componentRegisterNames.get(key) ?? key; const linkIndexNum = Number(linkIndex); if (isNaN(linkIndexNum) || linkIndexNum < 0) { - this.#error(`Socket links object keys must be positive numbers`, links.node); + this.#error( + `Socket links object keys must be positive numbers`, + links.node, + ); } if (linkIndexNum >= componentRegisters.length) { - this.#error(`Component only has ${componentRegisters.length} registers`, item.node) + this.#error( + `Component only has ${componentRegisters.length} registers`, + item.node, + ); } const registerNum = registerIndex + Number(linkIndex); updateLinks(registerNum, item); } } else { - this.#error(`${socketType} socket links must be array or object`, links.node); + this.#error( + `${socketType} socket links must be array or object`, + links.node, + ); } } registerIndex += componentRegisters.length; if (behavior?.value == null) { - this.#rawEmit(".component", - new LiteralValue({num: socketIndex + 1}), - new LiteralValue({id: id.value}) + this.#rawEmit( + ".component", + new LiteralValue({ num: socketIndex + 1 }), + new LiteralValue({ id: id.value }), ); } else { - this.#rawEmit(".component", - new LiteralValue({num: socketIndex + 1}), - new LiteralValue({id: id.value}), - new Label(behavior.value as string) + this.#rawEmit( + ".component", + new LiteralValue({ num: socketIndex + 1 }), + new LiteralValue({ id: id.value }), + new Label(behavior.value as string), ); } } @@ -657,40 +755,50 @@ class Compiler { for (let i = 0; i < parsedBlueprint.locks.value.length; i++) { const lock = parsedBlueprint.locks.value[i]; - if (typeof lock.value === 'string') { - this.#rawEmit(".lock", - new LiteralValue({num: i}), - new LiteralValue({id: lock.value}) + if (typeof lock.value === "string") { + this.#rawEmit( + ".lock", + new LiteralValue({ num: i }), + new LiteralValue({ id: lock.value }), ); - } else if (typeof lock.value === 'boolean') { - this.#rawEmit(".lock", - new LiteralValue({num: i}), - lock.value ? TRUE : FALSE + } else if (typeof lock.value === "boolean") { + this.#rawEmit( + ".lock", + new LiteralValue({ num: i }), + lock.value ? TRUE : FALSE, ); } else if (lock.value != null) { - this.#error("Locks must be string or boolean", parsedBlueprint.locks.node); + this.#error( + "Locks must be string or boolean", + parsedBlueprint.locks.node, + ); } } } - // Emit the literal values for registers for (const key in registerValues) { - this.#rawEmit(".reg", - new LiteralValue({num: Number(key) - 1}), - registerValues[key] + this.#rawEmit( + ".reg", + new LiteralValue({ num: Number(key) - 1 }), + registerValues[key], ); } const resolvedLinks = new Set(); for (const registerLink of registerLinks) { let to: number; - if(typeof registerLink.to === 'number') { + if (typeof registerLink.to === "number") { to = registerLink.to; } else { - const resolvedTo = registerNames.get(registerLink.to) ?? behaviorControllerParameterNames.get(registerLink.to); + const resolvedTo = + registerNames.get(registerLink.to) ?? + behaviorControllerParameterNames.get(registerLink.to); if (resolvedTo == null) { - this.#error(`Unknown register name: ${registerLink.to}`, registerLink.node); + this.#error( + `Unknown register name: ${registerLink.to}`, + registerLink.node, + ); } to = resolvedTo; @@ -700,9 +808,10 @@ class Compiler { if (resolvedLinks.has(linkId)) continue; resolvedLinks.add(linkId); - this.#rawEmit(".link", - new LiteralValue({num: to}), - new LiteralValue({num: registerLink.from}) + this.#rawEmit( + ".link", + new LiteralValue({ num: to }), + new LiteralValue({ num: registerLink.from }), ); } } @@ -715,7 +824,10 @@ class Compiler { const thisArg = call.expression.expression; if (!ts.isIdentifier(thisArg)) { - this.#error(`Property access must be on identifier: ${ts.SyntaxKind[thisArg.kind]}`, thisArg); + this.#error( + `Property access must be on identifier: ${ts.SyntaxKind[thisArg.kind]}`, + thisArg, + ); } switch (thisArg.text) { @@ -730,7 +842,10 @@ class Compiler { const hasBehaviorArgument = component.id === "c_behavior"; if (call.arguments.length > 2) { - this.#error("Component function accept 0, 1 or 2 arguments", call); + this.#error( + "Component function accept 0, 1 or 2 arguments", + call, + ); } if (!hasBehaviorArgument && call.arguments.length === 2) { @@ -748,15 +863,18 @@ class Compiler { ...handlers, identifier: (identifier, handlers) => { return identifier.text; - } + }, }); if (parsed.value == null) { behavior = null; - } else if (typeof parsed.value === 'string') { + } else if (typeof parsed.value === "string") { behavior = parsed as SpecificLiteral; } else { - this.#error(`Behavior reference must be an identifier: ${ts.SyntaxKind[call.arguments[argIdx].kind]}`, call.arguments[argIdx]); + this.#error( + `Behavior reference must be an identifier: ${ts.SyntaxKind[call.arguments[argIdx].kind]}`, + call.arguments[argIdx], + ); } argIdx++; @@ -767,22 +885,30 @@ class Compiler { links = this.#parseLiteral(arg, { ...handlers, identifier: (identifier, handlers) => { - if(identifier.text in regNums) { + if (identifier.text in regNums) { return Math.abs(regNums[identifier.text]); } - return handlers.identifier?.(identifier, handlers) - ?? this.#error(`Unsupported identifier: ${identifier.text}`, identifier); - } + return ( + handlers.identifier?.(identifier, handlers) ?? + this.#error( + `Unsupported identifier: ${identifier.text}`, + identifier, + ) + ); + }, }); argIdx++; } return { - id: {node: call.expression.name, value: component.id} as SpecificLiteral, + id: { + node: call.expression.name, + value: component.id, + } as SpecificLiteral, behavior, - links + links, }; } } @@ -795,12 +921,15 @@ class Compiler { for (const argument of call.arguments) { const parsed = this.#parseLiteral(argument, handlers); if (typeof parsed.value !== "string") { - this.#error(`${functionName} function accept string literal argument`, call); + this.#error( + `${functionName} function accept string literal argument`, + call, + ); } values.push(parsed.value); } - return {[functionName]: values}; + return { [functionName]: values }; } case "value": { return this.builtins.value(call).value; @@ -808,8 +937,11 @@ class Compiler { } } - this.#error(`Unsupported call: ${call.expression.getText()} (${ts.SyntaxKind[call.expression.kind]})`, call); - } + this.#error( + `Unsupported call: ${call.expression.getText()} (${ts.SyntaxKind[call.expression.kind]})`, + call, + ); + }, }).value; } @@ -829,7 +961,7 @@ class Compiler { compileInstructions(f: ts.FunctionDeclaration) { f.parameters.forEach((param, i) => { const name = param.name.getText(); - const reg = new RegRef(i+1); + const reg = new RegRef(i + 1); this.currentScope.paramCounter = i + 1; this.#rawEmit(".pname", reg, new StringLiteral(name)); this.variable(param.name as ts.Identifier, reg); @@ -850,11 +982,11 @@ class Compiler { .map((c) => new RegRef(c)); let newParameters = this.currentScope.scope.allocate( availables, - this.currentScope.paramCounter + this.currentScope.paramCounter, ); for (let i = 0; i < newParameters; ++i) { let reg = new RegRef(++this.currentScope.paramCounter); - this.#rawEmit(".pname", reg, new LiteralValue({id:`temp`})); + this.#rawEmit(".pname", reg, new LiteralValue({ id: `temp` })); } } @@ -920,7 +1052,7 @@ class Compiler { () => { this.compileStatement(n.statement); this.#emitLabel(theEnd); - } + }, ); } }); @@ -977,7 +1109,7 @@ class Compiler { } else { this.#error( `unsupported statement ${n.kind} ${ts.SyntaxKind[n.kind]}`, - n + n, ); } } @@ -1011,15 +1143,15 @@ class Compiler { vars = [this.variable(init)]; } else if (ts.isArrayBindingPattern(init)) { vars = init.elements.map((el) => - ts.isOmittedExpression(el) - ? undefined - : this.variable(el.name as ts.Identifier) + ts.isOmittedExpression(el) + ? undefined + : this.variable(el.name as ts.Identifier), ); } else if (ts.isArrayLiteralExpression(init)) { vars = init.elements.map((el) => - ts.isOmittedExpression(el) - ? undefined - : this.variable(el as ts.Identifier) + ts.isOmittedExpression(el) + ? undefined + : this.variable(el as ts.Identifier), ); } else { this.#error(`expected variable: ${ts.SyntaxKind[init.kind]}`, init); @@ -1034,7 +1166,7 @@ class Compiler { name, undefined, [...n.expression.arguments], - vars + vars, ); const body = this.#label(); const theEnd = this.#label(); @@ -1052,13 +1184,13 @@ class Compiler { this.compileStatement(n.statement); this.#rawEmit(".ret"); this.#emitLabel(theEnd); - } + }, ); } compileLoop( n: ts.ForStatement | ts.WhileStatement | ts.DoStatement, - label?: string + label?: string, ) { const head = this.#label(); const body = this.#label(); @@ -1106,7 +1238,7 @@ class Compiler { } this.#jump(head); this.#emitLabel(brk); - } + }, ); } @@ -1142,7 +1274,7 @@ class Compiler { `unsupported binary expression ${e.operatorToken.kind} ${ ts.SyntaxKind[e.operatorToken.kind] }`, - e + e, ); } } else if (ts.isCallExpression(e)) { @@ -1154,7 +1286,7 @@ class Compiler { e.name.text, e.expression, [], - [dest] + [dest], ); } } else if (this.isNullOrUndefined(e)) { @@ -1162,7 +1294,7 @@ class Compiler { this.#emit( methods.setReg, nilReg, - this.ref(dest, VariableOperations.Write) + this.ref(dest, VariableOperations.Write), ); } else { return new Variable(nilReg); @@ -1177,7 +1309,7 @@ class Compiler { this.#emit( methods.setReg, this.variable(e), - this.ref(dest, VariableOperations.Write) + this.ref(dest, VariableOperations.Write), ); } return this.variable(e); @@ -1187,19 +1319,21 @@ class Compiler { this.#emit( methods.setReg, value, - this.ref(dest, VariableOperations.Write) + this.ref(dest, VariableOperations.Write), ); } else { return new Variable(value); } return dest; } else if (ts.isStringLiteral(e)) { - const value = new LiteralValue({id: gameData.get(e.text)?.id ?? e.text}); + const value = new LiteralValue({ + id: gameData.get(e.text)?.id ?? e.text, + }); if (dest) { this.#emit( methods.setReg, value, - this.ref(dest, VariableOperations.Write) + this.ref(dest, VariableOperations.Write), ); } else { return new Variable(value); @@ -1207,9 +1341,9 @@ class Compiler { return dest; } else if (ts.isArrayLiteralExpression(e)) { let arr: number[] = []; - for(const property of e.elements) { + for (const property of e.elements) { const value = this.compileExpr(property); - if(value.reg?.type !== 'value' || value.reg.value.num == null) { + if (value.reg?.type !== "value" || value.reg.value.num == null) { this.#error(`unsupported property ${property.kind}`, property); } @@ -1219,14 +1353,14 @@ class Compiler { const value = new LiteralValue({ coord: { x: arr[0], - y: arr[1] - } + y: arr[1], + }, }); if (dest) { this.#emit( methods.setReg, value, - this.ref(dest, VariableOperations.Write) + this.ref(dest, VariableOperations.Write), ); } else { return new Variable(value); @@ -1234,22 +1368,22 @@ class Compiler { return dest; } else if (ts.isObjectLiteralExpression(e)) { let obj = {}; - for(const property of e.properties) { + for (const property of e.properties) { const name = property.name; - if(!name) { + if (!name) { this.#error(`property missing name`, property); } if (ts.isPropertyAssignment(property)) { const value = this.compileExpr(property.initializer); - if(value.reg?.type !== 'value') { + if (value.reg?.type !== "value") { this.#error(`unsupported property ${property.kind}`, property); } obj = { ...obj, - ...value.reg.value - } + ...value.reg.value, + }; } else { this.#error(`unsupported property ${property.kind}`, property); } @@ -1260,7 +1394,7 @@ class Compiler { this.#emit( methods.setReg, value, - this.ref(dest, VariableOperations.Write) + this.ref(dest, VariableOperations.Write), ); } else { return new Variable(value); @@ -1271,12 +1405,22 @@ class Compiler { } else if (ts.isAsExpression(e)) { return this.compileExpr(e.expression, dest); } else if (ts.isPrefixUnaryExpression(e)) { - if(e.operator == ts.SyntaxKind.PlusToken) { + if (e.operator == ts.SyntaxKind.PlusToken) { return this.compileExpr(e.operand, dest); } else if (e.operator == ts.SyntaxKind.MinusToken) { - return this.compileExpr(ts.factory.createBinaryExpression(ts.factory.createNumericLiteral(0), ts.SyntaxKind.MinusToken, e.operand), dest); + return this.compileExpr( + ts.factory.createBinaryExpression( + ts.factory.createNumericLiteral(0), + ts.SyntaxKind.MinusToken, + e.operand, + ), + dest, + ); } else { - this.#error(`unsupported prefix expression ${e.kind} ${ts.SyntaxKind[e.kind]}`, e); + this.#error( + `unsupported prefix expression ${e.kind} ${ts.SyntaxKind[e.kind]}`, + e, + ); } } this.#error(`unsupported expression ${e.kind} ${ts.SyntaxKind[e.kind]}`, e); @@ -1305,21 +1449,21 @@ class Compiler { `unsupported compound assignment ${e.operatorToken.kind} ${ ts.SyntaxKind[e.operatorToken.kind] }`, - e + e, ); } return this.compileAssignment( ts.factory.createAssignment( e.left, - ts.factory.createBinaryExpression(e.left, op, e.right) + ts.factory.createBinaryExpression(e.left, op, e.right), ), - dest + dest, ); } compileAssignment( e: ts.AssignmentExpression, - dest?: Variable + dest?: Variable, ): Variable { if (ts.isIdentifier(e.left)) { const lvar = this.variable(e.left); @@ -1342,7 +1486,7 @@ class Compiler { } else { this.#error( `unsupported array element ${el.kind} ${ts.SyntaxKind[el.kind]}`, - e + e, ); } }); @@ -1354,13 +1498,13 @@ class Compiler { ) { return this.compileAssignment( ts.factory.createAssignment(e.left.expression, e.right), - dest + dest, ); } } this.#error( `unsupported assignment to ${e.left.kind} ${ts.SyntaxKind[e.left.kind]}`, - e + e, ); } @@ -1369,7 +1513,7 @@ class Compiler { const rightArg = this.compileExpr(e.right); const getNum = (v: Variable) => v.reg?.type === "value" && v.reg.value.num; - const isNum = (v: unknown): v is number => typeof v === 'number'; + const isNum = (v: unknown): v is number => typeof v === "number"; const leftLiteral = getNum(leftArg); const rightLiteral = getNum(rightArg); @@ -1398,13 +1542,13 @@ class Compiler { if (dest) { this.#emit( - methods.setReg, - new LiteralValue({num: value}), - this.ref(dest, VariableOperations.Write) + methods.setReg, + new LiteralValue({ num: value }), + this.ref(dest, VariableOperations.Write), ); return dest; } else { - return new Variable(new LiteralValue({num: value})); + return new Variable(new LiteralValue({ num: value })); } } @@ -1428,13 +1572,19 @@ class Compiler { default: this.#error(`unsupported binary expression ${e.operatorToken.kind}`, e); } - return this.compileResolvedCall(e, name, undefined, [leftArg, rightArg], [dest]); + return this.compileResolvedCall( + e, + name, + undefined, + [leftArg, rightArg], + [dest], + ); } parseBuiltinArg(arg: ts.Expression) { const value = this.compileExpr(arg); - if(value.reg?.type === 'value') { + if (value.reg?.type === "value") { const v = value.reg.value; if (v.num != null) { return v.num; @@ -1444,7 +1594,7 @@ class Compiler { } this.#error(`Unsupported argument type: ${ts.SyntaxKind[arg.kind]}`, arg); - }; + } builtins = { value: (e: ts.CallExpression): LiteralValue => { @@ -1454,24 +1604,30 @@ class Compiler { const a = this.parseBuiltinArg(e.arguments[0]); - if (typeof a !== 'string') { - this.#error(`Unsupported argument type for argument 1: (${ts.SyntaxKind[e.arguments[0].kind]})`, e.arguments[0]); + if (typeof a !== "string") { + this.#error( + `Unsupported argument type for argument 1: (${ts.SyntaxKind[e.arguments[0].kind]})`, + e.arguments[0], + ); } if (e.arguments.length === 1) { return new LiteralValue({ - id: gameData.get(a)?.id ?? a - }) + id: gameData.get(a)?.id ?? a, + }); } const b = this.parseBuiltinArg(e.arguments[1]); - if (typeof b !== 'number') { - this.#error(`Unsupported argument type for argument 2: (${ts.SyntaxKind[e.arguments[1].kind]})`, e.arguments[1]); + if (typeof b !== "number") { + this.#error( + `Unsupported argument type for argument 2: (${ts.SyntaxKind[e.arguments[1].kind]})`, + e.arguments[1], + ); } return new LiteralValue({ id: gameData.get(a)?.id ?? a, - num: b + num: b, }); }, coord: (e: ts.CallExpression): LiteralValue => { @@ -1482,42 +1638,51 @@ class Compiler { const a = this.parseBuiltinArg(e.arguments[0]); const b = this.parseBuiltinArg(e.arguments[1]); - if (typeof a !== 'number' || typeof b !== 'number') { - this.#error(`Unsupported argument types: (${ts.SyntaxKind[e.arguments[0].kind]}, ${ts.SyntaxKind[e.arguments[1].kind]})`, e); + if (typeof a !== "number" || typeof b !== "number") { + this.#error( + `Unsupported argument types: (${ts.SyntaxKind[e.arguments[0].kind]}, ${ts.SyntaxKind[e.arguments[1].kind]})`, + e, + ); } return new LiteralValue({ coord: { x: a, - y: b - } + y: b, + }, }); - } - } + }, + }; - #parseLiteral( - node: ts.Node, - handlers: ParseLiteralHandlers - ): ParsedLiteral { - const handleCall = handlers.call ?? (call => this.#error(`Unsupported call: ${call.expression.getText()}`, call)); - const handleIdentifier = handlers.identifier ?? (identifier => this.#error(`Unsupported identifier: ${identifier.text}`, identifier)); + #parseLiteral(node: ts.Node, handlers: ParseLiteralHandlers): ParsedLiteral { + const handleCall = + handlers.call ?? + ((call) => + this.#error(`Unsupported call: ${call.expression.getText()}`, call)); + const handleIdentifier = + handlers.identifier ?? + ((identifier) => + this.#error(`Unsupported identifier: ${identifier.text}`, identifier)); if (ts.isStringLiteral(node)) { - return {node, value: node.text}; + return { node, value: node.text }; } else if (ts.isNumericLiteral(node)) { - return {node, value: Number(node.text)}; + return { node, value: Number(node.text) }; } else if (ts.isPrefixUnaryExpression(node)) { switch (node.operator) { case ts.SyntaxKind.PlusToken: - return {node, value: +this.#parseLiteral(node.operand, handlers)!}; + return { node, value: +this.#parseLiteral(node.operand, handlers)! }; case ts.SyntaxKind.MinusToken: - return {node, value: -this.#parseLiteral(node.operand, handlers)!}; + return { node, value: -this.#parseLiteral(node.operand, handlers)! }; case ts.SyntaxKind.TildeToken: - return {node, value: ~this.#parseLiteral(node.operand, handlers)!}; + return { node, value: ~this.#parseLiteral(node.operand, handlers)! }; case ts.SyntaxKind.ExclamationToken: - return {node, value: !this.#parseLiteral(node.operand, handlers)!}; + return { node, value: !this.#parseLiteral(node.operand, handlers)! }; } - this.#error(`Unsupported literal ${ts.SyntaxKind[node.kind]}: ${ts.SyntaxKind[node.operator]}`, node); + this.#error( + `Unsupported literal ${ts.SyntaxKind[node.kind]}: ${ts.SyntaxKind[node.operator]}`, + node, + ); } else if (ts.isParenthesizedExpression(node)) { return this.#parseLiteral(node.expression, handlers); } else if (ts.isObjectLiteralExpression(node)) { @@ -1527,23 +1692,26 @@ class Compiler { if (ts.isPropertyAssignment(property)) { const key = this.#parseLiteral(property.name, { ...handlers, - identifier: (node) => node.text + identifier: (node) => node.text, }); - if (typeof key.value !== 'string' && typeof key.value !== 'number') { + if (typeof key.value !== "string" && typeof key.value !== "number") { this.#error("Object key must be string or number", key.node); } obj[key.value] = this.#parseLiteral(property.initializer, handlers); } else { - this.#error(`Unsupported property ${ts.SyntaxKind[property.kind]}`, property); + this.#error( + `Unsupported property ${ts.SyntaxKind[property.kind]}`, + property, + ); } } - return {node, value: obj}; + return { node, value: obj }; } else if (tsApiUtils.isTrueLiteral(node)) { - return {node, value: true}; + return { node, value: true }; } else if (tsApiUtils.isFalseLiteral(node)) { - return {node, value: false}; + return { node, value: false }; } else if (ts.isArrayLiteralExpression(node)) { const array: Array = []; @@ -1551,40 +1719,46 @@ class Compiler { array.push(this.#parseLiteral(element, handlers)); } - return {node, value: array}; + return { node, value: array }; } else if (ts.isCallExpression(node)) { - return {node, value: handleCall(node, handlers) as ParsedLiteral['value']}; + return { + node, + value: handleCall(node, handlers) as ParsedLiteral["value"], + }; } else if (tsApiUtils.isNullLiteral(node)) { - return {node, value: null}; + return { node, value: null }; } else if (ts.isIdentifier(node)) { const identifier = node.text; if (identifier === "undefined") { - return {node, value: undefined}; + return { node, value: undefined }; } - return {node, value: handleIdentifier(node, handlers) as ParsedLiteral['value']}; + return { + node, + value: handleIdentifier(node, handlers) as ParsedLiteral["value"], + }; } - this.#error(`Unsupported literal ${ts.SyntaxKind[node.kind]}`, node) + this.#error(`Unsupported literal ${ts.SyntaxKind[node.kind]}`, node); } compileCall( e: ts.CallExpression, - outs: (Variable | undefined)[] = [] + outs: (Variable | undefined)[] = [], ): Variable { let thisArg: ts.Expression | undefined; let name: string; if (ts.isIdentifier(e.expression)) { name = e.expression.text; - if(name in this.builtins) { + if (name in this.builtins) { const value = this.builtins[name](e); if (outs[0]) { this.#emit( methods.setReg, value, - this.ref(outs[0], VariableOperations.Write) + this.ref(outs[0], VariableOperations.Write), ); return outs[0]; @@ -1600,32 +1774,32 @@ class Compiler { `unsupported call ${e.expression.kind} ${ ts.SyntaxKind[e.expression.kind] }`, - e + e, ); } return this.compileResolvedCall(e, name, thisArg, [...e.arguments], outs); } compileResolvedCall( - refNode: ts.Node, - name: string, - thisArg?: ts.Expression, - rawArgs?: Array, - outs?: (Variable | undefined)[] + refNode: ts.Node, + name: string, + thisArg?: ts.Expression, + rawArgs?: Array, + outs?: (Variable | undefined)[], ): Variable; compileResolvedCall( - refNode: ts.Node, - name: string, - thisArg?: Variable, - rawArgs?: Array, - outs?: (Variable | undefined)[] + refNode: ts.Node, + name: string, + thisArg?: Variable, + rawArgs?: Array, + outs?: (Variable | undefined)[], ): Variable; compileResolvedCall( refNode: ts.Node, name: string, thisArg?: ts.Expression | Variable, rawArgs: Array = [], - outs: (Variable | undefined)[] = [] + outs: (Variable | undefined)[] = [], ): Variable { let dest = outs[0] || (outs[0] = this.#temp()); let info = methods[name]; @@ -1652,7 +1826,11 @@ class Compiler { const inst = new Instruction(info.id, []); - const extract = (v: ts.Expression | Variable | undefined, exprCb: (expr: ts.Expression) => E, varCb: (variable: Variable) => V) => { + const extract = ( + v: ts.Expression | Variable | undefined, + exprCb: (expr: ts.Expression) => E, + varCb: (variable: Variable) => V, + ) => { if (v != null && isVar(v)) { return varCb(v); } else if (v != null) { @@ -1660,19 +1838,27 @@ class Compiler { } else { return undefined; } - } + }; - const txtArg = info.special == "txt" && extract(rawArgs[0], - e => ts.isStringLiteral(e) && e.text, - v => v.reg?.type === "value" && v.reg.value.id); + const txtArg = + info.special == "txt" && + extract( + rawArgs[0], + (e) => ts.isStringLiteral(e) && e.text, + (v) => v.reg?.type === "value" && v.reg.value.id, + ); if (txtArg) { rawArgs.shift(); } - const bpArg = info.bp && extract(rawArgs[0], - e => ts.isIdentifier(e) && e.text, - v => v.reg?.type === "value" && v.reg.value.id); + const bpArg = + info.bp && + extract( + rawArgs[0], + (e) => ts.isIdentifier(e) && e.text, + (v) => v.reg?.type === "value" && v.reg.value.id, + ); if (bpArg) { rawArgs.shift(); @@ -1681,7 +1867,7 @@ class Compiler { const args: (Arg | Variable)[] = []; info.in - ?.filter(v => info.thisArg !== v) + ?.filter((v) => info.thisArg !== v) .forEach((v, i) => { const rawArg = rawArgs[i]; if (isVar(rawArg)) { @@ -1764,7 +1950,7 @@ class Compiler { s.expression, (s.expression.name as ts.Identifier).text, s.expression.expression, - [] + [], ); } else { this.#compileDynamicJump(s, theEnd); @@ -1773,7 +1959,7 @@ class Compiler { if (!variable.exec) { this.#error( "switch statement must use a flow control instruction", - s + s, ); } let hasDefault = false; @@ -1792,7 +1978,7 @@ class Compiler { clause.statements.forEach(this.compileStatement, this); } - if(!hasDefault) { + if (!hasDefault) { variable.exec.forEach((ref) => { this.#rewriteLabel(ref, theEnd, true); }); @@ -1800,7 +1986,7 @@ class Compiler { } this.#emitLabel(theEnd); - } + }, ); } @@ -1815,10 +2001,7 @@ class Compiler { this.#error(`unsupported case expression ${ts.SyntaxKind[e.kind]}`, e); } - #compileDynamicJump( - s: ts.SwitchStatement, - end: string - ) { + #compileDynamicJump(s: ts.SwitchStatement, end: string) { const cond = this.#temp(); const labelType = dynamicLabels[this.dynamicLabelCounter++]; if (!labelType) { @@ -1828,11 +2011,11 @@ class Compiler { methods.setNumber, new LiteralValue({ id: labelType }), this.ref(this.compileExpr(s.expression), VariableOperations.Read), - this.ref(cond, VariableOperations.Write) + this.ref(cond, VariableOperations.Write), ); const defaultClause = s.caseBlock.clauses.find((clause) => - ts.isDefaultClause(clause) + ts.isDefaultClause(clause), ); this.#emit(methods.jump, this.ref(cond, VariableOperations.Read)); let defaultLabel = defaultClause && this.#label(); @@ -1843,7 +2026,7 @@ class Compiler { if (!ts.isNumericLiteral(clause.expression)) { this.#error( `unsupported switch expression ${ts.SyntaxKind[s.expression.kind]}`, - s + s, ); } this.#emit( @@ -1851,7 +2034,7 @@ class Compiler { new LiteralValue({ id: labelType, num: Number(clause.expression.text), - }) + }), ); } else { this.#emitLabel(defaultLabel!); @@ -1908,7 +2091,7 @@ class Compiler { compileCondition( expression: ts.Expression, - dest: Variable | undefined + dest: Variable | undefined, ): { variable: Variable; ref: ArgRef } { let variable: Variable; let key: string | boolean; @@ -1945,7 +2128,7 @@ class Compiler { return this.#negate(this.#compileEquality(expression, dest)); case ts.SyntaxKind.LessThanEqualsToken: extraKey = "="; - // fallthrough + // fallthrough case ts.SyntaxKind.LessThanToken: key = "<"; assertNoDest(); @@ -1953,12 +2136,12 @@ class Compiler { expression, "checkNumber", undefined, - [getNumeric(expression.left), getNumeric(expression.right)] + [getNumeric(expression.left), getNumeric(expression.right)], ); break; case ts.SyntaxKind.GreaterThanEqualsToken: extraKey = "="; - // fallthrough + // fallthrough case ts.SyntaxKind.GreaterThanToken: key = ">"; assertNoDest(); @@ -1966,13 +2149,13 @@ class Compiler { expression, "checkNumber", undefined, - [getNumeric(expression.left), getNumeric(expression.right)] + [getNumeric(expression.left), getNumeric(expression.right)], ); break; default: this.#error( `unsupported condition ${expression.operatorToken.getText()}`, - expression + expression, ); } } else { @@ -1980,7 +2163,7 @@ class Compiler { `unsupported condition ${expression.kind} ${ ts.SyntaxKind[expression.kind] }`, - expression + expression, ); } let ref = variable.exec!.get(key)!; @@ -2009,7 +2192,7 @@ class Compiler { #compileEquality( expression: ts.BinaryExpression, - dest: Variable | undefined + dest: Variable | undefined, ): { variable: Variable; ref: ArgRef } { let variable: Variable | undefined; let key: string | boolean = true; @@ -2032,7 +2215,7 @@ class Compiler { expression, "compareEntity", undefined, - [expression.left, expression.right] + [expression.left, expression.right], ); return { variable, ref: variable.exec!.get(true)! }; } @@ -2053,7 +2236,7 @@ class Compiler { expression, "checkNumber", undefined, - [getNumeric(expression.left), getNumeric(expression.right)] + [getNumeric(expression.left), getNumeric(expression.right)], ); key = "="; } else if (ts.isStringLiteral(expression.left)) { @@ -2068,7 +2251,7 @@ class Compiler { expression, "compareEntity", undefined, - [expression.left, expression.right] + [expression.left, expression.right], ); } return { variable, ref: variable.exec!.get(key)! }; @@ -2120,7 +2303,7 @@ class Compiler { #error(msg: string, node: ts.Node): never { const lineNum = ts.getLineAndCharacterOfPosition( node.getSourceFile(), - node.getStart() + node.getStart(), ); const filename = node.getSourceFile().fileName; throw new Error(`${filename}:${lineNum.line + 1}: ${msg}`); @@ -2132,14 +2315,19 @@ class Compiler { compileVarDecl(s: ts.VariableDeclarationList) { s.declarations.forEach((decl: ts.VariableDeclaration) => { - const isConst = (ts.getCombinedNodeFlags(decl) & ts.NodeFlags.BlockScoped) === ts.NodeFlags.Const; + const isConst = + (ts.getCombinedNodeFlags(decl) & ts.NodeFlags.BlockScoped) === + ts.NodeFlags.Const; if (ts.isIdentifier(decl.name)) { if (!decl.initializer) { this.newVariable(decl.name); } else if (isConst) { const value = this.compileExpr(decl.initializer); - this.currentScope.scope.name(decl.name.text, this.ref(value, VariableOperations.Write)); + this.currentScope.scope.name( + decl.name.text, + this.ref(value, VariableOperations.Write), + ); } else { this.compileExpr(decl.initializer, this.newVariable(decl.name)); } @@ -2151,10 +2339,8 @@ class Compiler { return this.newVariable(el.name); } else { this.#error( - `unsupported array element ${el.kind} ${ - ts.SyntaxKind[el.kind] - }`, - decl + `unsupported array element ${el.kind} ${ts.SyntaxKind[el.kind]}`, + decl, ); } }); @@ -2164,7 +2350,7 @@ class Compiler { } else { this.#error( "only call expression are valid for array initializer", - decl + decl, ); } } else { @@ -2187,7 +2373,7 @@ class Compiler { ref( varname: string | ts.Identifier | Variable, - operation: VariableOperations + operation: VariableOperations, ): Variable { const v = isVar(varname) ? varname : this.variable(varname); v.operations |= operation; @@ -2239,7 +2425,7 @@ class Compiler { this.#rewrite( { instruction: ref.instruction, arg: ref.extraArg }, value, - skipIfSet + skipIfSet, ); } const instr = this.currentScope.program.code[ref.instruction]; @@ -2293,7 +2479,7 @@ function isVar(t: unknown): t is Variable { return (t as Variable)?.type === VariableSymbol; } -function resolveVariables(inst:Instruction) { +function resolveVariables(inst: Instruction) { for (let i = 0; i < inst.args.length; i++) { let arg = inst.args[i]; if (arg?.type == "variableRef" && arg.variable instanceof Variable) { @@ -2307,25 +2493,28 @@ function resolveVariables(inst:Instruction) { const nilReg = new RegRef(0); -export function compileProgram(mainFileName: string, program: ts.Program): string { +export function compileProgram( + mainFileName: string, + program: ts.Program, +): string { // TODO: ended up not using the typechecker. Should probably just parse // to reduce bundle size. ts.getPreEmitDiagnostics(program).forEach((diagnostic) => { if (diagnostic.file) { let { line, character } = ts.getLineAndCharacterOfPosition( diagnostic.file, - diagnostic.start! + diagnostic.start!, ); let message = ts.flattenDiagnosticMessageText( diagnostic.messageText, - "\n" + "\n", ); console.log( - `${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}` + `${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`, ); } else { console.log( - ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n") + ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n"), ); } }); @@ -2369,23 +2558,26 @@ function getNumeric(e: ts.Expression): ts.Expression { } type ParseLiteralHandlers = { - call?: (call: ts.CallExpression, handlers: ParseLiteralHandlers) => unknown, - identifier?: (identifier: ts.Identifier, handlers: ParseLiteralHandlers) => unknown + call?: (call: ts.CallExpression, handlers: ParseLiteralHandlers) => unknown; + identifier?: ( + identifier: ts.Identifier, + handlers: ParseLiteralHandlers, + ) => unknown; }; type SpecificLiteral = { - node: ts.Node, - value: T -} + node: ts.Node; + value: T; +}; type ParsedLiteral = { - node: ts.Node, + node: ts.Node; value: - | string - | number - | boolean - | null - | undefined - | { [key: string]: ParsedLiteral } - | ParsedLiteral[] + | string + | number + | boolean + | null + | undefined + | { [key: string]: ParsedLiteral } + | ParsedLiteral[]; }; diff --git a/compiler_bundle.ts b/compiler_bundle.ts index fdddf4d..0a1b2c4 100644 --- a/compiler_bundle.ts +++ b/compiler_bundle.ts @@ -1,20 +1,17 @@ - -import * as tsvfs from "@typescript/vfs"; -import * as ts from "typescript"; -import { CompilerOptions, compileProgram } from "./compile.js"; import { behavior_dts } from "./behavior_dts.js"; +import { CompilerOptions, compileProgram } from "./compile.js"; import { lib_dts } from "./lib_dts.js"; +import * as tsvfs from "@typescript/vfs"; +import * as ts from "typescript"; + export { CompilerOptions, compileProgram }; export { DesyncedStringToObject, ObjectToDesyncedString } from "./dsconvert.js"; export { Disassembler } from "./decompile/disasm.js"; export { assemble } from "./assembler"; -export function makeProgram( - tsCode: string, - compilerOptions = CompilerOptions -) { +export function makeProgram(tsCode: string, compilerOptions = CompilerOptions) { const fsMap = new Map(); - for(const lib in lib_dts) { + for (const lib in lib_dts) { fsMap.set(lib, lib_dts[lib]); } fsMap.set("index.ts", tsCode); diff --git a/compiler_options.ts b/compiler_options.ts index 83c8773..9df7017 100644 --- a/compiler_options.ts +++ b/compiler_options.ts @@ -1,10 +1,10 @@ import * as ts from "typescript"; export const CompilerOptions: ts.CompilerOptions = { - lib: ["lib.es2023.d.ts"], - types: [], - target: ts.ScriptTarget.ES2022, - moduleResolution: ts.ModuleResolutionKind.NodeNext, - module: ts.ModuleKind.NodeNext, - noEmit: true, -}; \ No newline at end of file + lib: ["lib.es2023.d.ts"], + types: [], + target: ts.ScriptTarget.ES2022, + moduleResolution: ts.ModuleResolutionKind.NodeNext, + module: ts.ModuleKind.NodeNext, + noEmit: true, +}; diff --git a/data.test.ts b/data.test.ts index ee6cf4f..153262b 100644 --- a/data.test.ts +++ b/data.test.ts @@ -1,19 +1,19 @@ -import {expect, test} from "@jest/globals"; -import {toJsFunctionName} from "./data"; +import { toJsFunctionName } from "./data"; +import { expect, test } from "@jest/globals"; test("toJsFunctionName", () => { - const tests: [string, string][] = [ - ["Dashbot", "dashbot"], - ["Command Center", "commandCenter"], - ["Hi-grade Capacitor", "hiGradeCapacitor"], - ["c_trilobyte_attack4", "trilobyteAttack4"], - ["AI Explorer", "aiExplorer"], - ["Building 1x1 (1M)", "building1x1_1M"], - ["Building 2x2 (1M3S)", "building2x2_1M3S"], - ["Human Explorer (Broken)", "humanExplorerBroken"] - ]; + const tests: [string, string][] = [ + ["Dashbot", "dashbot"], + ["Command Center", "commandCenter"], + ["Hi-grade Capacitor", "hiGradeCapacitor"], + ["c_trilobyte_attack4", "trilobyteAttack4"], + ["AI Explorer", "aiExplorer"], + ["Building 1x1 (1M)", "building1x1_1M"], + ["Building 2x2 (1M3S)", "building2x2_1M3S"], + ["Human Explorer (Broken)", "humanExplorerBroken"], + ]; - for(const [name, frameJsName] of tests) { - expect(toJsFunctionName(name)).toBe(frameJsName); - } -}); \ No newline at end of file + for (const [name, frameJsName] of tests) { + expect(toJsFunctionName(name)).toBe(frameJsName); + } +}); diff --git a/data.ts b/data.ts index c759cbe..8432a30 100644 --- a/data.ts +++ b/data.ts @@ -4,27 +4,27 @@ import overrides from "./scripts/game-data-overrides.json"; const allById: Map = new Map(); const allByJsName: Map = new Map(); -type Element = { id: string, base_id?: string, jsName: string }; +type Element = { id: string; base_id?: string; jsName: string }; function load( data: Record, overrides: Record, -): Map +): Map; function load( - data: Record, - overrides: Record, - mapper: (item: (S & Element)) => (T & Element) -): Map + data: Record, + overrides: Record, + mapper: (item: S & Element) => T & Element, +): Map; function load( - data: Record, - overrides: Record = {}, - mapper?: (item: (S & Element)) => (T & Element) -): Map{ + data: Record, + overrides: Record = {}, + mapper?: (item: S & Element) => T & Element, +): Map { const dataWithId: Map = new Map(); for (const id in data) { dataWithId.set(id, { ...data[id], - id + id, }); } @@ -34,15 +34,15 @@ function load( const item = (() => { let merged: Partial = dataWithId.get(id)!; - while ('base_id' in merged) { - let {base_id, ...rest} = merged; + while ("base_id" in merged) { + let { base_id, ...rest } = merged; const base = base_id != null ? dataWithId.get(base_id) : undefined; merged = { ...base, ...rest, - base_id - } + base_id, + }; if (merged.base_id === merged.id || merged.base_id === base?.id) { delete merged.base_id; @@ -53,11 +53,11 @@ function load( merged.jsName = merged.id; } - merged = mapper ? mapper(merged as (S & Element)) : merged; + merged = mapper ? mapper(merged as S & Element) : merged; merged = { ...merged, - ...overrides[id] + ...overrides[id], }; return merged as Element; @@ -80,11 +80,16 @@ function load( return loaded as Map; } -function indexBy(map: Map, key: K): Map { +function indexBy( + map: Map, + key: K, +): Map { const result: Map = new Map(); for (const value of map.values()) { if (result.has(value[key])) { - throw new Error(`Duplicate indexBy key ${key}: ${value[key]} (${value['id']}/${result.get(value[key])!['id']})`); + throw new Error( + `Duplicate indexBy key ${key}: ${value[key]} (${value["id"]}/${result.get(value[key])!["id"]})`, + ); } result.set(value[key], value); @@ -97,69 +102,95 @@ type MapValue = T extends Map ? K : never; export function toJsFunctionName(name: string) { return name - .replace(/^[a-z]_/, '') - .replace(/[^a-zA-Z0-9]/g, " ") - .replace(/ +/g, " ") - .toLowerCase() - .replace(/[0-9][a-z]/g, s => s.toUpperCase()) - .replace(/([0-9a-z]) ([a-z])/g, (s, a, b) => a + b.toUpperCase()) - .replace(/([A-Z]) ([a-z])/g, "$1$2") - .replace(/([0-9]) ([0-9])/g, "$1_$2") - .replace(/[0-9]X[0-9]/g, s => s.toLowerCase()) - .replace(/ ([0-9])/g, "$1") - .trim() - .replace(/ /g, '_'); + .replace(/^[a-z]_/, "") + .replace(/[^a-zA-Z0-9]/g, " ") + .replace(/ +/g, " ") + .toLowerCase() + .replace(/[0-9][a-z]/g, (s) => s.toUpperCase()) + .replace(/([0-9a-z]) ([a-z])/g, (s, a, b) => a + b.toUpperCase()) + .replace(/([A-Z]) ([a-z])/g, "$1$2") + .replace(/([0-9]) ([0-9])/g, "$1_$2") + .replace(/[0-9]X[0-9]/g, (s) => s.toLowerCase()) + .replace(/ ([0-9])/g, "$1") + .trim() + .replace(/ /g, "_"); } -const components = load(data["components"] as Record - slots?: Record, -}>, overrides["components"], component => ({ - ...component, - componentJsName: toJsFunctionName(component.name) -})); - -export type Component = MapValue<(typeof components)>; - -const frames = load(data["frames"] as Record, - start_disconnected?: boolean, -}>, overrides["frames"], frame => ({ - ...frame, - frameJsName: toJsFunctionName(frame.name ?? frame.jsName) -})); - -export type Frame = MapValue<(typeof frames)>; - -const items = load(data["items"] as Record, overrides["items"]); - -export type Item = MapValue<(typeof items)>; - -const values = load(data["values"] as Record, overrides["values"]); - -export type GameValue = MapValue<(typeof values)>; +const components = load( + data["components"] as Record< + string, + { + name: string; + attachment_size?: string; + registers?: Array<{ + type?: string; + tip?: string; + read_only?: boolean; + filter?: string; + }>; + slots?: Record; + } + >, + overrides["components"], + (component) => ({ + ...component, + componentJsName: toJsFunctionName(component.name), + }), +); + +export type Component = MapValue; + +const frames = load( + data["frames"] as Record< + string, + { + name?: string; + desc?: string; + type?: string; + flags?: string; + size?: string; + visual?: string; + slots?: Record; + start_disconnected?: boolean; + } + >, + overrides["frames"], + (frame) => ({ + ...frame, + frameJsName: toJsFunctionName(frame.name ?? frame.jsName), + }), +); + +export type Frame = MapValue; + +const items = load( + data["items"] as Record< + string, + { + name?: string; + visual?: string; + slot_type?: string; + tag?: string; + stack_size?: number; + } + >, + overrides["items"], +); + +export type Item = MapValue; + +const values = load( + data["values"] as Record< + string, + { + name?: string; + tag?: string; + } + >, + overrides["values"], +); + +export type GameValue = MapValue; const socketSizes = { Internal: 0, @@ -170,14 +201,20 @@ const socketSizes = { export type SocketSize = keyof typeof socketSizes; -const visuals = load(data["visuals"] as Record, overrides["visuals"]); +const visuals = load( + data["visuals"] as Record< + string, + { + name?: string; + flags?: string; + tile_size?: number[]; + sockets?: string[][]; + } + >, + overrides["visuals"], +); -export type Visual = MapValue<(typeof visuals)>; +export type Visual = MapValue; export type GameData = Component | Frame | Item | GameValue | Visual; @@ -192,6 +229,6 @@ export const gameData = { socketSizes, instructions: data["instructions"], get: (id: string) => { - return allByJsName.get(id) ?? allById.get(id) - } -} + return allByJsName.get(id) ?? allById.get(id); + }, +}; diff --git a/decompile/RawBehavior.ts b/decompile/RawBehavior.ts index 160e0ea..53bd362 100644 --- a/decompile/RawBehavior.ts +++ b/decompile/RawBehavior.ts @@ -1,6 +1,5 @@ import { RawInstruction } from "./RawInstruction"; - export interface RawBehavior { [key: number]: RawInstruction; parameters?: boolean[]; diff --git a/decompile/RawBlueprint.ts b/decompile/RawBlueprint.ts index e5c5e80..a32a709 100644 --- a/decompile/RawBlueprint.ts +++ b/decompile/RawBlueprint.ts @@ -18,8 +18,11 @@ export interface RawBlueprint { channel_3?: boolean; channel_4?: boolean; }; - regs?: Record; - locks?: (string|boolean)[]; + regs?: Record< + number, + { id?: string; num?: number; coord?: { x: number; y: number } } + >; + locks?: (string | boolean)[]; links?: [number, number][]; - components?: [type:string, slot:number, code?:RawBehavior][]; -} \ No newline at end of file + components?: [type: string, slot: number, code?: RawBehavior][]; +} diff --git a/decompile/RawInstruction.ts b/decompile/RawInstruction.ts index 911fe45..6d5aa22 100644 --- a/decompile/RawInstruction.ts +++ b/decompile/RawInstruction.ts @@ -7,7 +7,7 @@ export interface RawInstruction { [key: number]: unknown; c?: number; txt?: string; - bp?: string|RawBlueprint; + bp?: string | RawBlueprint; sub?: number; nx?: number; ny?: number; diff --git a/decompile/disasm.ts b/decompile/disasm.ts index 56ba1c9..bfe4dd5 100644 --- a/decompile/disasm.ts +++ b/decompile/disasm.ts @@ -1,9 +1,6 @@ -import {RawBehavior} from "./RawBehavior"; -import {RawBlueprint} from "./RawBlueprint"; -import {RawInstruction} from "./RawInstruction"; -import {instructions} from "./dsinstr"; -import {DesyncedStringToObject} from "../dsconvert"; -import {Code, Pass} from "../ir/code"; +import { gameData } from "../data"; +import { DesyncedStringToObject } from "../dsconvert"; +import { Code, Pass } from "../ir/code"; import { Arg, FALSE, @@ -17,7 +14,10 @@ import { StringLiteral, TRUE, } from "../ir/instruction"; -import {gameData} from "../data"; +import { RawBehavior } from "./RawBehavior"; +import { RawBlueprint } from "./RawBlueprint"; +import { RawInstruction } from "./RawInstruction"; +import { instructions } from "./dsinstr"; interface RawValue { id?: string; @@ -35,7 +35,7 @@ export class Disassembler { pendingLabels: string[] = []; - constructor(obj: RawBlueprint|RawBehavior) { + constructor(obj: RawBlueprint | RawBehavior) { this.#label("main"); if ("frame" in obj) { this.blueprint(obj); @@ -75,7 +75,7 @@ export class Disassembler { this.#emit( `.reg`, new LiteralValue({ num: Number(k) }), - new LiteralValue(v) + new LiteralValue(v), ); } } @@ -85,15 +85,15 @@ export class Disassembler { this.#emit( `.lock`, new LiteralValue({ num: i }), - new LiteralValue({ id: v }) - ) + new LiteralValue({ id: v }), + ), ); if (obj.links) { for (const [k, v] of obj.links) { this.#emit( `.link`, new LiteralValue({ num: k }), - new LiteralValue({ num: v }) + new LiteralValue({ num: v }), ); } } @@ -105,13 +105,13 @@ export class Disassembler { `.component`, new LiteralValue({ num: k }), new LiteralValue({ id: v }), - new Label(`behavior${this.extraBehaviors.length}`) + new Label(`behavior${this.extraBehaviors.length}`), ); } else { this.#emit( `.component`, new LiteralValue({ num: k }), - new LiteralValue({ id: v }) + new LiteralValue({ id: v }), ); } } @@ -143,7 +143,7 @@ export class Disassembler { raw: RawInstruction, nodeOffset: number, subOffset: number, - main: string + main: string, ) { const args: Arg[] = []; const def = instructions[raw.op]; @@ -221,7 +221,11 @@ export class Disassembler { let blueprintIndex = 0; do { - for(; extraBehaviorIndex < this.extraBehaviors.length; extraBehaviorIndex++) { + for ( + ; + extraBehaviorIndex < this.extraBehaviors.length; + extraBehaviorIndex++ + ) { const behavior = this.extraBehaviors[extraBehaviorIndex]; if (!behavior) continue; @@ -240,7 +244,7 @@ export class Disassembler { subOffset += behavior.subs?.length || 0; } - for(; blueprintIndex < this.bps.length; blueprintIndex++) { + for (; blueprintIndex < this.bps.length; blueprintIndex++) { const bp = this.bps[blueprintIndex]; this.#label(`bp${blueprintIndex + 1}`); this.blueprint(bp); @@ -391,4 +395,4 @@ export function generateAsm(prog: Code): string[] { const output: string[] = []; prog.apply(RenderAssembly(output)); return output; -} \ No newline at end of file +} diff --git a/disas.ts b/disas.ts index 754ba8e..3cfdfe2 100644 --- a/disas.ts +++ b/disas.ts @@ -1,7 +1,7 @@ #!/usr/bin/env node -import * as fs from "fs"; -import { DesyncedStringToObject } from "./dsconvert"; import { Disassembler } from "./decompile/disasm"; +import { DesyncedStringToObject } from "./dsconvert"; +import * as fs from "fs"; const code = fs.readFileSync(process.argv[2], "utf8"); const codeObj = DesyncedStringToObject(code); diff --git a/instructions.json b/instructions.json index 7ccfe8a..fad6d1f 100644 --- a/instructions.json +++ b/instructions.json @@ -31,40 +31,19 @@ "category": "Flow" }, "label": { - "args": [ - [ - "in", - "Label", - "Label identifier", - "any" - ] - ], + "args": [["in", "Label", "Label identifier", "any"]], "name": "Label", "desc": "Labels can be jumped to from anywhere in a behavior", "category": "Flow" }, "jump": { - "args": [ - [ - "in", - "Label", - "Label identifier", - "any" - ] - ], + "args": [["in", "Label", "Label identifier", "any"]], "name": "Jump", "desc": "Jumps execution to label with the same label id", "category": "Flow" }, "wait": { - "args": [ - [ - "in", - "Time", - "Number of ticks to wait", - "num" - ] - ], + "args": [["in", "Time", "Number of ticks to wait", "num"]], "name": "Wait Ticks", "desc": "Pauses execution of the behavior until 1 or more ticks later", "category": "Flow" @@ -76,19 +55,9 @@ "Where to continue if the types are the same" ], "args": [ - [ - "exec", - "If Different", - "Where to continue if the types differ" - ], - [ - "in", - "Value 1" - ], - [ - "in", - "Value 2" - ] + ["exec", "If Different", "Where to continue if the types differ"], + ["in", "Value 1"], + ["in", "Value 2"] ], "name": "Compare Item", "desc": "Compares Item or Unit type", @@ -101,19 +70,9 @@ "Where to continue if the entities are the same" ], "args": [ - [ - "exec", - "If Different", - "Where to continue if the entities differ" - ], - [ - "in", - "Entity 1" - ], - [ - "in", - "Entity 2" - ] + ["exec", "If Different", "Where to continue if the entities differ"], + ["in", "Entity 1"], + ["in", "Entity 2"] ], "name": "Compare Entity", "desc": "Compares Entities", @@ -126,19 +85,9 @@ "Where to continue if the entities are the same" ], "args": [ - [ - "exec", - "If Different", - "Where to continue if the entities differ" - ], - [ - "in", - "Item" - ], - [ - "in", - "Type" - ] + ["exec", "If Different", "Where to continue if the entities differ"], + ["in", "Item"], + ["in", "Type"] ], "name": "Is a", "desc": "Compares if an item of entity is of a specific type", @@ -146,109 +95,40 @@ }, "get_type": { "args": [ - [ - "in", - "Item/Entity" - ], - [ - "out", - "Type" - ] + ["in", "Item/Entity"], + ["out", "Type"] ], "name": "Get Type", "desc": "Gets the type from an item or entity", "category": "Global" }, "value_type": { - "exec_arg": [ - 1, - "No Match", - "Where to continue if there is no match" - ], + "exec_arg": [1, "No Match", "Where to continue if there is no match"], "args": [ - [ - "in", - "Data", - "Data to test" - ], - [ - "exec", - "Item", - "Item Type" - ], - [ - "exec", - "Entity", - "Entity Type" - ], - [ - "exec", - "Component", - "Component Type" - ], - [ - "exec", - "Tech", - "Tech Type", - null, - true - ], - [ - "exec", - "Value", - "Information Value Type", - null, - true - ], - [ - "exec", - "Coord", - "Coordinate Value Type", - null, - true - ] + ["in", "Data", "Data to test"], + ["exec", "Item", "Item Type"], + ["exec", "Entity", "Entity Type"], + ["exec", "Component", "Component Type"], + ["exec", "Tech", "Tech Type", null, true], + ["exec", "Value", "Information Value Type", null, true], + ["exec", "Coord", "Coordinate Value Type", null, true] ], "name": "Data type switch", "desc": "Switch based on type of value", "category": "Flow" }, "get_first_locked_0": { - "args": [ - [ - "out", - "Item", - "The first locked item id with no item" - ] - ], + "args": [["out", "Item", "The first locked item id with no item"]], "name": "Get First Locked Id", "desc": "Gets the first item where the locked slot exists but there is no item in it", "category": "Unit" }, "unit_type": { - "exec_arg": [ - 5, - "No Unit", - "No visible unit passed", - null, - true - ], + "exec_arg": [5, "No Unit", "No visible unit passed", null, true], "args": [ - [ - "in", - "Unit", - "The unit to check", - "entity" - ], - [ - "exec", - "Building", - "Where to continue if the entity is a building" - ], - [ - "exec", - "Bot", - "Where to continue if the entity is a bot" - ], + ["in", "Unit", "The unit to check", "entity"], + ["exec", "Building", "Where to continue if the entity is a building"], + ["exec", "Bot", "Where to continue if the entity is a bot"], [ "exec", "Construction", @@ -263,35 +143,11 @@ }, "select_nearest": { "args": [ - [ - "exec", - "A", - "A is nearer (or equal)" - ], - [ - "exec", - "B", - "B is nearer" - ], - [ - "in", - "Unit A", - null, - "entity" - ], - [ - "in", - "Unit B", - null, - "entity" - ], - [ - "out", - "Closest", - "Closest unit", - null, - true - ] + ["exec", "A", "A is nearer (or equal)"], + ["exec", "B", "B is nearer"], + ["in", "Unit A", null, "entity"], + ["in", "Unit B", null, "entity"], + ["out", "Closest", "Closest unit", null, true] ], "name": "Select Nearest", "desc": "Branches based on which unit is closer, optional branches for closer unit", @@ -299,42 +155,12 @@ }, "for_entities_in_range": { "args": [ - [ - "in", - "Range", - "Range (up to units visibility range)", - "num" - ], - [ - "in", - "Filter", - "Filter to check", - "radar" - ], - [ - "in", - "Filter", - "Second Filter", - "radar", - true - ], - [ - "in", - "Filter", - "Third Filter", - "radar", - true - ], - [ - "out", - "Entity", - "Current Entity" - ], - [ - "exec", - "Done", - "Finished looping through all entities in range" - ] + ["in", "Range", "Range (up to units visibility range)", "num"], + ["in", "Filter", "Filter to check", "radar"], + ["in", "Filter", "Second Filter", "radar", true], + ["in", "Filter", "Third Filter", "radar", true], + ["out", "Entity", "Current Entity"], + ["exec", "Done", "Finished looping through all entities in range"] ], "name": "Loop Entities (Range)", "desc": "Performs code for all entities in visibility range of the unit", @@ -342,54 +168,27 @@ }, "for_research": { "args": [ - [ - "out", - "Tech", - "Researchable Tech" - ], - [ - "exec", - "Done", - "Finished looping through all researchable tech" - ] + ["out", "Tech", "Researchable Tech"], + ["exec", "Done", "Finished looping through all researchable tech"] ], "name": "Loop Research", "desc": "Performs code for all researchable tech", "category": "Flow" }, "get_research": { - "args": [ - [ - "out", - "Tech", - "First active research" - ] - ], + "args": [["out", "Tech", "First active research"]], "name": "Get Research", "desc": "Returns the first active research tech", "category": "Flow" }, "set_research": { - "args": [ - [ - "in", - "Tech", - "First active research", - "tech" - ] - ], + "args": [["in", "Tech", "First active research", "tech"]], "name": "Set Research", "desc": "Returns the first active research tech", "category": "Flow" }, "clear_research": { - "args": [ - [ - "in", - "Tech", - "Tech to remove from research queue" - ] - ], + "args": [["in", "Tech", "Tech to remove from research queue"]], "name": "Clear Research", "desc": "Clears a research from queue, or entire queue if no tech passed", "category": "Flow" @@ -411,18 +210,8 @@ "If Smaller", "Where to continue if Value is smaller than Compare" ], - [ - "in", - "Value", - "The value to check with", - "num" - ], - [ - "in", - "Compare", - "The number to check against", - "num" - ] + ["in", "Value", "The value to check with", "num"], + ["in", "Compare", "The number to check against", "num"] ], "name": "Compare Number", "desc": "Divert program depending on number of Value and Compare", @@ -430,16 +219,8 @@ }, "set_reg": { "args": [ - [ - "in", - "Value", - null, - "any" - ], - [ - "out", - "Target" - ] + ["in", "Value", null, "any"], + ["out", "Target"] ], "name": "Copy", "desc": "Copy a value to a frame register, parameter or variable", @@ -447,12 +228,7 @@ }, "set_comp_reg": { "args": [ - [ - "in", - "Value", - null, - "any" - ], + ["in", "Value", null, "any"], [ "in", "Component/Index", @@ -479,10 +255,7 @@ "Component and register number to set", "comp_num" ], - [ - "out", - "Value" - ], + ["out", "Value"], [ "in", "Group/Index", @@ -502,12 +275,7 @@ "Is Not Working", "If the requested component is NOT currently working" ], - [ - "in", - "Component/Index", - "Component to get", - "comp_num" - ], + ["in", "Component/Index", "Component to get", "comp_num"], [ "in", "Group/Index", @@ -529,20 +297,9 @@ }, "set_number": { "args": [ - [ - "in", - "Value" - ], - [ - "in", - "Num/Coord", - null, - "coord_num" - ], - [ - "out", - "To" - ] + ["in", "Value"], + ["in", "Num/Coord", null, "coord_num"], + ["out", "To"] ], "name": "Set Number", "desc": "Sets the numerical/coordinate part of a value", @@ -550,22 +307,9 @@ }, "combine_coordinate": { "args": [ - [ - "in", - "x", - null, - "any" - ], - [ - "in", - "y", - null, - "any" - ], - [ - "out", - "Result" - ] + ["in", "x", null, "any"], + ["in", "y", null, "any"], + ["out", "Result"] ], "name": "Combine Coordinate", "desc": "Returns a coordinate made from x and y values", @@ -573,20 +317,9 @@ }, "separate_coordinate": { "args": [ - [ - "in", - "Coordinate", - null, - "coord_num" - ], - [ - "out", - "x" - ], - [ - "out", - "y" - ] + ["in", "Coordinate", null, "coord_num"], + ["out", "x"], + ["out", "y"] ], "name": "Separate Coordinate", "desc": "Split a coordinate into x and y values", @@ -594,34 +327,11 @@ }, "combine_register": { "args": [ - [ - "in", - "Num" - ], - [ - "in", - "Entity" - ], - [ - "out", - "Register", - null, - "entity" - ], - [ - "in", - "x", - null, - null, - true - ], - [ - "in", - "y", - null, - null, - true - ] + ["in", "Num"], + ["in", "Entity"], + ["out", "Register", null, "entity"], + ["in", "x", null, null, true], + ["in", "y", null, null, true] ], "name": "Combine Register", "desc": "Combine to make a register from separate parameters", @@ -629,44 +339,12 @@ }, "separate_register": { "args": [ - [ - "in", - "Register", - null, - "entity" - ], - [ - "out", - "Num" - ], - [ - "out", - "Entity", - null, - null, - true - ], - [ - "out", - "ID", - null, - null, - true - ], - [ - "out", - "x", - null, - null, - true - ], - [ - "out", - "y", - null, - null, - true - ] + ["in", "Register", null, "entity"], + ["out", "Num"], + ["out", "Entity", null, null, true], + ["out", "ID", null, null, true], + ["out", "x", null, null, true], + ["out", "y", null, null, true] ], "name": "Separate Register", "desc": "Split a register into separate parameters", @@ -674,22 +352,9 @@ }, "add": { "args": [ - [ - "in", - "To", - null, - "coord_num" - ], - [ - "in", - "Num", - null, - "coord_num" - ], - [ - "out", - "Result" - ] + ["in", "To", null, "coord_num"], + ["in", "Num", null, "coord_num"], + ["out", "Result"] ], "name": "Add", "desc": "Adds a number or coordinate to another number or coordinate", @@ -697,22 +362,9 @@ }, "sub": { "args": [ - [ - "in", - "From", - null, - "coord_num" - ], - [ - "in", - "Num", - null, - "coord_num" - ], - [ - "out", - "Result" - ] + ["in", "From", null, "coord_num"], + ["in", "Num", null, "coord_num"], + ["out", "Result"] ], "name": "Subtract", "desc": "Subtracts a number or coordinate from another number or coordinate", @@ -720,22 +372,9 @@ }, "mul": { "args": [ - [ - "in", - "To", - null, - "coord_num" - ], - [ - "in", - "Num", - null, - "coord_num" - ], - [ - "out", - "Result" - ] + ["in", "To", null, "coord_num"], + ["in", "Num", null, "coord_num"], + ["out", "Result"] ], "name": "Multiply", "desc": "Multiplies a number or coordinate from another number or coordinate", @@ -743,22 +382,9 @@ }, "div": { "args": [ - [ - "in", - "From", - null, - "coord_num" - ], - [ - "in", - "Num", - null, - "coord_num" - ], - [ - "out", - "Result" - ] + ["in", "From", null, "coord_num"], + ["in", "Num", null, "coord_num"], + ["out", "Result"] ], "name": "Divide", "desc": "Divides a number or coordinate from another number or coordinate", @@ -766,22 +392,9 @@ }, "modulo": { "args": [ - [ - "in", - "Num", - null, - "coord_num" - ], - [ - "in", - "By", - null, - "coord_num" - ], - [ - "out", - "Result" - ] + ["in", "Num", null, "coord_num"], + ["in", "By", null, "coord_num"], + ["out", "Result"] ], "name": "Modulo", "desc": "Get the remainder of a division", @@ -789,24 +402,9 @@ }, "getfreespace": { "args": [ - [ - "in", - "Item", - "Item to check can fit", - "item" - ], - [ - "out", - "Result", - "Number of a specific item that can fit on a unit" - ], - [ - "in", - "Unit", - "The unit to check (if not self)", - "entity", - true - ] + ["in", "Item", "Item to check can fit", "item"], + ["out", "Result", "Number of a specific item that can fit on a unit"], + ["in", "Unit", "The unit to check (if not self)", "entity", true] ], "name": "Get space for item", "desc": "Returns how many of the input item can fit in the inventory", @@ -814,17 +412,8 @@ }, "checkfreespace": { "args": [ - [ - "exec", - "Can't Fit", - "Execution if it can't fit the item" - ], - [ - "in", - "Item", - "Item and amount to check can fit", - "item_num" - ] + ["exec", "Can't Fit", "Execution if it can't fit the item"], + ["in", "Item", "Item and amount to check can fit", "item_num"] ], "name": "Check space for item", "desc": "Checks if free space is available for an item and amount", @@ -832,65 +421,25 @@ }, "lock_slots": { "args": [ - [ - "in", - "Item", - "Item type to try fixing to the slots", - "item_num" - ], - [ - "in", - "Slot index", - "Individual slot to fix", - "num", - true - ] + ["in", "Item", "Item type to try fixing to the slots", "item_num"], + ["in", "Slot index", "Individual slot to fix", "num", true] ], "name": "Fix Item Slots", "desc": "Fix all storage slots or a specific item slot index", "category": "Unit" }, "unlock_slots": { - "args": [ - [ - "in", - "Slot index", - "Individual slot to unfix", - "num", - true - ] - ], + "args": [["in", "Slot index", "Individual slot to unfix", "num", true]], "name": "Unfix Item Slots", "desc": "Unfix all inventory slots or a specific item slot index", "category": "Unit" }, "get_health": { "args": [ - [ - "in", - "Entity", - "Entity to check", - "entity" - ], - [ - "out", - "Percent", - "Percentage of health remaining" - ], - [ - "out", - "Current", - "Value of health remaining", - null, - true - ], - [ - "out", - "Max", - "Value of maximum health", - null, - true - ] + ["in", "Entity", "Entity to check", "entity"], + ["out", "Percent", "Percentage of health remaining"], + ["out", "Current", "Value of health remaining", null, true], + ["out", "Max", "Value of maximum health", null, true] ], "name": "Get Health", "desc": "Gets a units health as a percentage, current and max", @@ -898,67 +447,35 @@ }, "get_entity_at": { "args": [ - [ - "in", - "Coordinate", - "Coordinate to get Entity from", - "coord_num" - ], - [ - "out", - "Result" - ] + ["in", "Coordinate", "Coordinate to get Entity from", "coord_num"], + ["out", "Result"] ], "name": "Get Entity At", "desc": "Gets the best matching entity at a coordinate", "category": "Math" }, "get_grid_effeciency": { - "args": [ - [ - "out", - "Result" - ] - ], + "args": [["out", "Result"]], "name": "Get Grid Efficiency", "desc": "Gets the value of the Grid Efficiency as a percent", "category": "Math" }, "get_battery": { - "args": [ - [ - "out", - "Result" - ] - ], + "args": [["out", "Result"]], "name": "Get Battery", "desc": "Gets the value of the Battery level as a percent", "category": "Math" }, "get_self": { - "args": [ - [ - "out", - "Result" - ] - ], + "args": [["out", "Result"]], "name": "Get Self", "desc": "Gets the value of the Unit executing the behavior", "category": "Math" }, "read_signal": { "args": [ - [ - "in", - "Unit", - "The owned unit to check for", - "entity" - ], - [ - "out", - "Result", - "Value of units Signal register" - ] + ["in", "Unit", "The owned unit to check for", "entity"], + ["out", "Result", "Value of units Signal register"] ], "name": "Read Signal", "desc": "Reads the Signal register of another unit", @@ -966,16 +483,8 @@ }, "read_radio": { "args": [ - [ - "in", - "Band", - "The band to check for" - ], - [ - "out", - "Result", - "Value of the radio signal" - ] + ["in", "Band", "The band to check for"], + ["out", "Result", "Value of the radio signal"] ], "name": "Read Radio", "desc": "Reads the Radio signal on a specified band", @@ -983,21 +492,9 @@ }, "for_signal": { "args": [ - [ - "in", - "Signal", - "Signal" - ], - [ - "out", - "Entity", - "Entity with signal" - ], - [ - "exec", - "Done", - "Finished looping through all entities with signal" - ] + ["in", "Signal", "Signal"], + ["out", "Entity", "Entity with signal"], + ["exec", "Done", "Finished looping through all entities with signal"] ], "name": "*Loop Signal*", "desc": "*DEPRECATED* Use Loop Signal (Match) instead", @@ -1005,59 +502,21 @@ }, "for_signal_match": { "args": [ - [ - "in", - "Signal", - "Signal" - ], - [ - "out", - "Entity", - "Entity with signal" - ], - [ - "out", - "Signal", - "Found signal", - "entity", - true - ], - [ - "exec", - "Done", - "Finished looping through all entities with signal" - ] + ["in", "Signal", "Signal"], + ["out", "Entity", "Entity with signal"], + ["out", "Signal", "Found signal", "entity", true], + ["exec", "Done", "Finished looping through all entities with signal"] ], "name": "Loop Signal (Match)", "desc": "Loops through all units with a signal of similar type", "category": "Flow" }, "check_altitude": { - "exec_arg": [ - 4, - "No Unit", - "No visible unit passed", - null, - true - ], + "exec_arg": [4, "No Unit", "No visible unit passed", null, true], "args": [ - [ - "in", - "Unit", - "The unit to check for (if not self)", - "entity", - true - ], - [ - "exec", - "Valley", - "Where to continue if the unit is in a valley" - ], - [ - "exec", - "Plateau", - "Where to continue if the unit is on a plateau" - ] + ["in", "Unit", "The unit to check for (if not self)", "entity", true], + ["exec", "Valley", "Where to continue if the unit is in a valley"], + ["exec", "Plateau", "Where to continue if the unit is on a plateau"] ], "name": "Check Altitude", "desc": "Divert program depending on location of a unit", @@ -1065,18 +524,8 @@ }, "check_blightness": { "args": [ - [ - "in", - "Unit", - "The unit to check for (if not self)", - "entity", - true - ], - [ - "exec", - "Blight", - "Where to continue if the unit is in the blight" - ] + ["in", "Unit", "The unit to check for (if not self)", "entity", true], + ["exec", "Blight", "Where to continue if the unit is in the blight"] ], "name": "Check Blightness", "desc": "Divert program depending on location of a unit", @@ -1084,18 +533,8 @@ }, "check_health": { "args": [ - [ - "exec", - "Full", - "Where to continue if at full health" - ], - [ - "in", - "Unit", - "The unit to check for (if not self)", - "entity", - true - ] + ["exec", "Full", "Where to continue if at full health"], + ["in", "Unit", "The unit to check for (if not self)", "entity", true] ], "name": "Check Health", "desc": "Check a units health", @@ -1108,13 +547,7 @@ "Full", "Where to continue if battery power is fully recharged" ], - [ - "in", - "Unit", - "The unit to check for (if not self)", - "entity", - true - ] + ["in", "Unit", "The unit to check for (if not self)", "entity", true] ], "name": "Check Battery", "desc": "Checks the Battery level of a unit", @@ -1122,18 +555,8 @@ }, "check_grid_effeciency": { "args": [ - [ - "exec", - "Full", - "Where to continue if at full efficiency" - ], - [ - "in", - "Unit", - "The unit to check for (if not self)", - "entity", - true - ] + ["exec", "Full", "Where to continue if at full efficiency"], + ["in", "Unit", "The unit to check for (if not self)", "entity", true] ], "name": "Check Grid Efficiency", "desc": "Checks the Efficiency of the power grid the unit is on", @@ -1141,24 +564,13 @@ }, "count_item": { "args": [ - [ - "in", - "Item", - "Item to count", - "item" - ], + ["in", "Item", "Item to count", "item"], [ "out", "Result", "Number of this item in inventory or empty if none exist" ], - [ - "in", - "Unit", - "The unit to check for (if not self)", - "entity", - true - ] + ["in", "Unit", "The unit to check for (if not self)", "entity", true] ], "name": "Count Items", "desc": "Counts the number of the passed item in its inventory", @@ -1166,18 +578,8 @@ }, "count_slots": { "args": [ - [ - "out", - "Result", - "Number of slots of this type" - ], - [ - "in", - "Unit", - "The unit to check for (if not self)", - "entity", - true - ] + ["out", "Result", "Number of slots of this type"], + ["in", "Unit", "The unit to check for (if not self)", "entity", true] ], "name": "Count Slots", "desc": "Returns the number of slots in this unit of the given type", @@ -1185,17 +587,8 @@ }, "get_max_stack": { "args": [ - [ - "in", - "Item", - "Item to count", - "item_num" - ], - [ - "out", - "Max Stack", - "Max Stack" - ] + ["in", "Item", "Item to count", "item_num"], + ["out", "Max Stack", "Max Stack"] ], "name": "Get Max Stack", "desc": "Returns the amount an item can stack to", @@ -1203,24 +596,9 @@ }, "have_item": { "args": [ - [ - "in", - "Item", - "Item to count", - "item_num" - ], - [ - "exec", - "Have Item", - "have the specified item" - ], - [ - "in", - "Unit", - "The unit to check for (if not self)", - "entity", - true - ] + ["in", "Item", "Item to count", "item_num"], + ["exec", "Have Item", "have the specified item"], + ["in", "Unit", "The unit to check for (if not self)", "entity", true] ], "name": "Have Item", "desc": "Checks if you have at least a specified amount of an item", @@ -1233,12 +611,7 @@ "No Component", "If you don't current hold the requested component" ], - [ - "in", - "Component", - "Component to equip", - "comp" - ], + ["in", "Component", "Component to equip", "comp"], [ "in", "Slot index", @@ -1258,12 +631,7 @@ "No Component", "If you don't current hold the requested component or slot was empty" ], - [ - "in", - "Component", - "Component to unequip", - "comp" - ], + ["in", "Component", "Component to unequip", "comp"], [ "in", "Slot index", @@ -1278,31 +646,10 @@ }, "get_closest_entity": { "args": [ - [ - "in", - "Filter", - "Filter to check", - "radar" - ], - [ - "in", - "Filter", - "Second Filter", - "radar", - true - ], - [ - "in", - "Filter", - "Third Filter", - "radar", - true - ], - [ - "out", - "Output", - "Entity" - ] + ["in", "Filter", "Filter to check", "radar"], + ["in", "Filter", "Second Filter", "radar", true], + ["in", "Filter", "Third Filter", "radar", true], + ["out", "Output", "Entity"] ], "name": "Get Closest Entity", "desc": "Gets the closest visible entity matching a filter", @@ -1310,122 +657,30 @@ }, "match": { "args": [ - [ - "in", - "Unit", - "Unit to Filter, defaults to Self", - "entity" - ], - [ - "in", - "Filter", - "Filter to check", - "radar" - ], - [ - "in", - "Filter", - "Second Filter", - "radar", - true - ], - [ - "in", - "Filter", - "Third Filter", - "radar", - true - ], - [ - "exec", - "Failed", - "Did not match filter" - ] + ["in", "Unit", "Unit to Filter, defaults to Self", "entity"], + ["in", "Filter", "Filter to check", "radar"], + ["in", "Filter", "Second Filter", "radar", true], + ["in", "Filter", "Third Filter", "radar", true], + ["exec", "Failed", "Did not match filter"] ], "name": "Match", "desc": "Filters the passed entity", "category": "Unit" }, "switch": { - "exec_arg": [ - 1, - "Default", - "Did not match filter" - ], - "args": [ - [ - "in", - "Unit", - "Unit to Filter, defaults to Self", - "entity" - ], - [ - "in", - "Case 1", - "Case 1", - "radar" - ], - [ - "exec", - "1", - "Case 1" - ], - [ - "in", - "Case 2", - "Case 2", - "radar", - true - ], - [ - "exec", - "2", - "Case 2", - null, - true - ], - [ - "in", - "Case 3", - "Case 3", - "radar", - true - ], - [ - "exec", - "3", - "Case 3", - null, - true - ], - [ - "in", - "Case 4", - "Case 4", - "radar", - true - ], - [ - "exec", - "4", - "Case 4", - null, - true - ], - [ - "in", - "Case 5", - "Case 5", - "radar", - true - ], - [ - "exec", - "5", - "Case 5", - null, - true - ] + "exec_arg": [1, "Default", "Did not match filter"], + "args": [ + ["in", "Unit", "Unit to Filter, defaults to Self", "entity"], + ["in", "Case 1", "Case 1", "radar"], + ["exec", "1", "Case 1"], + ["in", "Case 2", "Case 2", "radar", true], + ["exec", "2", "Case 2", null, true], + ["in", "Case 3", "Case 3", "radar", true], + ["exec", "3", "Case 3", null, true], + ["in", "Case 4", "Case 4", "radar", true], + ["exec", "4", "Case 4", null, true], + ["in", "Case 5", "Case 5", "radar", true], + ["exec", "5", "Case 5", null, true] ], "name": "Switch", "desc": "Filters the passed entity", @@ -1439,13 +694,7 @@ "Unit or destination to bring items to", "entity" ], - [ - "in", - "Item / Amount", - "Item and amount to drop off", - "item_num", - true - ] + ["in", "Item / Amount", "Item and amount to drop off", "item_num", true] ], "name": "Drop Off Items", "desc": "Drop off items at a unit or destination\n\nIf a number is set it will drop off an amount to fill the target unit up to that amount\nIf unset it will try to drop off everything.", @@ -1453,33 +702,15 @@ }, "dopickup": { "args": [ - [ - "in", - "Source", - "Unit to take items from", - "entity" - ], - [ - "in", - "Item / Amount", - "Item and amount to pick up", - "item_num", - true - ] + ["in", "Source", "Unit to take items from", "entity"], + ["in", "Item / Amount", "Item and amount to pick up", "item_num", true] ], "name": "Pick Up Items", "desc": "Picks up a specific number of items from an entity\n\nWill try to pick up the specified amount, if no amount\nis specified it will try to pick up everything.", "category": "Unit" }, "request_item": { - "args": [ - [ - "in", - "Item", - "Item and amount to order", - "item_num" - ] - ], + "args": [["in", "Item", "Item and amount to order", "item_num"]], "name": "Request Item", "desc": "Requests an item if it doesn't exist in the inventory", "category": "Unit" @@ -1490,30 +721,15 @@ "category": "Unit" }, "request_wait": { - "args": [ - [ - "in", - "Item", - "Item and amount to order", - "item_num" - ] - ], + "args": [["in", "Item", "Item and amount to order", "item_num"]], "name": "Request Wait", "desc": "Requests an item and waits until it exists in inventory", "category": "Unit" }, "get_resource_num": { "args": [ - [ - "in", - "Resource", - "Resource Node to check", - "entity" - ], - [ - "out", - "Result" - ] + ["in", "Resource", "Resource Node to check", "entity"], + ["out", "Result"] ], "name": "Get Resource Num", "desc": "Gets the amount of resource", @@ -1521,15 +737,8 @@ }, "get_inventory_item": { "args": [ - [ - "out", - "Item" - ], - [ - "exec", - "No Items", - "No items in inventory" - ] + ["out", "Item"], + ["exec", "No Items", "No items in inventory"] ], "name": "First Item", "desc": "Reads the first item in your inventory", @@ -1537,21 +746,9 @@ }, "get_inventory_item_index": { "args": [ - [ - "in", - "Index", - "Slot index", - "num" - ], - [ - "out", - "Item" - ], - [ - "exec", - "No Item", - "Item not found" - ] + ["in", "Index", "Slot index", "num"], + ["out", "Item"], + ["exec", "No Item", "Item not found"] ], "name": "Get Inventory Item", "desc": "Reads the item contained in the specified slot index", @@ -1559,16 +756,8 @@ }, "for_inventory_item": { "args": [ - [ - "out", - "Inventory", - "Item Inventory" - ], - [ - "exec", - "Done", - "Finished loop" - ], + ["out", "Inventory", "Item Inventory"], + ["exec", "Done", "Finished loop"], [ "out", "Reserved Stack", @@ -1576,13 +765,7 @@ "num", true ], - [ - "out", - "Unreserved Stack", - "Items available", - "num", - true - ], + ["out", "Unreserved Stack", "Items available", "num", true], [ "out", "Reserved Space", @@ -1590,13 +773,7 @@ "num", true ], - [ - "out", - "Unreserved Space", - "Remaining space", - "num", - true - ] + ["out", "Unreserved Space", "Remaining space", "num", true] ], "name": "Loop Inventory Slots", "desc": "Loops through Inventory", @@ -1604,22 +781,9 @@ }, "for_recipe_ingredients": { "args": [ - [ - "in", - "Recipe", - null, - "item" - ], - [ - "out", - "Ingredient", - "Recipe Ingredient" - ], - [ - "exec", - "Done", - "Finished loop" - ] + ["in", "Recipe", null, "item"], + ["out", "Ingredient", "Recipe Ingredient"], + ["exec", "Done", "Finished loop"] ], "name": "Loop Recipe Ingredients", "desc": "Loops through Ingredients", @@ -1627,24 +791,13 @@ }, "get_distance": { "args": [ - [ - "in", - "Target", - "Target unit", - "entity" - ], + ["in", "Target", "Target unit", "entity"], [ "out", "Distance", "Unit and its distance in the numerical part of the value" ], - [ - "in", - "Unit", - "The unit to measure from (if not self)", - "entity", - true - ] + ["in", "Unit", "The unit to measure from (if not self)", "entity", true] ], "name": "Distance", "desc": "Returns distance to a unit", @@ -1652,81 +805,39 @@ }, "order_transfer": { "args": [ - [ - "in", - "Target", - "Target unit", - "entity" - ], - [ - "in", - "Item", - "Item and amount to transfer", - "item_num" - ] + ["in", "Target", "Target unit", "entity"], + ["in", "Item", "Item and amount to transfer", "item_num"] ], "name": "Order Transfer To", "desc": "Transfers an Item to another Unit", "category": "Unit" }, "is_same_grid": { - "exec_arg": [ - 1, - "Same Grid", - "Where to continue if both entities are in the same power grid" - ], - "args": [ - [ - "in", - "Entity", - "First Entity", - "entity" - ], - [ - "in", - "Entity", - "Second Entity", - "entity" - ], - [ - "exec", - "Different", - "Different power grids" - ] + "exec_arg": [ + 1, + "Same Grid", + "Where to continue if both entities are in the same power grid" + ], + "args": [ + ["in", "Entity", "First Entity", "entity"], + ["in", "Entity", "Second Entity", "entity"], + ["exec", "Different", "Different power grids"] ], "name": "Is Same Grid", "desc": "Checks if two entities are in the same power grid", "category": "Unit" }, "is_moving": { - "exec_arg": [ - 1, - "Moving", - "Where to continue if entity is moving" - ], + "exec_arg": [1, "Moving", "Where to continue if entity is moving"], "args": [ - [ - "exec", - "Not Moving", - "Where to continue if entity is not moving" - ], - [ - "exec", - "Path Blocked", - "Where to continue if entity is path blocked" - ], + ["exec", "Not Moving", "Where to continue if entity is not moving"], + ["exec", "Path Blocked", "Where to continue if entity is path blocked"], [ "exec", "No Result", "Where to continue if entity is out of visual range" ], - [ - "in", - "Unit", - "The unit to check (if not self)", - "entity", - true - ] + ["in", "Unit", "The unit to check (if not self)", "entity", true] ], "name": "Is Moving", "desc": "Checks the movement state of an entity", @@ -1734,17 +845,8 @@ }, "is_fixed": { "args": [ - [ - "in", - "Slot index", - "Individual slot to check", - "num" - ], - [ - "exec", - "Is Fixed", - "Where to continue if inventory slot is fixed" - ] + ["in", "Slot index", "Individual slot to check", "num"], + ["exec", "Is Fixed", "Where to continue if inventory slot is fixed"] ], "name": "Is Fixed", "desc": "Check if a specific item slot index is fixed", @@ -1752,12 +854,7 @@ }, "is_equipped": { "args": [ - [ - "in", - "Component", - "Component to check", - "comp" - ], + ["in", "Component", "Component to check", "comp"], [ "exec", "Component Equipped", @@ -1840,22 +937,13 @@ }, "solve": { "args": [ - [ - "in", - "Target", - "Explorable to solve", - "entity" - ], + ["in", "Target", "Explorable to solve", "entity"], [ "out", "Missing", "Missing repair item, scanner component or Unpowered" ], - [ - "exec", - "Failed", - "Missing item, component or power to scan" - ] + ["exec", "Failed", "Missing item, component or power to scan"] ], "name": "Solve Explorable", "desc": "Attempt to solve explorable with inventory items", @@ -1868,83 +956,39 @@ }, "get_location": { "args": [ - [ - "in", - "Entity", - "Entity to get coordinates of", - "entity" - ], - [ - "out", - "Coord", - "Coordinate of entity" - ] + ["in", "Entity", "Entity to get coordinates of", "entity"], + ["out", "Coord", "Coordinate of entity"] ], "name": "Get Location", "desc": "Gets location of a a seen entity", "category": "Global" }, "move_east": { - "args": [ - [ - "in", - "Number", - "Number of tiles to move East", - "num" - ] - ], + "args": [["in", "Number", "Number of tiles to move East", "num"]], "name": "Move East", "desc": "Moves towards a tile East of the current location at the specified distance", "category": "Move" }, "move_west": { - "args": [ - [ - "in", - "Number", - "Number of tiles to move West", - "num" - ] - ], + "args": [["in", "Number", "Number of tiles to move West", "num"]], "name": "Move West", "desc": "Moves towards a tile West of the current location at the specified distance", "category": "Move" }, "move_north": { - "args": [ - [ - "in", - "Number", - "Number of tiles to move North", - "num" - ] - ], + "args": [["in", "Number", "Number of tiles to move North", "num"]], "name": "Move North", "desc": "Moves towards a tile North of the current location at the specified distance", "category": "Move" }, "move_south": { - "args": [ - [ - "in", - "Number", - "Number of tiles to move South", - "num" - ] - ], + "args": [["in", "Number", "Number of tiles to move South", "num"]], "name": "Move South", "desc": "Moves towards a tile South of the current location at the specified distance", "category": "Move" }, "domove_async": { - "args": [ - [ - "in", - "Target", - "Unit to move to", - "entity" - ] - ], + "args": [["in", "Target", "Unit to move to", "entity"]], "name": "Move Unit (Async)", "desc": "Move to another unit while continuing the program", "category": "Move" @@ -1976,14 +1020,7 @@ "category": "Move" }, "moveaway_range": { - "args": [ - [ - "in", - "Target", - "Unit to move away from", - "entity" - ] - ], + "args": [["in", "Target", "Unit to move away from", "entity"]], "name": "Move Away (Range)", "desc": "Moves out of range of another unit", "category": "Move" @@ -1995,33 +1032,11 @@ }, "scan": { "args": [ - [ - "in", - "Filter 1", - "First filter", - "radar" - ], - [ - "in", - "Filter 2", - "Second filter", - "radar" - ], - [ - "in", - "Filter 3", - "Third filter", - "radar" - ], - [ - "out", - "Result" - ], - [ - "exec", - "No Result", - "Execution path if no results are found" - ] + ["in", "Filter 1", "First filter", "radar"], + ["in", "Filter 2", "Second filter", "radar"], + ["in", "Filter 3", "Third filter", "radar"], + ["out", "Result"], + ["exec", "No Result", "Execution path if no results are found"] ], "name": "Radar", "desc": "Scan for the closest unit that matches the filters", @@ -2029,56 +1044,29 @@ }, "mine": { "args": [ - [ - "in", - "Resource", - "Resource to Mine", - "resource_num" - ], + ["in", "Resource", "Resource to Mine", "resource_num"], [ "exec", "Cannot Mine", "Execution path if mining was unable to be performed" ], - [ - "exec", - "Full", - "Execution path if can't fit resource into inventory" - ] + ["exec", "Full", "Execution path if can't fit resource into inventory"] ], "name": "Mine", "desc": "Mines a single resource", "category": "Component" }, "get_stability": { - "args": [ - [ - "out", - "Number", - "Stability" - ] - ], + "args": [["out", "Number", "Stability"]], "name": "Get Stability", "desc": "Gets the current world stability", "category": "Global" }, "percent_value": { "args": [ - [ - "in", - "Value", - "Value to check" - ], - [ - "in", - "Max Value", - "Max Value to get percentage of" - ], - [ - "out", - "Number", - "Percent" - ] + ["in", "Value", "Value to check"], + ["in", "Max Value", "Max Value to get percentage of"], + ["out", "Number", "Percent"] ], "name": "Percent", "desc": "Gives you the percent that value is of Max Value", @@ -2086,36 +1074,12 @@ }, "remap_value": { "args": [ - [ - "in", - "Value", - "Value to Remap" - ], - [ - "in", - "Input Low", - "Low value for input" - ], - [ - "in", - "Input High", - "High value for input" - ], - [ - "in", - "Target Low", - "Low value for target" - ], - [ - "in", - "Target high", - "High value for target" - ], - [ - "out", - "Result", - "Remapped value" - ] + ["in", "Value", "Value to Remap"], + ["in", "Input Low", "Low value for input"], + ["in", "Input High", "High value for input"], + ["in", "Target Low", "Low value for target"], + ["in", "Target high", "High value for target"], + ["out", "Result", "Remapped value"] ], "name": "Remap", "desc": "Remaps a value between two ranges", @@ -2124,16 +1088,8 @@ "is_daynight": { "exec_arg": false, "args": [ - [ - "exec", - "Day", - "Where to continue if it is nighttime" - ], - [ - "exec", - "Night", - "Where to continue if it is daytime" - ] + ["exec", "Day", "Where to continue if it is nighttime"], + ["exec", "Night", "Where to continue if it is daytime"] ], "name": "Is Day/Night", "desc": "Divert program depending time of day", @@ -2141,17 +1097,8 @@ }, "faction_item_amount": { "args": [ - [ - "in", - "Item", - "Item to count", - "item" - ], - [ - "out", - "Result", - "Number of this item in your faction" - ], + ["in", "Item", "Item to count", "item"], + ["out", "Result", "Number of this item in your faction"], [ "exec", "None", @@ -2164,17 +1111,8 @@ }, "readkey": { "args": [ - [ - "in", - "Frame", - "Structure to read the key for", - "entity" - ], - [ - "out", - "Key", - "Number key of structure" - ] + ["in", "Frame", "Structure to read the key for", "entity"], + ["out", "Key", "Number key of structure"] ], "name": "Read Key", "desc": "Attempts to reads the internal key of the unit", @@ -2194,12 +1132,7 @@ "Can Produce", "Where to continue if the item can be produced" ], - [ - "in", - "Item", - "Production Item", - "item" - ], + ["in", "Item", "Production Item", "item"], [ "in", "Component", @@ -2212,121 +1145,51 @@ }, "get_ingredients": { "args": [ - [ - "in", - "Product", - null, - "item" - ], - [ - "out", - "Out 1", - "First Ingredient" - ], - [ - "out", - "Out 2", - "Second Ingredient" - ], - [ - "out", - "Out 3", - "Third Ingredient" - ] + ["in", "Product", null, "item"], + ["out", "Out 1", "First Ingredient"], + ["out", "Out 2", "Second Ingredient"], + ["out", "Out 3", "Third Ingredient"] ], "name": "Get Ingredients", "desc": "Returns the ingredients required to produce an item", "category": "Global" }, "notify": { - "args": [ - [ - "in", - "Notify Value", - "Notification Value" - ] - ], + "args": [["in", "Notify Value", "Notification Value"]], "name": "Notify", "desc": "Triggers a faction notification", "category": "Global" }, "get_resource_item": { "args": [ - [ - "in", - "Resource Node", - "Resource Node", - "entity" - ], - [ - "out", - "Resource", - "Resource Type" - ], - [ - "exec", - "Not Resource", - "Continue here if it wasn't a resource node" - ] + ["in", "Resource Node", "Resource Node", "entity"], + ["out", "Resource", "Resource Type"], + ["exec", "Not Resource", "Continue here if it wasn't a resource node"] ], "name": "Resource Type", "desc": "Gets the resource type from an resource node", "category": "Global" }, "gettrust": { - "exec_arg": [ - 1, - "No Unit", - "No Unit Passed" - ], + "exec_arg": [1, "No Unit", "No Unit Passed"], "args": [ - [ - "exec", - "Ally", - "Target unit considers you an ally" - ], - [ - "exec", - "Neutral", - "Target unit considers you neutral" - ], - [ - "exec", - "Enemy", - "Target unit considers you an enemy" - ], - [ - "in", - "Unit", - "Target Unit", - "entity" - ] + ["exec", "Ally", "Target unit considers you an ally"], + ["exec", "Neutral", "Target unit considers you neutral"], + ["exec", "Enemy", "Target unit considers you an enemy"], + ["in", "Unit", "Target Unit", "entity"] ], "name": "Get Trust", "desc": "Gets the trust level of the unit towards you", "category": "Global" }, "gethome": { - "args": [ - [ - "out", - "Result", - "Factions home unit" - ] - ], + "args": [["out", "Result", "Factions home unit"]], "name": "Get Home", "desc": "Gets the factions home unit", "category": "Global" }, "ping": { - "args": [ - [ - "in", - "Target", - "Target unit", - "entity" - ] - ], + "args": [["in", "Target", "Target unit", "entity"]], "name": "Pings a Unit", "desc": "Plays the Ping effect and notifies other players", "category": "Global" @@ -2378,31 +1241,15 @@ "category": "Global" }, "gather_information": { - "args": [ - [ - "in", - "Range", - "Range of operation", - "num" - ] - ], + "args": [["in", "Range", "Range of operation", "num"]], "name": "Gather Information", "desc": "Collect information for running the auto base controller", "category": "AutoBase" }, "make_carrier": { "args": [ - [ - "in", - "Carriers", - "Type and count of carriers to make", - "frame_num" - ], - [ - "exec", - "If Working", - "Where to continue if the unit started working" - ] + ["in", "Carriers", "Type and count of carriers to make", "frame_num"], + ["exec", "If Working", "Where to continue if the unit started working"] ], "name": "Make Carriers", "desc": "Construct carrier bots for delivering orders or to use for other tasks", @@ -2416,11 +1263,7 @@ "Resource type and number of miners to maintain", "item_num" ], - [ - "exec", - "If Working", - "Where to continue if the unit started working" - ] + ["exec", "If Working", "Where to continue if the unit started working"] ], "name": "Make Miners", "desc": "Construct and equip miner components on available carrier bots", @@ -2428,11 +1271,7 @@ }, "serve_construction": { "args": [ - [ - "exec", - "If Working", - "Where to continue if the unit started working" - ] + ["exec", "If Working", "Where to continue if the unit started working"] ], "name": "Serve Construction", "desc": "Produce materials needed in construction sites", @@ -2446,29 +1285,10 @@ "Item type and number of producers to maintain", "item_num" ], - [ - "in", - "Component", - "Production component", - "comp" - ], - [ - "in", - "Building", - "Building type to use as producer", - "frame" - ], - [ - "in", - "Location", - "Location offset from self", - "coord" - ], - [ - "exec", - "If Working", - "Where to continue if the unit started working" - ] + ["in", "Component", "Production component", "comp"], + ["in", "Building", "Building type to use as producer", "frame"], + ["in", "Location", "Location offset from self", "coord"], + ["exec", "If Working", "Where to continue if the unit started working"] ], "name": "Make Producer", "desc": "Build and maintain dedicated production buildings", @@ -2476,21 +1296,12 @@ }, "make_turret_bots": { "args": [ - [ - "in", - "Number", - "Number of turret bots to maintain", - "num" - ], - [ - "exec", - "If Working", - "Where to continue if the unit started working" - ] + ["in", "Number", "Number of turret bots to maintain", "num"], + ["exec", "If Working", "Where to continue if the unit started working"] ], "name": "Make Turret Bots", "desc": "Construct and equip turret components on available carrier bots", "category": "AutoBase" } } -} \ No newline at end of file +} diff --git a/ir/behavior.ts b/ir/behavior.ts index e8bec4a..7b681d7 100644 --- a/ir/behavior.ts +++ b/ir/behavior.ts @@ -1,50 +1,50 @@ -import {Code, Pass} from "./code"; +import { Code, Pass } from "./code"; type NamedCode = Map; export interface Behavior { - mainLabel?: string; - main: Code; - subs: NamedCode; - others: NamedCode; // Other behaviors for use in blueprints - bps: NamedCode; + mainLabel?: string; + main: Code; + subs: NamedCode; + others: NamedCode; // Other behaviors for use in blueprints + bps: NamedCode; } export function splitProgram(prog: Code): Behavior { - const result: Behavior = { - mainLabel: prog.code[0]?.labels[0], - main: prog, - subs: new Map(), - bps: new Map(), - others: new Map(), - }; - const splitter: Pass = (instr, i) => { - let key: "subs" | "others" | "bps" | undefined; - if (i == 0) return; - switch (instr.op) { - case ".sub": - key = "subs"; - break; - case ".behavior": - key = "others"; - break; - case ".blueprint": - key = "bps"; - break; - } - if (key) { - const instructions = prog.code.splice(i); - const newCode = new Code(); - newCode.code = instructions; - const label = instr.labels[0] ?? instructions[1]?.labels[0]; - if (!label) { - throw new Error(`No label for ${instr.op} at line ${instr.lineno}`); - } - const group: NamedCode = result[key]; - group.set(label, newCode); - } - }; - splitter.reverse = true; - prog.apply(splitter); - return result; -} \ No newline at end of file + const result: Behavior = { + mainLabel: prog.code[0]?.labels[0], + main: prog, + subs: new Map(), + bps: new Map(), + others: new Map(), + }; + const splitter: Pass = (instr, i) => { + let key: "subs" | "others" | "bps" | undefined; + if (i == 0) return; + switch (instr.op) { + case ".sub": + key = "subs"; + break; + case ".behavior": + key = "others"; + break; + case ".blueprint": + key = "bps"; + break; + } + if (key) { + const instructions = prog.code.splice(i); + const newCode = new Code(); + newCode.code = instructions; + const label = instr.labels[0] ?? instructions[1]?.labels[0]; + if (!label) { + throw new Error(`No label for ${instr.op} at line ${instr.lineno}`); + } + const group: NamedCode = result[key]; + group.set(label, newCode); + } + }; + splitter.reverse = true; + prog.apply(splitter); + return result; +} diff --git a/ir/code.ts b/ir/code.ts index ef10bdd..e04afab 100644 --- a/ir/code.ts +++ b/ir/code.ts @@ -1,47 +1,47 @@ import { Instruction } from "./instruction"; export interface Pass { - reverse?: boolean; - (instr: Instruction, ip: number, program:Code): void; + reverse?: boolean; + (instr: Instruction, ip: number, program: Code): void; } export class Code { - code: Instruction[]; + code: Instruction[]; - constructor(code: Instruction[] = []) { - this.code = code; - } + constructor(code: Instruction[] = []) { + this.code = code; + } - clone(): Code { - return new Code(this.code.map(instr => instr.clone())); - } + clone(): Code { + return new Code(this.code.map((instr) => instr.clone())); + } - add(instr: Instruction) { - this.code.push(instr); - } + add(instr: Instruction) { + this.code.push(instr); + } - apply(pass: Pass) { - if (pass.reverse) { - this.#applyReverse(pass); - return; - } - for (let i = 0; i < this.code.length; i++) { - const instr = this.code[i]; - pass(instr, i, this); - } + apply(pass: Pass) { + if (pass.reverse) { + this.#applyReverse(pass); + return; } + for (let i = 0; i < this.code.length; i++) { + const instr = this.code[i]; + pass(instr, i, this); + } + } - #applyReverse(pass: Pass) { - for (let i = this.code.length - 1; i >= 0; i--) { - const instr = this.code[i]; - pass(instr, i, this); - } + #applyReverse(pass: Pass) { + for (let i = this.code.length - 1; i >= 0; i--) { + const instr = this.code[i]; + pass(instr, i, this); } + } - // TODO: moveInstruction + // TODO: moveInstruction } export function reversePass(pass: Pass): Pass { - pass.reverse = true; - return pass; -} \ No newline at end of file + pass.reverse = true; + return pass; +} diff --git a/ir/instruction.ts b/ir/instruction.ts index 514a0d0..9474e0d 100644 --- a/ir/instruction.ts +++ b/ir/instruction.ts @@ -5,7 +5,7 @@ export class LiteralValue { num?: number; id?: string; coord?: { x: number; y: number }; - } + }, ) {} stringValue() { @@ -97,7 +97,7 @@ export class ResolvedSub { constructor(public index: number) {} } -export class VariableRef { +export class VariableRef { readonly type = "variableRef"; constructor(public variable: T) {} } @@ -113,7 +113,7 @@ export type Arg = | VariableRef; export function isId( - value: Arg | undefined + value: Arg | undefined, ): value is LiteralValue & { value: { id: string } } { return value?.type == "value" && typeof value.value.id === "string"; } @@ -139,7 +139,10 @@ export class Instruction { nx?: number; ny?: number; - constructor(readonly op: string, public args: (Arg | undefined)[]) {} + constructor( + readonly op: string, + public args: (Arg | undefined)[], + ) {} clone(): Instruction { const clone = new Instruction(this.op, [...this.args]); @@ -152,14 +155,14 @@ export class Instruction { clone.comment = this.comment; clone.labels = [...this.labels]; clone.lineno = this.lineno; - clone.nx = this.nx + clone.nx = this.nx; clone.ny = this.ny; return clone; } forArgs( indexes: number[] | undefined, - f: (arg: Arg | undefined, i: number) => void + f: (arg: Arg | undefined, i: number) => void, ) { if (indexes == null) { return; diff --git a/js2ds.ts b/js2ds.ts index 22d2886..59dc022 100644 --- a/js2ds.ts +++ b/js2ds.ts @@ -1,7 +1,7 @@ #!/usr/bin/env node +import { CompilerOptions, compileProgram } from "./compile"; import * as fs from "fs"; import * as ts from "typescript"; -import { CompilerOptions, compileProgram } from "./compile"; const filename = process.argv[2]; const files = [filename, `${__dirname}/../behavior.d.ts`]; diff --git a/scripts/dumped-game-data.json b/scripts/dumped-game-data.json index a5437a4..72198d9 100644 --- a/scripts/dumped-game-data.json +++ b/scripts/dumped-game-data.json @@ -1746,9 +1746,7 @@ "slots": { "drone": 1 }, - "registers": [ - {} - ] + "registers": [{}] }, "c_drone_launcher": { "base_id": "c_drone_launcher", @@ -1758,9 +1756,7 @@ "slots": { "drone": 6 }, - "registers": [ - {} - ] + "registers": [{}] }, "c_drone_port": { "base_id": "c_drone_port", @@ -1770,9 +1766,7 @@ "slots": { "drone": 2 }, - "registers": [ - {} - ] + "registers": [{}] }, "c_explorable_admin_fix": { "base_id": "c_explorable_fix", @@ -1781,9 +1775,7 @@ "c_explorable_autosolve": { "base_id": "c_explorable_autosolve", "name": "c_explorable_autosolve", - "registers": [ - {} - ] + "registers": [{}] }, "c_explorable_balance": { "base_id": "c_explorable_balance", @@ -3489,164 +3481,81 @@ }, "visuals": { "blight_set_01": { - "tile_size": [ - 8, - 6 - ] + "tile_size": [8, 6] }, "blight_set_02": { - "tile_size": [ - 8, - 6 - ] + "tile_size": [8, 6] }, "blight_set_03": { - "tile_size": [ - 8, - 6 - ] + "tile_size": [8, 6] }, "blight_set_04": { - "tile_size": [ - 8, - 6 - ] + "tile_size": [8, 6] }, "blight_set_05": { - "tile_size": [ - 14, - 9 - ] + "tile_size": [14, 9] }, "blight_set_06": { - "tile_size": [ - 13, - 11 - ] + "tile_size": [13, 11] }, "blight_set_07": { - "tile_size": [ - 6, - 7 - ] + "tile_size": [6, 7] }, "blight_set_08": { - "tile_size": [ - 7, - 10 - ] + "tile_size": [7, 10] }, "blight_set_09": { - "tile_size": [ - 6, - 7 - ] + "tile_size": [6, 7] }, "plateau_set_01": { - "tile_size": [ - 3, - 3 - ] + "tile_size": [3, 3] }, "plateau_set_02": { - "tile_size": [ - 6, - 5 - ] + "tile_size": [6, 5] }, "plateau_set_03": { - "tile_size": [ - 4, - 5 - ] + "tile_size": [4, 5] }, "plateau_set_hole_01": { "flags": "CutsHole", - "tile_size": [ - 5, - 5 - ] + "tile_size": [5, 5] }, "plateau_set_hole_02": { "flags": "CutsHole", - "tile_size": [ - 12, - 22 - ] + "tile_size": [12, 22] }, "v_2x2_a_ruined": { - "tile_size": [ - 2, - 2 - ] + "tile_size": [2, 2] }, "v_advanced_robotics_research": {}, "v_alien_artifact": {}, "v_alien_data": {}, "v_alien_extractor_dead": { "flags": "RandomRotation", - "sockets": [ - [ - "", - "Internal" - ] - ], - "tile_size": [ - 2, - 2 - ] + "sockets": [["", "Internal"]], + "tile_size": [2, 2] }, "v_alien_feeder_dead": { "flags": "RandomRotation", - "sockets": [ - [ - "", - "Internal" - ] - ], - "tile_size": [ - 2, - 2 - ] + "sockets": [["", "Internal"]], + "tile_size": [2, 2] }, "v_alien_research_item": {}, "v_alien_soldier": { - "sockets": [ - [ - "", - "Internal" - ] - ] + "sockets": [["", "Internal"]] }, "v_alien_soldier_shadow": { - "sockets": [ - [ - "", - "Internal" - ] - ] + "sockets": [["", "Internal"]] }, "v_aluminium_rod": {}, "v_aluminium_sheet": {}, "v_amac_01_xl": { "sockets": [ - [ - "", - "Internal" - ], - [ - "", - "Internal" - ], - [ - "large1", - "Large" - ] + ["", "Internal"], + ["", "Internal"], + ["large1", "Large"] ], - "tile_size": [ - 3, - 2 - ] + "tile_size": [3, 2] }, "v_amalgamator_01_l": {}, "v_Antlers_01_S": {}, @@ -3654,662 +3563,247 @@ "v_assembler_01_m": {}, "v_base1x1a": { "sockets": [ - [ - "Medium1", - "Medium" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["Medium1", "Medium"], + ["", "Internal"], + ["", "Internal"] ], - "tile_size": [ - 1, - 1 - ] + "tile_size": [1, 1] }, "v_base1x1b": { "sockets": [ - [ - "Large1", - "Large" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["Large1", "Large"], + ["", "Internal"], + ["", "Internal"] ], - "tile_size": [ - 1, - 1 - ] + "tile_size": [1, 1] }, "v_base1x1c": { "sockets": [ - [ - "small1", - "Small" - ], - [ - "small2", - "Small" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["small1", "Small"], + ["small2", "Small"], + ["", "Internal"], + ["", "Internal"] ], - "tile_size": [ - 1, - 1 - ] + "tile_size": [1, 1] }, "v_base1x1d": { "sockets": [ - [ - "small1", - "Small" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["small1", "Small"], + ["", "Internal"], + ["", "Internal"] ], - "tile_size": [ - 1, - 1 - ] + "tile_size": [1, 1] }, "v_base1x1e": { "sockets": [ - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["", "Internal"], + ["", "Internal"] ], - "tile_size": [ - 1, - 1 - ] + "tile_size": [1, 1] }, "v_base1x1f": { "sockets": [ - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["", "Internal"], + ["", "Internal"] ], - "tile_size": [ - 1, - 1 - ] + "tile_size": [1, 1] }, "v_base1x1g": { "sockets": [ - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["", "Internal"], + ["", "Internal"] ], - "tile_size": [ - 1, - 1 - ] + "tile_size": [1, 1] }, "v_base2x1a": { "sockets": [ - [ - "Medium2", - "Medium" - ], - [ - "Medium1", - "Medium" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["Medium2", "Medium"], + ["Medium1", "Medium"], + ["", "Internal"], + ["", "Internal"], + ["", "Internal"], + ["", "Internal"] ], - "tile_size": [ - 1, - 2 - ] + "tile_size": [1, 2] }, "v_base2x1b": { "sockets": [ - [ - "Medium1", - "Medium" - ], - [ - "Large1", - "Large" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["Medium1", "Medium"], + ["Large1", "Large"], + ["", "Internal"], + ["", "Internal"] ], - "tile_size": [ - 1, - 2 - ] + "tile_size": [1, 2] }, "v_base2x1c": { "sockets": [ - [ - "Medium1", - "Medium" - ], - [ - "Medium2", - "Medium" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["Medium1", "Medium"], + ["Medium2", "Medium"], + ["", "Internal"], + ["", "Internal"], + ["", "Internal"], + ["", "Internal"] ], - "tile_size": [ - 1, - 2 - ] + "tile_size": [1, 2] }, "v_base2x1d": { "sockets": [ - [ - "Medium1", - "Medium" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["Medium1", "Medium"], + ["", "Internal"], + ["", "Internal"] ], - "tile_size": [ - 1, - 2 - ] + "tile_size": [1, 2] }, "v_base2x1e": { "sockets": [ - [ - "medium1", - "Medium" - ], - [ - "small1", - "Small" - ], - [ - "small2", - "Small" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["medium1", "Medium"], + ["small1", "Small"], + ["small2", "Small"], + ["", "Internal"], + ["", "Internal"] ], - "tile_size": [ - 1, - 2 - ] + "tile_size": [1, 2] }, "v_base2x1f": { "sockets": [ - [ - "Medium1", - "Medium" - ], - [ - "Small1", - "Small" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["Medium1", "Medium"], + ["Small1", "Small"], + ["", "Internal"], + ["", "Internal"] ], - "tile_size": [ - 1, - 2 - ] + "tile_size": [1, 2] }, "v_base2x1g": { "sockets": [ - [ - "Medium1", - "Medium" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["Medium1", "Medium"], + ["", "Internal"], + ["", "Internal"], + ["", "Internal"] ], - "tile_size": [ - 1, - 2 - ] + "tile_size": [1, 2] }, "v_base2x2_as": { "sockets": [ - [ - "Medium1", - "Medium" - ], - [ - "Medium2", - "Medium" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["Medium1", "Medium"], + ["Medium2", "Medium"], + ["", "Internal"], + ["", "Internal"], + ["", "Internal"] ], - "tile_size": [ - 3, - 3 - ] + "tile_size": [3, 3] }, "v_base2x2a": { "sockets": [ - [ - "Medium1", - "Medium" - ], - [ - "Medium2", - "Medium" - ], - [ - "Large1", - "Large" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["Medium1", "Medium"], + ["Medium2", "Medium"], + ["Large1", "Large"], + ["", "Internal"], + ["", "Internal"], + ["", "Internal"] ], - "tile_size": [ - 2, - 2 - ] + "tile_size": [2, 2] }, "v_base2x2b": { "sockets": [ - [ - "Medium1", - "Medium" - ], - [ - "Medium2", - "Medium" - ], - [ - "Medium3", - "Medium" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["Medium1", "Medium"], + ["Medium2", "Medium"], + ["Medium3", "Medium"], + ["", "Internal"], + ["", "Internal"], + ["", "Internal"] ], - "tile_size": [ - 2, - 2 - ] + "tile_size": [2, 2] }, "v_base2x2c": { "sockets": [ - [ - "Large1", - "Large" - ], - [ - "Medium1", - "Medium" - ], - [ - "Medium2", - "Medium" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["Large1", "Large"], + ["Medium1", "Medium"], + ["Medium2", "Medium"], + ["", "Internal"], + ["", "Internal"], + ["", "Internal"] ], - "tile_size": [ - 2, - 2 - ] + "tile_size": [2, 2] }, "v_base2x2d": { "sockets": [ - [ - "Large1", - "Large" - ], - [ - "Medium1", - "Medium" - ], - [ - "Medium2", - "Medium" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["Large1", "Large"], + ["Medium1", "Medium"], + ["Medium2", "Medium"], + ["", "Internal"], + ["", "Internal"], + ["", "Internal"] ], - "tile_size": [ - 2, - 2 - ] + "tile_size": [2, 2] }, "v_base2x2e": { "sockets": [ - [ - "Medium1", - "Medium" - ], - [ - "Small1", - "Small" - ], - [ - "Small2", - "Small" - ], - [ - "Small3", - "Small" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["Medium1", "Medium"], + ["Small1", "Small"], + ["Small2", "Small"], + ["Small3", "Small"], + ["", "Internal"], + ["", "Internal"], + ["", "Internal"] ], - "tile_size": [ - 2, - 2 - ] + "tile_size": [2, 2] }, "v_base2x2f": { "sockets": [ - [ - "Medium1", - "Medium" - ], - [ - "Medium2", - "Medium" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["Medium1", "Medium"], + ["Medium2", "Medium"], + ["", "Internal"], + ["", "Internal"] ], - "tile_size": [ - 2, - 2 - ] + "tile_size": [2, 2] }, "v_base2x2f_broken": { - "sockets": [ - [ - "Medium1", - "Medium" - ] - ], - "tile_size": [ - 2, - 2 - ] + "sockets": [["Medium1", "Medium"]], + "tile_size": [2, 2] }, "v_base3x2a": { "sockets": [ - [ - "medium1", - "Medium" - ], - [ - "medium2", - "Medium" - ], - [ - "medium3", - "Medium" - ], - [ - "large1", - "Large" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["medium1", "Medium"], + ["medium2", "Medium"], + ["medium3", "Medium"], + ["large1", "Large"], + ["", "Internal"], + ["", "Internal"], + ["", "Internal"], + ["", "Internal"] ], - "tile_size": [ - 3, - 2 - ] + "tile_size": [3, 2] }, "v_base3x2b": { "sockets": [ - [ - "medium1", - "Medium" - ], - [ - "medium2", - "Medium" - ], - [ - "small1", - "Small" - ], - [ - "small2", - "Small" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["medium1", "Medium"], + ["medium2", "Medium"], + ["small1", "Small"], + ["small2", "Small"], + ["", "Internal"], + ["", "Internal"], + ["", "Internal"] ], - "tile_size": [ - 2, - 3 - ] + "tile_size": [2, 3] }, "v_battery_01_l": {}, "v_battery_01_l_ruined": { - "tile_size": [ - 1, - 1 - ] + "tile_size": [1, 1] }, "v_battery_01_m": {}, "v_beacon": { - "sockets": [ - [ - "", - "Internal" - ] - ] + "sockets": [["", "Internal"]] }, "v_beacon_l": { "sockets": [ - [ - "", - "Internal" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["", "Internal"], + ["", "Internal"], + ["", "Internal"] ] }, "v_big_daikon": { "flags": "RandomRotation", - "tile_size": [ - 2, - 2 - ] + "tile_size": [2, 2] }, "v_blight_control": {}, "v_blight_converter": {}, @@ -4337,354 +3831,159 @@ "v_blightpowergenerator_01_m": {}, "v_bot_1l_a": { "sockets": [ - [ - "Large1", - "Large" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["Large1", "Large"], + ["", "Internal"], + ["", "Internal"] ] }, "v_bot_1m_a": { "sockets": [ - [ - "Medium1", - "Medium" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["Medium1", "Medium"], + ["", "Internal"], + ["", "Internal"] ] }, "v_bot_1m_b": { "sockets": [ - [ - "Medium1", - "Medium" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["Medium1", "Medium"], + ["", "Internal"], + ["", "Internal"], + ["", "Internal"] ] }, "v_bot_1m_c": { "sockets": [ - [ - "Medium1", - "Medium" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["Medium1", "Medium"], + ["", "Internal"], + ["", "Internal"], + ["", "Internal"], + ["", "Internal"] ] }, "v_bot_1m1s_a": { "sockets": [ - [ - "Medium1", - "Medium" - ], - [ - "Small1", - "Small" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["Medium1", "Medium"], + ["Small1", "Small"], + ["", "Internal"], + ["", "Internal"], + ["", "Internal"] ] }, "v_bot_1s_a": { "sockets": [ - [ - "Small1", - "Small" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["Small1", "Small"], + ["", "Internal"], + ["", "Internal"] ] }, "v_bot_1s_adw": { "sockets": [ - [ - "Small1", - "Small" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["Small1", "Small"], + ["", "Internal"], + ["", "Internal"], + ["", "Internal"], + ["", "Internal"] ] }, "v_bot_1s_as": { "sockets": [ - [ - "Small1", - "Small" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["Small1", "Small"], + ["", "Internal"], + ["", "Internal"], + ["", "Internal"] ] }, "v_bot_1s_b": { "sockets": [ - [ - "Small1", - "Small" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["Small1", "Small"], + ["", "Internal"], + ["", "Internal"] ] }, "v_bot_2m_as": { "sockets": [ - [ - "Medium1", - "Medium" - ], - [ - "Medium2", - "Medium" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["Medium1", "Medium"], + ["Medium2", "Medium"], + ["", "Internal"], + ["", "Internal"] ] }, "v_bot_2s_a": { "sockets": [ - [ - "Small1", - "Small" - ], - [ - "Small2", - "Small" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["Small1", "Small"], + ["Small2", "Small"], + ["", "Internal"], + ["", "Internal"] ] }, "v_bot_ai_core": {}, "v_bughive": { "flags": "IsStatic | RandomRotation | RandomScale", - "tile_size": [ - 2, - 2 - ] + "tile_size": [2, 2] }, "v_bughive_large": { "flags": "IsStatic | RandomRotation | RandomScale", - "tile_size": [ - 3, - 3 - ] + "tile_size": [3, 3] }, "v_bughole": { "flags": "IsStatic | RandomRotation | RandomScale" }, "v_building_fg": { - "tile_size": [ - 3, - 3 - ] + "tile_size": [3, 3] }, "v_building_pf": { - "tile_size": [ - 3, - 3 - ] + "tile_size": [3, 3] }, "v_building_sim": { "sockets": [ - [ - "", - "Internal" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["", "Internal"], + ["", "Internal"], + ["", "Internal"], + ["", "Internal"] ], - "tile_size": [ - 3, - 3 - ] + "tile_size": [3, 3] }, "v_building_simulator": { "sockets": [ - [ - "", - "Internal" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["", "Internal"], + ["", "Internal"], + ["", "Internal"], + ["", "Internal"] ], - "tile_size": [ - 6, - 6 - ] + "tile_size": [6, 6] }, "v_cable": {}, "v_capacitor_01_s": {}, "v_carrier_bot": {}, "v_charcharosaurus1": { "sockets": [ - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["", "Internal"], + ["", "Internal"] ], - "tile_size": [ - 1, - 1 - ] + "tile_size": [1, 1] }, "v_circuit_board": {}, "v_circuit_board_infected": {}, "v_cpu": {}, "v_crashedship_2x1_desert": { - "tile_size": [ - 1, - 2 - ] + "tile_size": [1, 2] }, "v_crashedship_2x1_moss": { - "tile_size": [ - 1, - 2 - ] + "tile_size": [1, 2] }, "v_crashedship_2x2_desert": { "flags": "RandomRotation", - "tile_size": [ - 2, - 2 - ] + "tile_size": [2, 2] }, "v_crashedship_2x2_moss": { "flags": "RandomRotation", - "tile_size": [ - 2, - 2 - ] + "tile_size": [2, 2] }, "v_crystal": {}, "v_crystal_powder": {}, "v_crystal_rich1": { "flags": "IsStatic | RandomRotation", - "tile_size": [ - 3, - 3 - ] + "tile_size": [3, 3] }, "v_crystalbattery_01_m": {}, "v_crystalmedium1a": { @@ -4696,165 +3995,96 @@ "v_crystalpower_01_s": {}, "v_crystalscatter_node1": { "flags": "IsStatic | RandomRotation | RandomScale | RandomTranslation | NoShadows | AlignToTerrain", - "tile_size": [ - 1, - 1 - ] + "tile_size": [1, 1] }, "v_crystalsmalla": { "flags": "IsStatic | RandomRotation | RandomTranslation | RandomScale | NoShadows" }, "v_damage_plant": { "flags": "IsStatic | RandomRotation | RandomScale | AlignToTerrain", - "tile_size": [ - 1, - 1 - ] + "tile_size": [1, 1] }, "v_dataanalyzer_L": {}, "v_deconstructor_01_s": {}, "v_decorationrock_largeplateau_1a": { "flags": "IsStatic | RandomRotation | RandomScale | AlignToTerrain", - "tile_size": [ - 4, - 4 - ] + "tile_size": [4, 4] }, "v_decorationrock_largeplateau_1b": { "flags": "IsStatic | RandomRotation | RandomScale | AlignToTerrain", - "tile_size": [ - 4, - 4 - ] + "tile_size": [4, 4] }, "v_decorationrock_largeplateau_1c": { "flags": "IsStatic | RandomRotation | RandomScale | AlignToTerrain", - "tile_size": [ - 4, - 4 - ] + "tile_size": [4, 4] }, "v_decorationrock_largeplateau_2a": { "flags": "IsStatic | RandomRotation | RandomScale | AlignToTerrain", - "tile_size": [ - 2, - 2 - ] + "tile_size": [2, 2] }, "v_decorationrock_largeplateau_2b": { "flags": "IsStatic | RandomRotation | RandomScale | AlignToTerrain", - "tile_size": [ - 2, - 2 - ] + "tile_size": [2, 2] }, "v_decorationrock_largeplateau_2c": { "flags": "IsStatic | RandomRotation | RandomScale | AlignToTerrain", - "tile_size": [ - 2, - 2 - ] + "tile_size": [2, 2] }, "v_decorationrock_largeplateau_2d": { "flags": "IsStatic | RandomRotation | RandomScale | AlignToTerrain", - "tile_size": [ - 2, - 2 - ] + "tile_size": [2, 2] }, "v_decorationrock_largeplateau_3a": { "flags": "IsStatic | RandomRotation | RandomScale | AlignToTerrain", - "tile_size": [ - 1, - 1 - ] + "tile_size": [1, 1] }, "v_decorationrock_largeplateau_3b": { "flags": "IsStatic | RandomRotation | RandomScale | AlignToTerrain", - "tile_size": [ - 1, - 1 - ] + "tile_size": [1, 1] }, "v_decorationrock_largeplateau_3c": { "flags": "IsStatic | RandomRotation | RandomScale | AlignToTerrain", - "tile_size": [ - 1, - 1 - ] + "tile_size": [1, 1] }, "v_decorationrock_largeplateau_3d": { "flags": "IsStatic | RandomRotation | RandomScale | AlignToTerrain", - "tile_size": [ - 1, - 1 - ] + "tile_size": [1, 1] }, "v_default_component": {}, "v_default_item": {}, "v_drone_adv_miner": { "flags": "RandomHeight|RandomTranslation", "sockets": [ - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["", "Internal"], + ["", "Internal"] ] }, "v_drone_defense_a": { "flags": "RandomHeight|RandomTranslation", "sockets": [ - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["", "Internal"], + ["", "Internal"] ] }, "v_drone_miner_a": { "flags": "RandomHeight|RandomTranslation", "sockets": [ - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["", "Internal"], + ["", "Internal"] ] }, "v_drone_transfer_a": { "flags": "RandomHeight|RandomTranslation", "sockets": [ - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["", "Internal"], + ["", "Internal"] ] }, "v_drone_transfer_b": { "flags": "RandomHeight|RandomTranslation", "sockets": [ - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["", "Internal"], + ["", "Internal"] ] }, "v_dronehub_01_m": {}, @@ -4865,14 +4095,8 @@ "v_empty": {}, "v_empty_alien": { "sockets": [ - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["", "Internal"], + ["", "Internal"] ] }, "v_empty_inventory": {}, @@ -4881,200 +4105,90 @@ "v_engine": {}, "v_explorable_blightanomaly_01": { "flags": "RandomRotation|RandomScale", - "tile_size": [ - 2, - 2 - ] + "tile_size": [2, 2] }, "v_explorable_blightanomaly_02": { "flags": "RandomRotation|RandomScale", - "tile_size": [ - 2, - 2 - ] + "tile_size": [2, 2] }, "v_explorable_blightanomaly_03": { "flags": "RandomRotation|RandomScale", - "tile_size": [ - 2, - 2 - ] + "tile_size": [2, 2] }, "v_explorable_blightgiantoddball": { "flags": "RandomRotation|RandomScale", - "tile_size": [ - 4, - 4 - ] + "tile_size": [4, 4] }, "v_explorable_bot": { "sockets": [ - [ - "", - "Small" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["", "Small"], + ["", "Internal"], + ["", "Internal"] ] }, "v_explorable_bot2": { "sockets": [ - [ - "", - "Small" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["", "Small"], + ["", "Internal"], + ["", "Internal"] ] }, "v_explorable_brokenship_1": { - "tile_size": [ - 1, - 1 - ] + "tile_size": [1, 1] }, "v_explorable_building_2": { "sockets": [ - [ - "", - "Internal" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["", "Internal"], + ["", "Internal"], + ["", "Internal"], + ["", "Internal"] ], - "tile_size": [ - 3, - 3 - ] + "tile_size": [3, 3] }, "v_explorable_building_3": { "sockets": [ - [ - "", - "Internal" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["", "Internal"], + ["", "Internal"], + ["", "Internal"], + ["", "Internal"] ], - "tile_size": [ - 3, - 3 - ] + "tile_size": [3, 3] }, "v_explorable_building_4": { "sockets": [ - [ - "", - "Internal" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["", "Internal"], + ["", "Internal"], + ["", "Internal"], + ["", "Internal"] ], - "tile_size": [ - 3, - 3 - ] + "tile_size": [3, 3] }, "v_explorable_building_6": { "sockets": [ - [ - "", - "Internal" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["", "Internal"], + ["", "Internal"], + ["", "Internal"], + ["", "Internal"] ], - "tile_size": [ - 3, - 3 - ] + "tile_size": [3, 3] }, "v_explorable_glitchbuilding": { - "tile_size": [ - 1, - 1 - ] + "tile_size": [1, 1] }, "v_explorable_monolith_01": { "flags": "RandomRotation|RandomScale", - "tile_size": [ - 2, - 2 - ] + "tile_size": [2, 2] }, "v_explorable_spaceelevator": { - "tile_size": [ - 8, - 8 - ] + "tile_size": [8, 8] }, "v_explorable_timeegg_01": { "flags": "RandomRotation|RandomScale", - "tile_size": [ - 2, - 2 - ] + "tile_size": [2, 2] }, "v_fabricator_01_s": {}, "v_flyer_bot": { - "sockets": [ - [ - "", - "Internal" - ] - ] + "sockets": [["", "Internal"]] }, "v_flyer_m": {}, "v_foliagegrass1a": { @@ -5091,10 +4205,7 @@ }, "v_foundation": { "flags": "CanBePlacedOnSlopes|IsStatic", - "tile_size": [ - 1, - 1 - ] + "tile_size": [1, 1] }, "v_fungus2a": { "flags": "IsStatic | RandomTranslation | RandomRotation | RandomScale" @@ -5120,35 +4231,17 @@ "v_fused_electrodes": {}, "v_gastarias1": { "sockets": [ - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["", "Internal"], + ["", "Internal"] ], - "tile_size": [ - 1, - 1 - ] + "tile_size": [1, 1] }, "v_gastarid1": { "sockets": [ - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["", "Internal"], + ["", "Internal"] ], - "tile_size": [ - 1, - 1 - ] + "tile_size": [1, 1] }, "v_gate": { "flags": "CanBePlacedOnSlopes|CanBePlacedOnCliffs" @@ -5157,196 +4250,81 @@ "v_generic_i": {}, "v_geyser_tree": { "flags": "IsStatic | RandomRotation", - "tile_size": [ - 4, - 4 - ] + "tile_size": [4, 4] }, "v_hacking_tool_s": { "flags": "ComponentFaceTarget" }, "v_high_density_frame": {}, "v_human_ark": { - "sockets": [ - [ - "", - "Internal" - ] - ] + "sockets": [["", "Internal"]] }, "v_human_ark_broken": {}, "v_human_barracks": { - "sockets": [ - [ - "", - "Internal" - ] - ], - "tile_size": [ - 3, - 3 - ] + "sockets": [["", "Internal"]], + "tile_size": [3, 3] }, "v_human_buggy": { - "sockets": [ - [ - "", - "Internal" - ] - ] + "sockets": [["", "Internal"]] }, "v_human_buggy_broken": {}, "v_human_buggy_upgraded": { - "sockets": [ - [ - "", - "Internal" - ] - ] + "sockets": [["", "Internal"]] }, "v_human_building_broken_a": { - "tile_size": [ - 2, - 2 - ] + "tile_size": [2, 2] }, "v_human_bunker": { - "sockets": [ - [ - "", - "Internal" - ] - ], - "tile_size": [ - 2, - 2 - ] + "sockets": [["", "Internal"]], + "tile_size": [2, 2] }, "v_human_commandcenter": { - "sockets": [ - [ - "", - "Internal" - ] - ], - "tile_size": [ - 4, - 3 - ] + "sockets": [["", "Internal"]], + "tile_size": [4, 3] }, "v_human_communication": { - "sockets": [ - [ - "", - "Internal" - ] - ], - "tile_size": [ - 3, - 3 - ] + "sockets": [["", "Internal"]], + "tile_size": [3, 3] }, "v_human_data": {}, "v_human_explorable_5x5_a": { - "sockets": [ - [ - "", - "Internal" - ] - ], - "tile_size": [ - 5, - 5 - ] + "sockets": [["", "Internal"]], + "tile_size": [5, 5] }, "v_human_factory": { - "sockets": [ - [ - "", - "Internal" - ] - ], - "tile_size": [ - 3, - 4 - ] + "sockets": [["", "Internal"]], + "tile_size": [3, 4] }, "v_human_flyer": { - "sockets": [ - [ - "", - "Internal" - ] - ] + "sockets": [["", "Internal"]] }, "v_human_foundation_basic": { "flags": "CanBePlacedOnSlopes|IsStatic", - "tile_size": [ - 1, - 1 - ] + "tile_size": [1, 1] }, "v_human_lander": {}, "v_human_miner": {}, "v_human_powerplant": { - "sockets": [ - [ - "", - "Internal" - ] - ], - "tile_size": [ - 3, - 3 - ] + "sockets": [["", "Internal"]], + "tile_size": [3, 3] }, "v_human_refinery": { - "sockets": [ - [ - "", - "Internal" - ] - ], - "tile_size": [ - 3, - 3 - ] + "sockets": [["", "Internal"]], + "tile_size": [3, 3] }, "v_human_research_item": {}, "v_human_sciencelab": { - "sockets": [ - [ - "", - "Internal" - ] - ], - "tile_size": [ - 3, - 3 - ] + "sockets": [["", "Internal"]], + "tile_size": [3, 3] }, "v_human_spaceport": { - "sockets": [ - [ - "", - "Internal" - ] - ], - "tile_size": [ - 4, - 3 - ] + "sockets": [["", "Internal"]], + "tile_size": [4, 3] }, "v_human_tank": { "sockets": [ - [ - "Medium1", - "Medium" - ], - [ - "", - "Internal" - ] + ["Medium1", "Medium"], + ["", "Internal"] ] }, "v_human_tank_turret": { @@ -5354,16 +4332,8 @@ }, "v_human_transport": {}, "v_human_warehouse": { - "sockets": [ - [ - "", - "Internal" - ] - ], - "tile_size": [ - 4, - 2 - ] + "sockets": [["", "Internal"]], + "tile_size": [4, 2] }, "v_icchip": {}, "v_landingpad_01_l": {}, @@ -5377,10 +4347,7 @@ }, "v_laterite_node_large1": { "flags": "IsStatic | RandomRotation | RandomScale", - "tile_size": [ - 3, - 3 - ] + "tile_size": [3, 3] }, "v_laterite_small1": { "flags": "IsStatic | RandomRotation | RandomScale | RandomTranslation | AlignToTerrain" @@ -5404,17 +4371,11 @@ "v_metalplate": {}, "v_metalrich1": { "flags": "IsStatic | RandomRotation", - "tile_size": [ - 2, - 2 - ] + "tile_size": [2, 2] }, "v_metalrich2": { "flags": "IsStatic | RandomRotation", - "tile_size": [ - 2, - 2 - ] + "tile_size": [2, 2] }, "v_metalsmall1a": { "flags": "IsStatic | RandomRotation | RandomTranslation" @@ -5431,10 +4392,7 @@ "flags": "ComponentFaceTarget" }, "v_missile_launcher_m_ruined": { - "tile_size": [ - 1, - 1 - ] + "tile_size": [1, 1] }, "v_modulebase_l": {}, "v_modulebase_m": {}, @@ -5455,17 +4413,11 @@ "v_packed_satellite": {}, "v_pearls_03": { "flags": "IsStatic|RandomTranslation | RandomScale| RandomRotation", - "tile_size": [ - 2, - 2 - ] + "tile_size": [2, 2] }, "v_phase_plant": { "flags": "IsStatic | RandomRotation | RandomScale | AlignToTerrain", - "tile_size": [ - 1, - 1 - ] + "tile_size": [1, 1] }, "v_photon_canon_m": {}, "v_plasma_canon_m": {}, @@ -5478,16 +4430,8 @@ "v_power_transmitter_m": {}, "v_Present_01_S": {}, "v_Present_1x1": { - "sockets": [ - [ - "", - "Internal" - ] - ], - "tile_size": [ - 1, - 1 - ] + "sockets": [["", "Internal"]], + "tile_size": [1, 1] }, "v_radar_m": {}, "v_radar_s": {}, @@ -5500,120 +4444,48 @@ "v_robot_data": {}, "v_robot_s": { "sockets": [ - [ - "Small1", - "Small" - ], - [ - "Small2", - "Small" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["Small1", "Small"], + ["Small2", "Small"], + ["", "Internal"], + ["", "Internal"] ] }, "v_robot2": { "sockets": [ - [ - "Medium1", - "Medium" - ], - [ - "Small1", - "Small" - ], - [ - "Small2", - "Small" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["Medium1", "Medium"], + ["Small1", "Small"], + ["Small2", "Small"], + ["", "Internal"], + ["", "Internal"] ] }, "v_robot3": { "sockets": [ - [ - "Medium1", - "Medium" - ], - [ - "Medium2", - "Medium" - ], - [ - "Small1", - "Small" - ], - [ - "Small2", - "Small" - ], - [ - "Small3", - "Small" - ] + ["Medium1", "Medium"], + ["Medium2", "Medium"], + ["Small1", "Small"], + ["Small2", "Small"], + ["Small3", "Small"] ] }, "v_robot4": { "sockets": [ - [ - "Large1", - "Large" - ], - [ - "Small1", - "Small" - ], - [ - "Small2", - "Small" - ], - [ - "Small3", - "Small" - ], - [ - "Small4", - "Small" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["Large1", "Large"], + ["Small1", "Small"], + ["Small2", "Small"], + ["Small3", "Small"], + ["Small4", "Small"], + ["", "Internal"], + ["", "Internal"] ] }, "v_roboticsfactory_01_m": {}, "v_SantaHat_01_M": {}, "v_satellite": { "sockets": [ - [ - "", - "Small" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["", "Small"], + ["", "Internal"], + ["", "Internal"] ] }, "v_satellite_inventory": {}, @@ -5622,36 +4494,18 @@ }, "v_scaramar1": { "sockets": [ - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["", "Internal"], + ["", "Internal"] ], - "tile_size": [ - 1, - 1 - ] + "tile_size": [1, 1] }, "v_scaramar2": { "flags": "RandomHeight", "sockets": [ - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["", "Internal"], + ["", "Internal"] ], - "tile_size": [ - 1, - 1 - ] + "tile_size": [1, 1] }, "v_scienceanalyzer_l": {}, "v_shortgrass_01": { @@ -5666,16 +4520,8 @@ }, "v_silica_node": { "flags": "IsStatic | RandomRotation | RandomScale | AlignToTerrain", - "sockets": [ - [ - "large1", - "Large" - ] - ], - "tile_size": [ - 2, - 2 - ] + "sockets": [["large1", "Large"]], + "tile_size": [2, 2] }, "v_silicascatter_node1": { "flags": "IsStatic | RandomRotation | RandomScale | RandomTranslation | NoShadows | AlignToTerrain" @@ -5683,20 +4529,14 @@ "v_silicon": {}, "v_simulation_data": {}, "v_simulator_ruined": { - "tile_size": [ - 3, - 3 - ] + "tile_size": [3, 3] }, "v_small_reactor": {}, "v_smartstorage_m": {}, "v_solarpanel_01_m": {}, "v_solarpanel_01_s": {}, "v_spacedrop_1": { - "tile_size": [ - 1, - 1 - ] + "tile_size": [1, 1] }, "v_starterturret_adv_s": { "flags": "ComponentFaceTarget" @@ -5736,18 +4576,9 @@ "v_transformer": {}, "v_transport_bot": { "sockets": [ - [ - "", - "Internal" - ], - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["", "Internal"], + ["", "Internal"], + ["", "Internal"] ] }, "v_transporter_01_m": {}, @@ -5828,19 +4659,10 @@ }, "v_trilobite1": { "sockets": [ - [ - "", - "Internal" - ], - [ - "", - "Internal" - ] + ["", "Internal"], + ["", "Internal"] ], - "tile_size": [ - 1, - 1 - ] + "tile_size": [1, 1] }, "v_turret_m": {}, "v_uplink_m": {}, @@ -5918,22 +4740,9 @@ "desc": "Adds a number or coordinate to another number or coordinate", "category": "Math", "args": [ - [ - "in", - "To", - null, - "coord_num" - ], - [ - "in", - "Num", - null, - "coord_num" - ], - [ - "out", - "Result" - ] + ["in", "To", null, "coord_num"], + ["in", "Num", null, "coord_num"], + ["out", "Result"] ] }, "build": { @@ -5975,12 +4784,7 @@ "Can Produce", "Where to continue if the item can be produced" ], - [ - "in", - "Item", - "Production Item", - "item" - ], + ["in", "Item", "Production Item", "item"], [ "in", "Component", @@ -6000,31 +4804,11 @@ "desc": "Divert program depending on location of a unit", "category": "Unit", "args": [ - [ - "in", - "Unit", - "The unit to check for (if not self)", - "entity", - true - ], - [ - "exec", - "Valley", - "Where to continue if the unit is in a valley" - ], - [ - "exec", - "Plateau", - "Where to continue if the unit is on a plateau" - ] + ["in", "Unit", "The unit to check for (if not self)", "entity", true], + ["exec", "Valley", "Where to continue if the unit is in a valley"], + ["exec", "Plateau", "Where to continue if the unit is on a plateau"] ], - "exec_arg": [ - 4, - "No Unit", - "No visible unit passed", - null, - true - ] + "exec_arg": [4, "No Unit", "No visible unit passed", null, true] }, "check_battery": { "name": "Check Battery", @@ -6036,13 +4820,7 @@ "Full", "Where to continue if battery power is fully recharged" ], - [ - "in", - "Unit", - "The unit to check for (if not self)", - "entity", - true - ] + ["in", "Unit", "The unit to check for (if not self)", "entity", true] ] }, "check_blightness": { @@ -6050,18 +4828,8 @@ "desc": "Divert program depending on location of a unit", "category": "Unit", "args": [ - [ - "in", - "Unit", - "The unit to check for (if not self)", - "entity", - true - ], - [ - "exec", - "Blight", - "Where to continue if the unit is in the blight" - ] + ["in", "Unit", "The unit to check for (if not self)", "entity", true], + ["exec", "Blight", "Where to continue if the unit is in the blight"] ] }, "check_grid_effeciency": { @@ -6069,18 +4837,8 @@ "desc": "Checks the Efficiency of the power grid the unit is on", "category": "Unit", "args": [ - [ - "exec", - "Full", - "Where to continue if at full efficiency" - ], - [ - "in", - "Unit", - "The unit to check for (if not self)", - "entity", - true - ] + ["exec", "Full", "Where to continue if at full efficiency"], + ["in", "Unit", "The unit to check for (if not self)", "entity", true] ] }, "check_health": { @@ -6088,18 +4846,8 @@ "desc": "Check a units health", "category": "Unit", "args": [ - [ - "exec", - "Full", - "Where to continue if at full health" - ], - [ - "in", - "Unit", - "The unit to check for (if not self)", - "entity", - true - ] + ["exec", "Full", "Where to continue if at full health"], + ["in", "Unit", "The unit to check for (if not self)", "entity", true] ] }, "check_number": { @@ -6117,18 +4865,8 @@ "If Smaller", "Where to continue if Value is smaller than Compare" ], - [ - "in", - "Value", - "The value to check with", - "num" - ], - [ - "in", - "Compare", - "The number to check against", - "num" - ] + ["in", "Value", "The value to check with", "num"], + ["in", "Compare", "The number to check against", "num"] ], "exec_arg": [ 1, @@ -6141,52 +4879,24 @@ "desc": "Checks if free space is available for an item and amount", "category": "Math", "args": [ - [ - "exec", - "Can't Fit", - "Execution if it can't fit the item" - ], - [ - "in", - "Item", - "Item and amount to check can fit", - "item_num" - ] + ["exec", "Can't Fit", "Execution if it can't fit the item"], + ["in", "Item", "Item and amount to check can fit", "item_num"] ] }, "clear_research": { "name": "Clear Research", "desc": "Clears a research from queue, or entire queue if no tech passed", "category": "Flow", - "args": [ - [ - "in", - "Tech", - "Tech to remove from research queue" - ] - ] + "args": [["in", "Tech", "Tech to remove from research queue"]] }, "combine_coordinate": { "name": "Combine Coordinate", "desc": "Returns a coordinate made from x and y values", "category": "Math", "args": [ - [ - "in", - "x", - null, - "any" - ], - [ - "in", - "y", - null, - "any" - ], - [ - "out", - "Result" - ] + ["in", "x", null, "any"], + ["in", "y", null, "any"], + ["out", "Result"] ] }, "combine_register": { @@ -6194,34 +4904,11 @@ "desc": "Combine to make a register from separate parameters", "category": "Math", "args": [ - [ - "in", - "Num" - ], - [ - "in", - "Entity" - ], - [ - "out", - "Register", - null, - "entity" - ], - [ - "in", - "x", - null, - null, - true - ], - [ - "in", - "y", - null, - null, - true - ] + ["in", "Num"], + ["in", "Entity"], + ["out", "Register", null, "entity"], + ["in", "x", null, null, true], + ["in", "y", null, null, true] ] }, "compare_entity": { @@ -6229,19 +4916,9 @@ "desc": "Compares Entities", "category": "Flow", "args": [ - [ - "exec", - "If Different", - "Where to continue if the entities differ" - ], - [ - "in", - "Entity 1" - ], - [ - "in", - "Entity 2" - ] + ["exec", "If Different", "Where to continue if the entities differ"], + ["in", "Entity 1"], + ["in", "Entity 2"] ], "exec_arg": [ 1, @@ -6254,25 +4931,11 @@ "desc": "Compares Item or Unit type", "category": "Flow", "args": [ - [ - "exec", - "If Different", - "Where to continue if the types differ" - ], - [ - "in", - "Value 1" - ], - [ - "in", - "Value 2" - ] + ["exec", "If Different", "Where to continue if the types differ"], + ["in", "Value 1"], + ["in", "Value 2"] ], - "exec_arg": [ - 1, - "If Equal", - "Where to continue if the types are the same" - ] + "exec_arg": [1, "If Equal", "Where to continue if the types are the same"] }, "connect": { "name": "Connect", @@ -6284,24 +4947,13 @@ "desc": "Counts the number of the passed item in its inventory", "category": "Unit", "args": [ - [ - "in", - "Item", - "Item to count", - "item" - ], + ["in", "Item", "Item to count", "item"], [ "out", "Result", "Number of this item in inventory or empty if none exist" ], - [ - "in", - "Unit", - "The unit to check for (if not self)", - "entity", - true - ] + ["in", "Unit", "The unit to check for (if not self)", "entity", true] ] }, "count_slots": { @@ -6309,18 +4961,8 @@ "desc": "Returns the number of slots in this unit of the given type", "category": "Unit", "args": [ - [ - "out", - "Result", - "Number of slots of this type" - ], - [ - "in", - "Unit", - "The unit to check for (if not self)", - "entity", - true - ] + ["out", "Result", "Number of slots of this type"], + ["in", "Unit", "The unit to check for (if not self)", "entity", true] ] }, "disable_transport_route": { @@ -6338,22 +4980,9 @@ "desc": "Divides a number or coordinate from another number or coordinate", "category": "Math", "args": [ - [ - "in", - "From", - null, - "coord_num" - ], - [ - "in", - "Num", - null, - "coord_num" - ], - [ - "out", - "Result" - ] + ["in", "From", null, "coord_num"], + ["in", "Num", null, "coord_num"], + ["out", "Result"] ] }, "dodrop": { @@ -6367,13 +4996,7 @@ "Unit or destination to bring items to", "entity" ], - [ - "in", - "Item / Amount", - "Item and amount to drop off", - "item_num", - true - ] + ["in", "Item / Amount", "Item and amount to drop off", "item_num", true] ] }, "domove": { @@ -6393,14 +5016,7 @@ "name": "Move Unit (Async)", "desc": "Move to another unit while continuing the program", "category": "Move", - "args": [ - [ - "in", - "Target", - "Unit to move to", - "entity" - ] - ] + "args": [["in", "Target", "Unit to move to", "entity"]] }, "domove_range": { "name": "*Move Unit (Range)*", @@ -6420,19 +5036,8 @@ "desc": "Picks up a specific number of items from an entity\n\nWill try to pick up the specified amount, if no amount\nis specified it will try to pick up everything.", "category": "Unit", "args": [ - [ - "in", - "Source", - "Unit to take items from", - "entity" - ], - [ - "in", - "Item / Amount", - "Item and amount to pick up", - "item_num", - true - ] + ["in", "Source", "Unit to take items from", "entity"], + ["in", "Item / Amount", "Item and amount to pick up", "item_num", true] ] }, "enable_transport_route": { @@ -6450,12 +5055,7 @@ "No Component", "If you don't current hold the requested component" ], - [ - "in", - "Component", - "Component to equip", - "comp" - ], + ["in", "Component", "Component to equip", "comp"], [ "in", "Slot index", @@ -6476,17 +5076,8 @@ "desc": "Counts the number of the passed item in your logistics network", "category": "Global", "args": [ - [ - "in", - "Item", - "Item to count", - "item" - ], - [ - "out", - "Result", - "Number of this item in your faction" - ], + ["in", "Item", "Item to count", "item"], + ["out", "Result", "Number of this item in your faction"], [ "exec", "None", @@ -6499,42 +5090,12 @@ "desc": "Performs code for all entities in visibility range of the unit", "category": "Flow", "args": [ - [ - "in", - "Range", - "Range (up to units visibility range)", - "num" - ], - [ - "in", - "Filter", - "Filter to check", - "radar" - ], - [ - "in", - "Filter", - "Second Filter", - "radar", - true - ], - [ - "in", - "Filter", - "Third Filter", - "radar", - true - ], - [ - "out", - "Entity", - "Current Entity" - ], - [ - "exec", - "Done", - "Finished looping through all entities in range" - ] + ["in", "Range", "Range (up to units visibility range)", "num"], + ["in", "Filter", "Filter to check", "radar"], + ["in", "Filter", "Second Filter", "radar", true], + ["in", "Filter", "Third Filter", "radar", true], + ["out", "Entity", "Current Entity"], + ["exec", "Done", "Finished looping through all entities in range"] ] }, "for_inventory_item": { @@ -6542,16 +5103,8 @@ "desc": "Loops through Inventory", "category": "Flow", "args": [ - [ - "out", - "Inventory", - "Item Inventory" - ], - [ - "exec", - "Done", - "Finished loop" - ], + ["out", "Inventory", "Item Inventory"], + ["exec", "Done", "Finished loop"], [ "out", "Reserved Stack", @@ -6559,13 +5112,7 @@ "num", true ], - [ - "out", - "Unreserved Stack", - "Items available", - "num", - true - ], + ["out", "Unreserved Stack", "Items available", "num", true], [ "out", "Reserved Space", @@ -6573,13 +5120,7 @@ "num", true ], - [ - "out", - "Unreserved Space", - "Remaining space", - "num", - true - ] + ["out", "Unreserved Space", "Remaining space", "num", true] ] }, "for_recipe_ingredients": { @@ -6587,22 +5128,9 @@ "desc": "Loops through Ingredients", "category": "Flow", "args": [ - [ - "in", - "Recipe", - null, - "item" - ], - [ - "out", - "Ingredient", - "Recipe Ingredient" - ], - [ - "exec", - "Done", - "Finished loop" - ] + ["in", "Recipe", null, "item"], + ["out", "Ingredient", "Recipe Ingredient"], + ["exec", "Done", "Finished loop"] ] }, "for_research": { @@ -6610,16 +5138,8 @@ "desc": "Performs code for all researchable tech", "category": "Flow", "args": [ - [ - "out", - "Tech", - "Researchable Tech" - ], - [ - "exec", - "Done", - "Finished looping through all researchable tech" - ] + ["out", "Tech", "Researchable Tech"], + ["exec", "Done", "Finished looping through all researchable tech"] ] }, "for_signal": { @@ -6627,21 +5147,9 @@ "desc": "*DEPRECATED* Use Loop Signal (Match) instead", "category": "Flow", "args": [ - [ - "in", - "Signal", - "Signal" - ], - [ - "out", - "Entity", - "Entity with signal" - ], - [ - "exec", - "Done", - "Finished looping through all entities with signal" - ] + ["in", "Signal", "Signal"], + ["out", "Entity", "Entity with signal"], + ["exec", "Done", "Finished looping through all entities with signal"] ] }, "for_signal_match": { @@ -6649,101 +5157,47 @@ "desc": "Loops through all units with a signal of similar type", "category": "Flow", "args": [ - [ - "in", - "Signal", - "Signal" - ], - [ - "out", - "Entity", - "Entity with signal" - ], - [ - "out", - "Signal", - "Found signal", - "entity", - true - ], - [ - "exec", - "Done", - "Finished looping through all entities with signal" - ] + ["in", "Signal", "Signal"], + ["out", "Entity", "Entity with signal"], + ["out", "Signal", "Found signal", "entity", true], + ["exec", "Done", "Finished looping through all entities with signal"] ] }, "gather_information": { "name": "Gather Information", "desc": "Collect information for running the auto base controller", "category": "AutoBase", - "args": [ - [ - "in", - "Range", - "Range of operation", - "num" - ] - ] + "args": [["in", "Range", "Range of operation", "num"]] }, "get_battery": { "name": "Get Battery", "desc": "Gets the value of the Battery level as a percent", "category": "Math", - "args": [ - [ - "out", - "Result" - ] - ] + "args": [["out", "Result"]] }, "get_closest_entity": { "name": "Get Closest Entity", "desc": "Gets the closest visible entity matching a filter", "category": "Unit", + "args": [ + ["in", "Filter", "Filter to check", "radar"], + ["in", "Filter", "Second Filter", "radar", true], + ["in", "Filter", "Third Filter", "radar", true], + ["out", "Output", "Entity"] + ] + }, + "get_comp_reg": { + "name": "Get from Component", + "desc": "Reads a value from a component register", + "category": "Math", "args": [ [ "in", - "Filter", - "Filter to check", - "radar" - ], - [ - "in", - "Filter", - "Second Filter", - "radar", - true - ], - [ - "in", - "Filter", - "Third Filter", - "radar", - true - ], - [ - "out", - "Output", - "Entity" - ] - ] - }, - "get_comp_reg": { - "name": "Get from Component", - "desc": "Reads a value from a component register", - "category": "Math", - "args": [ - [ - "in", - "Component/Index", - "Component and register number to set", - "comp_num" - ], - [ - "out", - "Value" + "Component/Index", + "Component and register number to set", + "comp_num" ], + ["out", "Value"], [ "in", "Group/Index", @@ -6758,24 +5212,13 @@ "desc": "Returns distance to a unit", "category": "Global", "args": [ - [ - "in", - "Target", - "Target unit", - "entity" - ], + ["in", "Target", "Target unit", "entity"], [ "out", "Distance", "Unit and its distance in the numerical part of the value" ], - [ - "in", - "Unit", - "The unit to measure from (if not self)", - "entity", - true - ] + ["in", "Unit", "The unit to measure from (if not self)", "entity", true] ] }, "get_entity_at": { @@ -6783,71 +5226,31 @@ "desc": "Gets the best matching entity at a coordinate", "category": "Math", "args": [ - [ - "in", - "Coordinate", - "Coordinate to get Entity from", - "coord_num" - ], - [ - "out", - "Result" - ] + ["in", "Coordinate", "Coordinate to get Entity from", "coord_num"], + ["out", "Result"] ] }, "get_first_locked_0": { "name": "Get First Locked Id", "desc": "Gets the first item where the locked slot exists but there is no item in it", "category": "Unit", - "args": [ - [ - "out", - "Item", - "The first locked item id with no item" - ] - ] + "args": [["out", "Item", "The first locked item id with no item"]] }, "get_grid_effeciency": { "name": "Get Grid Efficiency", "desc": "Gets the value of the Grid Efficiency as a percent", "category": "Math", - "args": [ - [ - "out", - "Result" - ] - ] + "args": [["out", "Result"]] }, "get_health": { "name": "Get Health", "desc": "Gets a units health as a percentage, current and max", "category": "Math", "args": [ - [ - "in", - "Entity", - "Entity to check", - "entity" - ], - [ - "out", - "Percent", - "Percentage of health remaining" - ], - [ - "out", - "Current", - "Value of health remaining", - null, - true - ], - [ - "out", - "Max", - "Value of maximum health", - null, - true - ] + ["in", "Entity", "Entity to check", "entity"], + ["out", "Percent", "Percentage of health remaining"], + ["out", "Current", "Value of health remaining", null, true], + ["out", "Max", "Value of maximum health", null, true] ] }, "get_ingredients": { @@ -6855,27 +5258,10 @@ "desc": "Returns the ingredients required to produce an item", "category": "Global", "args": [ - [ - "in", - "Product", - null, - "item" - ], - [ - "out", - "Out 1", - "First Ingredient" - ], - [ - "out", - "Out 2", - "Second Ingredient" - ], - [ - "out", - "Out 3", - "Third Ingredient" - ] + ["in", "Product", null, "item"], + ["out", "Out 1", "First Ingredient"], + ["out", "Out 2", "Second Ingredient"], + ["out", "Out 3", "Third Ingredient"] ] }, "get_inventory_item": { @@ -6883,15 +5269,8 @@ "desc": "Reads the first item in your inventory", "category": "Unit", "args": [ - [ - "out", - "Item" - ], - [ - "exec", - "No Items", - "No items in inventory" - ] + ["out", "Item"], + ["exec", "No Items", "No items in inventory"] ] }, "get_inventory_item_index": { @@ -6899,21 +5278,9 @@ "desc": "Reads the item contained in the specified slot index", "category": "Unit", "args": [ - [ - "in", - "Index", - "Slot index", - "num" - ], - [ - "out", - "Item" - ], - [ - "exec", - "No Item", - "Item not found" - ] + ["in", "Index", "Slot index", "num"], + ["out", "Item"], + ["exec", "No Item", "Item not found"] ] }, "get_location": { @@ -6921,17 +5288,8 @@ "desc": "Gets location of a a seen entity", "category": "Global", "args": [ - [ - "in", - "Entity", - "Entity to get coordinates of", - "entity" - ], - [ - "out", - "Coord", - "Coordinate of entity" - ] + ["in", "Entity", "Entity to get coordinates of", "entity"], + ["out", "Coord", "Coordinate of entity"] ] }, "get_max_stack": { @@ -6939,52 +5297,24 @@ "desc": "Returns the amount an item can stack to", "category": "Flow", "args": [ - [ - "in", - "Item", - "Item to count", - "item_num" - ], - [ - "out", - "Max Stack", - "Max Stack" - ] + ["in", "Item", "Item to count", "item_num"], + ["out", "Max Stack", "Max Stack"] ] }, "get_research": { "name": "Get Research", "desc": "Returns the first active research tech", "category": "Flow", - "args": [ - [ - "out", - "Tech", - "First active research" - ] - ] + "args": [["out", "Tech", "First active research"]] }, "get_resource_item": { "name": "Resource Type", "desc": "Gets the resource type from an resource node", "category": "Global", "args": [ - [ - "in", - "Resource Node", - "Resource Node", - "entity" - ], - [ - "out", - "Resource", - "Resource Type" - ], - [ - "exec", - "Not Resource", - "Continue here if it wasn't a resource node" - ] + ["in", "Resource Node", "Resource Node", "entity"], + ["out", "Resource", "Resource Type"], + ["exec", "Not Resource", "Continue here if it wasn't a resource node"] ] }, "get_resource_num": { @@ -6992,54 +5322,29 @@ "desc": "Gets the amount of resource", "category": "Math", "args": [ - [ - "in", - "Resource", - "Resource Node to check", - "entity" - ], - [ - "out", - "Result" - ] + ["in", "Resource", "Resource Node to check", "entity"], + ["out", "Result"] ] }, "get_self": { "name": "Get Self", "desc": "Gets the value of the Unit executing the behavior", "category": "Math", - "args": [ - [ - "out", - "Result" - ] - ] + "args": [["out", "Result"]] }, "get_stability": { "name": "Get Stability", "desc": "Gets the current world stability", "category": "Global", - "args": [ - [ - "out", - "Number", - "Stability" - ] - ] + "args": [["out", "Number", "Stability"]] }, "get_type": { "name": "Get Type", "desc": "Gets the type from an item or entity", "category": "Global", "args": [ - [ - "in", - "Item/Entity" - ], - [ - "out", - "Type" - ] + ["in", "Item/Entity"], + ["out", "Type"] ] }, "getfreespace": { @@ -7047,94 +5352,37 @@ "desc": "Returns how many of the input item can fit in the inventory", "category": "Math", "args": [ - [ - "in", - "Item", - "Item to check can fit", - "item" - ], - [ - "out", - "Result", - "Number of a specific item that can fit on a unit" - ], - [ - "in", - "Unit", - "The unit to check (if not self)", - "entity", - true - ] + ["in", "Item", "Item to check can fit", "item"], + ["out", "Result", "Number of a specific item that can fit on a unit"], + ["in", "Unit", "The unit to check (if not self)", "entity", true] ] }, "gethome": { "name": "Get Home", "desc": "Gets the factions home unit", "category": "Global", - "args": [ - [ - "out", - "Result", - "Factions home unit" - ] - ] + "args": [["out", "Result", "Factions home unit"]] }, "gettrust": { "name": "Get Trust", "desc": "Gets the trust level of the unit towards you", "category": "Global", "args": [ - [ - "exec", - "Ally", - "Target unit considers you an ally" - ], - [ - "exec", - "Neutral", - "Target unit considers you neutral" - ], - [ - "exec", - "Enemy", - "Target unit considers you an enemy" - ], - [ - "in", - "Unit", - "Target Unit", - "entity" - ] + ["exec", "Ally", "Target unit considers you an ally"], + ["exec", "Neutral", "Target unit considers you neutral"], + ["exec", "Enemy", "Target unit considers you an enemy"], + ["in", "Unit", "Target Unit", "entity"] ], - "exec_arg": [ - 1, - "No Unit", - "No Unit Passed" - ] + "exec_arg": [1, "No Unit", "No Unit Passed"] }, "have_item": { "name": "Have Item", "desc": "Checks if you have at least a specified amount of an item", "category": "Flow", "args": [ - [ - "in", - "Item", - "Item to count", - "item_num" - ], - [ - "exec", - "Have Item", - "have the specified item" - ], - [ - "in", - "Unit", - "The unit to check for (if not self)", - "entity", - true - ] + ["in", "Item", "Item to count", "item_num"], + ["exec", "Have Item", "have the specified item"], + ["in", "Unit", "The unit to check for (if not self)", "entity", true] ] }, "is_a": { @@ -7142,19 +5390,9 @@ "desc": "Compares if an item of entity is of a specific type", "category": "Flow", "args": [ - [ - "exec", - "If Different", - "Where to continue if the entities differ" - ], - [ - "in", - "Item" - ], - [ - "in", - "Type" - ] + ["exec", "If Different", "Where to continue if the entities differ"], + ["in", "Item"], + ["in", "Type"] ], "exec_arg": [ 1, @@ -7167,16 +5405,8 @@ "desc": "Divert program depending time of day", "category": "Global", "args": [ - [ - "exec", - "Day", - "Where to continue if it is nighttime" - ], - [ - "exec", - "Night", - "Where to continue if it is daytime" - ] + ["exec", "Day", "Where to continue if it is nighttime"], + ["exec", "Night", "Where to continue if it is daytime"] ], "exec_arg": false }, @@ -7185,12 +5415,7 @@ "desc": "Check if a specific component has been equipped", "category": "Unit", "args": [ - [ - "in", - "Component", - "Component to check", - "comp" - ], + ["in", "Component", "Component to check", "comp"], [ "exec", "Component Equipped", @@ -7210,17 +5435,8 @@ "desc": "Check if a specific item slot index is fixed", "category": "Unit", "args": [ - [ - "in", - "Slot index", - "Individual slot to check", - "num" - ], - [ - "exec", - "Is Fixed", - "Where to continue if inventory slot is fixed" - ] + ["in", "Slot index", "Individual slot to check", "num"], + ["exec", "Is Fixed", "Where to continue if inventory slot is fixed"] ] }, "is_moving": { @@ -7228,57 +5444,25 @@ "desc": "Checks the movement state of an entity", "category": "Unit", "args": [ - [ - "exec", - "Not Moving", - "Where to continue if entity is not moving" - ], - [ - "exec", - "Path Blocked", - "Where to continue if entity is path blocked" - ], + ["exec", "Not Moving", "Where to continue if entity is not moving"], + ["exec", "Path Blocked", "Where to continue if entity is path blocked"], [ "exec", "No Result", "Where to continue if entity is out of visual range" ], - [ - "in", - "Unit", - "The unit to check (if not self)", - "entity", - true - ] + ["in", "Unit", "The unit to check (if not self)", "entity", true] ], - "exec_arg": [ - 1, - "Moving", - "Where to continue if entity is moving" - ] + "exec_arg": [1, "Moving", "Where to continue if entity is moving"] }, "is_same_grid": { "name": "Is Same Grid", "desc": "Checks if two entities are in the same power grid", "category": "Unit", "args": [ - [ - "in", - "Entity", - "First Entity", - "entity" - ], - [ - "in", - "Entity", - "Second Entity", - "entity" - ], - [ - "exec", - "Different", - "Different power grids" - ] + ["in", "Entity", "First Entity", "entity"], + ["in", "Entity", "Second Entity", "entity"], + ["exec", "Different", "Different power grids"] ], "exec_arg": [ 1, @@ -7296,12 +5480,7 @@ "Is Not Working", "If the requested component is NOT currently working" ], - [ - "in", - "Component/Index", - "Component to get", - "comp_num" - ], + ["in", "Component/Index", "Component to get", "comp_num"], [ "in", "Group/Index", @@ -7322,27 +5501,13 @@ "name": "Jump", "desc": "Jumps execution to label with the same label id", "category": "Flow", - "args": [ - [ - "in", - "Label", - "Label identifier", - "any" - ] - ] + "args": [["in", "Label", "Label identifier", "any"]] }, "label": { "name": "Label", "desc": "Labels can be jumped to from anywhere in a behavior", "category": "Flow", - "args": [ - [ - "in", - "Label", - "Label identifier", - "any" - ] - ] + "args": [["in", "Label", "Label identifier", "any"]] }, "land": { "name": "Land", @@ -7370,50 +5535,23 @@ "desc": "Fix all storage slots or a specific item slot index", "category": "Unit", "args": [ - [ - "in", - "Item", - "Item type to try fixing to the slots", - "item_num" - ], - [ - "in", - "Slot index", - "Individual slot to fix", - "num", - true - ] + ["in", "Item", "Item type to try fixing to the slots", "item_num"], + ["in", "Slot index", "Individual slot to fix", "num", true] ] }, "lookat": { "name": "Lookat", "desc": "Turns the unit to look at a unit or a coordinate", "category": "Global", - "args": [ - [ - "in", - "Target", - "Target unit or coordinate", - "coord" - ] - ] + "args": [["in", "Target", "Target unit or coordinate", "coord"]] }, "make_carrier": { "name": "Make Carriers", "desc": "Construct carrier bots for delivering orders or to use for other tasks", "category": "AutoBase", "args": [ - [ - "in", - "Carriers", - "Type and count of carriers to make", - "frame_num" - ], - [ - "exec", - "If Working", - "Where to continue if the unit started working" - ] + ["in", "Carriers", "Type and count of carriers to make", "frame_num"], + ["exec", "If Working", "Where to continue if the unit started working"] ] }, "make_miner": { @@ -7427,11 +5565,7 @@ "Resource type and number of miners to maintain", "item_num" ], - [ - "exec", - "If Working", - "Where to continue if the unit started working" - ] + ["exec", "If Working", "Where to continue if the unit started working"] ] }, "make_producer": { @@ -7445,29 +5579,10 @@ "Item type and number of producers to maintain", "item_num" ], - [ - "in", - "Component", - "Production component", - "comp" - ], - [ - "in", - "Building", - "Building type to use as producer", - "frame" - ], - [ - "in", - "Location", - "Location offset from self", - "coord" - ], - [ - "exec", - "If Working", - "Where to continue if the unit started working" - ] + ["in", "Component", "Production component", "comp"], + ["in", "Building", "Building type to use as producer", "frame"], + ["in", "Location", "Location offset from self", "coord"], + ["exec", "If Working", "Where to continue if the unit started working"] ] }, "make_turret_bots": { @@ -7475,17 +5590,8 @@ "desc": "Construct and equip turret components on available carrier bots", "category": "AutoBase", "args": [ - [ - "in", - "Number", - "Number of turret bots to maintain", - "num" - ], - [ - "exec", - "If Working", - "Where to continue if the unit started working" - ] + ["in", "Number", "Number of turret bots to maintain", "num"], + ["exec", "If Working", "Where to continue if the unit started working"] ] }, "match": { @@ -7493,37 +5599,11 @@ "desc": "Filters the passed entity", "category": "Unit", "args": [ - [ - "in", - "Unit", - "Unit to Filter, defaults to Self", - "entity" - ], - [ - "in", - "Filter", - "Filter to check", - "radar" - ], - [ - "in", - "Filter", - "Second Filter", - "radar", - true - ], - [ - "in", - "Filter", - "Third Filter", - "radar", - true - ], - [ - "exec", - "Failed", - "Did not match filter" - ] + ["in", "Unit", "Unit to Filter, defaults to Self", "entity"], + ["in", "Filter", "Filter to check", "radar"], + ["in", "Filter", "Second Filter", "radar", true], + ["in", "Filter", "Third Filter", "radar", true], + ["exec", "Failed", "Did not match filter"] ] }, "mine": { @@ -7531,22 +5611,13 @@ "desc": "Mines a single resource", "category": "Component", "args": [ - [ - "in", - "Resource", - "Resource to Mine", - "resource_num" - ], + ["in", "Resource", "Resource to Mine", "resource_num"], [ "exec", "Cannot Mine", "Execution path if mining was unable to be performed" ], - [ - "exec", - "Full", - "Execution path if can't fit resource into inventory" - ] + ["exec", "Full", "Execution path if can't fit resource into inventory"] ] }, "modulo": { @@ -7554,110 +5625,49 @@ "desc": "Get the remainder of a division", "category": "Math", "args": [ - [ - "in", - "Num", - null, - "coord_num" - ], - [ - "in", - "By", - null, - "coord_num" - ], - [ - "out", - "Result" - ] + ["in", "Num", null, "coord_num"], + ["in", "By", null, "coord_num"], + ["out", "Result"] ] }, "move_east": { "name": "Move East", "desc": "Moves towards a tile East of the current location at the specified distance", "category": "Move", - "args": [ - [ - "in", - "Number", - "Number of tiles to move East", - "num" - ] - ] + "args": [["in", "Number", "Number of tiles to move East", "num"]] }, "move_north": { "name": "Move North", "desc": "Moves towards a tile North of the current location at the specified distance", "category": "Move", - "args": [ - [ - "in", - "Number", - "Number of tiles to move North", - "num" - ] - ] + "args": [["in", "Number", "Number of tiles to move North", "num"]] }, "move_south": { "name": "Move South", "desc": "Moves towards a tile South of the current location at the specified distance", "category": "Move", - "args": [ - [ - "in", - "Number", - "Number of tiles to move South", - "num" - ] - ] + "args": [["in", "Number", "Number of tiles to move South", "num"]] }, "move_west": { "name": "Move West", "desc": "Moves towards a tile West of the current location at the specified distance", "category": "Move", - "args": [ - [ - "in", - "Number", - "Number of tiles to move West", - "num" - ] - ] + "args": [["in", "Number", "Number of tiles to move West", "num"]] }, "moveaway_range": { "name": "Move Away (Range)", "desc": "Moves out of range of another unit", "category": "Move", - "args": [ - [ - "in", - "Target", - "Unit to move away from", - "entity" - ] - ] + "args": [["in", "Target", "Unit to move away from", "entity"]] }, "mul": { "name": "Multiply", "desc": "Multiplies a number or coordinate from another number or coordinate", "category": "Math", "args": [ - [ - "in", - "To", - null, - "coord_num" - ], - [ - "in", - "Num", - null, - "coord_num" - ], - [ - "out", - "Result" - ] + ["in", "To", null, "coord_num"], + ["in", "Num", null, "coord_num"], + ["out", "Result"] ] }, "nop": { @@ -7669,13 +5679,7 @@ "name": "Notify", "desc": "Triggers a faction notification", "category": "Global", - "args": [ - [ - "in", - "Notify Value", - "Notification Value" - ] - ] + "args": [["in", "Notify Value", "Notification Value"]] }, "order_to_shared_storage": { "name": "Order to Shared Storage", @@ -7687,18 +5691,8 @@ "desc": "Transfers an Item to another Unit", "category": "Unit", "args": [ - [ - "in", - "Target", - "Target unit", - "entity" - ], - [ - "in", - "Item", - "Item and amount to transfer", - "item_num" - ] + ["in", "Target", "Target unit", "entity"], + ["in", "Item", "Item and amount to transfer", "item_num"] ] }, "package_all": { @@ -7720,35 +5714,16 @@ "desc": "Gives you the percent that value is of Max Value", "category": "Global", "args": [ - [ - "in", - "Value", - "Value to check" - ], - [ - "in", - "Max Value", - "Max Value to get percentage of" - ], - [ - "out", - "Number", - "Percent" - ] + ["in", "Value", "Value to check"], + ["in", "Max Value", "Max Value to get percentage of"], + ["out", "Number", "Percent"] ] }, "ping": { "name": "Pings a Unit", "desc": "Plays the Ping effect and notifies other players", "category": "Global", - "args": [ - [ - "in", - "Target", - "Target unit", - "entity" - ] - ] + "args": [["in", "Target", "Target unit", "entity"]] }, "produce": { "name": "Produce Unit", @@ -7760,16 +5735,8 @@ "desc": "Reads the Radio signal on a specified band", "category": "Unit", "args": [ - [ - "in", - "Band", - "The band to check for" - ], - [ - "out", - "Result", - "Value of the radio signal" - ] + ["in", "Band", "The band to check for"], + ["out", "Result", "Value of the radio signal"] ] }, "read_signal": { @@ -7777,17 +5744,8 @@ "desc": "Reads the Signal register of another unit", "category": "Unit", "args": [ - [ - "in", - "Unit", - "The owned unit to check for", - "entity" - ], - [ - "out", - "Result", - "Value of units Signal register" - ] + ["in", "Unit", "The owned unit to check for", "entity"], + ["out", "Result", "Value of units Signal register"] ] }, "readkey": { @@ -7795,17 +5753,8 @@ "desc": "Attempts to reads the internal key of the unit", "category": "Global", "args": [ - [ - "in", - "Frame", - "Structure to read the key for", - "entity" - ], - [ - "out", - "Key", - "Number key of structure" - ] + ["in", "Frame", "Structure to read the key for", "entity"], + ["out", "Key", "Number key of structure"] ] }, "remap_value": { @@ -7813,96 +5762,36 @@ "desc": "Remaps a value between two ranges", "category": "Global", "args": [ - [ - "in", - "Value", - "Value to Remap" - ], - [ - "in", - "Input Low", - "Low value for input" - ], - [ - "in", - "Input High", - "High value for input" - ], - [ - "in", - "Target Low", - "Low value for target" - ], - [ - "in", - "Target high", - "High value for target" - ], - [ - "out", - "Result", - "Remapped value" - ] + ["in", "Value", "Value to Remap"], + ["in", "Input Low", "Low value for input"], + ["in", "Input High", "High value for input"], + ["in", "Target Low", "Low value for target"], + ["in", "Target high", "High value for target"], + ["out", "Result", "Remapped value"] ] }, "request_item": { "name": "Request Item", "desc": "Requests an item if it doesn't exist in the inventory", "category": "Unit", - "args": [ - [ - "in", - "Item", - "Item and amount to order", - "item_num" - ] - ] + "args": [["in", "Item", "Item and amount to order", "item_num"]] }, "request_wait": { "name": "Request Wait", "desc": "Requests an item and waits until it exists in inventory", "category": "Unit", - "args": [ - [ - "in", - "Item", - "Item and amount to order", - "item_num" - ] - ] + "args": [["in", "Item", "Item and amount to order", "item_num"]] }, "scan": { "name": "Radar", "desc": "Scan for the closest unit that matches the filters", "category": "Component", "args": [ - [ - "in", - "Filter 1", - "First filter", - "radar" - ], - [ - "in", - "Filter 2", - "Second filter", - "radar" - ], - [ - "in", - "Filter 3", - "Third filter", - "radar" - ], - [ - "out", - "Result" - ], - [ - "exec", - "No Result", - "Execution path if no results are found" - ] + ["in", "Filter 1", "First filter", "radar"], + ["in", "Filter 2", "Second filter", "radar"], + ["in", "Filter 3", "Third filter", "radar"], + ["out", "Result"], + ["exec", "No Result", "Execution path if no results are found"] ] }, "scout": { @@ -7915,35 +5804,11 @@ "desc": "Branches based on which unit is closer, optional branches for closer unit", "category": "Flow", "args": [ - [ - "exec", - "A", - "A is nearer (or equal)" - ], - [ - "exec", - "B", - "B is nearer" - ], - [ - "in", - "Unit A", - null, - "entity" - ], - [ - "in", - "Unit B", - null, - "entity" - ], - [ - "out", - "Closest", - "Closest unit", - null, - true - ] + ["exec", "A", "A is nearer (or equal)"], + ["exec", "B", "B is nearer"], + ["in", "Unit A", null, "entity"], + ["in", "Unit B", null, "entity"], + ["out", "Closest", "Closest unit", null, true] ] }, "separate_coordinate": { @@ -7951,20 +5816,9 @@ "desc": "Split a coordinate into x and y values", "category": "Math", "args": [ - [ - "in", - "Coordinate", - null, - "coord_num" - ], - [ - "out", - "x" - ], - [ - "out", - "y" - ] + ["in", "Coordinate", null, "coord_num"], + ["out", "x"], + ["out", "y"] ] }, "separate_register": { @@ -7972,44 +5826,12 @@ "desc": "Split a register into separate parameters", "category": "Math", "args": [ - [ - "in", - "Register", - null, - "entity" - ], - [ - "out", - "Num" - ], - [ - "out", - "Entity", - null, - null, - true - ], - [ - "out", - "ID", - null, - null, - true - ], - [ - "out", - "x", - null, - null, - true - ], - [ - "out", - "y", - null, - null, - true - ] + ["in", "Register", null, "entity"], + ["out", "Num"], + ["out", "Entity", null, null, true], + ["out", "ID", null, null, true], + ["out", "x", null, null, true], + ["out", "y", null, null, true] ] }, "serve_construction": { @@ -8017,11 +5839,7 @@ "desc": "Produce materials needed in construction sites", "category": "AutoBase", "args": [ - [ - "exec", - "If Working", - "Where to continue if the unit started working" - ] + ["exec", "If Working", "Where to continue if the unit started working"] ] }, "set_comp_reg": { @@ -8029,12 +5847,7 @@ "desc": "Writes a value into a component register", "category": "Math", "args": [ - [ - "in", - "Value", - null, - "any" - ], + ["in", "Value", null, "any"], [ "in", "Component/Index", @@ -8055,20 +5868,9 @@ "desc": "Sets the numerical/coordinate part of a value", "category": "Math", "args": [ - [ - "in", - "Value" - ], - [ - "in", - "Num/Coord", - null, - "coord_num" - ], - [ - "out", - "To" - ] + ["in", "Value"], + ["in", "Num/Coord", null, "coord_num"], + ["out", "To"] ] }, "set_reg": { @@ -8076,30 +5878,15 @@ "desc": "Copy a value to a frame register, parameter or variable", "category": "Math", "args": [ - [ - "in", - "Value", - null, - "any" - ], - [ - "out", - "Target" - ] + ["in", "Value", null, "any"], + ["out", "Target"] ] }, "set_research": { "name": "Set Research", "desc": "Returns the first active research tech", "category": "Flow", - "args": [ - [ - "in", - "Tech", - "First active research", - "tech" - ] - ] + "args": [["in", "Tech", "First active research", "tech"]] }, "set_signpost": { "name": "Set Signpost", @@ -8116,22 +5903,13 @@ "desc": "Attempt to solve explorable with inventory items", "category": "Unit", "args": [ - [ - "in", - "Target", - "Explorable to solve", - "entity" - ], + ["in", "Target", "Explorable to solve", "entity"], [ "out", "Missing", "Missing repair item, scanner component or Unpowered" ], - [ - "exec", - "Failed", - "Missing item, component or power to scan" - ] + ["exec", "Failed", "Missing item, component or power to scan"] ] }, "sort_storage": { @@ -8149,22 +5927,9 @@ "desc": "Subtracts a number or coordinate from another number or coordinate", "category": "Math", "args": [ - [ - "in", - "From", - null, - "coord_num" - ], - [ - "in", - "Num", - null, - "coord_num" - ], - [ - "out", - "Result" - ] + ["in", "From", null, "coord_num"], + ["in", "Num", null, "coord_num"], + ["out", "Result"] ] }, "switch": { @@ -8172,85 +5937,19 @@ "desc": "Filters the passed entity", "category": "Unit", "args": [ - [ - "in", - "Unit", - "Unit to Filter, defaults to Self", - "entity" - ], - [ - "in", - "Case 1", - "Case 1", - "radar" - ], - [ - "exec", - "1", - "Case 1" - ], - [ - "in", - "Case 2", - "Case 2", - "radar", - true - ], - [ - "exec", - "2", - "Case 2", - null, - true - ], - [ - "in", - "Case 3", - "Case 3", - "radar", - true - ], - [ - "exec", - "3", - "Case 3", - null, - true - ], - [ - "in", - "Case 4", - "Case 4", - "radar", - true - ], - [ - "exec", - "4", - "Case 4", - null, - true - ], - [ - "in", - "Case 5", - "Case 5", - "radar", - true - ], - [ - "exec", - "5", - "Case 5", - null, - true - ] + ["in", "Unit", "Unit to Filter, defaults to Self", "entity"], + ["in", "Case 1", "Case 1", "radar"], + ["exec", "1", "Case 1"], + ["in", "Case 2", "Case 2", "radar", true], + ["exec", "2", "Case 2", null, true], + ["in", "Case 3", "Case 3", "radar", true], + ["exec", "3", "Case 3", null, true], + ["in", "Case 4", "Case 4", "radar", true], + ["exec", "4", "Case 4", null, true], + ["in", "Case 5", "Case 5", "radar", true], + ["exec", "5", "Case 5", null, true] ], - "exec_arg": [ - 1, - "Default", - "Did not match filter" - ] + "exec_arg": [1, "Default", "Did not match filter"] }, "turnon": { "name": "Turn On", @@ -8267,12 +5966,7 @@ "No Component", "If you don't current hold the requested component or slot was empty" ], - [ - "in", - "Component", - "Component to unequip", - "comp" - ], + ["in", "Component", "Component to unequip", "comp"], [ "in", "Slot index", @@ -8287,22 +5981,9 @@ "desc": "Divert program depending on unit type", "category": "Flow", "args": [ - [ - "in", - "Unit", - "The unit to check", - "entity" - ], - [ - "exec", - "Building", - "Where to continue if the entity is a building" - ], - [ - "exec", - "Bot", - "Where to continue if the entity is a bot" - ], + ["in", "Unit", "The unit to check", "entity"], + ["exec", "Building", "Where to continue if the entity is a building"], + ["exec", "Bot", "Where to continue if the entity is a bot"], [ "exec", "Construction", @@ -8311,13 +5992,7 @@ true ] ], - "exec_arg": [ - 5, - "No Unit", - "No visible unit passed", - null, - true - ] + "exec_arg": [5, "No Unit", "No visible unit passed", null, true] }, "unlock": { "name": "Unlock", @@ -8328,15 +6003,7 @@ "name": "Unfix Item Slots", "desc": "Unfix all inventory slots or a specific item slot index", "category": "Unit", - "args": [ - [ - "in", - "Slot index", - "Individual slot to unfix", - "num", - true - ] - ] + "args": [["in", "Slot index", "Individual slot to unfix", "num", true]] }, "unpackage_all": { "name": "Unpackage All", @@ -8357,66 +6024,21 @@ "desc": "Switch based on type of value", "category": "Flow", "args": [ - [ - "in", - "Data", - "Data to test" - ], - [ - "exec", - "Item", - "Item Type" - ], - [ - "exec", - "Entity", - "Entity Type" - ], - [ - "exec", - "Component", - "Component Type" - ], - [ - "exec", - "Tech", - "Tech Type", - null, - true - ], - [ - "exec", - "Value", - "Information Value Type", - null, - true - ], - [ - "exec", - "Coord", - "Coordinate Value Type", - null, - true - ] + ["in", "Data", "Data to test"], + ["exec", "Item", "Item Type"], + ["exec", "Entity", "Entity Type"], + ["exec", "Component", "Component Type"], + ["exec", "Tech", "Tech Type", null, true], + ["exec", "Value", "Information Value Type", null, true], + ["exec", "Coord", "Coordinate Value Type", null, true] ], - "exec_arg": [ - 1, - "No Match", - "Where to continue if there is no match" - ] + "exec_arg": [1, "No Match", "Where to continue if there is no match"] }, "wait": { "name": "Wait Ticks", "desc": "Pauses execution of the behavior until 1 or more ticks later (5 ticks=1 second)", "category": "Flow", - "args": [ - [ - "in", - "Time", - "Number of ticks to wait", - "num" - ] - ] + "args": [["in", "Time", "Number of ticks to wait", "num"]] } }, "techs": { @@ -8691,4 +6313,4 @@ "v_foundation_basic": "v_foundation", "f_building2x2C": "f_building2x2c" } -} \ No newline at end of file +} diff --git a/scripts/game-data-overrides.json b/scripts/game-data-overrides.json index 72c6292..adfb9e7 100644 --- a/scripts/game-data-overrides.json +++ b/scripts/game-data-overrides.json @@ -54,4 +54,4 @@ "frameJsName": "landingPod" } } -} \ No newline at end of file +} diff --git a/scripts/geninstr.ts b/scripts/geninstr.ts index 51f6db9..5cd2f16 100644 --- a/scripts/geninstr.ts +++ b/scripts/geninstr.ts @@ -6,13 +6,12 @@ // - Paste clipboard contents in Data String, press Convert to JSON // - Paste resulting JSON in dumped-game-data.json // - `npx ts-node scripts/geninstr.ts` - -import * as fs from "fs"; -import {gameData, GameData} from "../data"; +import { CompilerOptions } from "../compiler_options"; +import { gameData, GameData } from "../data"; import overrides from "./overrides.json"; -import {CompilerOptions} from "../compiler_options"; -import * as ts from "typescript"; +import * as fs from "fs"; import path from "path"; +import * as ts from "typescript"; const dtsProps: string[] = []; const dtsMethods: string[] = []; @@ -95,7 +94,7 @@ interface CompileInfo { } const instructions = gameData.instructions as unknown as { - [key: string]: InstrInfo + [key: string]: InstrInfo; }; for (const op in instructions) { @@ -260,7 +259,7 @@ function generateTypes(genInfo: GenInfo, doc?: string) { type, optional, }; - }) + }), ); if (genInfo.txt) { params.unshift({ @@ -272,7 +271,7 @@ function generateTypes(genInfo: GenInfo, doc?: string) { params.unshift({ name: "blueprint", type: "Blueprint", - doc: "The blueprint to use" + doc: "The blueprint to use", }); } const jsdoc = generateDoc(genInfo, params, doc); @@ -282,8 +281,8 @@ function generateTypes(genInfo: GenInfo, doc?: string) { outTypes.length == 0 ? "void" : outTypes.length == 1 - ? outTypes[0] - : `[${outTypes.join(", ")}]`; + ? outTypes[0] + : `[${outTypes.join(", ")}]`; const inTypes = genInfo.inArgs .filter((v) => v[0] != genInfo.thisArg) .map((v) => (v[3] ? FilterTypes[v[3]] : "Value")); @@ -300,12 +299,14 @@ function generateTypes(genInfo: GenInfo, doc?: string) { if (q) { returnType = returnType.slice( 0, - returnType.length - " | undefined".length + returnType.length - " | undefined".length, ); } dtsProps.push(` ${jsdoc}${genInfo.js}${q}: ${returnType};`); } else { - const paramStrs = params.map((v) => `${v.name}${v.optional ? '?' : ''}: ${v.type}`); + const paramStrs = params.map( + (v) => `${v.name}${v.optional ? "?" : ""}: ${v.type}`, + ); const decl = `${genInfo.js}(${paramStrs.join(", ")}): ${returnType};`; if (genInfo.type == "function") { dtsFunctions.push(`${jsdoc}declare function ${decl}`); @@ -318,7 +319,7 @@ function generateTypes(genInfo: GenInfo, doc?: string) { function generateDoc( genInfo: GenInfo, params: ParamInfo[], - methodDoc?: string + methodDoc?: string, ): string | undefined { let indent = genInfo.type == "function" ? "" : " "; let allDocs: string[] = []; @@ -327,13 +328,13 @@ function generateDoc( methodDoc ||= genInfo.outArgs[0]?.[2] || undefined; } else { allDocs.push( - ...params.filter((v) => v.doc).map((v) => `@param ${v.name} ${v.doc}`) + ...params.filter((v) => v.doc).map((v) => `@param ${v.name} ${v.doc}`), ); if (genInfo.outArgs.length == 1 && genInfo.outArgs[0][2]) { allDocs.push(`@returns ${genInfo.outArgs[0][2]}`); } else if (genInfo.outArgs.length > 1) { allDocs.push( - `@returns [${genInfo.outArgs.map((v) => v[2] || v[1]).join(", ")}]` + `@returns [${genInfo.outArgs.map((v) => v[2] || v[1]).join(", ")}]`, ); } } @@ -388,14 +389,17 @@ function quote(str: string) { return JSON.stringify(str); } -function toEnum(data: Array | Map, fn?: (item: T) => boolean): string { +function toEnum( + data: Array | Map, + fn?: (item: T) => boolean, +): string { const filter = fn ?? (() => true); const array = Array.isArray(data) ? data : data.values(); const result: string[] = []; for (const e of array) { if (filter(e)) { - result.push(` | ${quote(e.jsName)}`) + result.push(` | ${quote(e.jsName)}`); } } @@ -427,7 +431,7 @@ fs.writeFileSync( export const methods: { [key: string]: MethodInfo } = ${JSON.stringify( compileInfos, undefined, - 2 + 2, )}; export const ops: { @@ -436,97 +440,132 @@ export const ops: { for (const op of Object.values(methods)) { ops[op.id] = op; } -` +`, ); function naturalSort(a: string, b: string) { - return a.localeCompare(b, undefined, {numeric: true, sensitivity: 'base'}); + return a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }); } -const bpComponents = Array.from(gameData.componentsByJsName.keys()).sort(naturalSort).map(componentJsName => { - const component = gameData.componentsByJsName.get(componentJsName)!; - if (component.attachment_size == null || !(component.attachment_size in gameData.socketSizes)) { - return; - } - - // Handled separately in template - if (component.id === "c_behavior") return; - - const jsName = component.componentJsName; - const linkArgsArray = "[" + (component.registers ?? []).map(register => { - return register.read_only ? "ReadOnlyLinkArg?" : "LinkArg?"; - }).join(", ") + "]"; - const linkArgsObject = "{" + (component.registers ?? []).map((register, index) => { - return index + "?: " + (register.read_only ? "ReadOnlyLinkArg" : "LinkArg"); - }).join(", ") + "}"; - let componentType = `${component.attachment_size}Component` +const bpComponents = Array.from(gameData.componentsByJsName.keys()) + .sort(naturalSort) + .map((componentJsName) => { + const component = gameData.componentsByJsName.get(componentJsName)!; + if ( + component.attachment_size == null || + !(component.attachment_size in gameData.socketSizes) + ) { + return; + } - return ` + // Handled separately in template + if (component.id === "c_behavior") return; + + const jsName = component.componentJsName; + const linkArgsArray = + "[" + + (component.registers ?? []) + .map((register) => { + return register.read_only ? "ReadOnlyLinkArg?" : "LinkArg?"; + }) + .join(", ") + + "]"; + const linkArgsObject = + "{" + + (component.registers ?? []) + .map((register, index) => { + return ( + index + "?: " + (register.read_only ? "ReadOnlyLinkArg" : "LinkArg") + ); + }) + .join(", ") + + "}"; + let componentType = `${component.attachment_size}Component`; + + return ` /** * ${component.name} (${component.id}) */ function ${jsName}(links?: ${linkArgsArray} | ${linkArgsObject}): ${componentType}; - `.trim().replace(/^/gm, " "); -}).filter(c => c != null); - -const dtsBlueprintFns = Array.from(gameData.framesByJsName.keys()).sort(naturalSort).map(frameJsName => { - const frame = gameData.framesByJsName.get(frameJsName)!; - if (!frame.visual) return; - const visual = gameData.visuals.get(frame.visual)!; - const sockets = visual.sockets ?? []; - const slots = frame.slots ?? {}; - - const socketCounts = sockets.reduce((prev, socket) => { - const key = socket[1]; - prev[key] = (prev[key] ?? 0) + 1; - return prev; - }, { - Large: 0, - Medium: 0, - Small: 0, - Internal: 0, - }); - - const socketDoc = Object.entries(socketCounts).map(([socketName, socketValue]) => { - if (socketValue > 0) { - return `${socketValue} ${socketName.toLowerCase()}` - } - }).filter(e => e != null).join(", "); + ` + .trim() + .replace(/^/gm, " "); + }) + .filter((c) => c != null); + +const dtsBlueprintFns = Array.from(gameData.framesByJsName.keys()) + .sort(naturalSort) + .map((frameJsName) => { + const frame = gameData.framesByJsName.get(frameJsName)!; + if (!frame.visual) return; + const visual = gameData.visuals.get(frame.visual)!; + const sockets = visual.sockets ?? []; + const slots = frame.slots ?? {}; + + const socketCounts = sockets.reduce( + (prev, socket) => { + const key = socket[1]; + prev[key] = (prev[key] ?? 0) + 1; + return prev; + }, + { + Large: 0, + Medium: 0, + Small: 0, + Internal: 0, + }, + ); - const slotDoc = Object.entries(slots).map(([slotName, slotValue]) => { - if (slotValue > 0) { - return `${slotValue} ${slotName.toLowerCase()}` - } - }).filter(e => e != null).join(", "); - - const docLines = [ - `${frame.name} (${frame.id})`, - "", - frame.desc ? frame.desc : null, - frame.desc ? "" : null, - socketDoc ? `Sockets: ${socketDoc}` : null, - slotDoc ? `Slots: ${slotDoc}` : null - ].filter(l => l != null).map(l => ` * ${l}`).join("\n"); - - const makeComponentTypeTuple = (key: keyof typeof socketCounts) => { - const count = socketCounts[key]; - const parts: string[] = []; - - for(let i = 0; i < count; i++) { - parts.push(`${key}ComponentArg?`); - } + const socketDoc = Object.entries(socketCounts) + .map(([socketName, socketValue]) => { + if (socketValue > 0) { + return `${socketValue} ${socketName.toLowerCase()}`; + } + }) + .filter((e) => e != null) + .join(", "); + + const slotDoc = Object.entries(slots) + .map(([slotName, slotValue]) => { + if (slotValue > 0) { + return `${slotValue} ${slotName.toLowerCase()}`; + } + }) + .filter((e) => e != null) + .join(", "); + + const docLines = [ + `${frame.name} (${frame.id})`, + "", + frame.desc ? frame.desc : null, + frame.desc ? "" : null, + socketDoc ? `Sockets: ${socketDoc}` : null, + slotDoc ? `Slots: ${slotDoc}` : null, + ] + .filter((l) => l != null) + .map((l) => ` * ${l}`) + .join("\n"); + + const makeComponentTypeTuple = (key: keyof typeof socketCounts) => { + const count = socketCounts[key]; + const parts: string[] = []; + + for (let i = 0; i < count; i++) { + parts.push(`${key}ComponentArg?`); + } - return `[${parts.join(', ')}]`; - }; + return `[${parts.join(", ")}]`; + }; - const jsName = frame.frameJsName; + const jsName = frame.frameJsName; - return ` + return ` /** ${docLines} */ - function ${jsName}(blueprint: BlueprintArgs<${makeComponentTypeTuple('Internal')}, ${makeComponentTypeTuple('Small')}, ${makeComponentTypeTuple('Medium')}, ${makeComponentTypeTuple('Large')}>): Blueprint;`; -}).filter(f => f != null); + function ${jsName}(blueprint: BlueprintArgs<${makeComponentTypeTuple("Internal")}, ${makeComponentTypeTuple("Small")}, ${makeComponentTypeTuple("Medium")}, ${makeComponentTypeTuple("Large")}>): Blueprint;`; + }) + .filter((f) => f != null); const dtsContents = ` type Value = number & BaseValue; @@ -559,21 +598,21 @@ type NumOrPair = T | number | { }; type Color = -${toEnum(gameData.values, e => e.tag === "color")}; +${toEnum(gameData.values, (e) => e.tag === "color")}; type ColorNum = NumOrPair; type Extra = -${toEnum(gameData.values, e => e.tag === "value")}; +${toEnum(gameData.values, (e) => e.tag === "value")}; type ExtraNum = NumOrPair; type RadarFilter = | Resource -${toEnum(gameData.values, e => e.tag === "entityfilter")}; +${toEnum(gameData.values, (e) => e.tag === "entityfilter")}; type Item = | Comp | Resource -${toEnum(gameData.items, item => item.tag !== "resource")}; +${toEnum(gameData.items, (item) => item.tag !== "resource")}; type ItemNum = NumOrPair; type Comp = @@ -581,7 +620,7 @@ ${toEnum(gameData.components)}; type CompNum = NumOrPair; type Resource = -${toEnum(gameData.items, item => item.tag === "resource")}; +${toEnum(gameData.items, (item) => item.tag === "resource")}; type ResourceNum = NumOrPair; type Frame = @@ -663,17 +702,23 @@ ${dtsBlueprintFns.join("\n")} `; fs.writeFileSync("behavior.d.ts", dtsContents); -fs.writeFileSync("behavior_dts.ts", `export const behavior_dts = ${JSON.stringify(dtsContents)}`); +fs.writeFileSync( + "behavior_dts.ts", + `export const behavior_dts = ${JSON.stringify(dtsContents)}`, +); const tsLibFiles = (() => { const program = ts.createProgram(CompilerOptions.lib!, CompilerOptions); const result = {}; for (const sourceFile of program.getSourceFiles()) { - result['/' + path.basename(sourceFile.fileName)] = sourceFile.text; + result["/" + path.basename(sourceFile.fileName)] = sourceFile.text; } return result; })(); -fs.writeFileSync("lib_dts.ts", `export const lib_dts = ${JSON.stringify(tsLibFiles, null, 2)}`); +fs.writeFileSync( + "lib_dts.ts", + `export const lib_dts = ${JSON.stringify(tsLibFiles, null, 2)}`, +); fs.writeFileSync( "decompile/dsinstr.ts", @@ -698,7 +743,7 @@ interface InstrInfo { export const instructions:{[key:string]:InstrInfo} = ${JSON.stringify( decompileInfos, undefined, - 2 + 2, )}; -` +`, ); diff --git a/scripts/overrides.json b/scripts/overrides.json index d65271d..4705b0b 100644 --- a/scripts/overrides.json +++ b/scripts/overrides.json @@ -47,16 +47,18 @@ } }, "select_nearest": { - "aliases":[{ - "js": "nearerThan", - "type": "method", - "thisArg": 2, - "conditions": { - "A": true, - "B": false - }, - "outArgs": [] - }], + "aliases": [ + { + "js": "nearerThan", + "type": "method", + "thisArg": 2, + "conditions": { + "A": true, + "B": false + }, + "outArgs": [] + } + ], "type": "operator" }, "is_same_grid": { @@ -303,7 +305,7 @@ } ] }, - "dopickup":{ + "dopickup": { "js": "pickup", "optional": 1 }, diff --git a/tests/assembler.test.ts b/tests/assembler.test.ts index bb6d41c..845d88c 100644 --- a/tests/assembler.test.ts +++ b/tests/assembler.test.ts @@ -1,10 +1,10 @@ -import {expect, test} from '@jest/globals'; -import * as fs from "fs"; import { assemble } from "../assembler"; -import {globSync} from "glob"; -import path from 'path'; +import { expect, test } from "@jest/globals"; +import * as fs from "fs"; +import { globSync } from "glob"; +import path from "path"; for (const filename of globSync(`${__dirname}/*.asm`)) { - const code = fs.readFileSync(filename, "utf8"); - test(path.basename(filename), () => expect(assemble(code)).toMatchSnapshot()); + const code = fs.readFileSync(filename, "utf8"); + test(path.basename(filename), () => expect(assemble(code)).toMatchSnapshot()); } diff --git a/tests/blueprint_in_behavior.ts b/tests/blueprint_in_behavior.ts index e92501b..ce911e7 100644 --- a/tests/blueprint_in_behavior.ts +++ b/tests/blueprint_in_behavior.ts @@ -1,8 +1,8 @@ export function foo() { - produce(bpBot); + produce(bpBot); } const bpBot = blueprint.cub({ - name: "Example Bot 1", - visual: "c_power_transmitter" + name: "Example Bot 1", + visual: "c_power_transmitter", }); diff --git a/tests/blueprint_with_behavior.ts b/tests/blueprint_with_behavior.ts index a605b5b..fac397c 100644 --- a/tests/blueprint_with_behavior.ts +++ b/tests/blueprint_with_behavior.ts @@ -1,92 +1,80 @@ export const bpBuilding1 = blueprint.building2x1_2M_1({ - name: "Bot Factory", - medium: [ - component.roboticsAssembler([ - {name: "craft1", to: "active1"}, - {to: visual}, - {name: "targetLocation1"} - ]), - component.roboticsAssembler({ - // Register links can use also use number-keyed objects - 0: {name: "craft2", to: "active2"}, - 1: {to: visual}, - 2: {name: "targetLocation2"} - }) - ], - internal: [ - component.internalStorage(), - component.internalStorage(), - component.internalStorage(), - component.behaviorController(fnBotFactory, { - // Behavior component links can use parameter names - targetLocation: {to: ["targetLocation1", "targetLocation2"]}, - craft1: {to: "craft1"}, - craft2: {to: "craft2"} - }), - ] + name: "Bot Factory", + medium: [ + component.roboticsAssembler([ + { name: "craft1", to: "active1" }, + { to: visual }, + { name: "targetLocation1" }, + ]), + component.roboticsAssembler({ + // Register links can use also use number-keyed objects + 0: { name: "craft2", to: "active2" }, + 1: { to: visual }, + 2: { name: "targetLocation2" }, + }), + ], + internal: [ + component.internalStorage(), + component.internalStorage(), + component.internalStorage(), + component.behaviorController(fnBotFactory, { + // Behavior component links can use parameter names + targetLocation: { to: ["targetLocation1", "targetLocation2"] }, + craft1: { to: "craft1" }, + craft2: { to: "craft2" }, + }), + ], }); function fnBotFactory( - targetLocation: Value, - craft1: Value, - active1: Value, - craft2: Value, - active2: Value + targetLocation: Value, + craft1: Value, + active1: Value, + craft2: Value, + active2: Value, ) { - produce(bpBot1); - while(!compareItem(active1, null)) {} - produce(bpBot2); - while(!compareItem(active1, null)) {} - craft2 = value("f_bot_1m_a", 1) - while(!compareItem(active2, null)) {} + produce(bpBot1); + while (!compareItem(active1, null)) {} + produce(bpBot2); + while (!compareItem(active1, null)) {} + craft2 = value("f_bot_1m_a", 1); + while (!compareItem(active2, null)) {} } const bpBot1 = blueprint.cub({ - name: "Example Bot 1", - visual: "c_power_transmitter", - connected: true, - channels: [2, 4], - medium: [ - component.powerTransmitter() - ], - internal: [ - // Empty slot - null, - // Nested behaviors - component.behaviorController(fnBot1, [ - value("metalore", 1), - { value: value("metalore", 2), to: goto }, - { value: "metalore" }, - 3 - ]) - ] + name: "Example Bot 1", + visual: "c_power_transmitter", + connected: true, + channels: [2, 4], + medium: [component.powerTransmitter()], + internal: [ + // Empty slot + null, + // Nested behaviors + component.behaviorController(fnBot1, [ + value("metalore", 1), + { value: value("metalore", 2), to: goto }, + { value: "metalore" }, + 3, + ]), + ], }); function fnBot1(p1: Value, p2: Value, p3: Value, p4: Value) { - notify("Hello World"); + notify("Hello World"); } const bpBot2 = blueprint.markV({ - name: "Example Bot 2", - connected: false, - deliver: false, - construction: false, - transportRoute: true, - medium: [ - component.mediumStorage() - ], - internal: [ - component.internalSpeedModule(), - // Empty behavior controllers - component.behaviorController() - ], - locks: [ - "metalore", - "metalbar", - true, - false, - null, - true, - "metalore" - ] -}); \ No newline at end of file + name: "Example Bot 2", + connected: false, + deliver: false, + construction: false, + transportRoute: true, + medium: [component.mediumStorage()], + internal: [ + component.internalSpeedModule(), + // Empty behavior controllers + component.behaviorController(), + ], + locks: ["metalore", "metalbar", true, false, null, true, "metalore"], +}); diff --git a/tests/call_with_computation.ts b/tests/call_with_computation.ts index 2b24ca8..f22059b 100644 --- a/tests/call_with_computation.ts +++ b/tests/call_with_computation.ts @@ -1,3 +1,3 @@ export function foo(v: Value) { - setNumber(v, v-1); + setNumber(v, v - 1); } diff --git a/tests/compile.test.ts b/tests/compile.test.ts index 823a943..d82acf3 100644 --- a/tests/compile.test.ts +++ b/tests/compile.test.ts @@ -1,8 +1,8 @@ -import { expect, test } from "@jest/globals"; -import * as ts from "typescript"; import { CompilerOptions, compileProgram } from "../compile"; +import { expect, test } from "@jest/globals"; import { globSync } from "glob"; import * as path from "path"; +import * as ts from "typescript"; for (const filename of globSync(`${__dirname}/*.ts`)) { if (filename.endsWith(".test.ts")) { diff --git a/tests/disas.test.ts b/tests/disas.test.ts index fe7dc57..01ed826 100644 --- a/tests/disas.test.ts +++ b/tests/disas.test.ts @@ -1,8 +1,8 @@ -import * as fs from "fs"; -import { DesyncedStringToObject } from "../dsconvert"; import { Disassembler } from "../decompile/disasm"; -import { globSync } from "glob"; +import { DesyncedStringToObject } from "../dsconvert"; import { expect, test } from "@jest/globals"; +import * as fs from "fs"; +import { globSync } from "glob"; import path from "path"; for (const filename of globSync(`${__dirname}/*.txt`)) { diff --git a/tests/if_unit_type.ts b/tests/if_unit_type.ts index 2003fd1..9cb2d4b 100644 --- a/tests/if_unit_type.ts +++ b/tests/if_unit_type.ts @@ -1,10 +1,10 @@ export function test(a) { - const t = a.unitType; - if (t == "Bot") { - notify("Bot"); - } else if (t == "Building") { - notify("Building"); - } else { - notify("Other"); - } -} \ No newline at end of file + const t = a.unitType; + if (t == "Bot") { + notify("Bot"); + } else if (t == "Building") { + notify("Building"); + } else { + notify("Other"); + } +} diff --git a/tests/inlining.ts b/tests/inlining.ts index 6aca01f..ebd2ce5 100644 --- a/tests/inlining.ts +++ b/tests/inlining.ts @@ -1,30 +1,30 @@ export function foo(p1: Value) { - const c1 = (1 + 2) * 3; - const c2 = c1 * 99; - const cUnused = 4; + const c1 = (1 + 2) * 3; + const c2 = c1 * 99; + const cUnused = 4; - let v1 = (5 + 6) * 7; - const c3 = 5 + c2 + v1; - let vUnused = 8; + let v1 = (5 + 6) * 7; + const c3 = 5 + c2 + v1; + let vUnused = 8; - p1 = -1; + p1 = -1; - notify(c1); - notify(c2); - notify(v1); - notify(12 * 12); - notify(c3 * 5); + notify(c1); + notify(c2); + notify(v1); + notify(12 * 12); + notify(c3 * 5); - let lVar2 = 9; - if (p1.fullHealth()) { - lVar2 = 10; - } else { - lVar2 = 11; - } + let lVar2 = 9; + if (p1.fullHealth()) { + lVar2 = 10; + } else { + lVar2 = 11; + } - notify(lVar2); + notify(lVar2); - const cCoord = coord(-5 * 3, -10); - domove(cCoord * 3); - domove(cCoord); -} \ No newline at end of file + const cCoord = coord(-5 * 3, -10); + domove(cCoord * 3); + domove(cCoord); +} diff --git a/tests/literals.ts b/tests/literals.ts index 02080d4..dbd027b 100644 --- a/tests/literals.ts +++ b/tests/literals.ts @@ -1,26 +1,26 @@ export function foo(v: Value) { - let x = 5; - x.fullBattery(); + let x = 5; + x.fullBattery(); - v = undefined; - v.fullBattery(); - v = 1; - v.fullBattery(); - v = value("c_battery"); - v.fullBattery(); - v = value("c_small_relay", 2); - v.fullBattery(); - v = coord(10, 20); - v.fullBattery(); - v = setNumber(v, 30); - v = self.count("c_battery"); - v = self.count(value("c_battery")) - v = self.count(v); + v = undefined; + v.fullBattery(); + v = 1; + v.fullBattery(); + v = value("c_battery"); + v.fullBattery(); + v = value("c_small_relay", 2); + v.fullBattery(); + v = coord(10, 20); + v.fullBattery(); + v = setNumber(v, 30); + v = self.count("c_battery"); + v = self.count(value("c_battery")); + v = self.count(v); - v = v - 1; - v = v + 1; + v = v - 1; + v = v + 1; - let v2: Value = value("c_battery"); - let v3: Value = 10; - v2 = v3 + 1; -} \ No newline at end of file + let v2: Value = value("c_battery"); + let v3: Value = 10; + v2 = v3 + 1; +} diff --git a/tests/loops.ts b/tests/loops.ts index e689629..d32e7e1 100644 --- a/tests/loops.ts +++ b/tests/loops.ts @@ -1,17 +1,17 @@ export function loops() { - for (let [a, b] of matchingSignals(value("metalore"))) { - notify(a); - notify(b); - } + for (let [a, b] of matchingSignals(value("metalore"))) { + notify(a); + notify(b); + } - let c: Value; - let d: Value; - for ([c, d] of matchingSignals(value("metalore"))) { - let x: Value = 1; - notify(x); - break; - } + let c: Value; + let d: Value; + for ([c, d] of matchingSignals(value("metalore"))) { + let x: Value = 1; + notify(x); + break; + } - notify(c); - notify(d); -} \ No newline at end of file + notify(c); + notify(d); +} diff --git a/tests/multi_file.ts b/tests/multi_file.ts index 547647d..1bfef97 100644 --- a/tests/multi_file.ts +++ b/tests/multi_file.ts @@ -2,4 +2,4 @@ import { rng } from "./rng"; export function foo(rngState: Value) { rng(100, 1, rngState); -} \ No newline at end of file +} diff --git a/tests/nested_sub.ts b/tests/nested_sub.ts index dbb0927..87e80c4 100644 --- a/tests/nested_sub.ts +++ b/tests/nested_sub.ts @@ -1,11 +1,11 @@ export function foo() { - sub1(); + sub1(); } function sub1() { - sub2(); + sub2(); } function sub2() { - notify("hello world"); -} \ No newline at end of file + notify("hello world"); +} diff --git a/tests/numeric_compare.ts b/tests/numeric_compare.ts index 4cd5b7d..7adfffa 100644 --- a/tests/numeric_compare.ts +++ b/tests/numeric_compare.ts @@ -1,15 +1,13 @@ - -export function foo(v:Value) { - let a = getBattery(); - if (a < 20) { - domove(gethome()); - return; - } - let [h] = getHealth(self); - if (h <= 50) { - domove(gethome()); - } else { - notify("ok") - } - +export function foo(v: Value) { + let a = getBattery(); + if (a < 20) { + domove(gethome()); + return; + } + let [h] = getHealth(self); + if (h <= 50) { + domove(gethome()); + } else { + notify("ok"); + } } diff --git a/tests/rng.ts b/tests/rng.ts index 183a269..8193ba5 100644 --- a/tests/rng.ts +++ b/tests/rng.ts @@ -1,9 +1,9 @@ -export function rng(max:Value, min:Value, state:Value) { - unlock(); - let r = max - min + 1; - if (state <= 0) { - state = factionItemAmount("metalore"); - } - state = modulo(17364*state+1, 65521); - return r*state/65521+min; +export function rng(max: Value, min: Value, state: Value) { + unlock(); + let r = max - min + 1; + if (state <= 0) { + state = factionItemAmount("metalore"); + } + state = modulo(17364 * state + 1, 65521); + return (r * state) / 65521 + min; } diff --git a/tests/switch_no_default.ts b/tests/switch_no_default.ts index b7ae8c6..96e35dc 100644 --- a/tests/switch_no_default.ts +++ b/tests/switch_no_default.ts @@ -1,7 +1,7 @@ export function foo(v: Value) { - switch(v.type) { - case "No Match": - notify("No Match"); - break; - } -} \ No newline at end of file + switch (v.type) { + case "No Match": + notify("No Match"); + break; + } +} diff --git a/tests/test1.ts b/tests/test1.ts index b5dc510..dc999f7 100644 --- a/tests/test1.ts +++ b/tests/test1.ts @@ -1,32 +1,31 @@ - -export function foo(v:Value) { - if (self.fullBattery()) { - return; +export function foo(v: Value) { + if (self.fullBattery()) { + return; + } + const missing = v.solve(); + if (missing) { + notify("no solution"); + } else { + notify("solved"); + } + let a: number; + switch (missing?.type) { + case "Item": { + a = 1; + break; } - const missing = v.solve(); - if (missing) { - notify("no solution"); - } else { - notify("solved"); + case "Entity": { + a = 2; + break; } - let a:number; - switch (missing?.type) { - case "Item": { - a = 1; - break; - } - case "Entity": { - a = 2; - break; - } - case "Component": { - a = 3; - break; - } - default: - a = 4; + case "Component": { + a = 3; + break; } - for (const e of entitiesInRange(20, "v_construction")) { - const l = self.getDistance(e); - } -} \ No newline at end of file + default: + a = 4; + } + for (const e of entitiesInRange(20, "v_construction")) { + const l = self.getDistance(e); + } +} diff --git a/tests/test2.ts b/tests/test2.ts index 9506d5b..ee8b52c 100644 --- a/tests/test2.ts +++ b/tests/test2.ts @@ -1,3 +1 @@ - -export function foo(p1 :Value) { -} +export function foo(p1: Value) {} diff --git a/tests/this_arg_param.ts b/tests/this_arg_param.ts index ddf05b1..d1035ec 100644 --- a/tests/this_arg_param.ts +++ b/tests/this_arg_param.ts @@ -1,8 +1,8 @@ export function test(a) { - let closest = a.nearerThan(signal); - if(closest) { - notify("a"); - } else { - notify("b"); - } -} \ No newline at end of file + let closest = a.nearerThan(signal); + if (closest) { + notify("a"); + } else { + notify("b"); + } +} diff --git a/tests/tsconfig.json b/tests/tsconfig.json index 69b40a2..c260a6d 100644 --- a/tests/tsconfig.json +++ b/tests/tsconfig.json @@ -1,13 +1,9 @@ { - "extends": "../tsconfig.json", - "compilerOptions": { - "strictNullChecks": false - }, - "include": [ - "*.ts" - ], - "exclude": ["*.test.ts"], - "files": [ - "../behavior.d.ts" - ] - } \ No newline at end of file + "extends": "../tsconfig.json", + "compilerOptions": { + "strictNullChecks": false + }, + "include": ["*.ts"], + "exclude": ["*.test.ts"], + "files": ["../behavior.d.ts"] +} diff --git a/tsconfig.json b/tsconfig.json index c413883..9bff609 100755 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,24 +1,17 @@ { - "compilerOptions":{ - "lib":[ - "ES6" - ], - "strict":true, - "target":"ES2020", - "moduleResolution": "nodenext", - "module": "nodenext", - "esModuleInterop": true, - "resolveJsonModule": true, - "noImplicitAny": false, - "allowJs": true, - // "checkJs": true, - "outDir": "dist", - }, - "include": [ - "decompile/*.ts", - "*.ts", - "*.js", - "package.json" - ], - "exclude": ["compiler_bundle.ts"] + "compilerOptions": { + "lib": ["ES6"], + "strict": true, + "target": "ES2020", + "moduleResolution": "nodenext", + "module": "nodenext", + "esModuleInterop": true, + "resolveJsonModule": true, + "noImplicitAny": false, + "allowJs": true, + // "checkJs": true, + "outDir": "dist" + }, + "include": ["decompile/*.ts", "*.ts", "*.js", "package.json"], + "exclude": ["compiler_bundle.ts"] } diff --git a/watch.ts b/watch.ts index c57643c..76e2e23 100644 --- a/watch.ts +++ b/watch.ts @@ -1,99 +1,109 @@ -import ts = require("typescript"); -import {compileProgram, CompilerOptions} from "./compile"; -import {basename, dirname} from "path"; +import { assemble } from "./assembler"; +import { compileProgram, CompilerOptions } from "./compile"; +import { ObjectToDesyncedString } from "./dsconvert"; import fs from "fs"; -import {assemble} from "./assembler"; -import {ObjectToDesyncedString} from "./dsconvert"; - -Promise.all([ - import("clipboardy") -]).then(([{default: clipboard}]) => { - const formatHost: ts.FormatDiagnosticsHost = { - getCanonicalFileName: path => path, - getCurrentDirectory: ts.sys.getCurrentDirectory, - getNewLine: () => ts.sys.newLine - }; - - function compile(filename: string, program: ts.SemanticDiagnosticsBuilderProgram) { - const asm = compileProgram(filename, program.getProgram()); - - const dir = dirname(filename); - const asmFilename = dir + "/out/" + basename(filename) + ".asm"; - fs.writeFileSync(asmFilename, asm); - - const obj = assemble(asm); - fs.writeFileSync(asmFilename + ".json", JSON.stringify(obj, undefined, 2)); - - let typ = "C"; - if ("frame" in obj) { - typ = "B"; - } +import { basename, dirname } from "path"; - const str = ObjectToDesyncedString(obj, typ); - clipboard.writeSync(str); - fs.writeFileSync(asmFilename + ".txt", str, { - flush: true, - }); - } - - function watchMain() { - // TypeScript can use several different program creation "strategies": - // * ts.createEmitAndSemanticDiagnosticsBuilderProgram, - // * ts.createSemanticDiagnosticsBuilderProgram - // * ts.createAbstractBuilder - // The first two produce "builder programs". These use an incremental strategy - // to only re-check and emit files whose contents may have changed, or whose - // dependencies may have changes which may impact change the result of prior - // type-check and emit. - // The last uses an ordinary program which does a full type check after every - // change. - // Between `createEmitAndSemanticDiagnosticsBuilderProgram` and - // `createSemanticDiagnosticsBuilderProgram`, the only difference is emit. - // For pure type-checking scenarios, or when another tool/process handles emit, - // using `createSemanticDiagnosticsBuilderProgram` may be more desirable. - const createProgram = ts.createSemanticDiagnosticsBuilderProgram; - - const filename = process.argv[2]; - const files = [filename, `${__dirname}/behavior.d.ts`]; - - const host = ts.createWatchCompilerHost( - files, - CompilerOptions, - ts.sys, - createProgram, - reportDiagnostic, - reportWatchStatusChanged - ); - - const origPostProgramCreate = host.afterProgramCreate; - - host.afterProgramCreate = program => { - try { - compile(filename, program); - console.log("** Compilation finished, copied to clipboard! **"); - } catch(e) { - console.error(e); - } - - origPostProgramCreate!(program); - }; - - // `createWatchProgram` creates an initial program, watches files, and updates - // the program over time. - ts.createWatchProgram(host); - } +import ts = require("typescript"); - function reportDiagnostic(diagnostic: ts.Diagnostic) { - console.error("Error", diagnostic.code, ":", ts.flattenDiagnosticMessageText(diagnostic.messageText, formatHost.getNewLine())); +Promise.all([import("clipboardy")]).then(([{ default: clipboard }]) => { + const formatHost: ts.FormatDiagnosticsHost = { + getCanonicalFileName: (path) => path, + getCurrentDirectory: ts.sys.getCurrentDirectory, + getNewLine: () => ts.sys.newLine, + }; + + function compile( + filename: string, + program: ts.SemanticDiagnosticsBuilderProgram, + ) { + const asm = compileProgram(filename, program.getProgram()); + + const dir = dirname(filename); + const asmFilename = dir + "/out/" + basename(filename) + ".asm"; + fs.writeFileSync(asmFilename, asm); + + const obj = assemble(asm); + fs.writeFileSync(asmFilename + ".json", JSON.stringify(obj, undefined, 2)); + + let typ = "C"; + if ("frame" in obj) { + typ = "B"; } - /** - * Prints a diagnostic every time the watch status changes. - * This is mainly for messages like "Starting compilation" or "Compilation completed". - */ - function reportWatchStatusChanged(diagnostic: ts.Diagnostic) { - console.info(ts.formatDiagnostic(diagnostic, formatHost)); - } + const str = ObjectToDesyncedString(obj, typ); + clipboard.writeSync(str); + fs.writeFileSync(asmFilename + ".txt", str, { + flush: true, + }); + } + + function watchMain() { + // TypeScript can use several different program creation "strategies": + // * ts.createEmitAndSemanticDiagnosticsBuilderProgram, + // * ts.createSemanticDiagnosticsBuilderProgram + // * ts.createAbstractBuilder + // The first two produce "builder programs". These use an incremental strategy + // to only re-check and emit files whose contents may have changed, or whose + // dependencies may have changes which may impact change the result of prior + // type-check and emit. + // The last uses an ordinary program which does a full type check after every + // change. + // Between `createEmitAndSemanticDiagnosticsBuilderProgram` and + // `createSemanticDiagnosticsBuilderProgram`, the only difference is emit. + // For pure type-checking scenarios, or when another tool/process handles emit, + // using `createSemanticDiagnosticsBuilderProgram` may be more desirable. + const createProgram = ts.createSemanticDiagnosticsBuilderProgram; + + const filename = process.argv[2]; + const files = [filename, `${__dirname}/behavior.d.ts`]; + + const host = ts.createWatchCompilerHost( + files, + CompilerOptions, + ts.sys, + createProgram, + reportDiagnostic, + reportWatchStatusChanged, + ); + + const origPostProgramCreate = host.afterProgramCreate; + + host.afterProgramCreate = (program) => { + try { + compile(filename, program); + console.log("** Compilation finished, copied to clipboard! **"); + } catch (e) { + console.error(e); + } + + origPostProgramCreate!(program); + }; - watchMain(); -}); \ No newline at end of file + // `createWatchProgram` creates an initial program, watches files, and updates + // the program over time. + ts.createWatchProgram(host); + } + + function reportDiagnostic(diagnostic: ts.Diagnostic) { + console.error( + "Error", + diagnostic.code, + ":", + ts.flattenDiagnosticMessageText( + diagnostic.messageText, + formatHost.getNewLine(), + ), + ); + } + + /** + * Prints a diagnostic every time the watch status changes. + * This is mainly for messages like "Starting compilation" or "Compilation completed". + */ + function reportWatchStatusChanged(diagnostic: ts.Diagnostic) { + console.info(ts.formatDiagnostic(diagnostic, formatHost)); + } + + watchMain(); +}); diff --git a/website/404.html b/website/404.html index 829eda8..e76cee4 100644 --- a/website/404.html +++ b/website/404.html @@ -1,23 +1,79 @@ - + - - + + Page Not Found @@ -25,9 +81,16 @@

404

Page Not Found

-

The specified file was not found on this website. Please check the URL for mistakes and try again.

+

+ The specified file was not found on this website. Please check the URL + for mistakes and try again. +

Why am I seeing this?

-

This page was generated by the Firebase Command-Line Interface. To modify it, edit the 404.html file in your project's configured public directory.

+

+ This page was generated by the Firebase Command-Line Interface. To + modify it, edit the 404.html file in your project's + configured public directory. +

diff --git a/website/index.html b/website/index.html index 258cf61..b8b39b0 100644 --- a/website/index.html +++ b/website/index.html @@ -1,6 +1,12 @@ - + Desynced Behavior Editor - +