diff --git a/WebGames-master/WebGames-master/games/cap/compiler.js b/WebGames-master/WebGames-master/games/cap/compiler.js
new file mode 100644
index 00000000..c7e912bd
--- /dev/null
+++ b/WebGames-master/WebGames-master/games/cap/compiler.js
@@ -0,0 +1,968 @@
+var Compiler, LocalLayer;
+
+Compiler = (function() {
+ class Compiler {
+ constructor(program) {
+ var i, j, len, ref, s;
+ this.program = program;
+ this.code_saves = [];
+ this.code = "";
+ this.code = [this.code];
+ this.routine = new Routine();
+ this.locals = new Locals(this);
+ this.count = 0;
+ ref = this.program.statements;
+ for (i = j = 0, len = ref.length; j < len; i = ++j) {
+ s = ref[i];
+ this.compile(s);
+ if (i < this.program.statements.length - 1) {
+ this.routine.POP(s);
+ }
+ }
+ this.routine.optimize();
+ this.routine.resolveLabels();
+ this.count += this.routine.opcodes.length;
+ this.routine.locals_size = this.locals.max_index;
+ }
+
+
+ // console.info(JSON.stringify @routine.export())
+ // @routine = new Routine(0).import( @routine.export() )
+ compile(statement) {
+ if (statement instanceof Program.Value) {
+ return this.compileValue(statement);
+ } else if (statement instanceof Program.Operation) {
+ return this.compileOperation(statement);
+ } else if (statement instanceof Program.Assignment) {
+ return this.compileAssignment(statement);
+ } else if (statement instanceof Program.Variable) {
+ return this.compileVariable(statement);
+ } else if (statement instanceof Program.Function) {
+ return this.compileFunction(statement);
+ } else if (statement instanceof Program.FunctionCall) {
+ return this.compileFunctionCall(statement);
+ } else if (statement instanceof Program.While) {
+ return this.compileWhile(statement);
+ }
+ if (statement instanceof Program.SelfAssignment) {
+ return this.compileSelfAssignment(statement);
+ } else if (statement instanceof Program.Braced) {
+ return this.compileBraced(statement);
+ } else if (statement instanceof Program.CreateObject) {
+ return this.compileCreateObject(statement);
+ } else if (statement instanceof Program.Field) {
+ return this.compileField(statement);
+ } else if (statement instanceof Program.Negate) {
+ return this.compileNegate(statement);
+ } else if (statement instanceof Program.For) {
+ return this.compileFor(statement);
+ } else if (statement instanceof Program.ForIn) {
+ return this.compileForIn(statement);
+ } else if (statement instanceof Program.Not) {
+ return this.compileNot(statement);
+ } else if (statement instanceof Program.Return) {
+ return this.compileReturn(statement);
+ } else if (statement instanceof Program.Condition) {
+ return this.compileCondition(statement);
+ } else if (statement instanceof Program.Break) {
+ return this.compileBreak(statement);
+ } else if (statement instanceof Program.Continue) {
+ return this.compileContinue(statement);
+ } else if (statement instanceof Program.CreateClass) {
+ return this.compileCreateClass(statement);
+ } else if (statement instanceof Program.NewCall) {
+ return this.compileNewCall(statement);
+ } else if (statement instanceof Program.After) {
+ return this.compileAfter(statement);
+ } else if (statement instanceof Program.Every) {
+ return this.compileEvery(statement);
+ } else if (statement instanceof Program.Do) {
+ return this.compileDo(statement);
+ } else if (statement instanceof Program.Sleep) {
+ return this.compileSleep(statement);
+ } else if (statement instanceof Program.Delete) {
+ return this.compileDelete(statement);
+ } else if (true) {
+ console.info(statement);
+ throw "Not implemented";
+ }
+ }
+
+ compileAssignment(statement) {
+ var arg_index, f, i, index, j, ref;
+ if (statement.local) {
+ if (statement.field instanceof Program.Variable) {
+ if (statement.expression instanceof Program.Function) {
+ index = this.locals.register(statement.field.identifier); //# register function locally first
+ this.compile(statement.expression); //# then compile function which may refer to itself
+ this.routine.arg1[this.routine.arg1.length - 1].import_self = index;
+ return this.routine.STORE_LOCAL(index, statement);
+ } else if (statement.expression instanceof Program.After || statement.expression instanceof Program.Do || statement.expression instanceof Program.Every) {
+ index = this.locals.register(statement.field.identifier); //# register thread locally first
+ arg_index = this.routine.arg1.length; //# thread main routine will land here
+ this.compile(statement.expression); //# then compile function which may refer to itself
+ this.routine.arg1[arg_index].import_self = index;
+ return this.routine.STORE_LOCAL(index, statement);
+ } else {
+ this.compile(statement.expression); //# first compile expression which may refer to another local with same name
+ index = this.locals.register(statement.field.identifier); //# then register a local for that name
+ return this.routine.STORE_LOCAL(index, statement);
+ }
+ } else {
+ throw "illegal";
+ }
+ } else {
+ if (statement.field instanceof Program.Variable) {
+ if (this.locals.get(statement.field.identifier) != null) {
+ this.compile(statement.expression);
+ index = this.locals.get(statement.field.identifier);
+ this.routine.STORE_LOCAL(index, statement);
+ } else if (statement.expression instanceof Program.CreateClass) {
+ return this.compileUpdateClass(statement.expression, statement.field.identifier);
+ } else {
+ this.compile(statement.expression);
+ this.routine.STORE_VARIABLE(statement.field.identifier, statement);
+ }
+ } else {
+ f = statement.field;
+ if (f.expression instanceof Program.Variable) {
+ if (f.expression.identifier === "this") {
+ this.routine.LOAD_THIS(f);
+ } else if (this.locals.get(f.expression.identifier) != null) {
+ index = this.locals.get(f.expression.identifier);
+ this.routine.LOAD_LOCAL_OBJECT(index, f.expression);
+ } else if (f.expression.identifier === "global") {
+ this.routine.LOAD_GLOBAL(f);
+ } else {
+ this.routine.LOAD_VARIABLE_OBJECT(f.expression.identifier, statement);
+ }
+ } else {
+ this.compile(f.expression);
+ this.routine.MAKE_OBJECT(statement);
+ }
+ for (i = j = 0, ref = f.chain.length - 2; j <= ref; i = j += 1) {
+ this.compile(f.chain[i]);
+ this.routine.LOAD_PROPERTY_OBJECT(f.chain[i]);
+ }
+ this.compile(f.chain[f.chain.length - 1]);
+ this.compile(statement.expression);
+ return this.routine.STORE_PROPERTY(statement);
+ }
+ }
+ }
+
+ compileSelfAssignment(statement) {
+ var c, f, i, index, j, op, ref;
+ switch (statement.operation) {
+ case Token.TYPE_PLUS_EQUALS:
+ op = "ADD";
+ break;
+ case Token.TYPE_MINUS_EQUALS:
+ op = "SUB";
+ break;
+ case Token.TYPE_MULTIPLY_EQUALS:
+ op = "MUL";
+ break;
+ case Token.TYPE_DIVIDE_EQUALS:
+ op = "DIV";
+ break;
+ case Token.TYPE_MODULO_EQUALS:
+ op = "MODULO";
+ break;
+ case Token.TYPE_AND_EQUALS:
+ op = "BINARY_AND";
+ break;
+ case Token.TYPE_OR_EQUALS:
+ op = "BINARY_OR";
+ }
+ if (statement.field instanceof Program.Variable) {
+ if (this.locals.get(statement.field.identifier) != null) {
+ index = this.locals.get(statement.field.identifier);
+ this.routine.LOAD_LOCAL(index, statement);
+ this.compile(statement.expression);
+ this.routine[op](statement, 1);
+ this.routine.STORE_LOCAL(index, statement);
+ } else {
+ this.routine.LOAD_VARIABLE(statement.field.identifier, statement);
+ this.compile(statement.expression);
+ this.routine[op](statement, 1);
+ this.routine.STORE_VARIABLE(statement.field.identifier, statement);
+ }
+ } else {
+ f = statement.field;
+ if (f.expression instanceof Program.Variable) {
+ if (f.expression.identifier === "this") {
+ this.routine.LOAD_THIS(f);
+ } else if (this.locals.get(f.expression.identifier) != null) {
+ index = this.locals.get(f.expression.identifier);
+ this.routine.LOAD_LOCAL_OBJECT(index, statement);
+ } else if (f.expression.identifier === "global") {
+ this.routine.LOAD_GLOBAL(f);
+ } else {
+ this.routine.LOAD_VARIABLE_OBJECT(f.expression.identifier, statement);
+ }
+ } else {
+ this.compile(f.expression);
+ this.routine.MAKE_OBJECT(statement);
+ }
+ for (i = j = 0, ref = f.chain.length - 2; j <= ref; i = j += 1) {
+ this.compile(f.chain[i]);
+ this.routine.LOAD_PROPERTY_OBJECT(f.chain[i]);
+ }
+ c = f.chain[f.chain.length - 1];
+ this.compile(f.chain[f.chain.length - 1]);
+ this.routine.LOAD_PROPERTY_ATOP(statement);
+ this.compile(statement.expression);
+ this.routine[op](statement, 1);
+ return this.routine.STORE_PROPERTY(statement);
+ }
+ }
+
+ compileOperation(op) {
+ var jump, ref, ref1;
+ if ((ref = op.operation) === "+" || ref === "-" || ref === "*" || ref === "/" || ref === "%" || ref === "&" || ref === "|" || ref === "<<" || ref === ">>") {
+ this.compile(op.term1);
+ this.compile(op.term2);
+ switch (op.operation) {
+ case "+":
+ this.routine.ADD(op);
+ break;
+ case "-":
+ this.routine.SUB(op);
+ break;
+ case "*":
+ this.routine.MUL(op);
+ break;
+ case "/":
+ this.routine.DIV(op);
+ break;
+ case "%":
+ this.routine.MODULO(op);
+ break;
+ case "&":
+ this.routine.BINARY_AND(op);
+ break;
+ case "|":
+ this.routine.BINARY_OR(op);
+ break;
+ case "<<":
+ this.routine.SHIFT_LEFT(op);
+ break;
+ case ">>":
+ this.routine.SHIFT_RIGHT(op);
+ }
+ } else if ((ref1 = op.operation) === "==" || ref1 === "!=" || ref1 === "<" || ref1 === ">" || ref1 === "<=" || ref1 === ">=") {
+ this.compile(op.term1);
+ this.compile(op.term2);
+ switch (op.operation) {
+ case "==":
+ this.routine.EQ(op);
+ break;
+ case "!=":
+ this.routine.NEQ(op);
+ break;
+ case "<":
+ this.routine.LT(op);
+ break;
+ case ">":
+ this.routine.GT(op);
+ break;
+ case "<=":
+ this.routine.LTE(op);
+ break;
+ case ">=":
+ this.routine.GTE(op);
+ }
+ } else if (op.operation === "and") {
+ jump = this.routine.createLabel("and");
+ op.term1.nowarning = true;
+ op.term2.nowarning = true;
+ this.compile(op.term1);
+ this.routine.JUMPN_NOPOP(jump, op);
+ this.routine.POP(op);
+ this.compile(op.term2);
+ return this.routine.setLabel(jump);
+ } else if (op.operation === "or") {
+ jump = this.routine.createLabel("or");
+ op.term1.nowarning = true;
+ op.term2.nowarning = true;
+ this.compile(op.term1);
+ this.routine.JUMPY_NOPOP(jump, op);
+ this.routine.POP(op);
+ this.compile(op.term2);
+ return this.routine.setLabel(jump);
+ } else if (op.operation === "^") {
+ this.compile(op.term1);
+ this.compile(op.term2);
+ return this.routine.BINARY_OP(Compiler.predefined_binary_functions.pow, op);
+ } else {
+ return "";
+ }
+ }
+
+ compileBraced(expression) {
+ this.compile(expression.expression);
+ }
+
+ compileNegate(expression) {
+ if (expression.expression instanceof Program.Value && expression.expression.type === Program.Value.TYPE_NUMBER) {
+ return this.routine.LOAD_VALUE(-expression.expression.value, expression);
+ } else {
+ this.compile(expression.expression);
+ return this.routine.NEGATE(expression);
+ }
+ }
+
+ compileNot(expression) {
+ expression.expression.nowarning = true;
+ this.compile(expression.expression);
+ return this.routine.NOT(expression);
+ }
+
+ compileValue(value) {
+ var i, j, ref;
+ switch (value.type) {
+ case Program.Value.TYPE_NUMBER:
+ this.routine.LOAD_VALUE(value.value, value);
+ break;
+ case Program.Value.TYPE_STRING:
+ this.routine.LOAD_VALUE(value.value, value);
+ break;
+ case Program.Value.TYPE_ARRAY:
+ this.routine.CREATE_ARRAY(value);
+ for (i = j = 0, ref = value.value.length - 1; j <= ref; i = j += 1) {
+ this.routine.LOAD_VALUE(i, value);
+ this.compile(value.value[i]);
+ this.routine.CREATE_PROPERTY(value);
+ }
+ }
+ }
+
+ compileVariable(variable) {
+ var index, v;
+ v = variable.identifier;
+ if (v === "this") {
+ return this.routine.LOAD_THIS(variable);
+ } else if (v === "global") {
+ return this.routine.LOAD_GLOBAL(variable);
+ } else if (Compiler.predefined_values[v] != null) {
+ return this.routine.LOAD_VALUE(Compiler.predefined_values[v], variable);
+ } else if (this.locals.get(v) != null) {
+ index = this.locals.get(v);
+ return this.routine.LOAD_LOCAL(index, variable);
+ } else {
+ return this.routine.LOAD_VARIABLE(v, variable);
+ }
+ }
+
+ compileField(field) {
+ var c, i, id, index, j, k, len, ref, ref1;
+ if (field.expression.identifier === "keyboard" || field.expression.identifier === "gamepad") {
+ field.nowarning = true;
+ }
+ c = field.chain[field.chain.length - 1];
+ if (c instanceof Program.Value && c.value === "type") {
+ if (field.chain.length === 1) {
+ if (field.expression instanceof Program.Variable) { // variable.type
+ id = field.expression.identifier;
+ if (this.locals.get(id) != null) {
+ index = this.locals.get(id);
+ this.routine.LOAD_LOCAL(index, field);
+ this.routine.TYPE(field);
+ } else if (Compiler.predefined_values[id] != null) {
+ this.routine.LOAD_VALUE("number", field);
+ } else if ((Compiler.predefined_unary_functions[id] != null) || Compiler.predefined_binary_functions[id]) {
+ this.routine.LOAD_VALUE("function", field);
+ } else {
+ this.routine.VARIABLE_TYPE(id, field.expression);
+ }
+ } else {
+ this.compile(field.expression);
+ this.routine.TYPE(field);
+ }
+ } else {
+ this.compile(field.expression);
+ for (i = j = 0, ref = field.chain.length - 3; j <= ref; i = j += 1) {
+ this.compile(field.chain[i]);
+ this.routine.LOAD_PROPERTY(field);
+ }
+ this.compile(field.chain[field.chain.length - 2]);
+ this.routine.PROPERTY_TYPE(field.expression);
+ }
+ } else {
+ this.compile(field.expression);
+ ref1 = field.chain;
+ for (k = 0, len = ref1.length; k < len; k++) {
+ c = ref1[k];
+ this.compile(c);
+ this.routine.LOAD_PROPERTY(field);
+ }
+ }
+ }
+
+ compileFieldParent(field) {
+ var c, i, j, ref;
+ this.compile(field.expression);
+ for (i = j = 0, ref = field.chain.length - 2; j <= ref; i = j += 1) {
+ c = field.chain[i];
+ this.compile(c);
+ this.routine.LOAD_PROPERTY(field);
+ }
+ }
+
+ compileFunctionCall(call) {
+ var a, funk, i, index, j, k, l, len, len1, len2, len3, len4, m, n, ref, ref1, ref2, ref3, ref4;
+ if (call.expression instanceof Program.Field) {
+ ref = call.args;
+ for (i = j = 0, len = ref.length; j < len; i = ++j) {
+ a = ref[i];
+ this.compile(a);
+ }
+ this.compileFieldParent(call.expression);
+ this.compile(call.expression.chain[call.expression.chain.length - 1]);
+ return this.routine.FUNCTION_APPLY_PROPERTY(call.args.length, call);
+ } else if (call.expression instanceof Program.Variable) {
+ if (Compiler.predefined_unary_functions[call.expression.identifier] != null) {
+ funk = Compiler.predefined_unary_functions[call.expression.identifier];
+ if (call.args.length > 0) {
+ this.compile(call.args[0]);
+ } else {
+ this.routine.LOAD_VALUE(0, call);
+ }
+ return this.routine.UNARY_OP(funk, call);
+ } else if (Compiler.predefined_binary_functions[call.expression.identifier] != null) {
+ funk = Compiler.predefined_binary_functions[call.expression.identifier];
+ if (call.args.length > 0) {
+ this.compile(call.args[0]);
+ } else {
+ this.routine.LOAD_VALUE(0, call);
+ }
+ if (call.args.length > 1) {
+ this.compile(call.args[1]);
+ } else {
+ this.routine.LOAD_VALUE(0, call);
+ }
+ return this.routine.BINARY_OP(funk, call);
+ } else if (call.expression.identifier === "super") {
+ ref1 = call.args;
+ for (i = k = 0, len1 = ref1.length; k < len1; i = ++k) {
+ a = ref1[i];
+ this.compile(a);
+ }
+ return this.routine.SUPER_CALL(call.args.length, call);
+ } else if (this.locals.get(call.expression.identifier) != null) {
+ ref2 = call.args;
+ for (i = l = 0, len2 = ref2.length; l < len2; i = ++l) {
+ a = ref2[i];
+ this.compile(a);
+ }
+ index = this.locals.get(call.expression.identifier);
+ this.routine.LOAD_LOCAL(index, call);
+ return this.routine.FUNCTION_CALL(call.args.length, call);
+ } else {
+ ref3 = call.args;
+ for (i = m = 0, len3 = ref3.length; m < len3; i = ++m) {
+ a = ref3[i];
+ this.compile(a);
+ }
+ this.routine.LOAD_VALUE(call.expression.identifier, call);
+ return this.routine.FUNCTION_APPLY_VARIABLE(call.args.length, call);
+ }
+ } else {
+ ref4 = call.args;
+ for (n = 0, len4 = ref4.length; n < len4; n++) {
+ a = ref4[n];
+ this.compile(a);
+ }
+ this.compile(call.expression);
+ return this.routine.FUNCTION_CALL(call.args.length, call);
+ }
+ }
+
+ compileFor(forloop) {
+ var for_continue, for_end, for_start, iterator, save_break, save_continue;
+ iterator = this.locals.register(forloop.iterator);
+ this.locals.allocate(); // range_to
+ this.locals.allocate(); // step
+ this.compile(forloop.range_from);
+ this.routine.STORE_LOCAL(iterator, forloop);
+ this.routine.POP(forloop);
+ this.compile(forloop.range_to);
+ if (forloop.range_by !== 0) {
+ this.compile(forloop.range_by);
+ } else {
+ this.routine.LOAD_VALUE(0, forloop);
+ }
+ for_start = this.routine.createLabel("for_start");
+ for_continue = this.routine.createLabel("for_continue");
+ for_end = this.routine.createLabel("for_end");
+ this.routine.FORLOOP_INIT([iterator, for_end], forloop);
+ this.routine.setLabel(for_start);
+ this.locals.push();
+ save_break = this.break_label;
+ save_continue = this.continue_label;
+ this.break_label = for_end;
+ this.continue_label = for_continue;
+ this.compileSequence(forloop.sequence);
+ this.break_label = save_break;
+ this.continue_label = save_continue;
+ this.routine.setLabel(for_continue);
+ this.routine.FORLOOP_CONTROL([iterator, for_start], forloop);
+ this.routine.setLabel(for_end);
+ return this.locals.pop();
+ }
+
+ compileForIn(forloop) {
+ var for_continue, for_end, for_start, iterator, save_break, save_continue;
+ iterator = this.locals.register(forloop.iterator);
+ this.locals.allocate(); // array
+ this.locals.allocate(); // index
+ this.compile(forloop.list);
+ for_start = this.routine.createLabel("for_start");
+ for_continue = this.routine.createLabel("for_continue");
+ for_end = this.routine.createLabel("for_end");
+ this.routine.FORIN_INIT([iterator, for_end], forloop);
+ this.routine.setLabel(for_start);
+ this.locals.push();
+ save_break = this.break_label;
+ save_continue = this.continue_label;
+ this.break_label = for_end;
+ this.continue_label = for_continue;
+ this.compileSequence(forloop.sequence);
+ this.break_label = save_break;
+ this.continue_label = save_continue;
+ this.routine.setLabel(for_continue);
+ this.routine.FORIN_CONTROL([iterator, for_start], forloop);
+ this.routine.setLabel(for_end);
+ return this.locals.pop();
+ }
+
+ compileSequence(sequence) {
+ var i, j, ref;
+ for (i = j = 0, ref = sequence.length - 1; j <= ref; i = j += 1) {
+ if (!sequence[i].nopop) {
+ this.routine.POP(sequence[i]);
+ }
+ this.compile(sequence[i]);
+ }
+ }
+
+ compileWhile(whiloop) {
+ var end, save_break, save_continue, start;
+ this.locals.push();
+ start = this.routine.createLabel("while_start");
+ end = this.routine.createLabel("while_end");
+ this.routine.LOAD_VALUE(0, whiloop);
+ this.routine.setLabel(start);
+ this.compile(whiloop.condition);
+ this.routine.JUMPN(end);
+ save_break = this.break_label;
+ save_continue = this.continue_label;
+ this.break_label = end;
+ this.continue_label = start;
+ this.compileSequence(whiloop.sequence);
+ this.routine.JUMP(start, whiloop);
+ this.break_label = save_break;
+ this.continue_label = save_continue;
+ this.routine.setLabel(end);
+ return this.locals.pop();
+ }
+
+ compileBreak(statement) {
+ if (this.break_label != null) {
+ return this.routine.JUMP(this.break_label);
+ }
+ }
+
+ compileContinue(statement) {
+ if (this.continue_label != null) {
+ return this.routine.JUMP(this.continue_label);
+ }
+ }
+
+ compileFunction(func) {
+ var r;
+ r = this.compileFunctionBody(func);
+ return this.routine.LOAD_ROUTINE(r, func);
+ }
+
+ compileFunctionBody(func) {
+ var a, args, i, index, j, k, l, label, len, local_index, locals, m, numargs, r, ref, ref1, ref2, ref3, routine;
+ routine = this.routine;
+ locals = this.locals;
+ this.routine = new Routine(func.args != null ? func.args.length : 0);
+ this.locals = new Locals(this, locals);
+ local_index = this.locals.index;
+ this.routine.uses_arguments = true;
+ if (func.args != null) {
+ if (this.routine.uses_arguments) {
+ args = this.locals.register("arguments");
+ this.routine.STORE_LOCAL(args, func);
+ this.routine.POP(func);
+ }
+ numargs = this.locals.register("+numargs");
+ this.routine.STORE_LOCAL(numargs, func);
+ this.routine.POP(func);
+ for (i = j = ref = func.args.length - 1; j >= 0; i = j += -1) {
+ a = func.args[i];
+ index = this.locals.register(a.name);
+ this.routine.STORE_LOCAL(index, func);
+ this.routine.POP(func);
+ }
+ for (i = k = 0, ref1 = func.args.length - 1; k <= ref1; i = k += 1) {
+ a = func.args[i];
+ if (a.default != null) {
+ index = this.locals.get(a.name);
+ label = this.routine.createLabel("default_arg");
+ this.routine.LOAD_VALUE(i, func);
+ this.routine.LOAD_LOCAL(numargs, func);
+ this.routine.LT(func);
+ this.routine.JUMPY(label, func);
+ this.compile(a.default);
+ this.routine.STORE_LOCAL(index, func);
+ this.routine.POP(func);
+ this.routine.setLabel(label);
+ }
+ }
+ }
+ if (func.sequence.length > 0) {
+ for (i = l = 0, ref2 = func.sequence.length - 1; l <= ref2; i = l += 1) {
+ this.compile(func.sequence[i]);
+ if (i < func.sequence.length - 1) {
+ this.routine.POP(func.sequence[i]);
+ } else {
+ this.routine.RETURN(func.sequence[i]);
+ }
+ }
+ } else {
+ this.routine.LOAD_VALUE(0, func);
+ this.routine.RETURN(func);
+ }
+ if ((func.args != null) && !this.locals.arguments_used) {
+ this.routine.uses_arguments = false;
+ this.routine.remove(0);
+ this.routine.remove(0);
+ }
+ index = 0;
+ ref3 = this.locals.imports;
+ for (m = 0, len = ref3.length; m < len; m++) {
+ i = ref3[m];
+ this.routine.OP_INSERT(OPCODES.LOAD_IMPORT, func, index, index * 3);
+ this.routine.OP_INSERT(OPCODES.STORE_LOCAL, func, i.index, index * 3 + 1);
+ this.routine.OP_INSERT(OPCODES.POP, func, 0, index * 3 + 2);
+ this.routine.import_refs.push(i.source);
+ index += 1;
+ }
+ this.routine.optimize();
+ this.routine.resolveLabels();
+ this.count += this.routine.opcodes.length;
+ r = this.routine;
+ // console.info r.toString()
+ this.routine.locals_size = this.locals.max_index;
+ this.routine = routine;
+ this.locals = locals;
+ return r;
+ }
+
+ compileReturn(ret) {
+ if (ret.expression != null) {
+ this.compile(ret.expression);
+ return this.routine.RETURN(ret);
+ } else {
+ this.routine.LOAD_VALUE(0, ret);
+ return this.routine.RETURN(ret);
+ }
+ }
+
+ compileCondition(condition) {
+ var c, chain, condition_end, condition_next, i, j, ref;
+ chain = condition.chain;
+ this.routine.LOAD_VALUE(0, condition);
+ condition_end = this.routine.createLabel("condition_end");
+ for (i = j = 0, ref = chain.length - 1; j <= ref; i = j += 1) {
+ condition_next = this.routine.createLabel("condition_next");
+ c = chain[i];
+ c.condition.nowarning = true;
+ this.compile(c.condition);
+ this.routine.JUMPN(condition_next);
+ this.locals.push();
+ this.compileSequence(c.sequence);
+ this.locals.pop();
+ this.routine.JUMP(condition_end, condition);
+ this.routine.setLabel(condition_next);
+ if (i === chain.length - 1 && (c.else != null)) {
+ this.locals.push();
+ this.compileSequence(c.else);
+ this.locals.pop();
+ }
+ }
+ this.routine.setLabel(condition_end);
+ }
+
+ formatField(field) {
+ if (field === "constructor") {
+ field = "_constructor";
+ }
+ return field.toString().replace(/"/g, "\\\"");
+ }
+
+ compileCreateObject(statement) {
+ var f, j, len, ref;
+ this.routine.CREATE_OBJECT(statement);
+ ref = statement.fields;
+ for (j = 0, len = ref.length; j < len; j++) {
+ f = ref[j];
+ this.routine.LOAD_VALUE(f.field, statement);
+ this.compile(f.value);
+ this.routine.CREATE_PROPERTY(statement);
+ }
+ }
+
+ compileCreateClass(statement) {
+ var f, j, len, ref, variable;
+ if (statement.ext != null) {
+ statement.ext.nowarning = true;
+ this.compile(statement.ext);
+ } else {
+ this.routine.LOAD_VALUE(0, statement);
+ }
+ variable = (statement.ext != null) && statement.ext instanceof Program.Variable ? statement.ext.identifier : 0;
+ this.routine.CREATE_CLASS(variable, statement);
+ ref = statement.fields;
+ for (j = 0, len = ref.length; j < len; j++) {
+ f = ref[j];
+ this.routine.LOAD_VALUE(f.field, statement);
+ this.compile(f.value);
+ this.routine.CREATE_PROPERTY(statement);
+ }
+ }
+
+ compileUpdateClass(statement, variable) {
+ this.compileCreateClass(statement);
+ return this.routine.UPDATE_CLASS(variable, statement);
+ }
+
+ compileNewCall(statement) {
+ var a, call, i, j, len, ref;
+ call = statement.expression;
+ this.routine.LOAD_VALUE(0, statement); // reserve spot on stack for the class instance
+ ref = call.args;
+ for (i = j = 0, len = ref.length; j < len; i = ++j) {
+ a = ref[i];
+ this.compile(a);
+ }
+ this.compile(call.expression);
+ this.routine.NEW_CALL(call.args.length, statement);
+ return this.routine.POP(statement); // pop return value of class constructor
+ }
+
+ compileAfter(after) {
+ var r;
+ r = this.compileFunctionBody(after);
+ this.routine.LOAD_ROUTINE(r, after);
+ this.compile(after.delay);
+ if ((after.multiplier != null) && after.multiplier !== 1) {
+ this.routine.LOAD_VALUE(after.multiplier, after);
+ this.routine.MUL(after);
+ }
+ return this.routine.AFTER(after);
+ }
+
+ compileEvery(every) {
+ var r;
+ r = this.compileFunctionBody(every);
+ this.routine.LOAD_ROUTINE(r, every);
+ this.compile(every.delay);
+ if ((every.multiplier != null) && every.multiplier !== 1) {
+ this.routine.LOAD_VALUE(every.multiplier, every);
+ this.routine.MUL(every);
+ }
+ return this.routine.EVERY(every);
+ }
+
+ compileDo(dostuff) {
+ var r;
+ r = this.compileFunctionBody(dostuff);
+ this.routine.LOAD_ROUTINE(r, dostuff);
+ return this.routine.DO(dostuff);
+ }
+
+ compileSleep(sleep) {
+ this.compile(sleep.delay);
+ if ((sleep.multiplier != null) && sleep.multiplier !== 1) {
+ this.routine.LOAD_VALUE(sleep.multiplier, sleep);
+ this.routine.MUL(sleep);
+ }
+ return this.routine.SLEEP(sleep);
+ }
+
+ compileDelete(del) {
+ var chain, i, j, ref;
+ if (del.field instanceof Program.Variable) {
+ this.routine.LOAD_THIS(del);
+ this.routine.LOAD_VALUE(del.field.identifier, del);
+ this.routine.DELETE(del);
+ } else {
+ this.compile(del.field.expression);
+ chain = del.field.chain;
+ for (i = j = 0, ref = chain.length - 1; j <= ref; i = j += 1) {
+ this.compile(chain[i]);
+ if (i < chain.length - 1) {
+ this.routine.LOAD_PROPERTY(del);
+ }
+ }
+ this.routine.DELETE(del);
+ }
+ }
+
+ exec(context) {
+ this.processor = new Processor();
+ this.processor.load(this.routine);
+ return this.processor.run(context);
+ }
+
+ };
+
+ Compiler.predefined_unary_functions = {
+ "round": Math.round,
+ "floor": Math.floor,
+ "ceil": Math.ceil,
+ "abs": Math.abs,
+ "sqrt": Math.sqrt,
+ "sin": Math.sin,
+ "cos": Math.cos,
+ "tan": Math.tan,
+ "acos": Math.acos,
+ "asin": Math.asin,
+ "atan": Math.atan,
+ "sind": function(x) {
+ return Math.sin(x * Math.PI / 180);
+ },
+ "cosd": function(x) {
+ return Math.cos(x * Math.PI / 180);
+ },
+ "tand": function(x) {
+ return Math.tan(x * Math.PI / 180);
+ },
+ "asind": function(x) {
+ return Math.asin(x) / Math.PI * 180;
+ },
+ "acosd": function(x) {
+ return Math.acos(x) / Math.PI * 180;
+ },
+ "atand": function(x) {
+ return Math.atan(x) / Math.PI * 180;
+ },
+ "log": Math.log,
+ "exp": Math.exp
+ };
+
+ Compiler.predefined_binary_functions = {
+ "min": Math.min,
+ "max": Math.max,
+ "pow": Math.pow,
+ "atan2": Math.atan2,
+ "atan2d": function(y, x) {
+ return Math.atan2(y, x) / Math.PI * 180;
+ }
+ };
+
+ Compiler.predefined_values = {
+ PI: Math.PI,
+ true: 1,
+ false: 0
+ };
+
+ return Compiler;
+
+}).call(this);
+
+this.Locals = class Locals {
+ constructor(compiler, parent = null) {
+ this.compiler = compiler;
+ this.parent = parent;
+ this.layers = [];
+ this.index = 0;
+ this.max_index = 0;
+ this.push();
+ this.imports = [];
+ }
+
+ increment() {
+ var spot;
+ spot = this.index++;
+ this.max_index = Math.max(this.index, this.max_index);
+ return spot;
+ }
+
+ push() {
+ return this.layers.push(new LocalLayer(this));
+ }
+
+ pop() {
+ // resetting the @index below was causing erasure of outer locals
+ // when used after the block ; such reset is not needed
+ //@index = @layers[@layers.length-1].start_index
+ return this.layers.splice(this.layers.length - 1, 1);
+ }
+
+ register(name) {
+ return this.layers[this.layers.length - 1].register(name);
+ }
+
+ allocate() {
+ return this.layers[this.layers.length - 1].allocate();
+ }
+
+ get(name) {
+ var i, index, j, ref, v;
+ if (name === "arguments") {
+ this.arguments_used = true;
+ }
+ for (i = j = ref = this.layers.length - 1; j >= 0; i = j += -1) {
+ v = this.layers[i].get(name);
+ if (v != null) {
+ return v;
+ }
+ }
+ if (this.parent != null) {
+ v = this.parent.get(name);
+ if (v != null) {
+ index = this.register(name);
+ this.imports.push({
+ name: name,
+ index: index,
+ source: v
+ });
+ return index;
+ }
+ }
+ return null;
+ }
+
+};
+
+LocalLayer = class LocalLayer {
+ constructor(locals1) {
+ this.locals = locals1;
+ this.start_index = this.locals.index;
+ this.registered = {};
+ }
+
+ register(name) {
+ return this.registered[name] = this.locals.increment();
+ }
+
+ allocate() {
+ return this.locals.increment();
+ }
+
+ get(name) {
+ if (this.registered[name] != null) {
+ return this.registered[name];
+ } else {
+ return null;
+ }
+ }
+
+};
diff --git a/WebGames-master/WebGames-master/games/cap/doc.md b/WebGames-master/WebGames-master/games/cap/doc.md
new file mode 100644
index 00000000..746e436e
--- /dev/null
+++ b/WebGames-master/WebGames-master/games/cap/doc.md
@@ -0,0 +1,5 @@
+Assets and gameplay from @yokoboko
+
+https://github.com/yokoboko/bas-pico-8
+
+Cube GFX from my friend @Vampirics
diff --git a/WebGames-master/WebGames-master/games/cap/fonts/BitCell.ttf b/WebGames-master/WebGames-master/games/cap/fonts/BitCell.ttf
new file mode 100644
index 00000000..7b585aa7
Binary files /dev/null and b/WebGames-master/WebGames-master/games/cap/fonts/BitCell.ttf differ
diff --git a/WebGames-master/WebGames-master/games/cap/icon1024.png b/WebGames-master/WebGames-master/games/cap/icon1024.png
new file mode 100644
index 00000000..ffae8286
Binary files /dev/null and b/WebGames-master/WebGames-master/games/cap/icon1024.png differ
diff --git a/WebGames-master/WebGames-master/games/cap/icon16.png b/WebGames-master/WebGames-master/games/cap/icon16.png
new file mode 100644
index 00000000..cd8d4157
Binary files /dev/null and b/WebGames-master/WebGames-master/games/cap/icon16.png differ
diff --git a/WebGames-master/WebGames-master/games/cap/icon180.png b/WebGames-master/WebGames-master/games/cap/icon180.png
new file mode 100644
index 00000000..3721896a
Binary files /dev/null and b/WebGames-master/WebGames-master/games/cap/icon180.png differ
diff --git a/WebGames-master/WebGames-master/games/cap/icon192.png b/WebGames-master/WebGames-master/games/cap/icon192.png
new file mode 100644
index 00000000..04226d23
Binary files /dev/null and b/WebGames-master/WebGames-master/games/cap/icon192.png differ
diff --git a/WebGames-master/WebGames-master/games/cap/icon32.png b/WebGames-master/WebGames-master/games/cap/icon32.png
new file mode 100644
index 00000000..126a1b41
Binary files /dev/null and b/WebGames-master/WebGames-master/games/cap/icon32.png differ
diff --git a/WebGames-master/WebGames-master/games/cap/icon512.png b/WebGames-master/WebGames-master/games/cap/icon512.png
new file mode 100644
index 00000000..9e6c8e69
Binary files /dev/null and b/WebGames-master/WebGames-master/games/cap/icon512.png differ
diff --git a/WebGames-master/WebGames-master/games/cap/icon64.png b/WebGames-master/WebGames-master/games/cap/icon64.png
new file mode 100644
index 00000000..739a30fc
Binary files /dev/null and b/WebGames-master/WebGames-master/games/cap/icon64.png differ
diff --git a/WebGames-master/WebGames-master/games/cap/index.html b/WebGames-master/WebGames-master/games/cap/index.html
new file mode 100644
index 00000000..1c6e4fff
--- /dev/null
+++ b/WebGames-master/WebGames-master/games/cap/index.html
@@ -0,0 +1,1419 @@
+
CubeAndSaw
\ No newline at end of file
diff --git a/WebGames-master/WebGames-master/games/cap/manifest.json b/WebGames-master/WebGames-master/games/cap/manifest.json
new file mode 100644
index 00000000..1743d4d7
--- /dev/null
+++ b/WebGames-master/WebGames-master/games/cap/manifest.json
@@ -0,0 +1,33 @@
+{
+ "name": "CubeAndSaw",
+ "short_name": "CubeAndSaw",
+ "theme_color": "#000000",
+ "background_color": "#000000",
+ "display": "fullscreen",
+ "orientation": "portrait",
+ "scope": "",
+ "start_url": ".",
+ "icons": [
+ {
+ "src": "icon192.png?v=0",
+ "type": "image/png",
+ "sizes": "192x192"
+ },
+ {
+ "src": "icon196.png?v=0",
+ "type": "image/png",
+ "sizes": "196x196",
+ "purpose": "maskable"
+ },
+ {
+ "src": "icon512.png?v=0",
+ "type": "image/png",
+ "sizes": "512x512"
+ },
+ {
+ "src": "icon1024.png?v=0",
+ "type": "image/png",
+ "sizes": "1024x1024"
+ }
+ ]
+}
diff --git a/WebGames-master/WebGames-master/games/cap/microengine.js b/WebGames-master/WebGames-master/games/cap/microengine.js
new file mode 100644
index 00000000..6625467d
--- /dev/null
+++ b/WebGames-master/WebGames-master/games/cap/microengine.js
@@ -0,0 +1,6623 @@
+CanvasRenderingContext2D.prototype.roundRect = function(x, y, w, h, r) {
+ if (w < 2 * r) {
+ r = w / 2;
+ }
+ if (h < 2 * r) {
+ r = h / 2;
+ }
+ this.beginPath();
+ this.moveTo(x + r, y);
+ this.arcTo(x + w, y, x + w, y + h, r);
+ this.arcTo(x + w, y + h, x, y + h, r);
+ this.arcTo(x, y + h, x, y, r);
+ this.arcTo(x, y, x + w, y, r);
+ return this.closePath();
+};
+
+CanvasRenderingContext2D.prototype.fillRoundRect = function(x, y, w, h, r) {
+ this.roundRect(x, y, w, h, r);
+ return this.fill();
+};
+
+CanvasRenderingContext2D.prototype.strokeRoundRect = function(x, y, w, h, r) {
+ this.roundRect(x, y, w, h, r);
+ return this.stroke();
+};
+
+var Random;
+
+Random = (function() {
+ function Random(_seed, hash) {
+ this._seed = _seed != null ? _seed : Math.random();
+ if (hash == null) {
+ hash = true;
+ }
+ if (this._seed === 0) {
+ this._seed = Math.random();
+ }
+ if (this._seed < 1) {
+ this._seed *= 1 << 30;
+ }
+ this.a = 13971;
+ this.b = 12345;
+ this.size = 1 << 30;
+ this.mask = this.size - 1;
+ this.norm = 1 / this.size;
+ if (hash) {
+ this.nextSeed();
+ this.nextSeed();
+ this.nextSeed();
+ }
+ }
+
+ Random.prototype.next = function() {
+ this._seed = (this._seed * this.a + this.b) & this.mask;
+ return this._seed * this.norm;
+ };
+
+ Random.prototype.nextInt = function(num) {
+ return Math.floor(this.next() * num);
+ };
+
+ Random.prototype.nextSeed = function() {
+ return this._seed = (this._seed * this.a + this.b) & this.mask;
+ };
+
+ Random.prototype.seed = function(_seed) {
+ this._seed = _seed != null ? _seed : Math.random();
+ if (this._seed < 1) {
+ this._seed *= 1 << 30;
+ }
+ this.nextSeed();
+ this.nextSeed();
+ return this.nextSeed();
+ };
+
+ Random.prototype.clone = function(seed) {
+ if (seed != null) {
+ return new Random(seed);
+ } else {
+ seed = this._seed;
+ return new Random(seed, false);
+ }
+ };
+
+ return Random;
+
+})();
+
+this.MPServerConnection = class MPServerConnection {
+ constructor(address) {
+ var impl;
+ this.status = "connecting";
+ impl = new MPServerConnectionImpl(this, address);
+ this.send = (data) => {
+ var err;
+ try {
+ impl.sendMessage(data);
+ return "sent";
+ } catch (error) {
+ err = error;
+ console.error(err);
+ return err.toString();
+ }
+ };
+ this.close = () => {
+ var err;
+ try {
+ return impl.close();
+ } catch (error) {
+ err = error;
+ return console.error(err);
+ }
+ };
+ this.messages = [];
+ }
+
+};
+
+this.MPServerConnectionImpl = class MPServerConnectionImpl {
+ constructor(_interface, address1) {
+ var err;
+ this.interface = _interface;
+ this.address = address1;
+ this.status = "connecting";
+ this.buffer = [];
+ if (this.address) {
+ this.connect(this.address);
+ } else {
+ try {
+ this.getRelay((address) => {
+ return this.connect(address);
+ });
+ } catch (error) {
+ err = error;
+ console.error(err);
+ }
+ }
+ this.messages = [];
+ player.runtime.addConnection(this);
+ }
+
+ getRelay(callback) {
+ return player.client.sendRequest({
+ name: "get_relay_server"
+ }, (msg) => {
+ var address;
+ if (msg.name === "error") {
+ this.interface.status = "error";
+ return this.interface.error = msg.error;
+ } else {
+ address = msg.address;
+ if (address === "self") {
+ address = location.origin.replace("http", "ws");
+ }
+ return callback(address);
+ }
+ });
+ }
+
+ connect(address) {
+ this.socket = new WebSocket(address);
+ this.socket.onmessage = (msg) => {
+ var err;
+ try {
+ msg = JSON.parse(msg.data);
+ switch (msg.name) {
+ case "mp_server_message":
+ return this.messages.push(msg.data);
+ }
+ } catch (error) {
+ err = error;
+ return console.error(err);
+ }
+ };
+ this.socket.onopen = () => {
+ var i, len, m, ref;
+ this.interface.status = "connected";
+ this.send({
+ name: "mp_client_connection",
+ server_id: ms_project_id
+ });
+ ref = this.buffer;
+ for (i = 0, len = ref.length; i < len; i++) {
+ m = ref[i];
+ this.sendMessage(m);
+ }
+ return this.buffer = [];
+ };
+ return this.socket.onclose = () => {
+ return this.interface.status = "disconnected";
+ };
+ }
+
+ update() {
+ if (this.messages.length > 0 || this.interface.messages.length > 0) {
+ this.interface.messages = this.messages;
+ return this.messages = [];
+ }
+ }
+
+ sendMessage(data) {
+ if ((this.socket != null) && this.socket.readyState === 1) {
+ return this.send({
+ name: "mp_client_message",
+ data: data
+ });
+ } else {
+ return this.buffer.push(data);
+ }
+ }
+
+ send(data) {
+ return this.socket.send(JSON.stringify(data));
+ }
+
+ close() {
+ return this.socket.close();
+ }
+
+};
+
+this.MicroVM = class MicroVM {
+ constructor(meta = {}, global = {}, namespace1 = "/microstudio", preserve_ls = false) {
+ var ctx, err;
+ this.namespace = namespace1;
+ this.preserve_ls = preserve_ls;
+ if (meta.print == null) {
+ meta.print = (text) => {
+ if (typeof text === "object" && (this.runner != null)) {
+ text = this.runner.toString(text);
+ }
+ return console.info(text);
+ };
+ }
+ Array.prototype.insert = function(e) {
+ this.splice(0, 0, e);
+ return e;
+ };
+ Array.prototype.insertAt = function(e, i) {
+ if (i >= 0 && i < this.length) {
+ this.splice(i, 0, e);
+ } else {
+ this.push(e);
+ }
+ return e;
+ };
+ Array.prototype.remove = function(i) {
+ if (i >= 0 && i < this.length) {
+ return this.splice(i, 1)[0];
+ } else {
+ return 0;
+ }
+ };
+ Array.prototype.removeAt = function(i) {
+ if (i >= 0 && i < this.length) {
+ return this.splice(i, 1)[0];
+ } else {
+ return 0;
+ }
+ };
+ Array.prototype.removeElement = function(e) {
+ var index;
+ index = this.indexOf(e);
+ if (index >= 0) {
+ return this.splice(index, 1)[0];
+ } else {
+ return 0;
+ }
+ };
+ Array.prototype.contains = function(e) {
+ if (this.indexOf(e) >= 0) {
+ return 1;
+ } else {
+ return 0;
+ }
+ };
+ meta.round = function(x) {
+ return Math.round(x);
+ };
+ meta.floor = function(x) {
+ return Math.floor(x);
+ };
+ meta.ceil = function(x) {
+ return Math.ceil(x);
+ };
+ meta.abs = function(x) {
+ return Math.abs(x);
+ };
+ meta.min = function(x, y) {
+ return Math.min(x, y);
+ };
+ meta.max = function(x, y) {
+ return Math.max(x, y);
+ };
+ meta.sqrt = function(x) {
+ return Math.sqrt(x);
+ };
+ meta.pow = function(x, y) {
+ return Math.pow(x, y);
+ };
+ meta.sin = function(x) {
+ return Math.sin(x);
+ };
+ meta.cos = function(x) {
+ return Math.cos(x);
+ };
+ meta.tan = function(x) {
+ return Math.tan(x);
+ };
+ meta.acos = function(x) {
+ return Math.acos(x);
+ };
+ meta.asin = function(x) {
+ return Math.asin(x);
+ };
+ meta.atan = function(x) {
+ return Math.atan(x);
+ };
+ meta.atan2 = function(y, x) {
+ return Math.atan2(y, x);
+ };
+ meta.sind = function(x) {
+ return Math.sin(x / 180 * Math.PI);
+ };
+ meta.cosd = function(x) {
+ return Math.cos(x / 180 * Math.PI);
+ };
+ meta.tand = function(x) {
+ return Math.tan(x / 180 * Math.PI);
+ };
+ meta.acosd = function(x) {
+ return Math.acos(x) * 180 / Math.PI;
+ };
+ meta.asind = function(x) {
+ return Math.asin(x) * 180 / Math.PI;
+ };
+ meta.atand = function(x) {
+ return Math.atan(x) * 180 / Math.PI;
+ };
+ meta.atan2d = function(y, x) {
+ return Math.atan2(y, x) * 180 / Math.PI;
+ };
+ meta.log = function(x) {
+ return Math.log(x);
+ };
+ meta.exp = function(x) {
+ return Math.exp(x);
+ };
+ meta.random = new Random(0);
+ meta.PI = Math.PI;
+ meta.true = 1;
+ meta.false = 0;
+ global.system = {
+ time: Date.now,
+ language: navigator.language,
+ update_rate: 60,
+ inputs: {
+ keyboard: 1,
+ mouse: 1,
+ touch: "ontouchstart" in window ? 1 : 0,
+ gamepad: 0
+ },
+ prompt: (text, callback) => {
+ return setTimeout((() => {
+ var args, result;
+ global.mouse.pressed = 0;
+ global.touch.touching = 0;
+ result = window.prompt(text);
+ if ((callback != null) && typeof callback === "function") {
+ args = [(result != null ? 1 : 0), result];
+ this.context.timeout = Date.now() + 1000;
+ return callback.apply(null, args);
+ }
+ }), 0);
+ },
+ say: (text) => {
+ return setTimeout((() => {
+ return window.alert(text);
+ }), 0);
+ }
+ };
+ try {
+ global.system.inputs.keyboard = window.matchMedia("(pointer:fine)").matches ? 1 : 0;
+ global.system.inputs.mouse = window.matchMedia("(any-hover:none)").matches ? 0 : 1;
+ } catch (error1) {
+ err = error1;
+ }
+ this.storage_service = this.createStorageService();
+ global.storage = this.storage_service.api;
+ meta.global = global;
+ this.context = {
+ meta: meta,
+ global: global,
+ local: global,
+ object: global,
+ breakable: 0,
+ continuable: 0,
+ returnable: 0,
+ stack_size: 0
+ };
+ ctx = this.context;
+ Array.prototype.sortList = function(f) {
+ var funk;
+ if ((f != null) && f instanceof Program.Function) {
+ funk = function(a, b) {
+ return f.call(ctx, [a, b], true);
+ };
+ } else if ((f != null) && typeof f === "function") {
+ funk = f;
+ }
+ return this.sort(funk);
+ };
+ this.clearWarnings();
+ this.runner = new Runner(this);
+ }
+
+ clearWarnings() {
+ return this.context.warnings = {
+ using_undefined_variable: {},
+ assigning_field_to_undefined: {},
+ invoking_non_function: {},
+ assigning_api_variable: {},
+ assignment_as_condition: {}
+ };
+ }
+
+ setMeta(key, value) {
+ return this.context.meta[key] = value;
+ }
+
+ setGlobal(key, value) {
+ return this.context.global[key] = value;
+ }
+
+ run(program, timeout = 3000, filename = "", callback) {
+ var err, res;
+ this.program = program;
+ this.error_info = null;
+ this.context.timeout = Date.now() + timeout;
+ this.context.stack_size = 0;
+ try {
+ res = this.runner.run(this.program, filename, callback);
+ this.storage_service.check();
+ if (res != null) {
+ return this.runner.toString(res);
+ } else {
+ return null;
+ }
+ } catch (error1) {
+ err = error1;
+ if ((err.type != null) && (err.line != null) && (err.error != null)) {
+ this.error_info = err;
+ } else if ((this.context.location != null) && (this.context.location.token != null)) {
+ this.error_info = {
+ error: this.context.location.token.error_text || err,
+ file: filename,
+ line: this.context.location.token.line,
+ column: this.context.location.token.column
+ };
+ console.info(`Error at line: ${this.context.location.token.line} column: ${this.context.location.token.column}`);
+ } else {
+ this.error_info = {
+ error: err,
+ file: filename
+ };
+ }
+ console.error(err);
+ return this.storage_service.check();
+ }
+ }
+
+ call(name, args = [], timeout = 3000) {
+ var err, res;
+ this.error_info = null;
+ this.context.timeout = Date.now() + timeout;
+ this.context.stack_size = 0;
+ try {
+ res = this.runner.call(name, args);
+ this.storage_service.check();
+ return res;
+ } catch (error1) {
+ err = error1;
+ console.error(err);
+ if ((this.context.location != null) && (this.context.location.token != null)) {
+ this.error_info = {
+ error: this.context.location.token.error_text || err,
+ line: this.context.location.token.line,
+ column: this.context.location.token.column,
+ file: this.context.location.token.file
+ };
+ } else {
+ this.error_info = {
+ error: err
+ };
+ }
+ if ((this.context.location != null) && (this.context.location.token != null)) {
+ console.info(`Error at line: ${this.context.location.token.line} column: ${this.context.location.token.column}`);
+ }
+ return this.storage_service.check();
+ }
+ }
+
+ createStorageService() {
+ var err, error, ls, namespace, s, service, storage, write_storage;
+ try {
+ ls = window.localStorage;
+ } catch (error1) {
+ error = error1; // in incognito mode, embedded by an iframe, localStorage isn't available
+ console.info("localStorage not available");
+ return service = {
+ api: {
+ set: function() {},
+ get: function() {
+ return 0;
+ }
+ },
+ check: function() {}
+ };
+ }
+ if (!this.preserve_ls) {
+ try {
+ delete window.localStorage;
+ } catch (error1) {
+ err = error1;
+ }
+ }
+ storage = {};
+ write_storage = false;
+ namespace = this.namespace;
+ try {
+ s = ls.getItem(`ms${namespace}`);
+ if (s) {
+ storage = JSON.parse(s);
+ }
+ } catch (error1) {
+ err = error1;
+ }
+ return service = {
+ api: {
+ set: (name, value) => {
+ value = this.storableObject(value);
+ if ((name != null) && (value != null)) {
+ storage[name] = value;
+ write_storage = true;
+ }
+ return value;
+ },
+ get: (name) => {
+ if (name != null) {
+ if (storage[name] != null) {
+ return storage[name];
+ } else {
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+ }
+ },
+ check: () => {
+ if (write_storage) {
+ write_storage = false;
+ try {
+ return ls.setItem(`ms${namespace}`, JSON.stringify(storage));
+ } catch (error1) {
+ err = error1;
+ }
+ }
+ }
+ };
+ }
+
+ storableObject(value) {
+ var referenced;
+ referenced = [this.context.global.screen, this.context.global.system, this.context.global.keyboard, this.context.global.audio, this.context.global.gamepad, this.context.global.touch, this.context.global.mouse, this.context.global.sprites, this.context.global.maps];
+ return this.makeStorableObject(value, referenced);
+ }
+
+ makeStorableObject(value, referenced) {
+ var i, j, key, len, res, v;
+ if (value == null) {
+ return value;
+ }
+ if (typeof value === "function" || ((typeof Program !== "undefined" && Program !== null) && value instanceof Program.Function) || ((typeof Routine !== "undefined" && Routine !== null) && value instanceof Routine)) {
+ return void 0;
+ } else if (typeof value === "object") {
+ if (referenced.indexOf(value) >= 0) {
+ return void 0;
+ }
+ referenced = referenced.slice();
+ referenced.push(value);
+ if (Array.isArray(value)) {
+ res = [];
+ for (i = j = 0, len = value.length; j < len; i = ++j) {
+ v = value[i];
+ v = this.makeStorableObject(v, referenced);
+ if (v != null) {
+ res[i] = v;
+ }
+ }
+ return res;
+ } else {
+ res = {};
+ for (key in value) {
+ v = value[key];
+ if (key === "class") {
+ continue;
+ }
+ v = this.makeStorableObject(v, referenced);
+ if (v != null) {
+ res[key] = v;
+ }
+ }
+ return res;
+ }
+ } else {
+ return value;
+ }
+ }
+
+};
+
+var arrayBufferToBase64, loadFile, loadLameJSLib, loadWaveFileLib, saveFile, writeProjectFile;
+
+this.Runtime = class Runtime {
+ constructor(url1, sources, resources, listener) {
+ this.url = url1;
+ this.sources = sources;
+ this.resources = resources;
+ this.listener = listener;
+ this.screen = new Screen(this);
+ this.audio = new AudioCore(this);
+ this.keyboard = new Keyboard();
+ this.gamepad = new Gamepad();
+ this.asset_manager = new AssetManager(this);
+ this.sprites = {};
+ this.maps = {};
+ this.sounds = {};
+ this.music = {};
+ this.assets = {};
+ this.touch = {};
+ this.mouse = this.screen.mouse;
+ this.previous_init = null;
+ this.random = new Random(0);
+ this.orientation = window.orientation;
+ this.aspect = window.aspect;
+ this.report_errors = true;
+ this.log = (text) => {
+ return this.listener.log(text);
+ };
+ this.update_memory = {};
+ this.time_machine = new TimeMachine(this);
+ this.createDropFeature();
+ window.ms_async_load = false;
+ this.connections = [];
+ }
+
+ addConnection(connection) {
+ return this.connections.push(connection);
+ }
+
+ updateSource(file, src, reinit = false) {
+ var err, init;
+ if (this.vm == null) {
+ return false;
+ }
+ if (src === this.update_memory[file]) {
+ return false;
+ }
+ this.update_memory[file] = src;
+ this.audio.cancelBeeps();
+ this.screen.clear();
+ try {
+ this.vm.run(src, 3000, file);
+ this.listener.postMessage({
+ name: "compile_success",
+ file: file
+ });
+ this.reportWarnings();
+ if (this.vm.error_info != null) {
+ err = this.vm.error_info;
+ err.type = "init";
+ err.file = file;
+ this.listener.reportError(err);
+ return false;
+ }
+ if (this.vm.runner.getFunctionSource != null) {
+ init = this.vm.runner.getFunctionSource("init");
+ if ((init != null) && init !== this.previous_init && reinit) {
+ this.previous_init = init;
+ this.vm.call("init");
+ if (this.vm.error_info != null) {
+ err = this.vm.error_info;
+ err.type = "init";
+ this.listener.reportError(err);
+ }
+ }
+ }
+ return true;
+ } catch (error) {
+ err = error;
+ if (this.report_errors) {
+ console.error(err);
+ err.file = file;
+ this.listener.reportError(err);
+ return false;
+ }
+ }
+ }
+
+ start() {
+ var a, i, j, k, key, l, len1, len2, len3, len4, len5, m, n, name, o, ref, ref1, ref2, ref3, ref4, ref5, s, value;
+ if (window.ms_async_load) {
+ this.startReady();
+ }
+ ref = this.resources.images;
+ for (j = 0, len1 = ref.length; j < len1; j++) {
+ i = ref[j];
+ s = LoadSprite(this.url + "sprites/" + i.file + "?v=" + i.version, i.properties, () => {
+ this.updateMaps();
+ return this.checkStartReady();
+ });
+ name = i.file.split(".")[0].replace(/-/g, "/");
+ s.name = name;
+ this.sprites[name] = s;
+ }
+ if (Array.isArray(this.resources.maps)) {
+ ref1 = this.resources.maps;
+ for (k = 0, len2 = ref1.length; k < len2; k++) {
+ m = ref1[k];
+ name = m.file.split(".")[0].replace(/-/g, "/");
+ this.maps[name] = LoadMap(this.url + `maps/${m.file}?v=${m.version}`, () => {
+ return this.checkStartReady();
+ });
+ this.maps[name].name = name;
+ }
+ } else if (this.resources.maps != null) {
+ if (window.player == null) {
+ window.player = this.listener;
+ }
+ ref2 = this.resources.maps;
+ for (key in ref2) {
+ value = ref2[key];
+ this.updateMap(key, 0, value);
+ }
+ }
+ ref3 = this.resources.sounds;
+ for (l = 0, len3 = ref3.length; l < len3; l++) {
+ s = ref3[l];
+ name = s.file.split(".")[0];
+ s = new Sound(this.audio, this.url + "sounds/" + s.file + "?v=" + s.version);
+ s.name = name;
+ this.sounds[name] = s;
+ }
+ ref4 = this.resources.music;
+ for (n = 0, len4 = ref4.length; n < len4; n++) {
+ m = ref4[n];
+ name = m.file.split(".")[0];
+ m = new Music(this.audio, this.url + "music/" + m.file + "?v=" + m.version);
+ m.name = name;
+ this.music[name] = m;
+ }
+ ref5 = this.resources.assets;
+ for (o = 0, len5 = ref5.length; o < len5; o++) {
+ a = ref5[o];
+ name = a.file.split(".")[0];
+ name = name.replace(/-/g, "/");
+ a.name = name;
+ this.assets[name] = a;
+ }
+ }
+
+ checkStartReady() {
+ var count, key, progress, ready, ref, ref1, value;
+ count = 0;
+ ready = 0;
+ ref = this.sprites;
+ for (key in ref) {
+ value = ref[key];
+ count += 1;
+ if (value.ready) {
+ ready += 1;
+ }
+ }
+ ref1 = this.maps;
+ for (key in ref1) {
+ value = ref1[key];
+ count += 1;
+ if (value.ready) {
+ ready += 1;
+ }
+ }
+ if (ready < count) {
+ if ((this.loading_bar_time == null) || Date.now() > this.loading_bar_time + 16) {
+ this.loading_bar_time = Date.now();
+ if (this.screen.fillRect != null) {
+ this.screen.clear();
+ this.screen.drawRect(0, 0, 100, 10, "#DDD");
+ progress = ready / count;
+ this.screen.fillRect(-(1 - progress) * 48, 0, progress * 96, 6, "#DDD");
+ }
+ if (window.ms_async_load && (this.vm != null)) {
+ this.vm.context.global.system.loading = Math.floor(ready / count * 100);
+ }
+ }
+ if (!window.ms_async_load) {
+ return;
+ }
+ } else {
+ if (window.ms_async_load && (this.vm != null)) {
+ this.vm.context.global.system.loading = 100;
+ }
+ }
+ if (!this.started) {
+ return this.startReady();
+ }
+ }
+
+ startReady() {
+ var err, file, global, init, j, len1, lib, meta, namespace, ref, ref1, src;
+ this.started = true;
+ meta = {
+ print: (text) => {
+ if ((typeof text === "object" || typeof text === "function") && (this.vm != null)) {
+ text = this.vm.runner.toString(text);
+ }
+ return this.listener.log(text);
+ }
+ };
+ global = {
+ screen: this.screen.getInterface(),
+ audio: this.audio.getInterface(),
+ keyboard: this.keyboard.keyboard,
+ gamepad: this.gamepad.status,
+ sprites: this.sprites,
+ sounds: this.sounds,
+ music: this.music,
+ assets: this.assets,
+ asset_manager: this.asset_manager.getInterface(),
+ maps: this.maps,
+ touch: this.touch,
+ mouse: this.mouse,
+ fonts: window.fonts,
+ Sound: Sound.createSoundClass(this.audio),
+ Image: msImage,
+ Sprite: Sprite,
+ Map: MicroMap
+ };
+ if (window.graphics === "M3D") {
+ global.M3D = M3D;
+ M3D.runtime = this;
+ } else if (window.graphics === "M2D") {
+ global.M2D = M2D;
+ M2D.runtime = this;
+ } else if (window.graphics.toLowerCase().startsWith("pixi")) {
+ global.PIXI = PIXI;
+ PIXI.runtime = this;
+ } else if (window.graphics.toLowerCase().startsWith("babylon")) {
+ global.BABYLON = BABYLON;
+ BABYLON.runtime = this;
+ }
+ ref = window.ms_libs;
+ for (j = 0, len1 = ref.length; j < len1; j++) {
+ lib = ref[j];
+ lib = lib.split("_")[0];
+ switch (lib) {
+ case "matterjs":
+ global.Matter = Matter;
+ break;
+ case "cannonjs":
+ global.CANNON = CANNON;
+ }
+ }
+ namespace = location.pathname;
+ this.vm = new MicroVM(meta, global, namespace, location.hash === "#transpiler");
+ if (window.ms_use_server) {
+ this.vm.context.global.ServerConnection = MPServerConnection;
+ }
+ this.vm.context.global.system.pause = () => {
+ return this.listener.codePaused();
+ };
+ this.vm.context.global.system.exit = () => {
+ return this.exit();
+ };
+ if (!window.ms_async_load) {
+ this.vm.context.global.system.loading = 100;
+ }
+ this.vm.context.global.system.disable_autofullscreen = 0;
+ this.vm.context.global.system.file = System.file;
+ this.vm.context.global.system.javascript = System.javascript;
+ if (window.ms_in_editor) {
+ this.vm.context.global.system.project = new ProjectInterface(this).interface;
+ }
+ System.runtime = this;
+ ref1 = this.sources;
+ for (file in ref1) {
+ src = ref1[file];
+ this.updateSource(file, src, false);
+ }
+ if (this.vm.runner.getFunctionSource != null) {
+ init = this.vm.runner.getFunctionSource("init");
+ if (init != null) {
+ this.previous_init = init;
+ this.vm.call("init");
+ if (this.vm.error_info != null) {
+ err = this.vm.error_info;
+ err.type = "draw";
+ this.listener.reportError(err);
+ }
+ }
+ } else {
+ this.vm.call("init");
+ if (this.vm.error_info != null) {
+ err = this.vm.error_info;
+ err.type = "draw";
+ this.listener.reportError(err);
+ }
+ }
+ this.dt = 1000 / 60;
+ this.last_time = Date.now();
+ this.current_frame = 0;
+ this.floating_frame = 0;
+ requestAnimationFrame(() => {
+ return this.timer();
+ });
+ this.screen.startControl();
+ return this.listener.postMessage({
+ name: "started"
+ });
+ }
+
+ updateMaps() {
+ var key, map, ref;
+ ref = this.maps;
+ for (key in ref) {
+ map = ref[key];
+ map.needs_update = true;
+ }
+ }
+
+ runCommand(command, callback) {
+ var err, res, warnings;
+ try {
+ warnings = this.vm.context.warnings;
+ this.vm.clearWarnings();
+ res = this.vm.run(command, void 0, void 0, callback);
+ this.reportWarnings();
+ this.vm.context.warnings = warnings;
+ if (this.vm.error_info != null) {
+ err = this.vm.error_info;
+ err.type = "exec";
+ this.listener.reportError(err);
+ }
+ this.watchStep();
+ if (callback == null) {
+ return res;
+ } else if (res != null) {
+ callback(res);
+ }
+ return null;
+ } catch (error) {
+ err = error;
+ return this.listener.reportError(err);
+ }
+ }
+
+ projectFileUpdated(type, file, version, data, properties) {
+ switch (type) {
+ case "sprites":
+ return this.updateSprite(file, version, data, properties);
+ case "maps":
+ return this.updateMap(file, version, data);
+ case "ms":
+ return this.updateCode(file, version, data);
+ }
+ }
+
+ projectFileDeleted(type, file) {
+ switch (type) {
+ case "sprites":
+ return delete this.sprites[file.substring(0, file.length - 4).replace(/-/g, "/")];
+ case "maps":
+ return delete this.maps[file.substring(0, file.length - 5).replace(/-/g, "/")];
+ }
+ }
+
+ projectOptionsUpdated(msg) {
+ this.orientation = msg.orientation;
+ this.aspect = msg.aspect;
+ return this.screen.resize();
+ }
+
+ updateSprite(name, version, data, properties) {
+ var img, slug;
+ slug = name;
+ name = name.replace(/-/g, "/");
+ if (data != null) {
+ data = "data:image/png;base64," + data;
+ if (this.sprites[name] != null) {
+ img = new Image;
+ img.crossOrigin = "Anonymous";
+ img.src = data;
+ return img.onload = () => {
+ UpdateSprite(this.sprites[name], img, properties);
+ return this.updateMaps();
+ };
+ } else {
+ this.sprites[name] = LoadSprite(data, properties, () => {
+ return this.updateMaps();
+ });
+ return this.sprites[name].name = name;
+ }
+ } else {
+ if (this.sprites[name] != null) {
+ img = new Image;
+ img.crossOrigin = "Anonymous";
+ img.src = this.url + "sprites/" + slug + `.png?v=${version}`;
+ return img.onload = () => {
+ UpdateSprite(this.sprites[name], img, properties);
+ return this.updateMaps();
+ };
+ } else {
+ this.sprites[name] = LoadSprite(this.url + "sprites/" + slug + `.png?v=${version}`, properties, () => {
+ return this.updateMaps();
+ });
+ return this.sprites[name].name = name;
+ }
+ }
+ }
+
+ updateMap(name, version, data) {
+ var m, url;
+ name = name.replace(/-/g, "/");
+ if (data != null) {
+ m = this.maps[name];
+ if (m != null) {
+ UpdateMap(m, data);
+ return m.needs_update = true;
+ } else {
+ m = new MicroMap(1, 1, 1, 1);
+ UpdateMap(m, data);
+ this.maps[name] = m;
+ return this.maps[name].name = name;
+ }
+ } else {
+ url = this.url + `maps/${name}.json?v=${version}`;
+ m = this.maps[name];
+ if (m != null) {
+ return m.loadFile(url);
+ } else {
+ this.maps[name] = LoadMap(url);
+ return this.maps[name].name = name;
+ }
+ }
+ }
+
+ updateCode(name, version, data) {
+ var req, url;
+ if (data != null) {
+ this.sources[name] = data;
+ if ((this.vm != null) && data !== this.update_memory[name]) {
+ this.vm.clearWarnings();
+ }
+ return this.updateSource(name, data, true);
+ } else {
+ url = this.url + `ms/${name}.ms?v=${version}`;
+ req = new XMLHttpRequest();
+ req.onreadystatechange = (event) => {
+ if (req.readyState === XMLHttpRequest.DONE) {
+ if (req.status === 200) {
+ this.sources[name] = req.responseText;
+ return this.updateSource(name, this.sources[name], true);
+ }
+ }
+ };
+ req.open("GET", url);
+ return req.send();
+ }
+ }
+
+ stop() {
+ this.stopped = true;
+ return this.audio.cancelBeeps();
+ }
+
+ stepForward() {
+ if (this.stopped) {
+ this.updateCall();
+ this.drawCall();
+ if (this.vm.runner.tick != null) {
+ this.vm.runner.tick();
+ }
+ return this.watchStep();
+ }
+ }
+
+ resume() {
+ if (this.stopped) {
+ this.stopped = false;
+ return requestAnimationFrame(() => {
+ return this.timer();
+ });
+ }
+ }
+
+ timer() {
+ var ds, dt, fps, i, j, ref, time, update_rate;
+ if (this.stopped) {
+ return;
+ }
+ requestAnimationFrame(() => {
+ return this.timer();
+ });
+ time = Date.now();
+ if (Math.abs(time - this.last_time) > 160) {
+ this.last_time = time - 16;
+ }
+ dt = time - this.last_time;
+ this.dt = this.dt * .9 + dt * .1;
+ this.last_time = time;
+ this.vm.context.global.system.fps = Math.round(fps = 1000 / this.dt);
+ update_rate = this.vm.context.global.system.update_rate;
+ if ((update_rate == null) || !(update_rate > 0) || !isFinite(update_rate)) {
+ update_rate = 60;
+ }
+ this.floating_frame += this.dt * update_rate / 1000;
+ ds = Math.min(10, Math.round(this.floating_frame - this.current_frame));
+ if ((ds === 0 || ds === 2) && update_rate === 60 && Math.abs(fps - 60) < 2) {
+ //console.info "INCORRECT DS: "+ds+ " floating = "+@floating_frame+" current = "+@current_frame
+ ds = 1;
+ this.floating_frame = this.current_frame + 1;
+ }
+ for (i = j = 1, ref = ds; j <= ref; i = j += 1) {
+ this.updateCall();
+ if (i < ds) {
+ if (this.vm.runner.tick != null) {
+ this.vm.runner.tick();
+ }
+ }
+ }
+ this.current_frame += ds;
+ this.drawCall();
+ if (this.vm.runner.tick != null) {
+ this.vm.runner.tick();
+ }
+ if (ds > 0) {
+ return this.watchStep();
+ }
+ }
+
+ //if ds != 1
+ // console.info "frame missed"
+ //if @current_frame%60 == 0
+ // console.info("fps: #{Math.round(1000/@dt)}")
+ updateCall() {
+ var err;
+ if (this.vm.runner.triggers_controls_update) {
+ if (this.vm.runner.updateControls == null) {
+ this.vm.runner.updateControls = () => {
+ return this.updateControls();
+ };
+ }
+ } else {
+ this.updateControls();
+ }
+ try {
+ //time = Date.now()
+ this.vm.call("update");
+ this.time_machine.step();
+ this.reportWarnings();
+ //console.info "update time: "+(Date.now()-time)
+ if (this.vm.error_info != null) {
+ err = this.vm.error_info;
+ err.type = "update";
+ return this.listener.reportError(err);
+ }
+ } catch (error) {
+ err = error;
+ if (this.report_errors) {
+ return this.listener.reportError(err);
+ }
+ }
+ }
+
+ drawCall() {
+ var err;
+ try {
+ this.screen.initDraw();
+ this.screen.updateInterface();
+ this.vm.call("draw");
+ this.reportWarnings();
+ if (this.vm.error_info != null) {
+ err = this.vm.error_info;
+ err.type = "draw";
+ return this.listener.reportError(err);
+ }
+ } catch (error) {
+ err = error;
+ if (this.report_errors) {
+ return this.listener.reportError(err);
+ }
+ }
+ }
+
+ reportWarnings() {
+ var key, ref, ref1, ref2, ref3, ref4, value;
+ if (this.vm != null) {
+ ref = this.vm.context.warnings.invoking_non_function;
+ for (key in ref) {
+ value = ref[key];
+ if (!value.reported) {
+ value.reported = true;
+ this.listener.reportError({
+ error: "",
+ type: "non_function",
+ expression: value.expression,
+ line: value.line,
+ column: value.column,
+ file: value.file
+ });
+ }
+ }
+ ref1 = this.vm.context.warnings.using_undefined_variable;
+ for (key in ref1) {
+ value = ref1[key];
+ if (!value.reported) {
+ value.reported = true;
+ this.listener.reportError({
+ error: "",
+ type: "undefined_variable",
+ expression: value.expression,
+ line: value.line,
+ column: value.column,
+ file: value.file
+ });
+ }
+ }
+ ref2 = this.vm.context.warnings.assigning_field_to_undefined;
+ for (key in ref2) {
+ value = ref2[key];
+ if (!value.reported) {
+ value.reported = true;
+ this.listener.reportError({
+ error: "",
+ type: "assigning_undefined",
+ expression: value.expression,
+ line: value.line,
+ column: value.column,
+ file: value.file
+ });
+ }
+ }
+ ref3 = this.vm.context.warnings.assigning_api_variable;
+ for (key in ref3) {
+ value = ref3[key];
+ if (!value.reported) {
+ value.reported = true;
+ this.listener.reportError({
+ error: "",
+ type: "assigning_api_variable",
+ expression: value.expression,
+ line: value.line,
+ column: value.column,
+ file: value.file
+ });
+ }
+ }
+ ref4 = this.vm.context.warnings.assignment_as_condition;
+ for (key in ref4) {
+ value = ref4[key];
+ if (!value.reported) {
+ value.reported = true;
+ this.listener.reportError({
+ error: "",
+ type: "assignment_as_condition",
+ line: value.line,
+ column: value.column,
+ file: value.file
+ });
+ }
+ }
+ }
+ }
+
+ updateControls() {
+ var c, err, j, k, key, len1, len2, ref, t, touches;
+ ref = this.connections;
+ for (j = 0, len1 = ref.length; j < len1; j++) {
+ c = ref[j];
+ c.update();
+ }
+ touches = Object.keys(this.screen.touches);
+ this.touch.touching = touches.length > 0 ? 1 : 0;
+ this.touch.touches = [];
+ for (k = 0, len2 = touches.length; k < len2; k++) {
+ key = touches[k];
+ t = this.screen.touches[key];
+ this.touch.x = t.x;
+ this.touch.y = t.y;
+ this.touch.touches.push({
+ x: t.x,
+ y: t.y,
+ id: key
+ });
+ }
+ if (this.mouse.pressed && !this.previous_mouse_pressed) {
+ this.previous_mouse_pressed = true;
+ this.mouse.press = 1;
+ } else {
+ this.mouse.press = 0;
+ }
+ if (!this.mouse.pressed && this.previous_mouse_pressed) {
+ this.previous_mouse_pressed = false;
+ this.mouse.release = 1;
+ } else {
+ this.mouse.release = 0;
+ }
+ this.mouse.wheel = this.screen.wheel || 0;
+ this.screen.wheel = 0;
+ if (this.touch.touching && !this.previous_touch) {
+ this.previous_touch = true;
+ this.touch.press = 1;
+ } else {
+ this.touch.press = 0;
+ }
+ if (!this.touch.touching && this.previous_touch) {
+ this.previous_touch = false;
+ this.touch.release = 1;
+ } else {
+ this.touch.release = 0;
+ }
+ this.vm.context.global.system.file.dropped = 0;
+ if (this.files_dropped != null) {
+ this.vm.context.global.system.file.dropped = this.files_dropped;
+ delete this.files_dropped;
+ }
+ this.vm.context.global.system.file.loaded = 0;
+ if (this.files_loaded != null) {
+ this.vm.context.global.system.file.loaded = this.files_loaded;
+ delete this.files_loaded;
+ }
+ this.gamepad.update();
+ this.keyboard.update();
+ try {
+ this.vm.context.global.system.inputs.gamepad = this.gamepad.count > 0 ? 1 : 0;
+ } catch (error) {
+ err = error;
+ }
+ }
+
+ getAssetURL(asset) {
+ return this.url + "assets/" + asset + ".glb";
+ }
+
+ getWatcher() {
+ return this.watcher || (this.watcher = new Watcher(this));
+ }
+
+ watch(variables) {
+ return this.getWatcher().watch(variables);
+ }
+
+ watchStep() {
+ return this.getWatcher().step();
+ }
+
+ stopWatching() {
+ return this.getWatcher().stop();
+ }
+
+ exit() {
+ var err;
+ this.stop();
+ if (this.screen.clear != null) {
+ setTimeout((() => {
+ return this.screen.clear();
+ }), 1);
+ }
+ try {
+ // microStudio embedded exit
+ this.listener.exit();
+ } catch (error) {
+ err = error;
+ }
+ try {
+ // TODO: Cordova exit, this might work
+ if ((navigator.app != null) && (navigator.app.exitApp != null)) {
+ navigator.app.exitApp();
+ }
+ } catch (error) {
+ err = error;
+ }
+ try {
+ // TODO: Electron exit, may already be covered by window.close()
+
+ // Windowed mode exit
+ return window.close();
+ } catch (error) {
+ err = error;
+ }
+ }
+
+ createDropFeature() {
+ document.addEventListener("dragenter", (event) => {
+ return event.stopPropagation();
+ });
+ document.addEventListener("dragleave", (event) => {
+ return event.stopPropagation();
+ });
+ document.addEventListener("dragover", (event) => {
+ event.preventDefault();
+ if (player.runtime.screen.mouseMove != null) {
+ return player.runtime.screen.mouseMove(event);
+ }
+ });
+ return document.addEventListener("drop", (event) => {
+ var err, file, files, i, index, j, len1, list, processFile, ref, result;
+ event.preventDefault();
+ event.stopPropagation();
+ try {
+ list = [];
+ files = [];
+ ref = event.dataTransfer.items;
+ for (j = 0, len1 = ref.length; j < len1; j++) {
+ i = ref[j];
+ if (i.kind === "file") {
+ file = i.getAsFile();
+ files.push(file);
+ }
+ }
+ result = [];
+ index = 0;
+ processFile = function() {
+ var f;
+ if (index < files.length) {
+ f = files[index++];
+ return loadFile(f, function(data) {
+ result.push({
+ name: f.name,
+ size: f.size,
+ content: data,
+ file_type: f.type
+ });
+ return processFile();
+ });
+ } else {
+ player.runtime.files_dropped = result;
+ if (typeof window.dropHandler === "function") {
+ return window.dropHandler(result);
+ }
+ }
+ };
+ return processFile();
+ } catch (error) {
+ err = error;
+ return console.error(err);
+ }
+ });
+ }
+
+};
+
+saveFile = function(data, name, type) {
+ var a, blob, url;
+ a = document.createElement("a");
+ document.body.appendChild(a);
+ a.style = "display: none";
+ blob = new Blob([data], {
+ type: type
+ });
+ url = window.URL.createObjectURL(blob);
+ a.href = url;
+ a.download = name;
+ a.click();
+ return window.URL.revokeObjectURL(url);
+};
+
+loadWaveFileLib = function(callback) {
+ var s;
+ if (typeof wavefile !== "undefined" && wavefile !== null) {
+ return callback();
+ } else {
+ s = document.createElement("script");
+ s.src = location.origin + "/lib/wavefile/wavefile.js";
+ document.head.appendChild(s);
+ return s.onload = function() {
+ return callback();
+ };
+ }
+};
+
+loadLameJSLib = function(callback) {
+ var s;
+ if (typeof lamejs !== "undefined" && lamejs !== null) {
+ return callback();
+ } else {
+ s = document.createElement("script");
+ s.src = location.origin + "/lib/lamejs/lame.min.js";
+ document.head.appendChild(s);
+ return s.onload = function() {
+ return callback();
+ };
+ }
+};
+
+writeProjectFile = function(name, data, thumb) {
+ return window.player.postMessage({
+ name: "write_project_file",
+ filename: name,
+ content: data,
+ thumbnail: thumb
+ });
+};
+
+arrayBufferToBase64 = function(buffer) {
+ var binary, bytes, i, j, len, ref;
+ binary = '';
+ bytes = new Uint8Array(buffer);
+ len = bytes.byteLength;
+ for (i = j = 0, ref = len - 1; j <= ref; i = j += 1) {
+ binary += String.fromCharCode(bytes[i]);
+ }
+ return window.btoa(binary);
+};
+
+loadFile = function(file, callback) {
+ var fr;
+ switch (file.type) {
+ case "image/png":
+ case "image/jpeg":
+ fr = new FileReader;
+ fr.onload = function() {
+ var img;
+ img = new Image;
+ img.onload = function() {
+ var image;
+ image = new msImage(img);
+ return callback(image);
+ };
+ return img.src = fr.result;
+ };
+ return fr.readAsDataURL(file);
+ case "audio/wav":
+ case "audio/x-wav":
+ case "audio/mp3":
+ fr = new FileReader;
+ fr.onload = function() {
+ return player.runtime.audio.getContext().decodeAudioData(fr.result, function(buffer) {
+ return callback(new Sound(player.runtime.audio, buffer));
+ });
+ };
+ return fr.readAsArrayBuffer(file);
+ case "application/json":
+ fr = new FileReader;
+ fr.onload = function() {
+ var err, object;
+ object = fr.result;
+ try {
+ object = JSON.parse(fr.result);
+ } catch (error) {
+ err = error;
+ }
+ return callback(object);
+ };
+ return fr.readAsText(file);
+ default:
+ fr = new FileReader;
+ fr.onload = function() {
+ return callback(fr.result);
+ };
+ return fr.readAsText(file);
+ }
+};
+
+this.System = {
+ javascript: function(s) {
+ var err, f, res;
+ try {
+ f = eval(`res = function(global) { ${s} }`);
+ res = f.call(player.runtime.vm.context.global, player.runtime.vm.context.global);
+ } catch (error) {
+ err = error;
+ console.error(err);
+ }
+ if (res != null) {
+ return res;
+ } else {
+ return 0;
+ }
+ },
+ file: {
+ save: function(obj, name, format, options) {
+ var a, c;
+ if (obj instanceof MicroSound) {
+ return loadWaveFileLib(function() {
+ var buffer, ch, ch1, ch2, i, j, k, ref, ref1, wav;
+ wav = new wavefile.WaveFile;
+ ch1 = [];
+ for (i = j = 0, ref = obj.length - 1; j <= ref; i = j += 1) {
+ ch1[i] = Math.round(Math.min(1, Math.max(-1, obj.read(0, i))) * 32767);
+ }
+ if (obj.channels === 2) {
+ ch2 = [];
+ for (i = k = 0, ref1 = obj.length - 1; k <= ref1; i = k += 1) {
+ ch2[i] = Math.round(Math.min(1, Math.max(-1, obj.read(1, i))) * 32767);
+ }
+ ch = [ch1, ch2];
+ } else {
+ ch = [ch1];
+ }
+ wav.fromScratch(ch.length, obj.sampleRate, '16', ch);
+ buffer = wav.toBuffer();
+ if (typeof name !== "string") {
+ name = "sound.wav";
+ } else if (!name.endsWith(".wav")) {
+ name += ".wav";
+ }
+ return saveFile(buffer, name, "octet/stream");
+ });
+ } else if (obj instanceof msImage) {
+ c = obj.canvas;
+ if (typeof name !== "string") {
+ name = "image";
+ }
+ format = typeof format === "string" && format.toLowerCase() === "jpg" ? "jpg" : "png";
+ if (!name.endsWith(`.${format}`)) {
+ name += `.${format}`;
+ }
+ a = document.createElement("a");
+ document.body.appendChild(a);
+ a.style = "display: none";
+ return c.toBlob(((blob) => {
+ var url;
+ url = window.URL.createObjectURL(blob);
+ a.href = url;
+ a.download = name;
+ a.click();
+ return window.URL.revokeObjectURL(url);
+ }), (format === "png" ? "image/png" : "image/jpeg"), options);
+ } else if (typeof obj === "object") {
+ obj = System.runtime.vm.storableObject(obj);
+ obj = JSON.stringify(obj, null, 2);
+ if (typeof name !== "string") {
+ name = "data";
+ }
+ if (!name.endsWith(".json")) {
+ name += ".json";
+ }
+ return saveFile(obj, name, "text/json");
+ } else if (typeof obj === "string") {
+ if (typeof name !== "string") {
+ name = "text";
+ }
+ if (!name.endsWith(".txt")) {
+ name += ".txt";
+ }
+ return saveFile(obj, name, "text/plain");
+ }
+ },
+ load: function(options, callback) {
+ var extensions, i, input, j, ref;
+ if (typeof options === "string" || Array.isArray(options)) {
+ extensions = options;
+ } else {
+ extensions = options.extensions || null;
+ }
+ input = document.createElement("input");
+ if (options.multiple) {
+ input.multiple = true;
+ }
+ input.type = "file";
+ if (typeof extensions === "string") {
+ input.accept = `.${extensions}`;
+ } else if (Array.isArray(extensions)) {
+ for (i = j = 0, ref = extensions.length - 1; (0 <= ref ? j <= ref : j >= ref); i = 0 <= ref ? ++j : --j) {
+ extensions[i] = `.${extensions[i]}`;
+ }
+ input.accept = extensions.join(",");
+ }
+ input.addEventListener("change", (event) => {
+ var files, index, processFile, result;
+ files = event.target.files;
+ result = [];
+ index = 0;
+ processFile = function() {
+ var f;
+ if (index < files.length) {
+ f = files[index++];
+ return loadFile(f, function(data) {
+ result.push({
+ name: f.name,
+ size: f.size,
+ content: data,
+ file_type: f.type
+ });
+ return processFile();
+ });
+ } else {
+ player.runtime.files_loaded = result;
+ if (typeof callback === "function") {
+ return callback(result);
+ }
+ }
+ };
+ return processFile();
+ });
+ return input.click();
+ },
+ setDropHandler: function(handler) {
+ return window.dropHandler = handler;
+ }
+ }
+};
+
+this.Watcher = class Watcher {
+ constructor(runtime) {
+ this.runtime = runtime;
+ this.vm = this.runtime.vm;
+ }
+
+ update() {
+ if (this.watching_variables) {
+ return this.step();
+ }
+ }
+
+ watch(variables) {
+ this.watching = true;
+ this.watching_variables = variables;
+ this.exclusion_list = [this.vm.context.global.screen, this.vm.context.global.system, this.vm.context.global.keyboard, this.vm.context.global.audio, this.vm.context.global.gamepad, this.vm.context.global.touch, this.vm.context.global.mouse, this.vm.context.global.sprites, this.vm.context.global.maps, this.vm.context.global.sounds, this.vm.context.global.music, this.vm.context.global.assets, this.vm.context.global.asset_manager, this.vm.context.global.fonts, this.vm.context.global.storage];
+ if (this.vm.context.global.Function != null) {
+ this.exclusion_list.push(this.vm.context.global.Function);
+ }
+ if (this.vm.context.global.String != null) {
+ this.exclusion_list.push(this.vm.context.global.String);
+ }
+ if (this.vm.context.global.List != null) {
+ this.exclusion_list.push(this.vm.context.global.List);
+ }
+ if (this.vm.context.global.Number != null) {
+ this.exclusion_list.push(this.vm.context.global.Number);
+ }
+ if (this.vm.context.global.Object != null) {
+ this.exclusion_list.push(this.vm.context.global.Object);
+ }
+ if (this.vm.context.global.Image != null) {
+ this.exclusion_list.push(this.vm.context.global.Image);
+ }
+ if (this.vm.context.global.Sound != null) {
+ this.exclusion_list.push(this.vm.context.global.Sound);
+ }
+ if (this.vm.context.global.Sprite != null) {
+ this.exclusion_list.push(this.vm.context.global.Sprite);
+ }
+ if (this.vm.context.global.Map != null) {
+ this.exclusion_list.push(this.vm.context.global.Map);
+ }
+ if (this.vm.context.global.random != null) {
+ this.exclusion_list.push(this.vm.context.global.random);
+ }
+ if (this.vm.context.global.print != null) {
+ this.exclusion_list.push(this.vm.context.global.print);
+ }
+ return this.step();
+ }
+
+ stop() {
+ return this.watching = false;
+ }
+
+ step(variables = this.watching_variables) {
+ var index, j, len, res, v, value, vs;
+ if (!this.watching) {
+ return;
+ }
+ res = {};
+ for (j = 0, len = variables.length; j < len; j++) {
+ v = variables[j];
+ if (v === "global") {
+ value = this.vm.context.global;
+ } else {
+ vs = v.split(".");
+ value = this.vm.context.global;
+ index = 0;
+ while (index < vs.length && (value != null)) {
+ value = value[vs[index++]];
+ }
+ }
+ if ((value != null) && this.exclusion_list.indexOf(value) < 0) {
+ res[v] = this.exploreValue(value, 1, 10);
+ }
+ }
+ return this.runtime.listener.postMessage({
+ name: "watch_update",
+ data: res
+ });
+ }
+
+ exploreValue(value, depth = 1, array_max = 10) {
+ var i, j, key, len, res, v;
+ if (value == null) {
+ return {
+ type: "number",
+ value: 0
+ };
+ }
+ if (typeof value === "function" || value instanceof Program.Function || (typeof Routine !== "undefined" && Routine !== null) && value instanceof Routine) {
+ return {
+ type: "function",
+ value: ""
+ };
+ } else if (typeof value === "object") {
+ if (Array.isArray(value)) {
+ if (depth === 0) {
+ return {
+ type: "list",
+ value: "",
+ length: value.length
+ };
+ }
+ res = [];
+ for (i = j = 0, len = value.length; j < len; i = ++j) {
+ v = value[i];
+ if (i >= 100) {
+ break;
+ }
+ if (this.exclusion_list.indexOf(v) < 0) {
+ res[i] = this.exploreValue(v, depth - 1, array_max);
+ }
+ }
+ return res;
+ } else {
+ if (depth === 0) {
+ v = "";
+ if (value.classname) {
+ v = "class " + value.classname;
+ }
+ if ((value.class != null) && (value.class.classname != null)) {
+ v = value.class.classname;
+ }
+ return {
+ type: "object",
+ value: v
+ };
+ }
+ res = {};
+ for (key in value) {
+ v = value[key];
+ if (this.exclusion_list.indexOf(v) < 0) {
+ res[key] = this.exploreValue(v, depth - 1, array_max);
+ }
+ }
+ return res;
+ }
+ } else if (typeof value === "string") {
+ return {
+ type: "string",
+ value: value.length < 43 ? value : value.substring(0, 40) + "..."
+ };
+ } else if (typeof value === "number") {
+ return {
+ type: "number",
+ value: isFinite(value) ? value : 0
+ };
+ } else if (typeof value === "boolean") {
+ return {
+ type: "number",
+ value: value ? 1 : 0
+ };
+ } else {
+ return {
+ type: "unknown",
+ value: value
+ };
+ }
+ }
+
+};
+
+this.ProjectInterface = class ProjectInterface {
+ constructor(runtime) {
+ this.runtime = runtime;
+ this.interface = {
+ listFiles: (path, callback) => {
+ return this.listFiles(path, callback);
+ },
+ readFile: (path, callback) => {
+ return this.readFile(path, callback);
+ },
+ writeFile: (path, obj, options, callback) => {
+ return this.writeFile(path, obj, options, callback);
+ },
+ deleteFile: (path, callback) => {
+ return this.deleteFile(path, callback);
+ }
+ };
+ }
+
+ callback(callback, data, res, error) {
+ if (error != null) {
+ res.error = error;
+ res.ready = 1;
+ if (typeof callback === "function") {
+ return callback(0, error);
+ }
+ } else {
+ res.data = data;
+ res.ready = 1;
+ if (typeof callback === "function") {
+ return callback(data);
+ }
+ }
+ }
+
+ writeFile(path, obj, options, callback) {
+ var kind;
+ kind = path.split("/")[0];
+ switch (kind) {
+ case "source":
+ return this.writeSourceFile(obj, path, options, callback);
+ case "sprites":
+ return this.writeSpriteFile(obj, path, options, callback);
+ case "maps":
+ return this.writeMapFile(obj, path, options, callback);
+ case "sounds":
+ return this.writeSoundFile(obj, path, options, callback);
+ case "music":
+ return this.writeMusicFile(obj, path, options, callback);
+ case "assets":
+ return this.writeAssetFile(obj, path, options, callback);
+ default:
+ return callback(0, `Root folder ${kind} does not exist`);
+ }
+ }
+
+ writeSourceFile(obj, path, options, callback) {
+ var msg, res;
+ res = {
+ ready: 0
+ };
+ if (typeof obj !== "string") {
+ this.callback(callback, 0, res, "Incorrect object type, expected string");
+ } else {
+ msg = {
+ name: "write_project_file",
+ path: path,
+ content: obj,
+ options: options
+ };
+ this.runtime.listener.postRequest(msg, (result) => {
+ return this.callback(callback, result.content, res, result.error);
+ });
+ }
+ return res;
+ }
+
+ writeSpriteFile(obj, path, options, callback) {
+ var canvas, context, fps, frames, i, j, msg, ref, res;
+ res = {
+ ready: 0
+ };
+ if (obj instanceof msImage) {
+ msg = {
+ name: "write_project_file",
+ path: path,
+ content: obj.canvas.toDataURL().split(",")[1],
+ options: options
+ };
+ this.runtime.listener.postRequest(msg, (result) => {
+ return this.callback(callback, result.content, res, result.error);
+ });
+ } else if (obj instanceof Sprite) {
+ fps = obj.fps;
+ if (obj.frames.length === 1) {
+ canvas = obj.frames[0].canvas;
+ frames = 1;
+ } else {
+ canvas = document.createElement("canvas");
+ canvas.width = obj.width;
+ canvas.height = obj.height * obj.frames.length;
+ context = canvas.getContext("2d");
+ for (i = j = 0, ref = obj.frames.length - 1; (0 <= ref ? j <= ref : j >= ref); i = 0 <= ref ? ++j : --j) {
+ context.drawImage(obj.frames[i].canvas, 0, i * obj.height);
+ }
+ frames = obj.frames.length;
+ }
+ msg = {
+ name: "write_project_file",
+ path: path,
+ content: canvas.toDataURL().split(",")[1],
+ fps: fps,
+ frames: frames,
+ options: options
+ };
+ this.runtime.listener.postRequest(msg, (result) => {
+ return this.callback(callback, result.content, res, result.error);
+ });
+ } else {
+ this.callback(callback, 0, res, "Incorrect object type, expected Image or Sprite");
+ }
+ return res;
+ }
+
+ writeMapFile(obj, path, options, callback) {
+ var msg, res;
+ res = {
+ ready: 0
+ };
+ if (obj instanceof MicroMap) {
+ msg = {
+ name: "write_project_file",
+ path: path,
+ content: SaveMap(obj),
+ options: options
+ };
+ this.runtime.listener.postRequest(msg, (result) => {
+ return this.callback(callback, result.content, res, result.error);
+ });
+ } else {
+ this.callback(callback, 0, res, "Incorrect object type, expected Map");
+ }
+ return res;
+ }
+
+ writeSoundFile(obj, path, options, callback) {
+ var res;
+ res = {
+ ready: 0
+ };
+ if (obj instanceof MicroSound) {
+ loadWaveFileLib(() => {
+ var buffer, ch, ch1, ch2, encoded, i, j, k, msg, ref, ref1, wav;
+ wav = new wavefile.WaveFile;
+ ch1 = [];
+ for (i = j = 0, ref = obj.length - 1; j <= ref; i = j += 1) {
+ ch1[i] = Math.round(Math.min(1, Math.max(-1, obj.read(0, i))) * 32767);
+ }
+ if (obj.channels === 2) {
+ ch2 = [];
+ for (i = k = 0, ref1 = obj.length - 1; k <= ref1; i = k += 1) {
+ ch2[i] = Math.round(Math.min(1, Math.max(-1, obj.read(1, i))) * 32767);
+ }
+ ch = [ch1, ch2];
+ } else {
+ ch = [ch1];
+ }
+ wav.fromScratch(ch.length, obj.sampleRate, '16', ch);
+ buffer = wav.toBuffer();
+ encoded = arrayBufferToBase64(buffer);
+ msg = {
+ name: "write_project_file",
+ path: path,
+ content: encoded,
+ options: options
+ };
+ return this.runtime.listener.postRequest(msg, (result) => {
+ return this.callback(callback, result.content, res, result.error);
+ });
+ });
+ } else {
+ this.callback(callback, 0, res, "Incorrect object type, expected Sound");
+ }
+ return res;
+ }
+
+ writeMusicFile(obj, path, options, callback) {
+ var res;
+ res = {
+ ready: 0
+ };
+ if (obj instanceof MicroSound) {
+ loadLameJSLib(() => {
+ var blob, fr, i, index, j, k, kbps, l, m, mp3Data, mp3buf, mp3encoder, ref, ref1, ref2, ref3, ref4, ref5, sampleBlockSize, samples, samplesR, toindex;
+ kbps = 128;
+ mp3encoder = new lamejs.Mp3Encoder(obj.channels, obj.sampleRate, kbps);
+ index = 0;
+ sampleBlockSize = 1152;
+ samples = new Int16Array(sampleBlockSize);
+ samplesR = new Int16Array(sampleBlockSize);
+ mp3Data = [];
+ while (index < obj.length) {
+ toindex = Math.min(sampleBlockSize - 1, obj.length - index - 1);
+ for (i = j = 0, ref = toindex; j <= ref; i = j += 1) {
+ samples[i] = Math.round(32767 * Math.max(-1, Math.min(1, obj.read(0, index + i))));
+ }
+ if (obj.channels === 2) {
+ for (i = k = 0, ref1 = toindex; k <= ref1; i = k += 1) {
+ samplesR[i] = Math.round(32767 * Math.max(-1, Math.min(1, obj.read(1, index + i))));
+ }
+ }
+ for (i = l = ref2 = toindex + 1, ref3 = sampleBlockSize - 1; l <= ref3; i = l += 1) {
+ samples[i] = 0;
+ }
+ if (obj.channels === 2) {
+ for (i = m = ref4 = toindex + 1, ref5 = sampleBlockSize - 1; m <= ref5; i = m += 1) {
+ samplesR[i] = 0;
+ }
+ }
+ index += sampleBlockSize;
+ if (obj.channels === 2) {
+ mp3buf = mp3encoder.encodeBuffer(samples, samplesR);
+ } else {
+ mp3buf = mp3encoder.encodeBuffer(samples);
+ }
+ if (mp3buf.length > 0) {
+ mp3Data.push(mp3buf);
+ }
+ }
+ mp3buf = mp3encoder.flush();
+ if (mp3buf.length > 0) {
+ mp3Data.push(mp3buf);
+ }
+ blob = new Blob(mp3Data, {
+ type: 'audio/mp3'
+ });
+ fr = new FileReader();
+ fr.onload = (e) => {
+ var msg;
+ msg = {
+ name: "write_project_file",
+ path: path,
+ content: fr.result.split(",")[1],
+ options: options
+ };
+ return this.runtime.listener.postRequest(msg, (result) => {
+ return this.callback(callback, result.content, res, result.error);
+ });
+ };
+ return fr.readAsDataURL(blob);
+ });
+ } else {
+ this.callback(callback, 0, res, "Incorrect object type, expected Sound");
+ }
+ return res;
+ }
+
+ writeAssetFile(obj, path, options, callback) {
+ var err, ext, mime, msg, ref, ref1, res;
+ res = {
+ ready: 0
+ };
+ if (obj instanceof msImage || obj instanceof Sprite) {
+ if (obj instanceof Sprite) {
+ obj = obj.frames[0];
+ }
+ if ((ref = options.ext) === "jpg" || ref === "png") {
+ ext = options.ext;
+ } else {
+ ext = "png";
+ }
+ mime = ext === "jpg" ? "image/jpeg" : "image/png";
+ msg = {
+ name: "write_project_file",
+ path: path,
+ content: obj.canvas.toDataURL(mime),
+ ext: ext,
+ options: options
+ };
+ this.runtime.listener.postRequest(msg, (result) => {
+ return this.callback(callback, result.content, res, result.error);
+ });
+ } else if (typeof obj === "string") {
+ if ((ref1 = options.ext) === "txt" || ref1 === "csv" || ref1 === "obj" || ref1 === "json" || ref1 === "md") {
+ ext = options.ext;
+ } else {
+ ext = "txt";
+ }
+ if (ext === "json" && typeof obj === "string") {
+ try {
+ obj = JSON.parse(obj);
+ } catch (error1) {
+ err = error1;
+ }
+ }
+ msg = {
+ name: "write_project_file",
+ path: path,
+ content: obj,
+ ext: ext,
+ options: options
+ };
+ this.runtime.listener.postRequest(msg, (result) => {
+ return this.callback(callback, result.content, res, result.error);
+ });
+ } else if (typeof obj === "object") {
+ obj = this.runtime.vm.storableObject(obj);
+ msg = {
+ name: "write_project_file",
+ path: path,
+ content: obj,
+ ext: "json",
+ options: options
+ };
+ this.runtime.listener.postRequest(msg, (result) => {
+ return this.callback(callback, result.content, res, result.error);
+ });
+ } else {
+ this.callback(callback, 0, res, "Unrecognized object type");
+ }
+ return res;
+ }
+
+ listFiles(path, callback) {
+ var msg, res;
+ msg = {
+ name: "list_project_files",
+ path: path
+ };
+ res = {
+ ready: 0
+ };
+ this.runtime.listener.postRequest(msg, function(result) {
+ res.ready = 1;
+ if (result.list) {
+ res.list = result.list;
+ }
+ if (result.error) {
+ res.error = result.error;
+ }
+ if (typeof callback === "function") {
+ return callback(result.list, result.error);
+ }
+ });
+ return res;
+ }
+
+ readFile(path, callback) {
+ var kind, msg, res;
+ msg = {
+ name: "read_project_file",
+ path: path
+ };
+ res = {
+ ready: 0
+ };
+ kind = path.split("/")[0];
+ this.runtime.listener.postRequest(msg, (result) => {
+ var img, map, s;
+ res.ready = 1;
+ if (result.error) {
+ res.error = result.error;
+ if (typeof callback === "function") {
+ return callback(0, result.error);
+ }
+ } else {
+ switch (kind) {
+ case "sprites":
+ s = LoadSprite(result.content.data, {
+ fps: result.content.fps,
+ frames: result.content.frames
+ }, () => {
+ res.result = s;
+ if (typeof callback === "function") {
+ return callback(res.result, 0);
+ }
+ });
+ break;
+ case "maps":
+ map = new MicroMap(1, 1, 1, 1);
+ UpdateMap(map, result.content);
+ res.result = map;
+ if (typeof callback === "function") {
+ callback(res.result, 0);
+ }
+ break;
+ case "sounds":
+ case "music":
+ s = new Sound(this.runtime.audio, result.content);
+ res.result = s;
+ if (typeof callback === "function") {
+ callback(s, 0);
+ }
+ break;
+ case "assets":
+ switch (result.content.type) {
+ case "text":
+ res.result = result.content.data;
+ callback(res.result, 0);
+ break;
+ case "json":
+ res.result = result.content.data;
+ callback(res.result, 0);
+ break;
+ case "image":
+ img = new Image;
+ img.src = result.content.data;
+ img.onload = () => {
+ var image;
+ image = new msImage(img);
+ res.result = image;
+ return callback(res.result, 0);
+ };
+ }
+ break;
+ default:
+ res.result = result.content.toString();
+ if (typeof callback === "function") {
+ return callback(res.result, 0);
+ }
+ }
+ }
+ });
+ return res;
+ }
+
+ deleteFile(path, callback) {
+ var msg, res;
+ msg = {
+ name: "delete_project_file",
+ path: path
+ };
+ res = {
+ ready: 0
+ };
+ this.runtime.listener.postRequest(msg, function(result) {
+ res.ready = 1;
+ res.result = result.content || 0;
+ if (result.error) {
+ res.error = result.error;
+ }
+ if (typeof callback === "function") {
+ return callback(res.result, result.error);
+ }
+ });
+ return res;
+ }
+
+};
+
+this.TimeMachine = class TimeMachine {
+ constructor(runtime) {
+ this.runtime = runtime;
+ this.history = [];
+ this.record_index = 0;
+ this.replay_position = 0;
+ this.recording = false;
+ this.max_length = 60 * 30;
+ this.record_length = 0;
+ this.loop_length = 60 * 4;
+ }
+
+ step() {
+ var end, err, histo, i, index, j, ref, ref1, start;
+ if (this.recording) {
+ try {
+ if (this.replay_position !== 0) {
+ histo = [];
+ start = this.record_length;
+ end = this.replay_position + 1;
+ for (i = j = ref = start, ref1 = end; j >= ref1; i = j += -1) {
+ index = (this.record_index - i + this.max_length) % this.max_length;
+ histo.push(this.history[index]);
+ }
+ if (this.looping) {
+ this.loop_start = this.loop_length;
+ }
+ this.history = histo;
+ this.record_index = this.history.length;
+ this.record_length = this.history.length;
+ this.replay_position = 0;
+ }
+ this.history[this.record_index++] = this.storableHistory(this.runtime.vm.context.global);
+ this.record_length = Math.min(this.record_length + 1, this.max_length);
+ if (this.record_index >= this.max_length) {
+ this.record_index = 0;
+ }
+ return this.sendStatus();
+ } catch (error) {
+ err = error;
+ return console.error(err);
+ }
+ }
+ }
+
+ messageReceived(data) {
+ var pos;
+ switch (data.command) {
+ case "start_recording":
+ if (!this.recording) {
+ this.recording = true;
+ this.record_index = 0;
+ this.replay_position = 0;
+ this.record_length = 0;
+ this.history = [];
+ return this.sendStatus();
+ }
+ break;
+ case "stop_recording":
+ if (this.recording) {
+ this.recording = false;
+ return this.sendStatus();
+ }
+ break;
+ case "step_backward":
+ return this.stepBackward();
+ case "step_forward":
+ return this.stepForward();
+ case "replay_position":
+ pos = Math.round(data.position);
+ this.replay_position = Math.max(2, Math.min(this.record_length - 1, pos));
+ if (this.looping) {
+ this.loop_start = this.replay_position;
+ this.loop_index = 0;
+ }
+ this.replay();
+ return this.sendStatus();
+ case "start_looping":
+ if (this.record_length === 0) {
+ return;
+ }
+ this.looping = true;
+ this.recording = false;
+ this.loop_start = Math.max(this.replay_position, 1);
+ this.loop_index = 0;
+ return this.loop();
+ case "stop_looping":
+ return this.stopLooping();
+ }
+ }
+
+ stopLooping() {
+ if (this.looping) {
+ this.looping = false;
+ this.replay_position = this.loop_start;
+ return this.sendStatus();
+ }
+ }
+
+ loop() {
+ if (!this.looping) {
+ return;
+ }
+ requestAnimationFrame(() => {
+ return this.loop();
+ });
+ if (this.loop_index === 0) {
+ this.replay_position = this.loop_start;
+ this.replay(true);
+ this.loop_index += 1;
+ } else {
+ this.loop_index += 1;
+ if (this.loop_index > this.loop_length) {
+ this.loop_index = 0;
+ }
+ this.replay_position = this.loop_start - this.loop_index;
+ this.replayControls();
+ this.runtime.updateCall();
+ this.runtime.drawCall();
+ this.runtime.watchStep();
+ this.resetControls();
+ }
+ return this.sendStatus();
+ }
+
+ stepBackward() {
+ if (this.replay_position + 1 >= this.record_length) {
+ return;
+ }
+ this.stopLooping();
+ this.replay_position += 1;
+ this.replay();
+ return this.sendStatus();
+ }
+
+ stepForward() {
+ if (this.replay_position <= 1) {
+ return;
+ }
+ this.stopLooping();
+ this.replay_position--;
+ this.replay();
+ return this.sendStatus();
+ }
+
+ replayControls() {
+ var index;
+ if (this.replay_position >= this.record_length) {
+ return;
+ }
+ if (this.replay_position <= 0) {
+ return;
+ }
+ index = (this.record_index - this.replay_position + this.max_length) % this.max_length;
+ this.copyGlobal(this.history[index].keyboard, this.runtime.vm.context.global.keyboard);
+ this.copyGlobal(this.history[index].gamepad, this.runtime.vm.context.global.gamepad);
+ this.copyGlobal(this.history[index].touch, this.runtime.vm.context.global.touch);
+ return this.copyGlobal(this.history[index].mouse, this.runtime.vm.context.global.mouse);
+ }
+
+ resetControls() {
+ var mouse, touch;
+ this.runtime.keyboard.reset();
+ touch = this.runtime.vm.context.global.touch;
+ touch.touching = 0;
+ touch.touches = [];
+ mouse = this.runtime.vm.context.global.mouse;
+ mouse.pressed = 0;
+ mouse.left = 0;
+ mouse.right = 0;
+ return mouse.middle = 0;
+ }
+
+ replay(clone = false) {
+ var index;
+ index = (this.record_index - this.replay_position + this.max_length) % this.max_length;
+ this.copyGlobal((clone ? this.storableHistory(this.history[index]) : this.history[index]), this.runtime.vm.context.global);
+ //@runtime.vm.context.global = if clone then @storableHistory(@history[index]) else @history[index]
+ //@runtime.vm.context.meta.global = @runtime.vm.context.global
+ //@runtime.vm.context.object = @runtime.vm.context.global
+ //@runtime.vm.context.local = @runtime.vm.context.global
+ this.runtime.vm.call("draw");
+ if (this.runtime.vm.runner.tick != null) {
+ this.runtime.vm.runner.tick();
+ }
+ return this.runtime.watchStep();
+ }
+
+ copyGlobal(source, dest) {
+ var key, value;
+ for (key in source) {
+ value = source[key];
+ if (key === "keyboard" || key === "gamepad" || key === "touch" || key === "mouse") {
+ continue;
+ }
+ if (((typeof Routine === "undefined" || Routine === null) || !(value instanceof Routine)) && !(value instanceof Program.Function) && typeof value !== "function" && (value.classname == null)) {
+ dest[key] = value;
+ }
+ }
+ for (key in dest) {
+ if (source[key] == null) {
+ delete dest[key];
+ }
+ }
+ }
+
+ sendStatus() {
+ return this.runtime.listener.postMessage({
+ name: "time_machine",
+ command: "status",
+ length: this.record_length,
+ head: this.record_length - this.replay_position,
+ max: this.max_length
+ });
+ }
+
+ storableHistory(value) {
+ var clones, global, refs;
+ global = this.runtime.vm.context.global;
+ this.excluded = [
+ global.screen,
+ global.system,
+ //global.keyboard
+ global.audio,
+ //global.gamepad
+ //global.touch
+ //global.mouse
+ global.sprites,
+ global.maps,
+ global.sounds,
+ global.music,
+ global.assets,
+ global.asset_manager,
+ global.fonts,
+ global.storage,
+ window
+ ];
+ if (global.PIXI != null) {
+ // for key,value of window
+ // @excluded.push value
+ this.excluded.push(global.PIXI);
+ }
+ if (global.BABYLON != null) {
+ this.excluded.push(global.BABYLON);
+ }
+ if (global.M2D != null) {
+ this.excluded.push(global.M2D);
+ }
+ if (global.M3D != null) {
+ this.excluded.push(global.M3D);
+ }
+ if (global.Matter != null) {
+ this.excluded.push(global.Matter);
+ }
+ if (global.CANNON != null) {
+ this.excluded.push(global.CANNON);
+ }
+ if (global.Object != null) {
+ this.excluded.push(global.Object);
+ }
+ if (global.List != null) {
+ this.excluded.push(global.List);
+ }
+ if (global.String != null) {
+ this.excluded.push(global.String);
+ }
+ if (global.Number != null) {
+ this.excluded.push(global.Number);
+ }
+ if (global.Function != null) {
+ this.excluded.push(global.Function);
+ }
+ if (global.random != null) {
+ this.excluded.push(global.random);
+ }
+ refs = [];
+ clones = [];
+ return this.makeStorableObject(value, refs, clones);
+ }
+
+ makeStorableObject(value, refs, clones) {
+ var i, index, j, key, len, res, v;
+ if (value == null) {
+ return value;
+ }
+ if (typeof value === "function" || value instanceof Program.Function || (typeof Routine !== "undefined" && Routine !== null) && value instanceof Routine) {
+ return value;
+ } else if (typeof value === "object") {
+ if (this.excluded.indexOf(value) >= 0) {
+ return value;
+ }
+ if (value instanceof Sprite || value instanceof MicroMap || value instanceof msImage || value instanceof MicroSound) {
+ return value;
+ }
+ if (value.classname != null) {
+ return value;
+ }
+ index = refs.indexOf(value);
+ if (index >= 0) {
+ return clones[index];
+ }
+ if (Array.isArray(value)) {
+ res = [];
+ refs.push(value);
+ clones.push(res);
+ for (i = j = 0, len = value.length; j < len; i = ++j) {
+ v = value[i];
+ v = this.makeStorableObject(v, refs, clones);
+ if (v != null) {
+ res[i] = v;
+ }
+ }
+ return res;
+ } else {
+ res = {};
+ refs.push(value);
+ clones.push(res);
+ for (key in value) {
+ v = value[key];
+ v = this.makeStorableObject(v, refs, clones);
+ if (v != null) {
+ res[key] = v;
+ }
+ }
+ return res;
+ }
+ } else {
+ return value;
+ }
+ }
+
+};
+
+this.Screen = class Screen {
+ constructor(runtime) {
+ this.runtime = runtime;
+ this.canvas = document.createElement("canvas");
+ this.canvas.width = 1080;
+ this.canvas.height = 1920;
+ this.touches = {};
+ this.mouse = {
+ x: -10000,
+ y: -10000,
+ pressed: 0,
+ left: 0,
+ middle: 0,
+ right: 0,
+ wheel: 0
+ };
+ this.alpha = 1;
+ this.pixelated = 1;
+ this.line_width = 1;
+ this.translation_x = 0;
+ this.translation_y = 0;
+ this.rotation = 0;
+ this.scale_x = 1;
+ this.scale_y = 1;
+ this.screen_transform = false;
+ this.object_rotation = 0;
+ this.object_scale_x = 1;
+ this.object_scale_y = 1;
+ this.anchor_x = 0;
+ this.anchor_y = 0;
+ this.supersampling = this.previous_supersampling = 1;
+ this.font = "BitCell";
+ this.font_load_requested = {};
+ this.font_loaded = {};
+ this.loadFont(this.font);
+ this.initContext();
+ this.cursor = "default";
+ this.canvas.addEventListener("mousemove", () => {
+ this.last_mouse_move = Date.now();
+ if (this.cursor !== "default" && this.cursor_visibility === "auto") {
+ this.cursor = "default";
+ return this.canvas.style.cursor = "default";
+ }
+ });
+ // when the context is lost and then restored, base transform needs to be reinstated.
+ this.canvas.addEventListener("contextrestored", () => {
+ return this.initContext();
+ });
+ setInterval((() => {
+ return this.checkMouseCursor();
+ }), 1000);
+ this.cursor_visibility = "auto";
+ }
+
+ checkMouseCursor() {
+ if (Date.now() > this.last_mouse_move + 4000 && this.cursor_visibility === "auto") {
+ if (this.cursor !== "none") {
+ this.cursor = "none";
+ return this.canvas.style.cursor = "none";
+ }
+ }
+ }
+
+ setCursorVisible(visible) {
+ this.cursor_visibility = visible;
+ if (visible) {
+ this.cursor = "default";
+ return this.canvas.style.cursor = "default";
+ } else {
+ this.cursor = "none";
+ return this.canvas.style.cursor = "none";
+ }
+ }
+
+ initContext() {
+ var b, c, j, len1, ratio, ref;
+ c = this.canvas.getContext("2d", {
+ alpha: false
+ });
+ if (c !== this.context) {
+ this.context = c;
+ } else {
+ this.context.restore();
+ }
+ this.context.save();
+ this.context.translate(this.canvas.width / 2, this.canvas.height / 2);
+ ratio = Math.min(this.canvas.width / 200, this.canvas.height / 200);
+ this.context.scale(ratio, ratio);
+ this.width = this.canvas.width / ratio;
+ this.height = this.canvas.height / ratio;
+ // @translation_x = 0
+ // @translation_y = 0
+ // @rotation = 0
+ // @scale_x = 1
+ // @scale_y = 1
+ // @screen_transform = false
+ this.context.lineCap = "round";
+ this.blending = {
+ normal: "source-over",
+ additive: "lighter"
+ };
+ ref = ["source-over", "source-in", "source-out", "source-atop", "destination-over", "destination-in", "destination-out", "destination-atop", "lighter", "copy", "xor", "multiply", "screen", "overlay", "darken", "lighten", "color-dodge", "color-burn", "hard-light", "soft-light", "difference", "exclusion", "hue", "saturation", "color", "luminosity"];
+ for (j = 0, len1 = ref.length; j < len1; j++) {
+ b = ref[j];
+ this.blending[b] = b;
+ }
+ }
+
+ getInterface() {
+ var screen;
+ if (this.interface != null) {
+ return this.interface;
+ }
+ screen = this;
+ return this.interface = {
+ width: this.width,
+ height: this.height,
+ clear: function(color) {
+ return screen.clear(color);
+ },
+ setColor: function(color) {
+ return screen.setColor(color);
+ },
+ setAlpha: function(alpha) {
+ return screen.setAlpha(alpha);
+ },
+ setPixelated: function(pixelated) {
+ return screen.setPixelated(pixelated);
+ },
+ setBlending: function(blending) {
+ return screen.setBlending(blending);
+ },
+ setLinearGradient: function(x1, y1, x2, y2, c1, c2) {
+ return screen.setLinearGradient(x1, y1, x2, y2, c1, c2);
+ },
+ setRadialGradient: function(x, y, radius, c1, c2) {
+ return screen.setRadialGradient(x, y, radius, c1, c2);
+ },
+ setFont: function(font) {
+ return screen.setFont(font);
+ },
+ setTranslation: function(tx, ty) {
+ return screen.setTranslation(tx, ty);
+ },
+ setScale: function(x, y) {
+ return screen.setScale(x, y);
+ },
+ setRotation: function(rotation) {
+ return screen.setRotation(rotation);
+ },
+ setDrawAnchor: function(ax, ay) {
+ return screen.setDrawAnchor(ax, ay);
+ },
+ setDrawRotation: function(rotation) {
+ return screen.setDrawRotation(rotation);
+ },
+ setDrawScale: function(x, y) {
+ return screen.setDrawScale(x, y);
+ },
+ fillRect: function(x, y, w, h, c) {
+ return screen.fillRect(x, y, w, h, c);
+ },
+ fillRoundRect: function(x, y, w, h, r, c) {
+ return screen.fillRoundRect(x, y, w, h, r, c);
+ },
+ fillRound: function(x, y, w, h, c) {
+ return screen.fillRound(x, y, w, h, c);
+ },
+ drawRect: function(x, y, w, h, c) {
+ return screen.drawRect(x, y, w, h, c);
+ },
+ drawRoundRect: function(x, y, w, h, r, c) {
+ return screen.drawRoundRect(x, y, w, h, r, c);
+ },
+ drawRound: function(x, y, w, h, c) {
+ return screen.drawRound(x, y, w, h, c);
+ },
+ drawSprite: function(sprite, x, y, w, h) {
+ return screen.drawSprite(sprite, x, y, w, h);
+ },
+ drawImage: function(sprite, x, y, w, h) {
+ return screen.drawSprite(sprite, x, y, w, h);
+ },
+ drawSpritePart: function(sprite, sx, sy, sw, sh, x, y, w, h) {
+ return screen.drawSpritePart(sprite, sx, sy, sw, sh, x, y, w, h);
+ },
+ drawImagePart: function(sprite, sx, sy, sw, sh, x, y, w, h) {
+ return screen.drawSpritePart(sprite, sx, sy, sw, sh, x, y, w, h);
+ },
+ drawMap: function(map, x, y, w, h) {
+ return screen.drawMap(map, x, y, w, h);
+ },
+ drawText: function(text, x, y, size, color) {
+ return screen.drawText(text, x, y, size, color);
+ },
+ drawTextOutline: function(text, x, y, size, color) {
+ return screen.drawTextOutline(text, x, y, size, color);
+ },
+ textWidth: function(text, size) {
+ return screen.textWidth(text, size);
+ },
+ setLineWidth: function(width) {
+ return screen.setLineWidth(width);
+ },
+ setLineDash: function(dash) {
+ return screen.setLineDash(dash);
+ },
+ drawLine: function(x1, y1, x2, y2, color) {
+ return screen.drawLine(x1, y1, x2, y2, color);
+ },
+ drawPolygon: function() {
+ return screen.drawPolygon(arguments);
+ },
+ drawPolyline: function() {
+ return screen.drawPolyline(arguments);
+ },
+ fillPolygon: function() {
+ return screen.fillPolygon(arguments);
+ },
+ drawQuadCurve: function() {
+ return screen.drawQuadCurve(arguments);
+ },
+ drawBezierCurve: function() {
+ return screen.drawBezierCurve(arguments);
+ },
+ drawArc: function(x, y, radius, angle1, angle2, ccw, color) {
+ return screen.drawArc(x, y, radius, angle1, angle2, ccw, color);
+ },
+ fillArc: function(x, y, radius, angle1, angle2, ccw, color) {
+ return screen.fillArc(x, y, radius, angle1, angle2, ccw, color);
+ },
+ setCursorVisible: function(visible) {
+ return screen.setCursorVisible(visible);
+ },
+ loadFont: function(font) {
+ return screen.loadFont(font);
+ },
+ isFontReady: function(font) {
+ return screen.isFontReady(font);
+ }
+ };
+ }
+
+ updateInterface() {
+ this.interface.width = this.width;
+ return this.interface.height = this.height;
+ }
+
+ clear(color) {
+ var blending_save, c, s;
+ c = this.context.fillStyle;
+ s = this.context.strokeStyle;
+ blending_save = this.context.globalCompositeOperation;
+ this.context.globalAlpha = 1;
+ this.context.globalCompositeOperation = "source-over";
+ if (color != null) {
+ this.setColor(color);
+ } else {
+ this.context.fillStyle = "#000";
+ }
+ this.context.fillRect(-this.width / 2, -this.height / 2, this.width, this.height);
+ this.context.fillStyle = c;
+ this.context.strokeStyle = s;
+ return this.context.globalCompositeOperation = blending_save;
+ }
+
+ initDraw() {
+ this.alpha = 1;
+ this.line_width = 1;
+ if (this.supersampling !== this.previous_supersampling) {
+ this.resize();
+ return this.previous_supersampling = this.supersampling;
+ }
+ }
+
+ setColor(color) {
+ var b, c, g, r;
+ if (color == null) {
+ return;
+ }
+ if (!Number.isNaN(Number.parseInt(color))) {
+ r = (Math.floor(color / 100) % 10) / 9 * 255;
+ g = (Math.floor(color / 10) % 10) / 9 * 255;
+ b = (Math.floor(color) % 10) / 9 * 255;
+ c = 0xFF000000;
+ c += r << 16;
+ c += g << 8;
+ c += b;
+ c = "#" + c.toString(16).substring(2, 8);
+ this.context.fillStyle = c;
+ return this.context.strokeStyle = c;
+ } else if (typeof color === "string") {
+ this.context.fillStyle = color;
+ return this.context.strokeStyle = color;
+ }
+ }
+
+ setAlpha(alpha1) {
+ this.alpha = alpha1;
+ }
+
+ setPixelated(pixelated1) {
+ this.pixelated = pixelated1;
+ }
+
+ setBlending(blending) {
+ blending = this.blending[blending || "normal"] || "source-over";
+ return this.context.globalCompositeOperation = blending;
+ }
+
+ setLineWidth(line_width) {
+ this.line_width = line_width;
+ }
+
+ setLineDash(dash) {
+ if (!Array.isArray(dash)) {
+ return this.context.setLineDash([]);
+ } else {
+ return this.context.setLineDash(dash);
+ }
+ }
+
+ setLinearGradient(x1, y1, x2, y2, c1, c2) {
+ var grd;
+ grd = this.context.createLinearGradient(x1, -y1, x2, -y2);
+ grd.addColorStop(0, c1);
+ grd.addColorStop(1, c2);
+ this.context.fillStyle = grd;
+ return this.context.strokeStyle = grd;
+ }
+
+ setRadialGradient(x, y, radius, c1, c2) {
+ var grd;
+ grd = this.context.createRadialGradient(x, -y, 0, x, -y, radius);
+ grd.addColorStop(0, c1);
+ grd.addColorStop(1, c2);
+ this.context.fillStyle = grd;
+ return this.context.strokeStyle = grd;
+ }
+
+ setFont(font) {
+ this.font = font || "Verdana";
+ return this.loadFont(this.font);
+ }
+
+ loadFont(font = "BitCell") {
+ var err;
+ if (!this.font_load_requested[font]) {
+ this.font_load_requested[font] = true;
+ try {
+ if ((document.fonts != null) && (document.fonts.load != null)) {
+ document.fonts.load(`16pt ${font}`);
+ }
+ } catch (error) {
+ err = error;
+ }
+ }
+ return 1;
+ }
+
+ isFontReady(font = this.font) {
+ var err, res;
+ if (this.font_loaded[font]) {
+ return 1;
+ }
+ try {
+ if ((document.fonts != null) && (document.fonts.check != null)) {
+ res = document.fonts.check(`16pt ${font}`);
+ if (res) {
+ this.font_loaded[font] = res;
+ }
+ if (res) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ } catch (error) {
+ err = error;
+ }
+ return 1;
+ }
+
+ setTranslation(translation_x, translation_y) {
+ this.translation_x = translation_x;
+ this.translation_y = translation_y;
+ if (!isFinite(this.translation_x)) {
+ this.translation_x = 0;
+ }
+ if (!isFinite(this.translation_y)) {
+ this.translation_y = 0;
+ }
+ return this.updateScreenTransform();
+ }
+
+ setScale(scale_x, scale_y) {
+ this.scale_x = scale_x;
+ this.scale_y = scale_y;
+ if (!isFinite(this.scale_x) || this.scale_x === 0) {
+ this.scale_x = 1;
+ }
+ if (!isFinite(this.scale_y) || this.scale_y === 0) {
+ this.scale_y = 1;
+ }
+ return this.updateScreenTransform();
+ }
+
+ setRotation(rotation1) {
+ this.rotation = rotation1;
+ if (!isFinite(this.rotation)) {
+ this.rotation = 0;
+ }
+ return this.updateScreenTransform();
+ }
+
+ updateScreenTransform() {
+ return this.screen_transform = this.translation_x !== 0 || this.translation_y !== 0 || this.scale_x !== 1 || this.scale_y !== 1 || this.rotation !== 0;
+ }
+
+ setDrawAnchor(anchor_x, anchor_y) {
+ this.anchor_x = anchor_x;
+ this.anchor_y = anchor_y;
+ if (typeof this.anchor_x !== "number") {
+ this.anchor_x = 0;
+ }
+ if (typeof this.anchor_y !== "number") {
+ return this.anchor_y = 0;
+ }
+ }
+
+ setDrawRotation(object_rotation) {
+ this.object_rotation = object_rotation;
+ }
+
+ setDrawScale(object_scale_x, object_scale_y = this.object_scale_x) {
+ this.object_scale_x = object_scale_x;
+ this.object_scale_y = object_scale_y;
+ }
+
+ initDrawOp(x, y, object_transform = true) {
+ var res;
+ res = false;
+ if (this.screen_transform) {
+ this.context.save();
+ res = true;
+ this.context.translate(this.translation_x, -this.translation_y);
+ this.context.scale(this.scale_x, this.scale_y);
+ this.context.rotate(-this.rotation / 180 * Math.PI);
+ this.context.translate(x, y);
+ }
+ if (object_transform && (this.object_rotation !== 0 || this.object_scale_x !== 1 || this.object_scale_y !== 1)) {
+ if (!res) {
+ this.context.save();
+ res = true;
+ this.context.translate(x, y);
+ }
+ if (this.object_rotation !== 0) {
+ this.context.rotate(-this.object_rotation / 180 * Math.PI);
+ }
+ if (this.object_scale_x !== 1 || this.object_scale_y !== 1) {
+ this.context.scale(this.object_scale_x, this.object_scale_y);
+ }
+ }
+ return res;
+ }
+
+ closeDrawOp(x, y) {
+ //if @object_scale_x != 1 or @object_scale_y != 1
+ // @context.scale 1/@object_scale_x,1/@object_scale_y
+
+ //if @object_rotation != 0
+ // @context.rotate -@object_rotation/180*Math.PI
+ //@context.translate -x,-y
+ return this.context.restore();
+ }
+
+ fillRect(x, y, w, h, color) {
+ this.setColor(color);
+ this.context.globalAlpha = this.alpha;
+ if (this.initDrawOp(x, -y)) {
+ this.context.fillRect(-w / 2 - this.anchor_x * w / 2, -h / 2 + this.anchor_y * h / 2, w, h);
+ return this.closeDrawOp(x, -y);
+ } else {
+ return this.context.fillRect(x - w / 2 - this.anchor_x * w / 2, -y - h / 2 + this.anchor_y * h / 2, w, h);
+ }
+ }
+
+ fillRoundRect(x, y, w, h, round = 10, color) {
+ this.setColor(color);
+ this.context.globalAlpha = this.alpha;
+ if (this.initDrawOp(x, -y)) {
+ this.context.fillRoundRect(-w / 2 - this.anchor_x * w / 2, -h / 2 + this.anchor_y * h / 2, w, h, round);
+ return this.closeDrawOp(x, -y);
+ } else {
+ return this.context.fillRoundRect(x - w / 2 - this.anchor_x * w / 2, -y - h / 2 + this.anchor_y * h / 2, w, h, round);
+ }
+ }
+
+ fillRound(x, y, w, h, color) {
+ this.setColor(color);
+ this.context.globalAlpha = this.alpha;
+ w = Math.abs(w);
+ h = Math.abs(h);
+ if (this.initDrawOp(x, -y)) {
+ this.context.beginPath();
+ this.context.ellipse(-this.anchor_x * w / 2, 0 + this.anchor_y * h / 2, w / 2, h / 2, 0, 0, Math.PI * 2, false);
+ this.context.fill();
+ return this.closeDrawOp(x, -y);
+ } else {
+ this.context.beginPath();
+ this.context.ellipse(x - this.anchor_x * w / 2, -y + this.anchor_y * h / 2, w / 2, h / 2, 0, 0, Math.PI * 2, false);
+ return this.context.fill();
+ }
+ }
+
+ drawRect(x, y, w, h, color) {
+ this.setColor(color);
+ this.context.globalAlpha = this.alpha;
+ this.context.lineWidth = this.line_width;
+ if (this.initDrawOp(x, -y)) {
+ this.context.strokeRect(-w / 2 - this.anchor_x * w / 2, -h / 2 + this.anchor_y * h / 2, w, h);
+ return this.closeDrawOp(x, -y);
+ } else {
+ return this.context.strokeRect(x - w / 2 - this.anchor_x * w / 2, -y - h / 2 + this.anchor_y * h / 2, w, h);
+ }
+ }
+
+ drawRoundRect(x, y, w, h, round = 10, color) {
+ this.setColor(color);
+ this.context.globalAlpha = this.alpha;
+ this.context.lineWidth = this.line_width;
+ if (this.initDrawOp(x, -y)) {
+ this.context.strokeRoundRect(-w / 2 - this.anchor_x * w / 2, -h / 2 + this.anchor_y * h / 2, w, h, round);
+ return this.closeDrawOp(x, -y);
+ } else {
+ return this.context.strokeRoundRect(x - w / 2 - this.anchor_x * w / 2, -y - h / 2 + this.anchor_y * h / 2, w, h, round);
+ }
+ }
+
+ drawRound(x, y, w, h, color) {
+ this.setColor(color);
+ this.context.globalAlpha = this.alpha;
+ this.context.lineWidth = this.line_width;
+ w = Math.abs(w);
+ h = Math.abs(h);
+ if (this.initDrawOp(x, -y)) {
+ this.context.beginPath();
+ this.context.ellipse(0 - this.anchor_x * w / 2, 0 + this.anchor_y * h / 2, w / 2, h / 2, 0, 0, Math.PI * 2, false);
+ this.context.stroke();
+ return this.closeDrawOp(x, -y);
+ } else {
+ this.context.beginPath();
+ this.context.ellipse(x - this.anchor_x * w / 2, -y + this.anchor_y * h / 2, w / 2, h / 2, 0, 0, Math.PI * 2, false);
+ return this.context.stroke();
+ }
+ }
+
+ drawLine(x1, y1, x2, y2, color) {
+ var transform;
+ this.setColor(color);
+ this.context.globalAlpha = this.alpha;
+ this.context.lineWidth = this.line_width;
+ transform = this.initDrawOp(0, 0, false);
+ this.context.beginPath();
+ this.context.moveTo(x1, -y1);
+ this.context.lineTo(x2, -y2);
+ this.context.stroke();
+ if (transform) {
+ return this.closeDrawOp();
+ }
+ }
+
+ drawPolyline(args) {
+ var i, j, len, ref, transform;
+ if (args.length > 0 && args.length % 2 === 1 && typeof args[args.length - 1] === "string") {
+ this.setColor(args[args.length - 1]);
+ }
+ if (Array.isArray(args[0])) {
+ if ((args[1] != null) && typeof args[1] === "string") {
+ this.setColor(args[1]);
+ }
+ args = args[0];
+ }
+ this.context.globalAlpha = this.alpha;
+ this.context.lineWidth = this.line_width;
+ if (args.length < 4) {
+ return;
+ }
+ len = Math.floor(args.length / 2);
+ transform = this.initDrawOp(0, 0, false);
+ this.context.beginPath();
+ this.context.moveTo(args[0], -args[1]);
+ for (i = j = 1, ref = len - 1; (1 <= ref ? j <= ref : j >= ref); i = 1 <= ref ? ++j : --j) {
+ this.context.lineTo(args[i * 2], -args[i * 2 + 1]);
+ }
+ this.context.stroke();
+ if (transform) {
+ return this.closeDrawOp();
+ }
+ }
+
+ drawPolygon(args) {
+ var i, j, len, ref, transform;
+ if (args.length > 0 && args.length % 2 === 1 && typeof args[args.length - 1] === "string") {
+ this.setColor(args[args.length - 1]);
+ }
+ if (Array.isArray(args[0])) {
+ if ((args[1] != null) && typeof args[1] === "string") {
+ this.setColor(args[1]);
+ }
+ args = args[0];
+ }
+ this.context.globalAlpha = this.alpha;
+ this.context.lineWidth = this.line_width;
+ if (args.length < 4) {
+ return;
+ }
+ len = Math.floor(args.length / 2);
+ transform = this.initDrawOp(0, 0, false);
+ this.context.beginPath();
+ this.context.moveTo(args[0], -args[1]);
+ for (i = j = 1, ref = len - 1; (1 <= ref ? j <= ref : j >= ref); i = 1 <= ref ? ++j : --j) {
+ this.context.lineTo(args[i * 2], -args[i * 2 + 1]);
+ }
+ this.context.closePath();
+ this.context.stroke();
+ if (transform) {
+ return this.closeDrawOp();
+ }
+ }
+
+ fillPolygon(args) {
+ var i, j, len, ref, transform;
+ if (args.length > 0 && args.length % 2 === 1 && typeof args[args.length - 1] === "string") {
+ this.setColor(args[args.length - 1]);
+ }
+ if (Array.isArray(args[0])) {
+ if ((args[1] != null) && typeof args[1] === "string") {
+ this.setColor(args[1]);
+ }
+ args = args[0];
+ }
+ this.context.globalAlpha = this.alpha;
+ this.context.lineWidth = this.line_width;
+ if (args.length < 4) {
+ return;
+ }
+ len = Math.floor(args.length / 2);
+ transform = this.initDrawOp(0, 0, false);
+ this.context.beginPath();
+ this.context.moveTo(args[0], -args[1]);
+ for (i = j = 1, ref = len - 1; (1 <= ref ? j <= ref : j >= ref); i = 1 <= ref ? ++j : --j) {
+ this.context.lineTo(args[i * 2], -args[i * 2 + 1]);
+ }
+ this.context.fill();
+ if (transform) {
+ return this.closeDrawOp();
+ }
+ }
+
+ drawQuadCurve(args) {
+ var index, len, transform;
+ if (args.length > 0 && args.length % 2 === 1 && typeof args[args.length - 1] === "string") {
+ this.setColor(args[args.length - 1]);
+ }
+ if (Array.isArray(args[0])) {
+ if ((args[1] != null) && typeof args[1] === "string") {
+ this.setColor(args[1]);
+ }
+ args = args[0];
+ }
+ this.context.globalAlpha = this.alpha;
+ this.context.lineWidth = this.line_width;
+ if (args.length < 4) {
+ return;
+ }
+ len = Math.floor(args.length / 2);
+ transform = this.initDrawOp(0, 0, false);
+ this.context.beginPath();
+ this.context.moveTo(args[0], -args[1]);
+ index = 2;
+ while (index <= args.length - 4) {
+ this.context.quadraticCurveTo(args[index], -args[index + 1], args[index + 2], -args[index + 3]);
+ index += 4;
+ }
+ this.context.stroke();
+ if (transform) {
+ return this.closeDrawOp();
+ }
+ }
+
+ drawBezierCurve(args) {
+ var index, len, transform;
+ if (args.length > 0 && args.length % 2 === 1 && typeof args[args.length - 1] === "string") {
+ this.setColor(args[args.length - 1]);
+ }
+ if (Array.isArray(args[0])) {
+ if ((args[1] != null) && typeof args[1] === "string") {
+ this.setColor(args[1]);
+ }
+ args = args[0];
+ }
+ this.context.globalAlpha = this.alpha;
+ this.context.lineWidth = this.line_width;
+ if (args.length < 4) {
+ return;
+ }
+ len = Math.floor(args.length / 2);
+ transform = this.initDrawOp(0, 0, false);
+ this.context.beginPath();
+ this.context.moveTo(args[0], -args[1]);
+ index = 2;
+ while (index <= args.length - 6) {
+ this.context.bezierCurveTo(args[index], -args[index + 1], args[index + 2], -args[index + 3], args[index + 4], -args[index + 5]);
+ index += 6;
+ }
+ this.context.stroke();
+ if (transform) {
+ return this.closeDrawOp();
+ }
+ }
+
+ drawArc(x, y, radius, angle1, angle2, ccw, color) {
+ this.setColor(color);
+ this.context.globalAlpha = this.alpha;
+ this.context.lineWidth = this.line_width;
+ if (this.initDrawOp(x, -y)) {
+ this.context.beginPath();
+ this.context.arc(0, 0, radius, -angle1 / 180 * Math.PI, -angle2 / 180 * Math.PI, ccw);
+ this.context.stroke();
+ return this.closeDrawOp(x, -y);
+ } else {
+ this.context.beginPath();
+ this.context.arc(x, -y, radius, -angle1 / 180 * Math.PI, -angle2 / 180 * Math.PI, ccw);
+ return this.context.stroke();
+ }
+ }
+
+ fillArc(x, y, radius, angle1, angle2, ccw, color) {
+ this.setColor(color);
+ this.context.globalAlpha = this.alpha;
+ this.context.lineWidth = this.line_width;
+ if (this.initDrawOp(x, -y)) {
+ this.context.beginPath();
+ this.context.arc(0, 0, radius, -angle1 / 180 * Math.PI, -angle2 / 180 * Math.PI, ccw);
+ this.context.fill();
+ return this.closeDrawOp(x, -y);
+ } else {
+ this.context.beginPath();
+ this.context.arc(x, -y, radius, -angle1 / 180 * Math.PI, -angle2 / 180 * Math.PI, ccw);
+ return this.context.fill();
+ }
+ }
+
+ textWidth(text, size) {
+ this.context.font = `${size}pt ${this.font}`;
+ return this.context.measureText(text).width;
+ }
+
+ drawText(text, x, y, size, color) {
+ var h, w;
+ this.setColor(color);
+ this.context.globalAlpha = this.alpha;
+ this.context.font = `${size}pt ${this.font}`;
+ this.context.textAlign = "center";
+ this.context.textBaseline = "middle";
+ w = this.context.measureText(text).width;
+ h = size;
+ if (this.initDrawOp(x, -y)) {
+ this.context.fillText(text, 0 - this.anchor_x * w / 2, 0 + this.anchor_y * h / 2);
+ return this.closeDrawOp(x, -y);
+ } else {
+ return this.context.fillText(text, x - this.anchor_x * w / 2, -y + this.anchor_y * h / 2);
+ }
+ }
+
+ drawTextOutline(text, x, y, size, color) {
+ var h, w;
+ this.setColor(color);
+ this.context.globalAlpha = this.alpha;
+ this.context.font = `${size}pt ${this.font}`;
+ this.context.lineWidth = this.line_width;
+ this.context.textAlign = "center";
+ this.context.textBaseline = "middle";
+ w = this.context.measureText(text).width;
+ h = size;
+ if (this.initDrawOp(x, -y)) {
+ this.context.strokeText(text, 0 - this.anchor_x * w / 2, 0 + this.anchor_y * h / 2);
+ return this.closeDrawOp(x, -y);
+ } else {
+ return this.context.strokeText(text, x - this.anchor_x * w / 2, -y + this.anchor_y * h / 2);
+ }
+ }
+
+ getSpriteFrame(sprite) {
+ var dt, frame, s;
+ frame = null;
+ if (typeof sprite === "string") {
+ s = this.runtime.sprites[sprite];
+ if (s != null) {
+ sprite = s;
+ } else {
+ s = sprite.split(".");
+ if (s.length > 1) {
+ sprite = this.runtime.sprites[s[0]];
+ frame = s[1] | 0;
+ }
+ }
+ } else if (sprite instanceof msImage) {
+ return sprite.canvas || sprite.image;
+ }
+ if ((sprite == null) || !sprite.ready) {
+ return null;
+ }
+ if (sprite.frames.length > 1) {
+ if (frame == null) {
+ dt = 1000 / sprite.fps;
+ frame = Math.floor((Date.now() - sprite.animation_start) / dt) % sprite.frames.length;
+ }
+ if (frame >= 0 && frame < sprite.frames.length) {
+ return sprite.frames[frame].canvas;
+ } else {
+ return sprite.frames[0].canvas;
+ }
+ } else if (sprite.frames[0] != null) {
+ return sprite.frames[0].canvas;
+ } else {
+ return null;
+ }
+ }
+
+ drawSprite(sprite, x, y, w, h) {
+ var canvas;
+ canvas = this.getSpriteFrame(sprite);
+ if (canvas == null) {
+ return;
+ }
+ if (w == null) {
+ w = canvas.width;
+ }
+ if (!h) {
+ h = w / canvas.width * canvas.height;
+ }
+ this.context.globalAlpha = this.alpha;
+ this.context.imageSmoothingEnabled = !this.pixelated;
+ if (this.initDrawOp(x, -y)) {
+ this.context.drawImage(canvas, -w / 2 - this.anchor_x * w / 2, -h / 2 + this.anchor_y * h / 2, w, h);
+ return this.closeDrawOp(x, -y);
+ } else {
+ return this.context.drawImage(canvas, x - w / 2 - this.anchor_x * w / 2, -y - h / 2 + this.anchor_y * h / 2, w, h);
+ }
+ }
+
+ drawSpritePart(sprite, sx, sy, sw, sh, x, y, w, h) {
+ var canvas;
+ canvas = this.getSpriteFrame(sprite);
+ if (canvas == null) {
+ return;
+ }
+ if (w == null) {
+ w = sw;
+ }
+ if (!h) {
+ h = w / sw * sh;
+ }
+ this.context.globalAlpha = this.alpha;
+ this.context.imageSmoothingEnabled = !this.pixelated;
+ if (this.initDrawOp(x, -y)) {
+ this.context.drawImage(canvas, sx, sy, sw, sh, -w / 2 - this.anchor_x * w / 2, -h / 2 + this.anchor_y * h / 2, w, h);
+ return this.closeDrawOp(x, -y);
+ } else {
+ return this.context.drawImage(canvas, sx, sy, sw, sh, x - w / 2 - this.anchor_x * w / 2, -y - h / 2 + this.anchor_y * h / 2, w, h);
+ }
+ }
+
+ drawMap(map, x, y, w, h) {
+ if (typeof map === "string") {
+ map = this.runtime.maps[map];
+ }
+ if ((map == null) || !map.ready) {
+ return;
+ }
+ this.context.globalAlpha = this.alpha;
+ this.context.imageSmoothingEnabled = !this.pixelated;
+ if (this.initDrawOp(x, -y)) {
+ map.draw(this.context, -w / 2 - this.anchor_x * w / 2, -h / 2 + this.anchor_y * h / 2, w, h);
+ //@context.drawImage map.getCanvas(),-w/2-@anchor_x*w/2,-h/2+@anchor_y*h/2,w,h
+ return this.closeDrawOp(x, -y);
+ } else {
+ return map.draw(this.context, x - w / 2 - this.anchor_x * w / 2, -y - h / 2 + this.anchor_y * h / 2, w, h);
+ }
+ }
+
+ //@context.drawImage map.getCanvas(),x-w/2-@anchor_x*w/2,-y-h/2+@anchor_y*h/2,w,h
+ resize() {
+ var backingStoreRatio, ch, cw, devicePixelRatio, h, min, r, ratio, w;
+ cw = window.innerWidth;
+ ch = window.innerHeight;
+ ratio = {
+ "4x3": 4 / 3,
+ "16x9": 16 / 9,
+ "2x1": 2 / 1,
+ "1x1": 1 / 1,
+ ">4x3": 4 / 3,
+ ">16x9": 16 / 9,
+ ">2x1": 2 / 1,
+ ">1x1": 1 / 1
+ }[this.runtime.aspect];
+ min = this.runtime.aspect.startsWith(">");
+ //if not ratio? and @runtime.orientation in ["portrait","landscape"]
+ // ratio = 16/9
+ if (ratio != null) {
+ if (min) {
+ switch (this.runtime.orientation) {
+ case "portrait":
+ ratio = Math.max(ratio, ch / cw);
+ break;
+ case "landscape":
+ ratio = Math.max(ratio, cw / ch);
+ break;
+ default:
+ if (ch > cw) {
+ ratio = Math.max(ratio, ch / cw);
+ } else {
+ ratio = Math.max(ratio, cw / ch);
+ }
+ }
+ }
+ switch (this.runtime.orientation) {
+ case "portrait":
+ r = Math.min(cw, ch / ratio) / cw;
+ w = cw * r;
+ h = cw * r * ratio;
+ break;
+ case "landscape":
+ r = Math.min(cw / ratio, ch) / ch;
+ w = ch * r * ratio;
+ h = ch * r;
+ break;
+ default:
+ if (cw > ch) {
+ r = Math.min(cw / ratio, ch) / ch;
+ w = ch * r * ratio;
+ h = ch * r;
+ } else {
+ r = Math.min(cw, ch / ratio) / cw;
+ w = cw * r;
+ h = cw * r * ratio;
+ }
+ }
+ } else {
+ w = cw;
+ h = ch;
+ }
+ this.canvas.style["margin-top"] = Math.round((ch - h) / 2) + "px";
+ this.canvas.style.width = Math.round(w) + "px";
+ this.canvas.style.height = Math.round(h) + "px";
+ devicePixelRatio = window.devicePixelRatio || 1;
+ backingStoreRatio = this.context.webkitBackingStorePixelRatio || this.context.mozBackingStorePixelRatio || this.context.msBackingStorePixelRatio || this.context.oBackingStorePixelRatio || this.context.backingStorePixelRatio || 1;
+ this.ratio = devicePixelRatio / backingStoreRatio * Math.max(1, Math.min(2, this.supersampling));
+ this.width = w * this.ratio;
+ this.height = h * this.ratio;
+ this.canvas.width = this.width;
+ this.canvas.height = this.height;
+ return this.initContext();
+ }
+
+ startControl(element) {
+ var backingStoreRatio, devicePixelRatio;
+ this.element = element;
+ document.addEventListener("touchstart", (event) => {
+ return this.touchStart(event);
+ });
+ document.addEventListener("touchmove", (event) => {
+ return this.touchMove(event);
+ });
+ document.addEventListener("touchend", (event) => {
+ return this.touchRelease(event);
+ });
+ document.addEventListener("touchcancel", (event) => {
+ return this.touchRelease(event);
+ });
+ document.addEventListener("mousedown", (event) => {
+ return this.mouseDown(event);
+ });
+ document.addEventListener("mousemove", (event) => {
+ return this.mouseMove(event);
+ });
+ document.addEventListener("mouseup", (event) => {
+ return this.mouseUp(event);
+ });
+ document.addEventListener("mousewheel", (event) => {
+ return this.mouseWheel(event);
+ });
+ document.addEventListener("DOMMouseScroll", (event) => {
+ return this.mouseWheel(event);
+ });
+ devicePixelRatio = window.devicePixelRatio || 1;
+ backingStoreRatio = this.context.webkitBackingStorePixelRatio || this.context.mozBackingStorePixelRatio || this.context.msBackingStorePixelRatio || this.context.oBackingStorePixelRatio || this.context.backingStorePixelRatio || 1;
+ return this.ratio = devicePixelRatio / backingStoreRatio;
+ }
+
+ touchStart(event) {
+ var b, i, j, min, ref, t, x, y;
+ event.preventDefault();
+ event.stopPropagation();
+ b = this.canvas.getBoundingClientRect();
+ for (i = j = 0, ref = event.changedTouches.length - 1; j <= ref; i = j += 1) {
+ t = event.changedTouches[i];
+ min = Math.min(this.canvas.clientWidth, this.canvas.clientHeight);
+ x = (t.clientX - b.left - this.canvas.clientWidth / 2) / min * 200;
+ y = (this.canvas.clientHeight / 2 - (t.clientY - b.top)) / min * 200;
+ this.touches[t.identifier] = {
+ x: x,
+ y: y
+ };
+ this.mouse.x = x;
+ this.mouse.y = y;
+ this.mouse.pressed = 1;
+ this.mouse.left = 1;
+ }
+ return false;
+ }
+
+ touchMove(event) {
+ var b, i, j, min, ref, t, x, y;
+ event.preventDefault();
+ event.stopPropagation();
+ b = this.canvas.getBoundingClientRect();
+ for (i = j = 0, ref = event.changedTouches.length - 1; j <= ref; i = j += 1) {
+ t = event.changedTouches[i];
+ if (this.touches[t.identifier] != null) {
+ min = Math.min(this.canvas.clientWidth, this.canvas.clientHeight);
+ x = (t.clientX - b.left - this.canvas.clientWidth / 2) / min * 200;
+ y = (this.canvas.clientHeight / 2 - (t.clientY - b.top)) / min * 200;
+ this.touches[t.identifier].x = x;
+ this.touches[t.identifier].y = y;
+ this.mouse.x = x;
+ this.mouse.y = y;
+ }
+ }
+ return false;
+ }
+
+ touchRelease(event) {
+ var i, j, ref, t, x, y;
+ for (i = j = 0, ref = event.changedTouches.length - 1; j <= ref; i = j += 1) {
+ t = event.changedTouches[i];
+ x = (t.clientX - this.canvas.offsetLeft) * this.ratio;
+ y = (t.clientY - this.canvas.offsetTop) * this.ratio;
+ delete this.touches[t.identifier];
+ this.mouse.pressed = 0;
+ this.mouse.left = 0;
+ this.mouse.right = 0;
+ this.mouse.middle = 0;
+ }
+ return false;
+ }
+
+ mouseDown(event) {
+ var b, min, x, y;
+ this.mousepressed = true;
+ b = this.canvas.getBoundingClientRect();
+ min = Math.min(this.canvas.clientWidth, this.canvas.clientHeight);
+ x = (event.clientX - b.left - this.canvas.clientWidth / 2) / min * 200;
+ y = (this.canvas.clientHeight / 2 - (event.clientY - b.top)) / min * 200;
+ this.touches["mouse"] = {
+ x: x,
+ y: y
+ };
+ //console.info @touches["mouse"]
+ this.mouse.x = x;
+ this.mouse.y = y;
+ switch (event.button) {
+ case 0:
+ this.mouse.left = 1;
+ break;
+ case 1:
+ this.mouse.middle = 1;
+ break;
+ case 2:
+ this.mouse.right = 1;
+ }
+ this.mouse.pressed = Math.min(1, this.mouse.left + this.mouse.right + this.mouse.middle);
+ return false;
+ }
+
+ mouseMove(event) {
+ var b, min, x, y;
+ event.preventDefault();
+ b = this.canvas.getBoundingClientRect();
+ min = Math.min(this.canvas.clientWidth, this.canvas.clientHeight);
+ x = (event.clientX - b.left - this.canvas.clientWidth / 2) / min * 200;
+ y = (this.canvas.clientHeight / 2 - (event.clientY - b.top)) / min * 200;
+ if (this.touches["mouse"] != null) {
+ this.touches["mouse"].x = x;
+ this.touches["mouse"].y = y;
+ }
+ this.mouse.x = x;
+ this.mouse.y = y;
+ return false;
+ }
+
+ mouseUp(event) {
+ var b, min, x, y;
+ delete this.touches["mouse"];
+ b = this.canvas.getBoundingClientRect();
+ min = Math.min(this.canvas.clientWidth, this.canvas.clientHeight);
+ x = (event.clientX - b.left - this.canvas.clientWidth / 2) / min * 200;
+ y = (this.canvas.clientHeight / 2 - (event.clientY - b.top)) / min * 200;
+ this.mouse.x = x;
+ this.mouse.y = y;
+ switch (event.button) {
+ case 0:
+ this.mouse.left = 0;
+ break;
+ case 1:
+ this.mouse.middle = 0;
+ break;
+ case 2:
+ this.mouse.right = 0;
+ }
+ this.mouse.pressed = Math.min(1, this.mouse.left + this.mouse.right + this.mouse.middle);
+ return false;
+ }
+
+ mouseWheel(e) {
+ if (e.wheelDelta < 0 || e.detail > 0) {
+ return this.wheel = -1;
+ } else {
+ return this.wheel = 1;
+ }
+ }
+
+ takePicture(callback) {
+ return callback(this.canvas.toDataURL());
+ }
+
+};
+
+this.AssetManager = class AssetManager {
+ constructor(runtime) {
+ this.runtime = runtime;
+ this.interface = {
+ loadFont: (font) => {
+ return this.loadFont(font);
+ },
+ loadModel: (path, scene, callback) => {
+ return this.loadModel(path, scene, callback);
+ },
+ loadImage: (path, callback) => {
+ return this.loadImage(path, callback);
+ },
+ loadJSON: (path, callback) => {
+ return this.loadJSON(path, callback);
+ },
+ loadText: (path, callback) => {
+ return this.loadText(path, callback);
+ },
+ loadCSV: (path, callback) => {
+ return this.loadCSV(path, callback);
+ },
+ loadMarkdown: (path, callback) => {
+ return this.loadMarkdown(path, callback);
+ },
+ wasmInstance: (path, callback) => {
+ return this.wasmInstance(path, callback);
+ }
+ };
+ }
+
+ getInterface() {
+ return this.interface;
+ }
+
+ loadFont(font) {
+ var err, file, name, split;
+ if (typeof font !== "string") {
+ return;
+ }
+ file = font.replace(/\//g, "-");
+ split = file.split("-");
+ name = split[split.length - 1];
+ try {
+ font = new FontFace(name, `url(assets/${file}.ttf)`);
+ return font.load().then(() => {
+ return document.fonts.add(font);
+ });
+ } catch (error) {
+ err = error;
+ return console.error(err);
+ }
+ }
+
+ loadModel(path, scene, callback) {
+ var loader;
+ if (typeof BABYLON === "undefined" || BABYLON === null) {
+ return;
+ }
+ loader = {
+ ready: 0
+ };
+ if (this.runtime.assets[path] != null) {
+ path = this.runtime.assets[path].file;
+ } else {
+ path = path.replace(/\//g, "-");
+ path += ".glb";
+ }
+ return BABYLON.SceneLoader.LoadAssetContainer("", `assets/${path}`, scene, (container) => {
+ loader.container = container;
+ loader.ready = 1;
+ if (callback) {
+ return callback(container);
+ }
+ });
+ }
+
+ loadImage(path, callback) {
+ var img, loader;
+ loader = {
+ ready: 0
+ };
+ if (this.runtime.assets[path] != null) {
+ path = this.runtime.assets[path].file;
+ }
+ img = new Image;
+ img.src = `assets/${path}`;
+ img.onload = () => {
+ var i;
+ i = new msImage(img);
+ loader.image = i;
+ loader.ready = 1;
+ if (callback) {
+ return callback(i);
+ }
+ };
+ return loader;
+ }
+
+ loadJSON(path, callback) {
+ var loader;
+ path = path.replace(/\//g, "-");
+ path = `assets/${path}.json`;
+ loader = {
+ ready: 0
+ };
+ fetch(path).then((result) => {
+ return result.json().then((data) => {
+ loader.data = data;
+ loader.ready = 1;
+ if (callback) {
+ return callback(data);
+ }
+ });
+ });
+ return loader;
+ }
+
+ loadText(path, callback, ext = "txt") {
+ var loader;
+ path = path.replace(/\//g, "-");
+ path = `assets/${path}.${ext}`;
+ loader = {
+ ready: 0
+ };
+ fetch(path).then((result) => {
+ return result.text().then((text) => {
+ loader.text = text;
+ loader.ready = 1;
+ if (callback) {
+ return callback(text);
+ }
+ });
+ });
+ return loader;
+ }
+
+ loadCSV(path, callback) {
+ return this.loadText(path, callback, "csv");
+ }
+
+ loadMarkdown(path, callback) {
+ return this.loadText(path, callback, "md");
+ }
+
+ wasmInstance(path, callback) {
+ var loader;
+ path = path.replace(/\//g, "-");
+ path = `assets/${path}.wasm`;
+ loader = {
+ ready: 0
+ };
+ fetch(path).then((response) => {
+ return response.arrayBuffer().then((buffer) => {
+ return WebAssembly.instantiate(buffer).then((result) => {
+ loader.instance = result.instance;
+ loader.ready = 1;
+ if (callback) {
+ return callback(loader.instance);
+ }
+ });
+ });
+ });
+ return loader;
+ }
+
+};
+
+this.Keyboard = (function() {
+ function Keyboard() {
+ document.addEventListener("keydown", (function(_this) {
+ return function(event) {
+ return _this.keydown(event);
+ };
+ })(this));
+ document.addEventListener("keyup", (function(_this) {
+ return function(event) {
+ return _this.keyup(event);
+ };
+ })(this));
+ this.keyboard = {
+ press: {},
+ release: {}
+ };
+ this.previous = {};
+ }
+
+ Keyboard.prototype.convertCode = function(code) {
+ var c, i, j, low, ref, res;
+ res = "";
+ low = false;
+ for (i = j = 0, ref = code.length - 1; 0 <= ref ? j <= ref : j >= ref; i = 0 <= ref ? ++j : --j) {
+ c = code.charAt(i);
+ if (c === c.toUpperCase() && low) {
+ res += "_";
+ low = false;
+ } else {
+ low = true;
+ }
+ res += c.toUpperCase();
+ }
+ return res;
+ };
+
+ Keyboard.prototype.keydown = function(event) {
+ var code, key;
+ if (!event.altKey && !event.ctrlKey && !event.metaKey && !/Escape|(F\d+)/.test(event.key)) {
+ event.preventDefault();
+ }
+ code = event.code;
+ key = event.key;
+ this.keyboard[this.convertCode(code)] = 1;
+ this.keyboard[key.toUpperCase()] = 1;
+ return this.updateDirectional();
+ };
+
+ Keyboard.prototype.keyup = function(event) {
+ var code, key;
+ code = event.code;
+ key = event.key;
+ this.keyboard[this.convertCode(code)] = 0;
+ this.keyboard[key.toUpperCase()] = 0;
+ return this.updateDirectional();
+ };
+
+ Keyboard.prototype.updateDirectional = function() {
+ this.keyboard.UP = this.keyboard.KEY_W || this.keyboard.ARROW_UP;
+ this.keyboard.DOWN = this.keyboard.KEY_S || this.keyboard.ARROW_DOWN;
+ this.keyboard.LEFT = this.keyboard.KEY_A || this.keyboard.ARROW_LEFT;
+ return this.keyboard.RIGHT = this.keyboard.KEY_D || this.keyboard.ARROW_RIGHT;
+ };
+
+ Keyboard.prototype.update = function() {
+ var key;
+ for (key in this.keyboard.press) {
+ this.keyboard.press[key] = 0;
+ }
+ for (key in this.keyboard.release) {
+ this.keyboard.release[key] = 0;
+ }
+ for (key in this.previous) {
+ if (this.previous[key] && !this.keyboard[key]) {
+ this.keyboard.release[key] = 1;
+ }
+ }
+ for (key in this.keyboard) {
+ if (key === "press" || key === "release") {
+ continue;
+ }
+ if (this.keyboard[key] && !this.previous[key]) {
+ this.keyboard.press[key] = 1;
+ }
+ }
+ for (key in this.previous) {
+ this.previous[key] = 0;
+ }
+ for (key in this.keyboard) {
+ if (key === "press" || key === "release") {
+ continue;
+ }
+ this.previous[key] = this.keyboard[key];
+ }
+ };
+
+ Keyboard.prototype.reset = function() {
+ var key;
+ for (key in this.keyboard) {
+ if (key === "press" || key === "release") {
+ continue;
+ }
+ this.keyboard[key] = 0;
+ }
+ };
+
+ return Keyboard;
+
+})();
+
+this.Gamepad = (function() {
+ function Gamepad(listener, index) {
+ var error, pads;
+ this.listener = listener;
+ this.index = index != null ? index : 0;
+ try {
+ if (navigator.getGamepads != null) {
+ pads = navigator.getGamepads();
+ if (this.index < pads.length && (pads[this.index] != null)) {
+ this.pad = pads[this.index];
+ }
+ }
+ } catch (error1) {
+ error = error1;
+ console.error(error);
+ }
+ this.buttons_map = {
+ 0: "A",
+ 1: "B",
+ 2: "X",
+ 3: "Y",
+ 4: "LB",
+ 5: "RB",
+ 8: "VIEW",
+ 9: "MENU",
+ 10: "LS",
+ 11: "RS",
+ 12: "DPAD_UP",
+ 13: "DPAD_DOWN",
+ 14: "DPAD_LEFT",
+ 15: "DPAD_RIGHT"
+ };
+ this.triggers_map = {
+ 6: "LT",
+ 7: "RT"
+ };
+ this.status = {
+ press: {},
+ release: {}
+ };
+ this.previous = {
+ global: {},
+ 0: {},
+ 1: {},
+ 2: {},
+ 3: {}
+ };
+ }
+
+ Gamepad.prototype.update = function() {
+ var angle, err, i, j, k, key, l, len, len1, len2, m, n, o, pad, pad_count, pads, r, ref, ref1, ref2, ref3, ref4, ref5, ref6, value, x, y;
+ try {
+ pads = navigator.getGamepads();
+ } catch (error1) {
+ err = error1;
+ return;
+ }
+ pad_count = 0;
+ for (i = j = 0, len = pads.length; j < len; i = ++j) {
+ pad = pads[i];
+ if (pad == null) {
+ break;
+ }
+ pad_count++;
+ if (!this.status[i]) {
+ this.status[i] = {
+ press: {},
+ release: {}
+ };
+ }
+ ref = this.buttons_map;
+ for (key in ref) {
+ value = ref[key];
+ if (pad.buttons[key] != null) {
+ this.status[i][value] = pad.buttons[key].pressed ? 1 : 0;
+ }
+ }
+ ref1 = this.triggers_map;
+ for (key in ref1) {
+ value = ref1[key];
+ if (pad.buttons[key] != null) {
+ this.status[i][value] = pad.buttons[key].value;
+ }
+ }
+ if (pad.axes.length >= 2) {
+ x = pad.axes[0];
+ y = -pad.axes[1];
+ r = Math.sqrt(x * x + y * y);
+ angle = Math.floor(((Math.atan2(y, x) + Math.PI * 2) % (Math.PI * 2)) / (Math.PI * 2) * 360);
+ this.status[i].LEFT_STICK_ANGLE = angle;
+ this.status[i].LEFT_STICK_AMOUNT = r;
+ this.status[i].LEFT_STICK_UP = y > .5;
+ this.status[i].LEFT_STICK_DOWN = y < -.5;
+ this.status[i].LEFT_STICK_LEFT = x < -.5;
+ this.status[i].LEFT_STICK_RIGHT = x > .5;
+ }
+ if (pad.axes.length >= 4) {
+ x = pad.axes[2];
+ y = -pad.axes[3];
+ r = Math.sqrt(x * x + y * y);
+ angle = Math.floor(((Math.atan2(y, x) + Math.PI * 2) % (Math.PI * 2)) / (Math.PI * 2) * 360);
+ this.status[i].RIGHT_STICK_ANGLE = angle;
+ this.status[i].RIGHT_STICK_AMOUNT = r;
+ this.status[i].RIGHT_STICK_UP = y > .5;
+ this.status[i].RIGHT_STICK_DOWN = y < -.5;
+ this.status[i].RIGHT_STICK_LEFT = x < -.5;
+ this.status[i].RIGHT_STICK_RIGHT = x > .5;
+ }
+ }
+ ref2 = this.buttons_map;
+ for (key in ref2) {
+ value = ref2[key];
+ this.status[value] = 0;
+ for (k = 0, len1 = pads.length; k < len1; k++) {
+ pad = pads[k];
+ if (pad == null) {
+ break;
+ }
+ if ((pad.buttons[key] != null) && pad.buttons[key].pressed) {
+ this.status[value] = 1;
+ }
+ }
+ }
+ ref3 = this.triggers_map;
+ for (key in ref3) {
+ value = ref3[key];
+ this.status[value] = 0;
+ for (l = 0, len2 = pads.length; l < len2; l++) {
+ pad = pads[l];
+ if (pad == null) {
+ break;
+ }
+ if (pad.buttons[key] != null) {
+ this.status[value] = pad.buttons[key].value;
+ }
+ }
+ }
+ this.status.UP = 0;
+ this.status.DOWN = 0;
+ this.status.LEFT = 0;
+ this.status.RIGHT = 0;
+ this.status.LEFT_STICK_UP = 0;
+ this.status.LEFT_STICK_DOWN = 0;
+ this.status.LEFT_STICK_LEFT = 0;
+ this.status.LEFT_STICK_RIGHT = 0;
+ this.status.RIGHT_STICK_UP = 0;
+ this.status.RIGHT_STICK_DOWN = 0;
+ this.status.RIGHT_STICK_LEFT = 0;
+ this.status.RIGHT_STICK_RIGHT = 0;
+ this.status.LEFT_STICK_ANGLE = 0;
+ this.status.LEFT_STICK_AMOUNT = 0;
+ this.status.RIGHT_STICK_ANGLE = 0;
+ this.status.RIGHT_STICK_AMOUNT = 0;
+ this.status.RT = 0;
+ this.status.LT = 0;
+ for (i = m = 0, ref4 = pad_count - 1; m <= ref4; i = m += 1) {
+ this.status[i].UP = this.status[i].DPAD_UP || this.status[i].LEFT_STICK_UP || this.status[i].RIGHT_STICK_UP;
+ this.status[i].DOWN = this.status[i].DPAD_DOWN || this.status[i].LEFT_STICK_DOWN || this.status[i].RIGHT_STICK_DOWN;
+ this.status[i].LEFT = this.status[i].DPAD_LEFT || this.status[i].LEFT_STICK_LEFT || this.status[i].RIGHT_STICK_LEFT;
+ this.status[i].RIGHT = this.status[i].DPAD_RIGHT || this.status[i].LEFT_STICK_RIGHT || this.status[i].RIGHT_STICK_RIGHT;
+ if (this.status[i].UP) {
+ this.status.UP = 1;
+ }
+ if (this.status[i].DOWN) {
+ this.status.DOWN = 1;
+ }
+ if (this.status[i].LEFT) {
+ this.status.LEFT = 1;
+ }
+ if (this.status[i].RIGHT) {
+ this.status.RIGHT = 1;
+ }
+ if (this.status[i].LEFT_STICK_UP) {
+ this.status.LEFT_STICK_UP = 1;
+ }
+ if (this.status[i].LEFT_STICK_DOWN) {
+ this.status.LEFT_STICK_DOWN = 1;
+ }
+ if (this.status[i].LEFT_STICK_LEFT) {
+ this.status.LEFT_STICK_LEFT = 1;
+ }
+ if (this.status[i].LEFT_STICK_RIGHT) {
+ this.status.LEFT_STICK_RIGHT = 1;
+ }
+ if (this.status[i].RIGHT_STICK_UP) {
+ this.status.RIGHT_STICK_UP = 1;
+ }
+ if (this.status[i].RIGHT_STICK_DOWN) {
+ this.status.RIGHT_STICK_DOWN = 1;
+ }
+ if (this.status[i].RIGHT_STICK_LEFT) {
+ this.status.RIGHT_STICK_LEFT = 1;
+ }
+ if (this.status[i].RIGHT_STICK_RIGHT) {
+ this.status.RIGHT_STICK_RIGHT = 1;
+ }
+ if (this.status[i].LT) {
+ this.status.LT = this.status[i].LT;
+ }
+ if (this.status[i].RT) {
+ this.status.RT = this.status[i].RT;
+ }
+ if (this.status[i].LEFT_STICK_AMOUNT > this.status.LEFT_STICK_AMOUNT) {
+ this.status.LEFT_STICK_AMOUNT = this.status[i].LEFT_STICK_AMOUNT;
+ this.status.LEFT_STICK_ANGLE = this.status[i].LEFT_STICK_ANGLE;
+ }
+ if (this.status[i].RIGHT_STICK_AMOUNT > this.status.RIGHT_STICK_AMOUNT) {
+ this.status.RIGHT_STICK_AMOUNT = this.status[i].RIGHT_STICK_AMOUNT;
+ this.status.RIGHT_STICK_ANGLE = this.status[i].RIGHT_STICK_ANGLE;
+ }
+ }
+ for (i = n = ref5 = pad_count; n <= 3; i = n += 1) {
+ delete this.status[i];
+ }
+ this.count = pad_count;
+ this.updateChanges(this.status, this.previous.global);
+ for (i = o = 0, ref6 = pad_count - 1; o <= ref6; i = o += 1) {
+ this.updateChanges(this.status[i], this.previous[i]);
+ }
+ };
+
+ Gamepad.prototype.updateChanges = function(current, previous) {
+ var key;
+ for (key in current.press) {
+ current.press[key] = 0;
+ }
+ for (key in current.release) {
+ current.release[key] = 0;
+ }
+ for (key in previous) {
+ if (previous[key] && !current[key]) {
+ current.release[key] = 1;
+ }
+ }
+ for (key in current) {
+ if (key === "press" || key === "release") {
+ continue;
+ }
+ if (current[key] && !previous[key]) {
+ current.press[key] = 1;
+ }
+ }
+ for (key in previous) {
+ previous[key] = 0;
+ }
+ for (key in current) {
+ if (key === "press" || key === "release") {
+ continue;
+ }
+ previous[key] = current[key];
+ }
+ };
+
+ return Gamepad;
+
+})();
+
+this.Sprite = class Sprite {
+ constructor(width, height) {
+ this.width = width;
+ this.height = height;
+ this.name = "";
+ this.frames = [];
+ this.animation_start = 0;
+ this.fps = 5;
+ if (this.width > 0 && this.height > 0) {
+ this.frames.push(new msImage(this.width, this.height));
+ this.ready = 1;
+ }
+ }
+
+ setFPS(fps) {
+ var dt, frame;
+ dt = 1000 / this.fps;
+ frame = ((Date.now() - this.animation_start) / dt) % this.frames.length;
+ this.fps = fps;
+ dt = 1000 / fps;
+ this.animation_start = Date.now() - frame * dt;
+ return fps;
+ }
+
+ setFrame(f) {
+ return this.animation_start = Date.now() - 1000 / this.fps * f;
+ }
+
+ getFrame() {
+ var dt;
+ dt = 1000 / this.fps;
+ return Math.floor((Date.now() - this.animation_start) / dt) % this.frames.length;
+ }
+
+};
+
+this.LoadSprite = function(url, properties, loaded) {
+ var img, sprite;
+ sprite = new Sprite(0, 0);
+ sprite.ready = 0;
+ img = new Image;
+ if (location.protocol !== "file:") {
+ img.crossOrigin = "Anonymous";
+ }
+ img.src = url;
+ img.onload = () => {
+ var frame, i, j, numframes, ref;
+ sprite.ready = true;
+ if (img.width > 0 && img.height > 0) {
+ numframes = 1;
+ if ((properties != null) && (properties.frames != null)) {
+ numframes = properties.frames;
+ }
+ if (properties.fps != null) {
+ sprite.fps = properties.fps;
+ }
+ sprite.width = img.width;
+ sprite.height = Math.round(img.height / numframes);
+ sprite.frames = [];
+ for (i = j = 0, ref = numframes - 1; (0 <= ref ? j <= ref : j >= ref); i = 0 <= ref ? ++j : --j) {
+ frame = new msImage(sprite.width, sprite.height);
+ frame.initContext();
+ frame.context.drawImage(img, 0, -i * sprite.height);
+ sprite.frames.push(frame);
+ }
+ sprite.ready = true;
+ }
+ if (loaded != null) {
+ return loaded();
+ }
+ };
+ img.onerror = () => {
+ return sprite.ready = 1;
+ };
+ return sprite;
+};
+
+this.UpdateSprite = function(sprite, img, properties) {
+ var frame, i, j, numframes, ref;
+ if (img.width > 0 && img.height > 0) {
+ numframes = 1;
+ if ((properties != null) && (properties.frames != null)) {
+ numframes = properties.frames;
+ }
+ if ((properties != null) && (properties.fps != null)) {
+ sprite.fps = properties.fps;
+ }
+ sprite.width = img.width;
+ sprite.height = Math.round(img.height / numframes);
+ sprite.frames = [];
+ for (i = j = 0, ref = numframes - 1; (0 <= ref ? j <= ref : j >= ref); i = 0 <= ref ? ++j : --j) {
+ frame = new msImage(sprite.width, sprite.height);
+ frame.initContext();
+ frame.context.drawImage(img, 0, -i * sprite.height);
+ sprite.frames.push(frame);
+ }
+ return sprite.ready = true;
+ }
+};
+
+var b, j, len1, ref;
+
+this.msImage = (function() {
+ class msImage {
+ constructor(width, height, centered = false) {
+ this.width = width;
+ this.height = height;
+ this.centered = centered;
+ this.class = msImage;
+ if (this.width instanceof Image) {
+ this.image = this.width;
+ this.width = this.image.width;
+ this.height = this.image.height;
+ } else if (this.width instanceof HTMLCanvasElement) {
+ this.canvas = this.width;
+ this.width = this.canvas.width;
+ this.height = this.canvas.height;
+ } else {
+ this.canvas = document.createElement("canvas");
+ this.canvas.width = this.width = Math.round(this.width);
+ this.canvas.height = this.height = Math.round(this.height);
+ }
+ }
+
+ setRGB(x, y, r, g, b) {
+ this.initContext();
+ if (this.pixeldata == null) {
+ this.pixeldata = this.context.getImageData(0, 0, 1, 1);
+ }
+ if (r.R != null) {
+ this.pixeldata.data[0] = r.R;
+ this.pixeldata.data[1] = r.G;
+ this.pixeldata.data[2] = r.B;
+ } else {
+ this.pixeldata.data[0] = r;
+ this.pixeldata.data[1] = g;
+ this.pixeldata.data[2] = b;
+ }
+ this.pixeldata.data[3] = 255;
+ return this.context.putImageData(this.pixeldata, x, y);
+ }
+
+ setRGBA(x, y, r, g, b, a) {
+ this.initContext();
+ if (this.pixeldata == null) {
+ this.pixeldata = this.context.getImageData(0, 0, 1, 1);
+ }
+ if (r.R != null) {
+ this.pixeldata.data[0] = r.R;
+ this.pixeldata.data[1] = r.G;
+ this.pixeldata.data[2] = r.B;
+ this.pixeldata.data[3] = r.A != null ? r.A : 255;
+ } else {
+ this.pixeldata.data[0] = r;
+ this.pixeldata.data[1] = g;
+ this.pixeldata.data[2] = b;
+ this.pixeldata.data[3] = a;
+ }
+ return this.context.putImageData(this.pixeldata, x, y);
+ }
+
+ getRGB(x, y, result = {}) {
+ var d;
+ this.initContext();
+ d = this.context.getImageData(x, y, 1, 1);
+ result.R = d.data[0];
+ result.G = d.data[1];
+ result.B = d.data[2];
+ return result;
+ }
+
+ getRGBA(x, y, result = {}) {
+ var d;
+ this.initContext();
+ d = this.context.getImageData(x, y, 1, 1);
+ result.R = d.data[0];
+ result.G = d.data[1];
+ result.B = d.data[2];
+ result.A = d.data[3];
+ return result;
+ }
+
+ initContext() {
+ if (this.context != null) {
+ return;
+ }
+ if ((this.canvas == null) && (this.image != null)) {
+ this.canvas = document.createElement("canvas");
+ this.canvas.width = this.image.width;
+ this.canvas.height = this.image.height;
+ this.context = this.canvas.getContext("2d");
+ this.context.drawImage(this.image, 0, 0);
+ this.image = null;
+ }
+ this.alpha = 1;
+ this.pixelated = 1;
+ this.line_width = 1;
+ this.context = this.canvas.getContext("2d");
+ this.context.lineCap = "round";
+ if (this.centered) {
+ this.translation_x = this.width / 2;
+ this.translation_y = this.height / 2;
+ this.rotation = 0;
+ this.scale_x = 1;
+ this.scale_y = -1;
+ this.image_transform = true;
+ this.anchor_x = 0;
+ this.anchor_y = 0;
+ this.object_scale_y = -1;
+ } else {
+ this.translation_x = 0;
+ this.translation_y = 0;
+ this.rotation = 0;
+ this.scale_x = 1;
+ this.scale_y = 1;
+ this.image_transform = false;
+ this.anchor_x = -1;
+ this.anchor_y = 1;
+ this.object_scale_y = 1;
+ }
+ this.object_rotation = 0;
+ this.object_scale_x = 1;
+ return this.font = "BitCell";
+ }
+
+ clear(color) {
+ var blending_save, c, s;
+ this.initContext();
+ c = this.context.fillStyle;
+ s = this.context.strokeStyle;
+ blending_save = this.context.globalCompositeOperation;
+ this.context.globalAlpha = 1;
+ this.context.globalCompositeOperation = "source-over";
+ if (color != null) {
+ this.setColor(color);
+ } else {
+ this.context.fillStyle = "#000";
+ }
+ this.context.fillRect(0, 0, this.width, this.height);
+ this.context.fillStyle = c;
+ this.context.strokeStyle = s;
+ return this.context.globalCompositeOperation = blending_save;
+ }
+
+ setColor(color) {
+ this.initContext();
+ if (color == null) {
+ return;
+ }
+ if (typeof color === "string") {
+ this.context.fillStyle = color;
+ return this.context.strokeStyle = color;
+ }
+ }
+
+ setAlpha(alpha) {
+ this.initContext();
+ return this.alpha = alpha;
+ }
+
+ setPixelated(pixelated) {
+ this.initContext();
+ return this.pixelated = pixelated;
+ }
+
+ setBlending(blending) {
+ this.initContext();
+ blending = BLENDING_MODES[blending || "normal"] || "source-over";
+ return this.context.globalCompositeOperation = blending;
+ }
+
+ setLineWidth(line_width) {
+ this.initContext();
+ return this.line_width = line_width;
+ }
+
+ setLineDash(dash) {
+ this.initContext();
+ if (!Array.isArray(dash)) {
+ return this.context.setLineDash([]);
+ } else {
+ return this.context.setLineDash(dash);
+ }
+ }
+
+ setLinearGradient(x1, y1, x2, y2, c1, c2) {
+ var grd;
+ this.initContext();
+ grd = this.context.createLinearGradient(x1, y1, x2, y2);
+ grd.addColorStop(0, c1);
+ grd.addColorStop(1, c2);
+ this.context.fillStyle = grd;
+ return this.context.strokeStyle = grd;
+ }
+
+ setRadialGradient(x, y, radius, c1, c2) {
+ var grd;
+ this.initContext();
+ grd = this.context.createRadialGradient(x, y, 0, x, y, radius);
+ grd.addColorStop(0, c1);
+ grd.addColorStop(1, c2);
+ this.context.fillStyle = grd;
+ return this.context.strokeStyle = grd;
+ }
+
+ setFont(font) {
+ return this.font = font || "Verdana";
+ }
+
+ setTranslation(translation_x, translation_y) {
+ this.initContext();
+ this.translation_x = translation_x;
+ this.translation_y = translation_y;
+ if (!isFinite(this.translation_x)) {
+ this.translation_x = 0;
+ }
+ if (!isFinite(this.translation_y)) {
+ this.translation_y = 0;
+ }
+ return this.updateScreenTransform();
+ }
+
+ setScale(scale_x, scale_y) {
+ this.initContext();
+ this.scale_x = scale_x;
+ this.scale_y = scale_y;
+ if (!isFinite(this.scale_x) || this.scale_x === 0) {
+ this.scale_x = 1;
+ }
+ if (!isFinite(this.scale_y) || this.scale_y === 0) {
+ this.scale_y = 1;
+ }
+ return this.updateScreenTransform();
+ }
+
+ setRotation(rotation) {
+ this.initContext();
+ this.rotation = rotation;
+ if (!isFinite(this.rotation)) {
+ this.rotation = 0;
+ }
+ return this.updateScreenTransform();
+ }
+
+ updateScreenTransform() {
+ return this.image_transform = this.translation_x !== 0 || this.translation_y !== 0 || this.scale_x !== 1 || this.scale_y !== 1 || this.rotation !== 0;
+ }
+
+ setDrawAnchor(anchor_x, anchor_y) {
+ this.initContext();
+ this.anchor_x = anchor_x;
+ this.anchor_y = anchor_y;
+ if (typeof this.anchor_x !== "number") {
+ this.anchor_x = 0;
+ }
+ if (typeof this.anchor_y !== "number") {
+ return this.anchor_y = 0;
+ }
+ }
+
+ setDrawRotation(object_rotation) {
+ this.initContext();
+ return this.object_rotation = object_rotation;
+ }
+
+ setDrawScale(object_scale_x, object_scale_y = object_scale_x) {
+ this.initContext();
+ this.object_scale_x = object_scale_x;
+ return this.object_scale_y = object_scale_y;
+ }
+
+ initDrawOp(x, y, object_transform = true) {
+ var res;
+ res = false;
+ if (this.image_transform) {
+ this.context.save();
+ res = true;
+ this.context.translate(this.translation_x, this.translation_y);
+ this.context.scale(this.scale_x, this.scale_y);
+ this.context.rotate(this.rotation / 180 * Math.PI);
+ this.context.translate(x, y);
+ }
+ if (object_transform && (this.object_rotation !== 0 || this.object_scale_x !== 1 || this.object_scale_y !== 1)) {
+ if (!res) {
+ this.context.save();
+ res = true;
+ this.context.translate(x, y);
+ }
+ if (this.object_rotation !== 0) {
+ this.context.rotate(this.object_rotation / 180 * Math.PI);
+ }
+ if (this.object_scale_x !== 1 || this.object_scale_y !== 1) {
+ this.context.scale(this.object_scale_x, this.object_scale_y);
+ }
+ }
+ return res;
+ }
+
+ closeDrawOp(x, y) {
+ return this.context.restore();
+ }
+
+ fillRect(x, y, w, h, color) {
+ this.initContext();
+ this.setColor(color);
+ this.context.globalAlpha = this.alpha;
+ if (this.initDrawOp(x, y)) {
+ this.context.fillRect(-w / 2 - this.anchor_x * w / 2, -h / 2 + this.anchor_y * h / 2, w, h);
+ return this.closeDrawOp(x, y);
+ } else {
+ return this.context.fillRect(x - w / 2 - this.anchor_x * w / 2, y - h / 2 + this.anchor_y * h / 2, w, h);
+ }
+ }
+
+ fillRoundRect(x, y, w, h, round = 10, color) {
+ this.initContext();
+ this.setColor(color);
+ this.context.globalAlpha = this.alpha;
+ if (this.initDrawOp(x, y)) {
+ this.context.fillRoundRect(-w / 2 - this.anchor_x * w / 2, -h / 2 + this.anchor_y * h / 2, w, h, round);
+ return this.closeDrawOp(x, y);
+ } else {
+ return this.context.fillRoundRect(x - w / 2 - this.anchor_x * w / 2, y - h / 2 + this.anchor_y * h / 2, w, h, round);
+ }
+ }
+
+ fillRound(x, y, w, h, color) {
+ this.initContext();
+ this.setColor(color);
+ this.context.globalAlpha = this.alpha;
+ w = Math.abs(w);
+ h = Math.abs(h);
+ if (this.initDrawOp(x, y)) {
+ this.context.beginPath();
+ this.context.ellipse(-this.anchor_x * w / 2, 0 + this.anchor_y * h / 2, w / 2, h / 2, 0, 0, Math.PI * 2, false);
+ this.context.fill();
+ return this.closeDrawOp(x, y);
+ } else {
+ this.context.beginPath();
+ this.context.ellipse(x - this.anchor_x * w / 2, y + this.anchor_y * h / 2, w / 2, h / 2, 0, 0, Math.PI * 2, false);
+ return this.context.fill();
+ }
+ }
+
+ drawRect(x, y, w, h, color) {
+ this.initContext();
+ this.setColor(color);
+ this.context.globalAlpha = this.alpha;
+ this.context.lineWidth = this.line_width;
+ if (this.initDrawOp(x, y)) {
+ this.context.strokeRect(-w / 2 - this.anchor_x * w / 2, -h / 2 + this.anchor_y * h / 2, w, h);
+ return this.closeDrawOp(x, y);
+ } else {
+ return this.context.strokeRect(x - w / 2 - this.anchor_x * w / 2, y - h / 2 + this.anchor_y * h / 2, w, h);
+ }
+ }
+
+ drawRoundRect(x, y, w, h, round = 10, color) {
+ this.initContext();
+ this.setColor(color);
+ this.context.globalAlpha = this.alpha;
+ this.context.lineWidth = this.line_width;
+ if (this.initDrawOp(x, y)) {
+ this.context.strokeRoundRect(-w / 2 - this.anchor_x * w / 2, -h / 2 + this.anchor_y * h / 2, w, h, round);
+ return this.closeDrawOp(x, y);
+ } else {
+ return this.context.strokeRoundRect(x - w / 2 - this.anchor_x * w / 2, y - h / 2 + this.anchor_y * h / 2, w, h, round);
+ }
+ }
+
+ drawRound(x, y, w, h, color) {
+ this.initContext();
+ this.setColor(color);
+ this.context.globalAlpha = this.alpha;
+ this.context.lineWidth = this.line_width;
+ w = Math.abs(w);
+ h = Math.abs(h);
+ if (this.initDrawOp(x, y)) {
+ this.context.beginPath();
+ this.context.ellipse(0 - this.anchor_x * w / 2, 0 + this.anchor_y * h / 2, w / 2, h / 2, 0, 0, Math.PI * 2, false);
+ this.context.stroke();
+ return this.closeDrawOp(x, y);
+ } else {
+ this.context.beginPath();
+ this.context.ellipse(x - this.anchor_x * w / 2, y + this.anchor_y * h / 2, w / 2, h / 2, 0, 0, Math.PI * 2, false);
+ return this.context.stroke();
+ }
+ }
+
+ drawLine(x1, y1, x2, y2, color) {
+ var transform;
+ this.initContext();
+ this.setColor(color);
+ this.context.globalAlpha = this.alpha;
+ this.context.lineWidth = this.line_width;
+ transform = this.initDrawOp(0, 0, false);
+ this.context.beginPath();
+ this.context.moveTo(x1, y1);
+ this.context.lineTo(x2, y2);
+ this.context.stroke();
+ if (transform) {
+ return this.closeDrawOp();
+ }
+ }
+
+ drawPolyline() {
+ var args, i, j, len, ref, transform;
+ args = arguments;
+ this.initContext();
+ if (args.length > 0 && args.length % 2 === 1 && typeof args[args.length - 1] === "string") {
+ this.setColor(args[args.length - 1]);
+ }
+ if (Array.isArray(args[0])) {
+ if ((args[1] != null) && typeof args[1] === "string") {
+ this.setColor(args[1]);
+ }
+ args = args[0];
+ }
+ this.context.globalAlpha = this.alpha;
+ this.context.lineWidth = this.line_width;
+ if (args.length < 4) {
+ return;
+ }
+ len = Math.floor(args.length / 2);
+ transform = this.initDrawOp(0, 0, false);
+ this.context.beginPath();
+ this.context.moveTo(args[0], args[1]);
+ for (i = j = 1, ref = len - 1; (1 <= ref ? j <= ref : j >= ref); i = 1 <= ref ? ++j : --j) {
+ this.context.lineTo(args[i * 2], args[i * 2 + 1]);
+ }
+ this.context.stroke();
+ if (transform) {
+ return this.closeDrawOp();
+ }
+ }
+
+ drawPolygon() {
+ var args, i, j, len, ref, transform;
+ args = arguments;
+ this.initContext();
+ if (args.length > 0 && args.length % 2 === 1 && typeof args[args.length - 1] === "string") {
+ this.setColor(args[args.length - 1]);
+ }
+ if (Array.isArray(args[0])) {
+ if ((args[1] != null) && typeof args[1] === "string") {
+ this.setColor(args[1]);
+ }
+ args = args[0];
+ }
+ this.context.globalAlpha = this.alpha;
+ this.context.lineWidth = this.line_width;
+ if (args.length < 4) {
+ return;
+ }
+ len = Math.floor(args.length / 2);
+ transform = this.initDrawOp(0, 0, false);
+ this.context.beginPath();
+ this.context.moveTo(args[0], args[1]);
+ for (i = j = 1, ref = len - 1; (1 <= ref ? j <= ref : j >= ref); i = 1 <= ref ? ++j : --j) {
+ this.context.lineTo(args[i * 2], args[i * 2 + 1]);
+ }
+ this.context.closePath();
+ this.context.stroke();
+ if (transform) {
+ return this.closeDrawOp();
+ }
+ }
+
+ fillPolygon() {
+ var args, i, j, len, ref, transform;
+ args = arguments;
+ this.initContext();
+ if (args.length > 0 && args.length % 2 === 1 && typeof args[args.length - 1] === "string") {
+ this.setColor(args[args.length - 1]);
+ }
+ if (Array.isArray(args[0])) {
+ if ((args[1] != null) && typeof args[1] === "string") {
+ this.setColor(args[1]);
+ }
+ args = args[0];
+ }
+ this.context.globalAlpha = this.alpha;
+ this.context.lineWidth = this.line_width;
+ if (args.length < 4) {
+ return;
+ }
+ len = Math.floor(args.length / 2);
+ transform = this.initDrawOp(0, 0, false);
+ this.context.beginPath();
+ this.context.moveTo(args[0], args[1]);
+ for (i = j = 1, ref = len - 1; (1 <= ref ? j <= ref : j >= ref); i = 1 <= ref ? ++j : --j) {
+ this.context.lineTo(args[i * 2], args[i * 2 + 1]);
+ }
+ this.context.fill();
+ if (transform) {
+ return this.closeDrawOp();
+ }
+ }
+
+ drawQuadCurve() {
+ var args, index, len, transform;
+ args = arguments;
+ this.initContext();
+ if (args.length > 0 && args.length % 2 === 1 && typeof args[args.length - 1] === "string") {
+ this.setColor(args[args.length - 1]);
+ }
+ if (Array.isArray(args[0])) {
+ if ((args[1] != null) && typeof args[1] === "string") {
+ this.setColor(args[1]);
+ }
+ args = args[0];
+ }
+ this.context.globalAlpha = this.alpha;
+ this.context.lineWidth = this.line_width;
+ if (args.length < 4) {
+ return;
+ }
+ len = Math.floor(args.length / 2);
+ transform = this.initDrawOp(0, 0, false);
+ this.context.beginPath();
+ this.context.moveTo(args[0], args[1]);
+ index = 2;
+ while (index <= args.length - 4) {
+ this.context.quadraticCurveTo(args[index], args[index + 1], args[index + 2], args[index + 3]);
+ index += 4;
+ }
+ this.context.stroke();
+ if (transform) {
+ return this.closeDrawOp();
+ }
+ }
+
+ drawBezierCurve() {
+ var args, index, len, transform;
+ args = arguments;
+ this.initContext();
+ if (args.length > 0 && args.length % 2 === 1 && typeof args[args.length - 1] === "string") {
+ this.setColor(args[args.length - 1]);
+ }
+ if (Array.isArray(args[0])) {
+ if ((args[1] != null) && typeof args[1] === "string") {
+ this.setColor(args[1]);
+ }
+ args = args[0];
+ }
+ this.context.globalAlpha = this.alpha;
+ this.context.lineWidth = this.line_width;
+ if (args.length < 4) {
+ return;
+ }
+ len = Math.floor(args.length / 2);
+ transform = this.initDrawOp(0, 0, false);
+ this.context.beginPath();
+ this.context.moveTo(args[0], args[1]);
+ index = 2;
+ while (index <= args.length - 6) {
+ this.context.bezierCurveTo(args[index], args[index + 1], args[index + 2], args[index + 3], args[index + 4], args[index + 5]);
+ index += 6;
+ }
+ this.context.stroke();
+ if (transform) {
+ return this.closeDrawOp();
+ }
+ }
+
+ drawArc(x, y, radius, angle1, angle2, ccw, color) {
+ this.initContext();
+ this.setColor(color);
+ this.context.globalAlpha = this.alpha;
+ this.context.lineWidth = this.line_width;
+ if (this.initDrawOp(x, y)) {
+ this.context.beginPath();
+ this.context.arc(0, 0, radius, angle1 / 180 * Math.PI, angle2 / 180 * Math.PI, ccw);
+ this.context.stroke();
+ return this.closeDrawOp(x, -y);
+ } else {
+ this.context.beginPath();
+ this.context.arc(x, y, radius, angle1 / 180 * Math.PI, angle2 / 180 * Math.PI, ccw);
+ return this.context.stroke();
+ }
+ }
+
+ fillArc(x, y, radius, angle1, angle2, ccw, color) {
+ this.initContext();
+ this.setColor(color);
+ this.context.globalAlpha = this.alpha;
+ this.context.lineWidth = this.line_width;
+ if (this.initDrawOp(x, y)) {
+ this.context.beginPath();
+ this.context.arc(0, 0, radius, angle1 / 180 * Math.PI, angle2 / 180 * Math.PI, ccw);
+ this.context.fill();
+ return this.closeDrawOp(x, -y);
+ } else {
+ this.context.beginPath();
+ this.context.arc(x, y, radius, angle1 / 180 * Math.PI, angle2 / 180 * Math.PI, ccw);
+ return this.context.fill();
+ }
+ }
+
+ textWidth(text, size) {
+ this.initContext();
+ this.context.font = `${size}pt ${this.font}`;
+ return this.context.measureText(text).width;
+ }
+
+ drawText(text, x, y, size, color) {
+ var h, w;
+ this.initContext();
+ this.setColor(color);
+ this.context.globalAlpha = this.alpha;
+ this.context.font = `${size}pt ${this.font}`;
+ this.context.textAlign = "center";
+ this.context.textBaseline = "middle";
+ w = this.context.measureText(text).width;
+ h = size;
+ if (this.initDrawOp(x, y)) {
+ this.context.fillText(text, 0 - this.anchor_x * w / 2, 0 + this.anchor_y * h / 2);
+ return this.closeDrawOp(x, y);
+ } else {
+ return this.context.fillText(text, x - this.anchor_x * w / 2, y + this.anchor_y * h / 2);
+ }
+ }
+
+ drawTextOutline(text, x, y, size, color) {
+ var h, w;
+ this.initContext();
+ this.setColor(color);
+ this.context.globalAlpha = this.alpha;
+ this.context.font = `${size}pt ${this.font}`;
+ this.context.lineWidth = this.line_width;
+ this.context.textAlign = "center";
+ this.context.textBaseline = "middle";
+ w = this.context.measureText(text).width;
+ h = size;
+ if (this.initDrawOp(x, y)) {
+ this.context.strokeText(text, 0 - this.anchor_x * w / 2, 0 + this.anchor_y * h / 2);
+ return this.closeDrawOp(x, y);
+ } else {
+ return this.context.strokeText(text, x - this.anchor_x * w / 2, y + this.anchor_y * h / 2);
+ }
+ }
+
+ getSpriteFrame(sprite) {
+ var dt, frame, s;
+ frame = null;
+ if (typeof sprite === "string") {
+ s = window.player.runtime.sprites[sprite];
+ if (s != null) {
+ sprite = s;
+ } else {
+ s = sprite.split(".");
+ if (s.length > 1) {
+ sprite = window.player.runtime.sprites[s[0]];
+ frame = s[1] | 0;
+ }
+ }
+ } else if (sprite instanceof msImage) {
+ return sprite.canvas || sprite.image;
+ }
+ if ((sprite == null) || !sprite.ready) {
+ return null;
+ }
+ if (sprite.frames.length > 1) {
+ if (frame == null) {
+ dt = 1000 / sprite.fps;
+ frame = Math.floor((Date.now() - sprite.animation_start) / dt) % sprite.frames.length;
+ }
+ if (frame >= 0 && frame < sprite.frames.length) {
+ return sprite.frames[frame].canvas;
+ } else {
+ return sprite.frames[0].canvas;
+ }
+ } else if (sprite.frames[0] != null) {
+ return sprite.frames[0].canvas;
+ } else {
+ return null;
+ }
+ }
+
+ drawImage(sprite, x, y, w, h) {
+ return this.drawSprite(sprite, x, y, w, h);
+ }
+
+ drawSprite(sprite, x, y, w, h) {
+ var canvas;
+ this.initContext();
+ canvas = this.getSpriteFrame(sprite);
+ if (canvas == null) {
+ return;
+ }
+ if (w == null) {
+ w = canvas.width;
+ }
+ if (!h) {
+ h = w / canvas.width * canvas.height;
+ }
+ this.context.globalAlpha = this.alpha;
+ this.context.imageSmoothingEnabled = !this.pixelated;
+ if (this.initDrawOp(x, y)) {
+ this.context.drawImage(canvas, -w / 2 - this.anchor_x * w / 2, -h / 2 + this.anchor_y * h / 2, w, h);
+ return this.closeDrawOp(x, y);
+ } else {
+ return this.context.drawImage(canvas, x - w / 2 - this.anchor_x * w / 2, y - h / 2 + this.anchor_y * h / 2, w, h);
+ }
+ }
+
+ drawImagePart(sprite, sx, sy, sw, sh, x, y, w, h) {
+ return this.drawSpritePart(sprite, sx, sy, sw, sh, x, y, w, h);
+ }
+
+ drawSpritePart(sprite, sx, sy, sw, sh, x, y, w, h) {
+ var canvas;
+ this.initContext();
+ canvas = this.getSpriteFrame(sprite);
+ if (canvas == null) {
+ return;
+ }
+ if (w == null) {
+ w = canvas.width;
+ }
+ if (!h) {
+ h = w / sw * sh;
+ }
+ this.context.globalAlpha = this.alpha;
+ this.context.imageSmoothingEnabled = !this.pixelated;
+ if (this.initDrawOp(x, y)) {
+ this.context.drawImage(canvas, sx, sy, sw, sh, -w / 2 - this.anchor_x * w / 2, -h / 2 + this.anchor_y * h / 2, w, h);
+ return this.closeDrawOp(x, y);
+ } else {
+ return this.context.drawImage(canvas, sx, sy, sw, sh, x - w / 2 - this.anchor_x * w / 2, y - h / 2 + this.anchor_y * h / 2, w, h);
+ }
+ }
+
+ drawMap(map, x, y, w, h) {
+ this.initContext();
+ if (typeof map === "string") {
+ map = window.player.runtime.maps[map];
+ }
+ if ((map == null) || !map.ready) {
+ return;
+ }
+ this.context.globalAlpha = this.alpha;
+ this.context.imageSmoothingEnabled = !this.pixelated;
+ if (this.initDrawOp(x, y)) {
+ map.draw(this.context, -w / 2 - this.anchor_x * w / 2, -h / 2 + this.anchor_y * h / 2, w, h);
+ return this.closeDrawOp(x, y);
+ } else {
+ return map.draw(this.context, x - w / 2 - this.anchor_x * w / 2, y - h / 2 + this.anchor_y * h / 2, w, h);
+ }
+ }
+
+ };
+
+ msImage.classname = "Image";
+
+ return msImage;
+
+}).call(this);
+
+this.BLENDING_MODES = {
+ normal: "source-over",
+ additive: "lighter"
+};
+
+ref = ["source-over", "source-in", "source-out", "source-atop", "destination-over", "destination-in", "destination-out", "destination-atop", "lighter", "copy", "xor", "multiply", "screen", "overlay", "darken", "lighten", "color-dodge", "color-burn", "hard-light", "soft-light", "difference", "exclusion", "hue", "saturation", "color", "luminosity"];
+for (j = 0, len1 = ref.length; j < len1; j++) {
+ b = ref[j];
+ this.BLENDING_MODES[b] = b;
+}
+
+this.MicroMap = (function() {
+ function MicroMap(width, height, block_width, block_height) {
+ this.width = width;
+ this.height = height;
+ this.block_width = block_width;
+ this.block_height = block_height;
+ this.sprites = window.player.runtime.sprites;
+ this.map = [];
+ this.ready = true;
+ this.clear();
+ }
+
+ MicroMap.prototype.clear = function() {
+ var i, j, k, l, ref1, ref2;
+ for (j = k = 0, ref1 = this.height - 1; k <= ref1; j = k += 1) {
+ for (i = l = 0, ref2 = this.width - 1; l <= ref2; i = l += 1) {
+ this.map[i + j * this.width] = null;
+ }
+ }
+ };
+
+ MicroMap.prototype.set = function(x, y, ref) {
+ if (x >= 0 && x < this.width && y >= 0 && y < this.height) {
+ if (typeof ref === "string") {
+ ref = ref.replace(/\//g, "-");
+ }
+ this.map[x + y * this.width] = ref;
+ return this.needs_update = true;
+ }
+ };
+
+ MicroMap.prototype.get = function(x, y) {
+ var c;
+ if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
+ return 0;
+ }
+ c = this.map[x + y * this.width];
+ if (typeof c === "string") {
+ c = c.replace(/-/g, "/");
+ }
+ return c || 0;
+ };
+
+ MicroMap.prototype.getCanvas = function() {
+ if ((this.canvas == null) || this.needs_update) {
+ this.update();
+ }
+ return this.canvas;
+ };
+
+ MicroMap.prototype.draw = function(context, x, y, w, h) {
+ var a, c, ctx, k, len, len1, ref1, time;
+ if ((this.animated != null) && this.animated.length > 0) {
+ time = Date.now();
+ if ((this.buffer == null) || this.buffer.width !== this.block_width * this.width || this.buffer.height !== this.block_height * this.height) {
+ console.info("creating buffer");
+ this.buffer = document.createElement("canvas");
+ this.buffer.width = this.block_width * this.width;
+ this.buffer.height = this.block_height * this.height;
+ }
+ ctx = this.buffer.getContext("2d");
+ ctx.clearRect(0, 0, this.buffer.width, this.buffer.height);
+ ctx.drawImage(this.getCanvas(), 0, 0);
+ ref1 = this.animated;
+ for (k = 0, len1 = ref1.length; k < len1; k++) {
+ a = ref1[k];
+ len = a.sprite.frames.length;
+ c = a.sprite.frames[Math.floor(time / 1000 * a.sprite.fps) % len].canvas;
+ if (a.tx != null) {
+ ctx.drawImage(c, a.tx, a.ty, this.block_width, this.block_height, a.x, a.y, this.block_width, this.block_height);
+ } else {
+ ctx.drawImage(c, a.x, a.y, this.block_width, this.block_height);
+ }
+ }
+ context.drawImage(this.buffer, x, y, w, h);
+ } else {
+ context.drawImage(this.getCanvas(), x, y, w, h);
+ }
+ };
+
+ MicroMap.prototype.update = function() {
+ var a, c, context, i, index, j, k, l, ref1, ref2, s, sprite, tx, ty, xy;
+ this.needs_update = false;
+ if (this.canvas == null) {
+ this.canvas = document.createElement("canvas");
+ }
+ if (this.canvas.width !== this.width * this.block_width || this.canvas.height !== this.height * this.block_height) {
+ this.canvas.width = this.width * this.block_width;
+ this.canvas.height = this.height * this.block_height;
+ }
+ context = this.canvas.getContext("2d");
+ context.clearRect(0, 0, this.canvas.width, this.canvas.height);
+ this.animated = [];
+ for (j = k = 0, ref1 = this.height - 1; k <= ref1; j = k += 1) {
+ for (i = l = 0, ref2 = this.width - 1; l <= ref2; i = l += 1) {
+ index = i + (this.height - 1 - j) * this.width;
+ s = this.map[index];
+ if ((s != null) && s.length > 0) {
+ s = s.split(":");
+ sprite = this.sprites[s[0]];
+ if (sprite == null) {
+ sprite = this.sprites[s[0].replace(/-/g, "/")];
+ }
+ if ((sprite != null) && (sprite.frames[0] != null)) {
+ if (sprite.frames.length > 1) {
+ a = {
+ x: this.block_width * i,
+ y: this.block_height * j,
+ w: this.block_width,
+ h: this.block_height,
+ sprite: sprite
+ };
+ if (s[1] != null) {
+ xy = s[1].split(",");
+ a.tx = xy[0] * this.block_width;
+ a.ty = xy[1] * this.block_height;
+ }
+ this.animated.push(a);
+ continue;
+ }
+ if (s[1] != null) {
+ xy = s[1].split(",");
+ tx = xy[0] * this.block_width;
+ ty = xy[1] * this.block_height;
+ c = sprite.frames[0].canvas;
+ if ((c != null) && c.width > 0 && c.height > 0) {
+ context.drawImage(c, tx, ty, this.block_width, this.block_height, this.block_width * i, this.block_height * j, this.block_width, this.block_height);
+ }
+ } else {
+ c = sprite.frames[0].canvas;
+ if ((c != null) && c.width > 0 && c.height > 0) {
+ context.drawImage(c, this.block_width * i, this.block_height * j);
+ }
+ }
+ }
+ }
+ }
+ }
+ };
+
+ MicroMap.prototype.loadFile = function(url) {
+ var req;
+ req = new XMLHttpRequest();
+ req.onreadystatechange = (function(_this) {
+ return function(event) {
+ if (req.readyState === XMLHttpRequest.DONE) {
+ if (req.status === 200) {
+ _this.load(req.responseText, _this.sprites);
+ return _this.update();
+ }
+ }
+ };
+ })(this);
+ req.open("GET", url);
+ return req.send();
+ };
+
+ MicroMap.prototype.load = function(data, sprites) {
+ var i, j, k, l, ref1, ref2, s;
+ data = JSON.parse(data);
+ this.width = data.width;
+ this.height = data.height;
+ this.block_width = data.block_width;
+ this.block_height = data.block_height;
+ for (j = k = 0, ref1 = data.height - 1; k <= ref1; j = k += 1) {
+ for (i = l = 0, ref2 = data.width - 1; l <= ref2; i = l += 1) {
+ s = data.data[i + j * data.width];
+ if (s > 0) {
+ this.map[i + j * data.width] = data.sprites[s];
+ } else {
+ this.map[i + j * data.width] = null;
+ }
+ }
+ }
+ };
+
+ MicroMap.prototype.clone = function() {
+ var i, j, k, l, map, ref1, ref2;
+ map = new MicroMap(this.width, this.height, this.block_width, this.block_height, this.sprites);
+ for (j = k = 0, ref1 = this.height - 1; k <= ref1; j = k += 1) {
+ for (i = l = 0, ref2 = this.width - 1; l <= ref2; i = l += 1) {
+ map.map[i + j * this.width] = this.map[i + j * this.width];
+ }
+ }
+ map.needs_update = true;
+ return map;
+ };
+
+ MicroMap.prototype.copyFrom = function(map) {
+ var i, j, k, l, ref1, ref2;
+ this.width = map.width;
+ this.height = map.height;
+ this.block_width = map.block_width;
+ this.block_height = map.block_height;
+ for (j = k = 0, ref1 = this.height - 1; k <= ref1; j = k += 1) {
+ for (i = l = 0, ref2 = this.width - 1; l <= ref2; i = l += 1) {
+ this.map[i + j * this.width] = map.map[i + j * this.width];
+ }
+ }
+ this.update();
+ return this;
+ };
+
+ return MicroMap;
+
+})();
+
+this.LoadMap = function(url, loaded) {
+ var map, req;
+ map = new MicroMap(1, 1, 1, 1);
+ map.ready = false;
+ req = new XMLHttpRequest();
+ req.onreadystatechange = (function(_this) {
+ return function(event) {
+ if (req.readyState === XMLHttpRequest.DONE) {
+ map.ready = true;
+ if (req.status === 200) {
+ UpdateMap(map, req.responseText);
+ }
+ map.needs_update = true;
+ if (loaded != null) {
+ return loaded();
+ }
+ }
+ };
+ })(this);
+ req.open("GET", url);
+ req.send();
+ return map;
+};
+
+this.UpdateMap = function(map, data) {
+ var i, j, k, l, ref1, ref2, s;
+ data = JSON.parse(data);
+ map.width = data.width;
+ map.height = data.height;
+ map.block_width = data.block_width;
+ map.block_height = data.block_height;
+ for (j = k = 0, ref1 = data.height - 1; k <= ref1; j = k += 1) {
+ for (i = l = 0, ref2 = data.width - 1; l <= ref2; i = l += 1) {
+ s = data.data[i + j * data.width];
+ if (s > 0) {
+ map.map[i + j * data.width] = data.sprites[s];
+ } else {
+ map.map[i + j * data.width] = null;
+ }
+ }
+ }
+ map.needs_update = true;
+ return map;
+};
+
+this.SaveMap = function(map) {
+ var data, i, index, j, k, l, list, m, n, o, ref1, ref2, ref3, ref4, s, table;
+ index = 1;
+ list = [0];
+ table = {};
+ for (j = k = 0, ref1 = map.height - 1; k <= ref1; j = k += 1) {
+ for (i = l = 0, ref2 = map.width - 1; l <= ref2; i = l += 1) {
+ s = map.map[i + j * map.width];
+ if ((s != null) && s.length > 0 && (table[s] == null)) {
+ list.push(s);
+ table[s] = index++;
+ }
+ }
+ }
+ m = [];
+ for (j = n = 0, ref3 = map.height - 1; n <= ref3; j = n += 1) {
+ for (i = o = 0, ref4 = map.width - 1; o <= ref4; i = o += 1) {
+ s = map.map[i + j * map.width];
+ m[i + j * map.width] = (s != null) && s.length > 0 ? table[s] : 0;
+ }
+ }
+ data = {
+ width: map.width,
+ height: map.height,
+ block_width: map.block_width,
+ block_height: map.block_height,
+ sprites: list,
+ data: m
+ };
+ return JSON.stringify(data);
+};
+
+this.AudioCore = (function() {
+ function AudioCore(runtime) {
+ this.runtime = runtime;
+ this.buffer = [];
+ this.getContext();
+ this.playing = [];
+ this.wakeup_list = [];
+ }
+
+ AudioCore.prototype.isStarted = function() {
+ return this.context.state === "running";
+ };
+
+ AudioCore.prototype.addToWakeUpList = function(item) {
+ return this.wakeup_list.push(item);
+ };
+
+ AudioCore.prototype.getInterface = function() {
+ var audio;
+ audio = this;
+ return this["interface"] = {
+ beep: function(sequence) {
+ return audio.beep(sequence);
+ },
+ cancelBeeps: function() {
+ return audio.cancelBeeps();
+ },
+ playSound: function(sound, volume, pitch, pan, loopit) {
+ return audio.playSound(sound, volume, pitch, pan, loopit);
+ },
+ playMusic: function(music, volume, loopit) {
+ return audio.playMusic(music, volume, loopit);
+ }
+ };
+ };
+
+ AudioCore.prototype.playSound = function(sound, volume, pitch, pan, loopit) {
+ var s;
+ if (volume == null) {
+ volume = 1;
+ }
+ if (pitch == null) {
+ pitch = 1;
+ }
+ if (pan == null) {
+ pan = 0;
+ }
+ if (loopit == null) {
+ loopit = 0;
+ }
+ if (typeof sound === "string") {
+ s = this.runtime.sounds[sound.replace(/\//g, "-")];
+ if (s != null) {
+ return s.play(volume, pitch, pan, loopit);
+ }
+ }
+ return 0;
+ };
+
+ AudioCore.prototype.playMusic = function(music, volume, loopit) {
+ var m;
+ if (volume == null) {
+ volume = 1;
+ }
+ if (loopit == null) {
+ loopit = 0;
+ }
+ if (typeof music === "string") {
+ m = this.runtime.music[music.replace(/\//g, "-")];
+ if (m != null) {
+ return m.play(volume, loopit);
+ }
+ }
+ return 0;
+ };
+
+ AudioCore.prototype.start = function() {
+ var blob, src;
+ if (false) {
+ blob = new Blob([AudioCore.processor], {
+ type: "text/javascript"
+ });
+ return this.context.audioWorklet.addModule(window.URL.createObjectURL(blob)).then((function(_this) {
+ return function() {
+ _this.node = new AudioWorkletNode(_this.context, "my-worklet-processor");
+ _this.node.connect(_this.context.destination);
+ return _this.flushBuffer();
+ };
+ })(this));
+ } else {
+ this.script_processor = this.context.createScriptProcessor(4096, 2, 2);
+ this.processor_funk = (function(_this) {
+ return function(event) {
+ return _this.onAudioProcess(event);
+ };
+ })(this);
+ this.script_processor.onaudioprocess = this.processor_funk;
+ this.script_processor.connect(this.context.destination);
+ src = "class AudioWorkletProcessor {\n constructor() {\n this.port = {} ;\n\n var _this = this ;\n\n this.port.postMessage = function(data) {\n var event = { data: data } ;\n _this.port.onmessage(event) ;\n }\n }\n\n} ;\nregisterProcessor = function(a,b) {\n return new MyWorkletProcessor()\n} ;\n";
+ src += AudioCore.processor;
+ this.node = eval(src);
+ this.flushBuffer();
+ return this.bufferizer = new AudioBufferizer(this.node);
+ }
+ };
+
+ AudioCore.prototype.flushBuffer = function() {
+ var results;
+ results = [];
+ while (this.buffer.length > 0) {
+ results.push(this.node.port.postMessage(this.buffer.splice(0, 1)[0]));
+ }
+ return results;
+ };
+
+ AudioCore.prototype.onAudioProcess = function(event) {
+ var left, outputs, right;
+ left = event.outputBuffer.getChannelData(0);
+ right = event.outputBuffer.getChannelData(1);
+ outputs = [[left, right]];
+ this.bufferizer.flush(outputs);
+ };
+
+ AudioCore.prototype.getContext = function() {
+ var activate;
+ if (this.context == null) {
+ this.context = new (window.AudioContext || window.webkitAudioContext);
+ if (this.context.state !== "running") {
+ activate = (function(_this) {
+ return function() {
+ var item, j, len, ref;
+ console.info("resuming context");
+ _this.context.resume();
+ if (_this.beeper != null) {
+ _this.start();
+ }
+ ref = _this.wakeup_list;
+ for (j = 0, len = ref.length; j < len; j++) {
+ item = ref[j];
+ item.wakeUp();
+ }
+ document.body.removeEventListener("touchend", activate);
+ return document.body.removeEventListener("mouseup", activate);
+ };
+ })(this);
+ document.body.addEventListener("touchend", activate);
+ document.body.addEventListener("mouseup", activate);
+ } else if (this.beeper != null) {
+ this.start();
+ }
+ }
+ return this.context;
+ };
+
+ AudioCore.prototype.getBeeper = function() {
+ if (this.beeper == null) {
+ this.beeper = new Beeper(this);
+ if (this.context.state === "running") {
+ this.start();
+ }
+ }
+ return this.beeper;
+ };
+
+ AudioCore.prototype.beep = function(sequence) {
+ return this.getBeeper().beep(sequence);
+ };
+
+ AudioCore.prototype.addBeeps = function(beeps) {
+ var b, j, len;
+ for (j = 0, len = beeps.length; j < len; j++) {
+ b = beeps[j];
+ b.duration *= this.context.sampleRate;
+ b.increment = b.frequency / this.context.sampleRate;
+ }
+ if (this.node != null) {
+ return this.node.port.postMessage(JSON.stringify({
+ name: "beep",
+ sequence: beeps
+ }));
+ } else {
+ return this.buffer.push(JSON.stringify({
+ name: "beep",
+ sequence: beeps
+ }));
+ }
+ };
+
+ AudioCore.prototype.cancelBeeps = function() {
+ if (this.node != null) {
+ this.node.port.postMessage(JSON.stringify({
+ name: "cancel_beeps"
+ }));
+ } else {
+ this.buffer.push(JSON.stringify({
+ name: "cancel_beeps"
+ }));
+ }
+ return this.stopAll();
+ };
+
+ AudioCore.prototype.addPlaying = function(item) {
+ return this.playing.push(item);
+ };
+
+ AudioCore.prototype.removePlaying = function(item) {
+ var index;
+ index = this.playing.indexOf(item);
+ if (index >= 0) {
+ return this.playing.splice(index, 1);
+ }
+ };
+
+ AudioCore.prototype.stopAll = function() {
+ var err, j, len, p, ref;
+ ref = this.playing;
+ for (j = 0, len = ref.length; j < len; j++) {
+ p = ref[j];
+ try {
+ p.stop();
+ } catch (error) {
+ err = error;
+ console.error(err);
+ }
+ }
+ return this.playing = [];
+ };
+
+ AudioCore.processor = "class MyWorkletProcessor extends AudioWorkletProcessor {\n constructor() {\n super();\n this.beeps = [] ;\n this.last = 0 ;\n this.port.onmessage = (event) => {\n let data = JSON.parse(event.data) ;\n if (data.name == \"cancel_beeps\")\n {\n this.beeps = [] ;\n }\n else if (data.name == \"beep\")\n {\n let seq = data.sequence ;\n for (let i=0;i0)\n {\n seq[i-1].next = note ;\n }\n\n if (note.loopto != null)\n {\n note.loopto = seq[note.loopto] ;\n }\n\n note.phase = 0 ;\n note.time = 0 ;\n }\n\n this.beeps.push(seq[0]) ;\n }\n } ;\n }\n\n process(inputs, outputs, parameters) {\n var output = outputs[0] ;\n var phase ;\n for (var i=0;i0)\n {\n for (var j=0;j=0;k--)\n {\n let b = this.beeps[k];\n let volume = b.volume ;\n if (b.time/b.duration>b.span)\n {\n volume = 0 ;\n }\n if (b.waveform == \"square\")\n {\n sig += b.phase>.5? volume : -volume ;\n }\n else if (b.waveform == \"saw\")\n {\n sig += (b.phase*2-1)*volume ;\n }\n else if (b.waveform == \"noise\")\n {\n sig += (Math.random()*2-1)*volume ;\n }\n else\n {\n sig += Math.sin(b.phase*Math.PI*2)*volume ;\n }\n\n b.phase = (b.phase+b.increment)%1 ;\n b.time += 1 ;\n if (b.time>=b.duration)\n {\n b.time = 0 ;\n if (b.loopto != null)\n {\n if (b.repeats != null && b.repeats>0)\n {\n if (b.loopcount == null)\n {\n b.loopcount = 0 ;\n }\n b.loopcount++ ;\n if (b.loopcount>=b.repeats)\n {\n b.loopcount = 0 ;\n if (b.next != null)\n {\n b.next.phase = b.phase ;\n b = b.next ;\n this.beeps[k] = b ;\n }\n else\n {\n this.beeps.splice(k,1) ;\n }\n }\n else\n {\n b.loopto.phase = b.phase ;\n b = b.loopto ;\n this.beeps[k] = b ;\n }\n }\n else\n {\n b.loopto.phase = b.phase ;\n b = b.loopto ;\n this.beeps[k] = b ;\n }\n }\n else if (b.next != null)\n {\n b.next.phase = b.phase ;\n b = b.next ;\n this.beeps[k] = b ;\n }\n else\n {\n this.beeps.splice(k,1) ;\n }\n }\n }\n this.last = this.last*.9+sig*.1 ;\n channel[j] = this.last ;\n }\n }\n }\n return true ;\n }\n}\n\nregisterProcessor('my-worklet-processor', MyWorkletProcessor);";
+
+ return AudioCore;
+
+})();
+
+this.AudioBufferizer = (function() {
+ function AudioBufferizer(node) {
+ var i, j, k, left, ref, right;
+ this.node = node;
+ this.buffer_size = 4096;
+ this.chunk_size = 512;
+ this.chunks = [];
+ this.nb_chunks = this.buffer_size / this.chunk_size;
+ for (i = j = 0, ref = this.nb_chunks - 1; j <= ref; i = j += 1) {
+ left = (function() {
+ var n, ref1, results;
+ results = [];
+ for (k = n = 0, ref1 = this.chunk_size - 1; 0 <= ref1 ? n <= ref1 : n >= ref1; k = 0 <= ref1 ? ++n : --n) {
+ results.push(0);
+ }
+ return results;
+ }).call(this);
+ right = (function() {
+ var n, ref1, results;
+ results = [];
+ for (k = n = 0, ref1 = this.chunk_size - 1; 0 <= ref1 ? n <= ref1 : n >= ref1; k = 0 <= ref1 ? ++n : --n) {
+ results.push(0);
+ }
+ return results;
+ }).call(this);
+ this.chunks[i] = [[left, right]];
+ }
+ this.current = 0;
+ setInterval(((function(_this) {
+ return function() {
+ return _this.step();
+ };
+ })(this)), this.chunk_size / 44100 * 1000);
+ }
+
+ AudioBufferizer.prototype.step = function() {
+ if (this.current >= this.chunks.length) {
+ return;
+ }
+ this.node.process(null, this.chunks[this.current], null);
+ this.current++;
+ };
+
+ AudioBufferizer.prototype.flush = function(outputs) {
+ var chunk, i, index, j, k, l, left, n, r, ref, ref1, right;
+ while (this.current < this.chunks.length) {
+ this.step();
+ }
+ this.current = 0;
+ left = outputs[0][0];
+ right = outputs[0][1];
+ index = 0;
+ chunk = 0;
+ for (i = j = 0, ref = this.chunks.length - 1; 0 <= ref ? j <= ref : j >= ref; i = 0 <= ref ? ++j : --j) {
+ chunk = this.chunks[i];
+ l = chunk[0][0];
+ r = chunk[0][1];
+ for (k = n = 0, ref1 = l.length - 1; 0 <= ref1 ? n <= ref1 : n >= ref1; k = 0 <= ref1 ? ++n : --n) {
+ left[index] = l[k];
+ right[index] = r[k];
+ index += 1;
+ }
+ }
+ };
+
+ return AudioBufferizer;
+
+})();
+
+this.Beeper = (function() {
+ function Beeper(audio) {
+ var i, j, k, l, len, len1, n, oct, ref, ref1, text;
+ this.audio = audio;
+ this.notes = {};
+ this.plain_notes = {};
+ text = [["C", "DO"], ["C#", "DO#", "Db", "REb"], ["D", "RE"], ["D#", "RE#", "Eb", "MIb"], ["E", "MI"], ["F", "FA"], ["F#", "FA#", "Gb", "SOLb"], ["G", "SOL"], ["G#", "SOL#", "Ab", "LAb"], ["A", "LA"], ["A#", "LA#", "Bb", "SIb"], ["B", "SI"]];
+ for (i = j = 0; j <= 127; i = j += 1) {
+ this.notes[i] = i;
+ oct = Math.floor(i / 12) - 1;
+ ref = text[i % 12];
+ for (k = 0, len = ref.length; k < len; k++) {
+ n = ref[k];
+ this.notes[n + oct] = i;
+ }
+ if (oct === -1) {
+ ref1 = text[i % 12];
+ for (l = 0, len1 = ref1.length; l < len1; l++) {
+ n = ref1[l];
+ this.plain_notes[n] = i;
+ }
+ }
+ }
+ this.current_octave = 5;
+ this.current_duration = .5;
+ this.current_volume = .5;
+ this.current_span = 1;
+ this.current_waveform = "square";
+ }
+
+ Beeper.prototype.beep = function(input) {
+ var i, j, k, len, loops, lop, n, note, parsed, ref, ref1, sequence, status, t, test;
+ test = "loop 0 square tempo 120 duration 500 volume 50 span 50 DO2 DO - FA SOL SOL FA -";
+ status = "normal";
+ sequence = [];
+ loops = [];
+ parsed = input.split(" ");
+ for (j = 0, len = parsed.length; j < len; j++) {
+ t = parsed[j];
+ if (t === "") {
+ continue;
+ }
+ switch (status) {
+ case "normal":
+ if (this.notes[t] != null) {
+ note = this.notes[t];
+ this.current_octave = Math.floor(note / 12);
+ sequence.push({
+ frequency: 440 * Math.pow(Math.pow(2, 1 / 12), note - 69),
+ volume: this.current_volume,
+ span: this.current_span,
+ duration: this.current_duration,
+ waveform: this.current_waveform
+ });
+ } else if (this.plain_notes[t] != null) {
+ note = this.plain_notes[t] + this.current_octave * 12;
+ sequence.push({
+ frequency: 440 * Math.pow(Math.pow(2, 1 / 12), note - 69),
+ volume: this.current_volume,
+ span: this.current_span,
+ duration: this.current_duration,
+ waveform: this.current_waveform
+ });
+ } else if (t === "square" || t === "sine" || t === "saw" || t === "noise") {
+ this.current_waveform = t;
+ } else if (t === "tempo" || t === "duration" || t === "volume" || t === "span" || t === "loop" || t === "to") {
+ status = t;
+ } else if (t === "-") {
+ sequence.push({
+ frequency: 440,
+ volume: 0,
+ span: this.current_span,
+ duration: this.current_duration,
+ waveform: this.current_waveform
+ });
+ } else if (t === "end") {
+ if (loops.length > 0 && sequence.length > 0) {
+ sequence.push({
+ frequency: 440,
+ volume: 0,
+ span: this.current_span,
+ duration: 0,
+ waveform: this.current_waveform
+ });
+ lop = loops.splice(loops.length - 1, 1)[0];
+ sequence[sequence.length - 1].loopto = lop.start;
+ sequence[sequence.length - 1].repeats = lop.repeats;
+ }
+ }
+ break;
+ case "tempo":
+ status = "normal";
+ t = Number.parseFloat(t);
+ if (!Number.isNaN(t) && t > 0) {
+ this.current_duration = 60 / t;
+ }
+ break;
+ case "duration":
+ status = "normal";
+ t = Number.parseFloat(t);
+ if (!Number.isNaN(t) && t > 0) {
+ this.current_duration = t / 1000;
+ }
+ break;
+ case "volume":
+ status = "normal";
+ t = Number.parseFloat(t);
+ if (!Number.isNaN(t)) {
+ this.current_volume = t / 100;
+ }
+ break;
+ case "span":
+ status = "normal";
+ t = Number.parseFloat(t);
+ if (!Number.isNaN(t)) {
+ this.current_span = t / 100;
+ }
+ break;
+ case "loop":
+ status = "normal";
+ loops.push({
+ start: sequence.length
+ });
+ t = Number.parseFloat(t);
+ if (!Number.isNaN(t)) {
+ loops[loops.length - 1].repeats = t;
+ }
+ break;
+ case "to":
+ status = "normal";
+ if (note != null) {
+ n = null;
+ if (this.notes[t] != null) {
+ n = this.notes[t];
+ } else if (this.plain_notes[t] != null) {
+ n = this.plain_notes[t] + this.current_octave * 12;
+ }
+ if ((n != null) && n !== note) {
+ for (i = k = ref = note, ref1 = n; ref <= ref1 ? k <= ref1 : k >= ref1; i = ref <= ref1 ? ++k : --k) {
+ if (i !== note) {
+ sequence.push({
+ frequency: 440 * Math.pow(Math.pow(2, 1 / 12), i - 69),
+ volume: this.current_volume,
+ span: this.current_span,
+ duration: this.current_duration,
+ waveform: this.current_waveform
+ });
+ }
+ }
+ note = n;
+ }
+ }
+ }
+ }
+ if (loops.length > 0 && sequence.length > 0) {
+ lop = loops.splice(loops.length - 1, 1)[0];
+ sequence.push({
+ frequency: 440,
+ volume: 0,
+ span: this.current_span,
+ duration: 0,
+ waveform: this.current_waveform
+ });
+ sequence[sequence.length - 1].loopto = lop.start;
+ sequence[sequence.length - 1].repeats = lop.repeats;
+ }
+ return this.audio.addBeeps(sequence);
+ };
+
+ return Beeper;
+
+})();
+
+this.Sound = class Sound {
+ constructor(audio, url) {
+ var request;
+ this.audio = audio;
+ this.url = url;
+ if (typeof MicroSound !== "undefined" && MicroSound !== null) {
+ this.class = MicroSound;
+ }
+ if (this.url instanceof AudioBuffer) {
+ this.buffer = this.url;
+ this.ready = 1;
+ } else {
+ this.ready = 0;
+ request = new XMLHttpRequest();
+ request.open('GET', this.url, true);
+ request.responseType = 'arraybuffer';
+ request.onload = () => {
+ return this.audio.context.decodeAudioData(request.response, (buffer1) => {
+ this.buffer = buffer1;
+ return this.ready = 1;
+ });
+ };
+ request.send();
+ }
+ }
+
+ play(volume = 1, pitch = 1, pan = 0, loopit = false) {
+ var gain, panner, playing, res, source;
+ if (this.buffer == null) {
+ return;
+ }
+ source = this.audio.context.createBufferSource();
+ source.playbackRate.value = pitch;
+ source.buffer = this.buffer;
+ if (loopit) {
+ source.loop = true;
+ }
+ gain = this.audio.context.createGain();
+ gain.gain.value = volume;
+ if (false && (this.audio.context.createStereoPanner != null)) {
+ panner = this.audio.context.createStereoPanner();
+ panner.setPan = function(pan) {
+ return panner.pan.value = pan;
+ };
+ } else {
+ panner = this.audio.context.createPanner();
+ panner.panningModel = "equalpower";
+ panner.setPan = function(pan) {
+ return panner.setPosition(pan, 0, 1 - Math.abs(pan));
+ };
+ }
+ panner.setPan(pan);
+ source.connect(gain);
+ gain.connect(panner);
+ panner.connect(this.audio.context.destination);
+ source.start();
+ playing = null;
+ if (loopit) {
+ playing = {
+ stop: () => {
+ return source.stop();
+ }
+ };
+ this.audio.addPlaying(playing);
+ }
+ res = {
+ stop: () => {
+ source.stop();
+ if (playing) {
+ this.audio.removePlaying(playing);
+ }
+ return 1;
+ },
+ setVolume: function(volume) {
+ return gain.gain.value = Math.max(0, Math.min(1, volume));
+ },
+ setPitch: function(pitch) {
+ return source.playbackRate.value = Math.max(.001, Math.min(1000, pitch));
+ },
+ setPan: function(pan) {
+ return panner.setPan(Math.max(-1, Math.min(1, pan)));
+ },
+ getDuration: function() {
+ return source.buffer.duration;
+ },
+ finished: false
+ };
+ source.onended = function() {
+ return res.finished = true;
+ };
+ return res;
+ }
+
+ static createSoundClass(audiocore) {
+ return window.MicroSound = (function() {
+ var _Class;
+
+ _Class = class {
+ constructor(channels, length, sampleRate = 44100) {
+ var buffer, ch1, ch2, snd;
+ this.class = MicroSound;
+ channels = channels === 1 ? 1 : 2;
+ if (!(length > 1) || !(length < 44100 * 1000)) {
+ length = 44100;
+ }
+ if (!(sampleRate >= 8000) || !(sampleRate <= 96000)) {
+ sampleRate = 44100;
+ }
+ buffer = audiocore.context.createBuffer(channels, length, sampleRate);
+ snd = new Sound(audiocore, buffer);
+ this.channels = channels;
+ this.length = length;
+ this.sampleRate = sampleRate;
+ ch1 = buffer.getChannelData(0);
+ if (channels === 2) {
+ ch2 = buffer.getChannelData(1);
+ }
+ this.play = function(volume, pitch, pan, loopit) {
+ return snd.play(volume, pitch, pan, loopit);
+ };
+ this.write = function(channel, position, value) {
+ if (channel === 0) {
+ ch1 = buffer.getChannelData(0);
+ return ch1[position] = value;
+ } else if (channels === 2) {
+ ch2 = buffer.getChannelData(1);
+ return ch2[position] = value;
+ }
+ };
+ this.read = function(channel, position) {
+ if (channel === 0) {
+ ch1 = buffer.getChannelData(0);
+ return ch1[position];
+ } else if (channels === 2) {
+ ch2 = buffer.getChannelData(1);
+ return ch2[position];
+ } else {
+ return 0;
+ }
+ };
+ }
+
+ };
+
+ _Class.classname = "Sound";
+
+ return _Class;
+
+ }).call(this);
+ }
+
+};
+
+this.Music = (function() {
+ function Music(audio, url) {
+ this.audio = audio;
+ this.url = url;
+ this.tag = new Audio(this.url);
+ this.playing = false;
+ }
+
+ Music.prototype.play = function(volume, loopit) {
+ if (volume == null) {
+ volume = 1;
+ }
+ if (loopit == null) {
+ loopit = false;
+ }
+ this.playing = true;
+ this.tag.loop = loopit ? true : false;
+ this.tag.volume = volume;
+ if (this.audio.isStarted()) {
+ this.tag.play();
+ } else {
+ this.audio.addToWakeUpList(this);
+ }
+ this.audio.addPlaying(this);
+ return {
+ play: (function(_this) {
+ return function() {
+ return _this.tag.play();
+ };
+ })(this),
+ stop: (function(_this) {
+ return function() {
+ _this.playing = false;
+ _this.tag.pause();
+ return _this.audio.removePlaying(_this);
+ };
+ })(this),
+ setVolume: (function(_this) {
+ return function(volume) {
+ return _this.tag.volume = Math.max(0, Math.min(1, volume));
+ };
+ })(this),
+ getPosition: (function(_this) {
+ return function() {
+ return _this.tag.currentTime;
+ };
+ })(this),
+ getDuration: (function(_this) {
+ return function() {
+ return _this.tag.duration;
+ };
+ })(this),
+ setPosition: (function(_this) {
+ return function(pos) {
+ _this.tag.pause();
+ _this.tag.currentTime = Math.max(0, Math.min(_this.tag.duration, pos));
+ if (_this.playing) {
+ return _this.tag.play();
+ }
+ };
+ })(this)
+ };
+ };
+
+ Music.prototype.wakeUp = function() {
+ if (this.playing) {
+ return this.tag.play();
+ }
+ };
+
+ Music.prototype.stop = function() {
+ this.playing = false;
+ return this.tag.pause();
+ };
+
+ return Music;
+
+})();
+
+this.Player = class Player {
+ constructor(listener) {
+ var i, len, ref, source;
+ this.listener = listener;
+ //src = document.getElementById("code").innerText
+ this.source_count = 0;
+ this.sources = {};
+ this.resources = resources;
+ this.request_id = 1;
+ this.pending_requests = {};
+ if (resources.sources != null) {
+ ref = resources.sources;
+ for (i = 0, len = ref.length; i < len; i++) {
+ source = ref[i];
+ this.loadSource(source);
+ }
+ } else {
+ this.sources.main = document.getElementById("code").innerText;
+ this.start();
+ }
+ }
+
+ loadSource(source) {
+ var req;
+ req = new XMLHttpRequest();
+ req.onreadystatechange = (event) => {
+ var name;
+ if (req.readyState === XMLHttpRequest.DONE) {
+ if (req.status === 200) {
+ name = source.file.split(".")[0];
+ this.sources[name] = req.responseText;
+ this.source_count++;
+ if (this.source_count >= resources.sources.length && (this.runtime == null)) {
+ return this.start();
+ }
+ }
+ }
+ };
+ req.open("GET", location.origin + location.pathname + `ms/${source.file}?v=${source.version}`);
+ return req.send();
+ }
+
+ start() {
+ var touchListener, touchStartListener, wrapper;
+ this.runtime = new Runtime((window.exported_project ? "" : location.origin + location.pathname), this.sources, resources, this);
+ this.client = new PlayerClient(this);
+ wrapper = document.getElementById("canvaswrapper");
+ wrapper.appendChild(this.runtime.screen.canvas);
+ window.addEventListener("resize", () => {
+ return this.resize();
+ });
+ this.resize();
+ //@runtime.start()
+ touchStartListener = (event) => {
+ event.preventDefault();
+ //event.stopPropagation()
+ //event.stopImmediatePropagation()
+ this.runtime.screen.canvas.removeEventListener("touchstart", touchStartListener);
+ return true;
+ };
+ touchListener = (event) => {
+ //event.preventDefault()
+ //event.stopPropagation()
+ //event.stopImmediatePropagation()
+ //@runtime.screen.canvas.removeEventListener "touchend",touchListener
+ if ((this.runtime != null) && (this.runtime.vm != null) && this.runtime.vm.context.global.system.disable_autofullscreen) {
+ return true;
+ } else {
+ this.setFullScreen();
+ }
+ return true;
+ };
+ this.runtime.screen.canvas.addEventListener("touchstart", touchStartListener);
+ this.runtime.screen.canvas.addEventListener("touchend", touchListener);
+ this.runtime.start();
+ window.addEventListener("message", (msg) => {
+ return this.messageReceived(msg);
+ });
+ return this.postMessage({
+ name: "focus"
+ });
+ }
+
+ resize() {
+ var file, ref, results, src;
+ this.runtime.screen.resize();
+ if (this.runtime.vm != null) {
+ if (this.runtime.vm.context.global.draw == null) {
+ this.runtime.update_memory = {};
+ ref = this.runtime.sources;
+ results = [];
+ for (file in ref) {
+ src = ref[file];
+ results.push(this.runtime.updateSource(file, src, false));
+ }
+ return results;
+ } else if (this.runtime.stopped) {
+ return this.runtime.drawCall();
+ }
+ }
+ }
+
+ setFullScreen() {
+ var ref;
+ if ((document.documentElement.webkitRequestFullScreen != null) && !document.webkitIsFullScreen) {
+ document.documentElement.webkitRequestFullScreen();
+ } else if ((document.documentElement.requestFullScreen != null) && !document.fullScreen) {
+ document.documentElement.requestFullScreen();
+ } else if ((document.documentElement.mozRequestFullScreen != null) && !document.mozFullScreen) {
+ document.documentElement.mozRequestFullScreen();
+ }
+ if ((window.screen != null) && (window.screen.orientation != null) && ((ref = window.orientation) === "portrait" || ref === "landscape")) {
+ return window.screen.orientation.lock(window.orientation).then(null, function(error) {});
+ }
+ }
+
+ //console.error error
+ reportError(err) {
+ return this.postMessage({
+ name: "error",
+ data: err
+ });
+ }
+
+ log(text) {
+ return this.postMessage({
+ name: "log",
+ data: text
+ });
+ }
+
+ codePaused() {
+ return this.postMessage({
+ name: "code_paused"
+ });
+ }
+
+ exit() {
+ return this.postMessage({
+ name: "exit"
+ });
+ }
+
+ messageReceived(msg) {
+ var code, data, err, file;
+ data = msg.data;
+ try {
+ data = JSON.parse(data);
+ switch (data.name) {
+ case "command":
+ return this.runtime.runCommand(data.line, (res) => {
+ if (!data.line.trim().startsWith("print")) {
+ return this.postMessage({
+ name: "output",
+ data: res,
+ id: data.id
+ });
+ }
+ });
+ case "pause":
+ return this.runtime.stop();
+ case "step_forward":
+ return this.runtime.stepForward();
+ case "resume":
+ return this.runtime.resume();
+ case "code_updated":
+ code = data.code;
+ file = data.file.split(".")[0];
+ if (this.runtime.vm != null) {
+ this.runtime.vm.clearWarnings();
+ }
+ return this.runtime.updateSource(file, code, true);
+ case "sprite_updated":
+ file = data.file;
+ return this.runtime.updateSprite(file, 0, data.data, data.properties);
+ case "map_updated":
+ file = data.file;
+ return this.runtime.updateMap(file, 0, data.data);
+ case "take_picture":
+ this.runtime.screen.takePicture((pic) => {
+ return this.postMessage({
+ name: "picture_taken",
+ data: pic
+ });
+ });
+ if (this.runtime.stopped) {
+ return this.runtime.drawCall();
+ }
+ break;
+ case "time_machine":
+ return this.runtime.time_machine.messageReceived(data);
+ case "watch":
+ return this.runtime.watch(data.list);
+ case "stop_watching":
+ return this.runtime.stopWatching();
+ default:
+ if (data.request_id != null) {
+ if (this.pending_requests[data.request_id] != null) {
+ this.pending_requests[data.request_id](data);
+ return delete this.pending_requests[data.request_id];
+ }
+ }
+ }
+ } catch (error1) {
+ err = error1;
+ return console.error(err);
+ }
+ }
+
+ call(name, args) {
+ if ((this.runtime != null) && (this.runtime.vm != null)) {
+ return this.runtime.vm.call(name, args);
+ }
+ }
+
+ setGlobal(name, value) {
+ if ((this.runtime != null) && (this.runtime.vm != null)) {
+ return this.runtime.vm.context.global[name] = value;
+ }
+ }
+
+ exec(command, callback) {
+ if (this.runtime != null) {
+ return this.runtime.runCommand(command, callback);
+ }
+ }
+
+ postMessage(data) {
+ var err;
+ if (window !== window.parent) {
+ window.parent.postMessage(JSON.stringify(data), "*");
+ }
+ if (this.listener != null) {
+ try {
+ return this.listener(data);
+ } catch (error1) {
+ err = error1;
+ return console.error(err);
+ }
+ }
+ }
+
+ postRequest(data, callback) {
+ data.request_id = this.request_id;
+ this.pending_requests[this.request_id++] = callback;
+ return this.postMessage(data);
+ }
+
+};
+
+if ((navigator.serviceWorker != null) && !window.skip_service_worker) {
+ navigator.serviceWorker.register('sw.js', {
+ scope: location.pathname
+ }).then(function(reg) {
+ return console.log('Registration succeeded. Scope is' + reg.scope);
+ }).catch(function(error) {
+ return console.log('Registration failed with' + error);
+ });
+}
+
+this.PlayerClient = class PlayerClient {
+ constructor(player) {
+ var err;
+ this.player = player;
+ this.pending_requests = {};
+ this.request_id = 0;
+ this.version_checked = false;
+ this.reconnect_delay = 1000;
+ if (location.protocol.startsWith("http") && !window.exported_project) {
+ try {
+ this.connect();
+ } catch (error) {
+ err = error;
+ console.error(err);
+ }
+ setInterval((() => {
+ if (this.socket != null) {
+ return this.sendRequest({
+ name: "ping"
+ });
+ }
+ }), 30000);
+ }
+ }
+
+ connect() {
+ this.socket = new WebSocket(window.location.origin.replace("http", "ws"));
+ this.socket.onmessage = (msg) => {
+ var err;
+ console.info("received: " + msg.data);
+ try {
+ msg = JSON.parse(msg.data);
+ if (msg.request_id != null) {
+ if (this.pending_requests[msg.request_id] != null) {
+ this.pending_requests[msg.request_id](msg);
+ delete this.pending_requests[msg.request_id];
+ }
+ }
+ //if msg.name == "code_updated"
+ // @player.runtime.updateSource(msg.file,msg.code,true)
+
+ //if msg.name == "sprite_updated"
+ // @player.runtime.updateSprite(msg.sprite)
+ if (msg.name === "project_file_updated") {
+ this.player.runtime.projectFileUpdated(msg.type, msg.file, msg.version, msg.data, msg.properties);
+ }
+ if (msg.name === "project_file_deleted") {
+ this.player.runtime.projectFileDeleted(msg.type, msg.file);
+ }
+ if (msg.name === "project_options_updated") {
+ return this.player.runtime.projectOptionsUpdated(msg);
+ }
+ } catch (error) {
+ err = error;
+ return console.error(err);
+ }
+ };
+ this.socket.onopen = () => {
+ var i, j, k, l, len, len1, len2, len3, m, maps, project, ref, ref1, ref2, ref3, s, sources, sprites, user;
+ //console.info "socket opened"
+ this.reconnect_delay = 1000;
+ user = location.pathname.split("/")[1];
+ project = location.pathname.split("/")[2];
+ if (this.buffer != null) {
+ ref = this.buffer;
+ for (i = 0, len = ref.length; i < len; i++) {
+ m = ref[i];
+ this.send(m);
+ }
+ delete this.buffer;
+ }
+ this.send({
+ name: "listen_to_project",
+ user: user,
+ project: project
+ });
+ if (!this.version_checked) {
+ this.version_checked = true;
+ sprites = {};
+ maps = {};
+ sources = {};
+ ref1 = this.player.resources.images;
+ for (j = 0, len1 = ref1.length; j < len1; j++) {
+ s = ref1[j];
+ sprites[s.file.split(".")[0]] = s.version;
+ }
+ ref2 = this.player.resources.maps;
+ for (k = 0, len2 = ref2.length; k < len2; k++) {
+ s = ref2[k];
+ maps[s.file.split(".")[0]] = s.version;
+ }
+ ref3 = this.player.resources.sources;
+ for (l = 0, len3 = ref3.length; l < len3; l++) {
+ s = ref3[l];
+ sources[s.file.split(".")[0]] = s.version;
+ }
+ return this.sendRequest({
+ name: "get_file_versions",
+ user: user,
+ project: project
+ }, (msg) => {
+ var info, name, ref4, ref5, ref6, results, v;
+ ref4 = msg.data.sources;
+ for (name in ref4) {
+ info = ref4[name];
+ v = sources[name];
+ if ((v == null) || v !== info.version) {
+ //console.info "updating #{name} to version #{version}"
+ this.player.runtime.projectFileUpdated("ms", name, info.version, null, info.properties);
+ }
+ }
+ ref5 = msg.data.sprites;
+ for (name in ref5) {
+ info = ref5[name];
+ v = sprites[name];
+ if ((v == null) || v !== info.version) {
+ //console.info "updating #{name} to version #{version}"
+ this.player.runtime.projectFileUpdated("sprites", name, info.version, null, info.properties);
+ }
+ }
+ ref6 = msg.data.maps;
+ results = [];
+ for (name in ref6) {
+ info = ref6[name];
+ v = maps[name];
+ if ((v == null) || v !== info.version) {
+ //console.info "updating #{name} to version #{version}"
+ results.push(this.player.runtime.projectFileUpdated("maps", name, info.version, null, info.properties));
+ } else {
+ results.push(void 0);
+ }
+ }
+ return results;
+ });
+ }
+ };
+ return this.socket.onclose = () => {
+ //console.info "socket closed"
+ setTimeout((() => {
+ return this.connect();
+ }), this.reconnect_delay);
+ return this.reconnect_delay += 1000;
+ };
+ }
+
+ send(data) {
+ if (this.socket.readyState !== 1) {
+ if (this.buffer == null) {
+ this.buffer = [];
+ }
+ return this.buffer.push(data);
+ } else {
+ return this.socket.send(JSON.stringify(data));
+ }
+ }
+
+ sendRequest(msg, callback) {
+ msg.request_id = this.request_id++;
+ this.pending_requests[msg.request_id] = callback;
+ return this.send(msg);
+ }
+
+};
+
diff --git a/cas.zip b/WebGames-master/WebGames-master/games/cap/music/music.mp3
similarity index 72%
rename from cas.zip
rename to WebGames-master/WebGames-master/games/cap/music/music.mp3
index 4cdfb4ab..e1656723 100644
Binary files a/cas.zip and b/WebGames-master/WebGames-master/games/cap/music/music.mp3 differ
diff --git a/WebGames-master/WebGames-master/games/cap/parser.js b/WebGames-master/WebGames-master/games/cap/parser.js
new file mode 100644
index 00000000..c9696477
--- /dev/null
+++ b/WebGames-master/WebGames-master/games/cap/parser.js
@@ -0,0 +1,812 @@
+this.Parser = (function() {
+ class Parser {
+ constructor(input, filename = "") {
+ this.input = input;
+ this.filename = filename;
+ if (/^\s*\/\/\s*javascript\s*\n/.test(this.input)) {
+ this.input = 'system.javascript("""\n\n' + this.input.replace(/\\/g, "\\\\") + '\n\n""")';
+ }
+ this.tokenizer = new Tokenizer(this.input, this.filename);
+ this.program = new Program();
+ this.current_block = [];
+ this.current = {
+ line: 1,
+ column: 1
+ };
+ this.verbose = false;
+ this.nesting = 0;
+ this.object_nesting = 0;
+ this.not_terminated = [];
+ this.api_reserved = {
+ screen: true,
+ audio: true,
+ keyboard: true,
+ gamepad: true,
+ sprites: true,
+ sounds: true,
+ music: true,
+ assets: true,
+ asset_manager: true,
+ maps: true,
+ touch: true,
+ mouse: true,
+ fonts: true,
+ Sound: true,
+ Image: true,
+ Sprite: true,
+ Map: true,
+ system: true,
+ storage: true,
+ print: true,
+ random: true,
+ Function: true,
+ List: true,
+ Object: true,
+ String: true,
+ Number: true
+ };
+ }
+
+ nextToken() {
+ var token;
+ token = this.tokenizer.next();
+ if (token == null) {
+ this.unexpected_eof = true;
+ throw "Unexpected end of file";
+ }
+ return this.current = token;
+ }
+
+ nextTokenOptional() {
+ var token;
+ token = this.tokenizer.next();
+ if (token != null) {
+ this.current = token;
+ }
+ return token;
+ }
+
+ parse() {
+ var err, expression, nt, token;
+ try {
+ this.warnings = [];
+ while (true) {
+ expression = this.parseLine();
+ if ((expression == null) && !this.tokenizer.finished()) {
+ token = this.tokenizer.next();
+ if ((token != null) && token.reserved_keyword) {
+ if (token.value === "end") {
+ this.error("Too many 'end'");
+ } else {
+ this.error(`Misuse of reserved keyword: '${token.value}'`);
+ }
+ } else {
+ this.error("Unexpected data");
+ }
+ }
+ if (expression === null) {
+ break;
+ }
+ this.current_block.push(expression);
+ this.program.add(expression);
+ if (this.verbose) {
+ console.info(expression);
+ }
+ }
+ return this;
+ } catch (error1) {
+ err = error1;
+ //console.info "Error at line: #{@current.line} column: #{@current.column}"
+ if (this.not_terminated.length > 0 && err === "Unexpected end of file") {
+ nt = this.not_terminated[this.not_terminated.length - 1];
+ return this.error_info = {
+ error: `Unterminated '${nt.value}' ; no matching 'end' found`,
+ line: nt.line,
+ column: nt.column
+ };
+ } else {
+ return this.error_info = {
+ error: err,
+ line: this.current.line,
+ column: this.current.column
+ };
+ }
+ }
+ }
+
+ //console.error err
+ parseLine() {
+ var token;
+ token = this.nextTokenOptional();
+ if (token == null) {
+ return null;
+ }
+ switch (token.type) {
+ case Token.TYPE_RETURN:
+ return new Program.Return(token, this.parseExpression());
+ case Token.TYPE_BREAK:
+ return new Program.Break(token);
+ case Token.TYPE_CONTINUE:
+ return new Program.Continue(token);
+ case Token.TYPE_LOCAL:
+ return this.parseLocalAssignment(token);
+ default:
+ this.tokenizer.pushBack(token);
+ return this.parseExpression();
+ }
+ }
+
+ parseExpression(filter, first_function_call = false) {
+ var access, expression;
+ expression = this.parseExpressionStart();
+ if (expression == null) {
+ return null;
+ }
+ while (true) {
+ access = this.parseExpressionSuffix(expression, filter);
+ if (access == null) {
+ return expression;
+ }
+ if (first_function_call && access instanceof Program.FunctionCall) {
+ return access;
+ }
+ expression = access;
+ }
+ }
+
+ assertExpression(filter, first_function_call = false) {
+ var exp;
+ exp = this.parseExpression(filter, first_function_call);
+ if (exp == null) {
+ throw "Expression expected";
+ }
+ return exp;
+ }
+
+ parseExpressionSuffix(expression, filter) {
+ var field, identifier, token;
+ token = this.nextTokenOptional();
+ if (token == null) {
+ return (filter === "self" ? expression : null);
+ }
+ switch (token.type) {
+ case Token.TYPE_DOT:
+ if (expression instanceof Program.Value && expression.type === Program.Value.TYPE_NUMBER) {
+ this.tokenizer.pushBack(token);
+ return null;
+ } else {
+ this.tokenizer.changeNumberToIdentifier();
+ identifier = this.assertBroadIdentifier("Expected identifier");
+ return Program.CreateFieldAccess(token, expression, new Program.Value(identifier, Program.Value.TYPE_STRING, identifier.value));
+ }
+ break;
+ case Token.TYPE_OPEN_BRACKET:
+ field = this.assertExpression();
+ this.assert(Token.TYPE_CLOSED_BRACKET, "Expected ']'");
+ return Program.CreateFieldAccess(token, expression, field);
+ case Token.TYPE_OPEN_BRACE:
+ return this.parseFunctionCall(token, expression);
+ case Token.TYPE_EQUALS:
+ return this.parseAssignment(token, expression);
+ case Token.TYPE_PLUS_EQUALS:
+ return this.parseSelfAssignment(token, expression, token.type);
+ case Token.TYPE_MINUS_EQUALS:
+ return this.parseSelfAssignment(token, expression, token.type);
+ case Token.TYPE_MULTIPLY_EQUALS:
+ return this.parseSelfAssignment(token, expression, token.type);
+ case Token.TYPE_DIVIDE_EQUALS:
+ return this.parseSelfAssignment(token, expression, token.type);
+ case Token.TYPE_MODULO_EQUALS:
+ case Token.TYPE_AND_EQUALS:
+ case Token.TYPE_OR_EQUALS:
+ return this.parseSelfAssignment(token, expression, token.type);
+ default:
+ if (filter === "self") {
+ this.tokenizer.pushBack(token);
+ return expression;
+ } else if (token.is_binary_operator && filter !== "noop") {
+ return this.parseBinaryOperation(token, expression);
+ } else {
+ this.tokenizer.pushBack(token);
+ return null;
+ }
+ }
+ }
+
+ parseExpressionStart() {
+ var next, token;
+ token = this.nextTokenOptional();
+ if (token == null) {
+ return null;
+ }
+ switch (token.type) {
+ case Token.TYPE_IDENTIFIER: // variable name
+ return new Program.Variable(token, token.value);
+ case Token.TYPE_NUMBER:
+ return this.parseNumberExpression(token);
+ case Token.TYPE_PLUS:
+ return this.assertExpression();
+ case Token.TYPE_MINUS:
+ return this.parseExpressionSuffix(new Program.Negate(token, this.assertExpression("noop")), "self");
+ case Token.TYPE_NOT:
+ return this.parseExpressionSuffix(new Program.Not(token, this.assertExpression("noop")), "self");
+ case Token.TYPE_STRING:
+ return this.parseStringExpression(token);
+ case Token.TYPE_IF:
+ return this.parseIf(token);
+ case Token.TYPE_FOR:
+ return this.parseFor(token);
+ case Token.TYPE_WHILE:
+ return this.parseWhile(token);
+ case Token.TYPE_OPEN_BRACE:
+ return this.parseBracedExpression(token);
+ case Token.TYPE_OPEN_BRACKET:
+ return this.parseArray(token);
+ case Token.TYPE_FUNCTION:
+ return this.parseFunction(token);
+ case Token.TYPE_OBJECT:
+ return this.parseObject(token);
+ case Token.TYPE_CLASS:
+ return this.parseClass(token);
+ case Token.TYPE_NEW:
+ return this.parseNew(token);
+ case Token.TYPE_DOT:
+ next = this.assert(Token.TYPE_NUMBER, "malformed number");
+ if (!Number.isInteger(next.value)) {
+ throw "malformed number";
+ }
+ return new Program.Value(token, Program.Value.TYPE_NUMBER, Number.parseFloat(`.${next.string_value}`));
+ case Token.TYPE_AFTER:
+ return this.parseAfter(token);
+ case Token.TYPE_EVERY:
+ return this.parseEvery(token);
+ case Token.TYPE_DO:
+ return this.parseDo(token);
+ case Token.TYPE_SLEEP:
+ return this.parseSleep(token);
+ case Token.TYPE_DELETE:
+ return this.parseDelete(token);
+ default:
+ this.tokenizer.pushBack(token);
+ return null;
+ }
+ }
+
+ parseNumberExpression(number) {
+ return new Program.Value(number, Program.Value.TYPE_NUMBER, number.value);
+ }
+
+ parseStringExpression(string) {
+ var token;
+ token = this.nextTokenOptional();
+ if (token == null) {
+ return new Program.Value(string, Program.Value.TYPE_STRING, string.value);
+ } else {
+ this.tokenizer.pushBack(token);
+ return new Program.Value(string, Program.Value.TYPE_STRING, string.value);
+ }
+ }
+
+ parseArray(bracket) {
+ var res, token;
+ res = [];
+ while (true) {
+ token = this.nextToken();
+ if (token.type === Token.TYPE_CLOSED_BRACKET) {
+ return new Program.Value(bracket, Program.Value.TYPE_ARRAY, res);
+ } else if (token.type === Token.TYPE_COMMA) {
+ continue;
+ } else {
+ this.tokenizer.pushBack(token);
+ res.push(this.assertExpression());
+ }
+ }
+ }
+
+ parseBinaryOperation(operation, term1) {
+ var ops, terms, token;
+ ops = [new Program.Operation(operation, operation.value)];
+ terms = [term1];
+ terms.push(this.assertExpression("noop"));
+ while (true) {
+ token = this.nextTokenOptional();
+ if (token == null) {
+ break;
+ }
+ if (!token.is_binary_operator) {
+ this.tokenizer.pushBack(token);
+ break;
+ }
+ ops.push(new Program.Operation(token, token.value));
+ terms.push(this.assertExpression("noop"));
+ }
+ return Program.BuildOperations(ops, terms);
+ }
+
+ parseAssignment(token, expression) {
+ var res;
+ if (!(expression instanceof Program.Variable) && !(expression instanceof Program.Field)) {
+ throw "Expected variable identifier or property";
+ }
+ if (this.object_nesting === 0 && expression instanceof Program.Variable && this.api_reserved[expression.identifier]) {
+ this.warnings.push({
+ type: "assigning_api_variable",
+ identifier: expression.identifier,
+ line: token.line,
+ column: token.column
+ });
+ }
+ if (expression instanceof Program.Field) {
+ this.object_nesting += 1;
+ res = new Program.Assignment(token, expression, this.assertExpression());
+ this.object_nesting -= 1;
+ } else {
+ res = new Program.Assignment(token, expression, this.assertExpression());
+ }
+ return res;
+ }
+
+ parseSelfAssignment(token, expression, operation) {
+ if (!(expression instanceof Program.Variable) && !(expression instanceof Program.Field)) {
+ throw "Expected variable identifier or property";
+ }
+ return new Program.SelfAssignment(token, expression, operation, this.assertExpression());
+ }
+
+ parseLocalAssignment(local) {
+ var identifier;
+ identifier = this.assert(Token.TYPE_IDENTIFIER, "Expected identifier");
+ this.assert(Token.TYPE_EQUALS, "Expected '='");
+ return new Program.Assignment(local, new Program.Variable(identifier, identifier.value), this.assertExpression(), true);
+ }
+
+ parseBracedExpression(open) {
+ var expression, token;
+ expression = this.assertExpression();
+ token = this.nextToken();
+ if (token.type === Token.TYPE_CLOSED_BRACE) {
+ return new Program.Braced(open, expression);
+ } else {
+ return this.error("missing closing parenthese");
+ }
+ }
+
+ parseFunctionCall(brace_token, expression) {
+ var args, start, token;
+ args = [];
+ this.last_function_call = new Program.FunctionCall(brace_token, expression, args);
+ this.last_function_call.argslimits = [];
+ while (true) {
+ token = this.nextTokenOptional();
+ if (token == null) {
+ return this.error("missing closing parenthese");
+ } else if (token.type === Token.TYPE_CLOSED_BRACE) {
+ return new Program.FunctionCall(token, expression, args);
+ } else if (token.type === Token.TYPE_COMMA) {
+ continue;
+ } else {
+ this.tokenizer.pushBack(token);
+ start = token.start;
+ args.push(this.assertExpression());
+ this.last_function_call.argslimits.push({
+ start: start,
+ end: this.tokenizer.index - 1
+ });
+ }
+ }
+ }
+
+ addTerminable(token) {
+ return this.not_terminated.push(token);
+ }
+
+ endTerminable() {
+ if (this.not_terminated.length > 0) {
+ this.not_terminated.splice(this.not_terminated.length - 1, 1);
+ }
+ }
+
+ parseFunction(funk) {
+ var args, line, sequence, token;
+ this.nesting += 1;
+ this.addTerminable(funk);
+ args = this.parseFunctionArgs();
+ sequence = [];
+ while (true) {
+ token = this.nextToken();
+ if (token.type === Token.TYPE_END) {
+ this.nesting -= 1;
+ this.endTerminable();
+ return new Program.Function(funk, args, sequence, token);
+ } else {
+ this.tokenizer.pushBack(token);
+ line = this.parseLine();
+ if (line != null) {
+ sequence.push(line);
+ } else {
+ this.error("Unexpected data while parsing function");
+ }
+ }
+ }
+ }
+
+ parseFunctionArgs() {
+ var args, exp, last, token;
+ token = this.nextToken();
+ args = [];
+ last = null;
+ if (token.type !== Token.TYPE_OPEN_BRACE) {
+ return this.error("Expected opening parenthese");
+ }
+ while (true) {
+ token = this.nextToken();
+ if (token.type === Token.TYPE_CLOSED_BRACE) {
+ return args;
+ } else if (token.type === Token.TYPE_COMMA) {
+ last = null;
+ continue;
+ } else if (token.type === Token.TYPE_EQUALS && last === "argument") {
+ exp = this.assertExpression();
+ args[args.length - 1].default = exp;
+ } else if (token.type === Token.TYPE_IDENTIFIER) {
+ last = "argument";
+ args.push({
+ name: token.value
+ });
+ } else {
+ return this.error("Unexpected token");
+ }
+ }
+ }
+
+ warningAssignmentCondition(expression) {
+ if (expression instanceof Program.Assignment) {
+ return this.warnings.push({
+ type: "assignment_as_condition",
+ line: expression.token.line,
+ column: expression.token.column
+ });
+ }
+ }
+
+ parseIf(iftoken) {
+ var chain, current, line, token;
+ this.addTerminable(iftoken);
+ current = {
+ condition: this.assertExpression(),
+ sequence: []
+ };
+ this.warningAssignmentCondition(current.condition);
+ chain = [];
+ token = this.nextToken();
+ if (token.type !== Token.TYPE_THEN) {
+ return this.error("Expected 'then'");
+ }
+ while (true) {
+ token = this.nextToken();
+ if (token.type === Token.TYPE_ELSIF) {
+ chain.push(current);
+ current = {
+ condition: this.assertExpression(),
+ sequence: []
+ };
+ this.warningAssignmentCondition(current.condition);
+ this.assert(Token.TYPE_THEN, "Expected 'then'");
+ } else if (token.type === Token.TYPE_ELSE) {
+ current.else = [];
+ } else if (token.type === Token.TYPE_END) {
+ chain.push(current);
+ this.endTerminable();
+ return new Program.Condition(iftoken, chain);
+ } else {
+ this.tokenizer.pushBack(token);
+ line = this.parseLine();
+ if (line == null) {
+ throw Error("Unexpected data while parsing if");
+ }
+ if (current.else != null) {
+ current.else.push(line);
+ } else {
+ current.sequence.push(line);
+ }
+ }
+ }
+ }
+
+ assert(type, error) {
+ var token;
+ token = this.nextToken();
+ if (token.type !== type) {
+ throw error;
+ }
+ return token;
+ }
+
+ assertBroadIdentifier(error) {
+ var token;
+ token = this.nextToken();
+ if (token.type !== Token.TYPE_IDENTIFIER && token.reserved_keyword) {
+ token.type = Token.TYPE_IDENTIFIER;
+ }
+ if (token.type !== Token.TYPE_IDENTIFIER) {
+ throw error;
+ }
+ return token;
+ }
+
+ error(text) {
+ throw text;
+ }
+
+ parseFor(fortoken) {
+ var iterator, list, range_by, range_from, range_to, token;
+ iterator = this.assertExpression();
+ if (iterator instanceof Program.Assignment) {
+ range_from = iterator.expression;
+ iterator = iterator.field;
+ token = this.nextToken();
+ if (token.type !== Token.TYPE_TO) {
+ return this.error("Expected 'to'");
+ }
+ range_to = this.assertExpression();
+ token = this.nextToken();
+ if (token.type === Token.TYPE_BY) {
+ range_by = this.assertExpression();
+ } else {
+ range_by = 0;
+ this.tokenizer.pushBack(token);
+ }
+ return new Program.For(fortoken, iterator.identifier, range_from, range_to, range_by, this.parseSequence(fortoken));
+ } else if (iterator instanceof Program.Variable) {
+ this.assert(Token.TYPE_IN, "Error expected keyword 'in'");
+ list = this.assertExpression();
+ return new Program.ForIn(fortoken, iterator.identifier, list, this.parseSequence(fortoken));
+ } else {
+ return this.error("Malformed for loop");
+ }
+ }
+
+ parseWhile(whiletoken) {
+ var condition;
+ condition = this.assertExpression();
+ return new Program.While(whiletoken, condition, this.parseSequence(whiletoken));
+ }
+
+ parseSequence(start_token) {
+ var line, sequence, token;
+ if (start_token != null) {
+ this.addTerminable(start_token);
+ }
+ this.nesting += 1;
+ sequence = [];
+ while (true) {
+ token = this.nextToken();
+ if (token.type === Token.TYPE_END) {
+ if (start_token != null) {
+ this.endTerminable();
+ }
+ this.nesting -= 1;
+ return sequence;
+ } else {
+ this.tokenizer.pushBack(token);
+ line = this.parseLine();
+ if (line == null) {
+ this.error("Unexpected data");
+ }
+ sequence.push(line);
+ }
+ }
+ return sequence;
+ }
+
+ parseObject(object) {
+ var exp, fields, token;
+ this.nesting += 1;
+ this.object_nesting += 1;
+ this.addTerminable(object);
+ fields = [];
+ while (true) {
+ token = this.nextToken();
+ if (token.type === Token.TYPE_END) {
+ this.nesting -= 1;
+ this.object_nesting -= 1;
+ this.endTerminable();
+ return new Program.CreateObject(object, fields);
+ } else {
+ if (token.type !== Token.TYPE_IDENTIFIER && token.reserved_keyword) {
+ token.type = Token.TYPE_IDENTIFIER;
+ }
+ if (token.type === Token.TYPE_STRING) {
+ token.type = Token.TYPE_IDENTIFIER;
+ }
+ if (token.type === Token.TYPE_IDENTIFIER) {
+ this.assert(Token.TYPE_EQUALS, "Expected '='");
+ exp = this.assertExpression();
+ fields.push({
+ field: token.value,
+ value: exp
+ });
+ } else {
+ return this.error("Malformed object");
+ }
+ }
+ }
+ }
+
+ parseClass(object) {
+ var exp, ext, fields, token;
+ this.nesting += 1;
+ this.object_nesting += 1;
+ this.addTerminable(object);
+ fields = [];
+ token = this.nextToken();
+ if (token.type === Token.TYPE_EXTENDS) {
+ ext = this.assertExpression();
+ token = this.nextToken();
+ }
+ while (true) {
+ if (token.type === Token.TYPE_END) {
+ this.nesting -= 1;
+ this.object_nesting -= 1;
+ this.endTerminable();
+ return new Program.CreateClass(object, ext, fields);
+ } else {
+ if (token.type !== Token.TYPE_IDENTIFIER && token.reserved_keyword) {
+ token.type = Token.TYPE_IDENTIFIER;
+ }
+ if (token.type === Token.TYPE_STRING) {
+ token.type = Token.TYPE_IDENTIFIER;
+ }
+ if (token.type === Token.TYPE_IDENTIFIER) {
+ this.assert(Token.TYPE_EQUALS, "Expected '='");
+ exp = this.assertExpression();
+ fields.push({
+ field: token.value,
+ value: exp
+ });
+ } else {
+ return this.error("Malformed object");
+ }
+ }
+ token = this.nextToken();
+ }
+ }
+
+ parseNew(token) {
+ var exp;
+ exp = this.assertExpression(null, true);
+ return new Program.NewCall(token, exp);
+ }
+
+ parseAfter(after) {
+ var delay, line, multiplier, sequence, token;
+ this.nesting += 1;
+ this.addTerminable(after);
+ delay = this.assertExpression();
+ token = this.nextToken();
+ multiplier = null;
+ if (token.type === Token.TYPE_IDENTIFIER && this.multipliers[token.value]) {
+ multiplier = this.multipliers[token.value];
+ token = this.nextToken();
+ }
+ if ((token == null) || token.type !== Token.TYPE_DO) {
+ this.error("Expected keyword 'do'");
+ }
+ sequence = [];
+ while (true) {
+ token = this.nextToken();
+ if (token.type === Token.TYPE_END) {
+ this.nesting -= 1;
+ this.endTerminable();
+ return new Program.After(after, delay, sequence, token, multiplier);
+ } else {
+ this.tokenizer.pushBack(token);
+ line = this.parseLine();
+ if (line != null) {
+ sequence.push(line);
+ } else {
+ this.error("Unexpected data while parsing after");
+ }
+ }
+ }
+ }
+
+ parseEvery(every) {
+ var delay, line, multiplier, sequence, token;
+ this.nesting += 1;
+ this.addTerminable(every);
+ delay = this.assertExpression();
+ token = this.nextToken();
+ multiplier = null;
+ if (token.type === Token.TYPE_IDENTIFIER && this.multipliers[token.value]) {
+ multiplier = this.multipliers[token.value];
+ token = this.nextToken();
+ }
+ if ((token == null) || token.type !== Token.TYPE_DO) {
+ this.error("Expected keyword 'do'");
+ }
+ sequence = [];
+ while (true) {
+ token = this.nextToken();
+ if (token.type === Token.TYPE_END) {
+ this.nesting -= 1;
+ this.endTerminable();
+ return new Program.Every(every, delay, sequence, token, multiplier);
+ } else {
+ this.tokenizer.pushBack(token);
+ line = this.parseLine();
+ if (line != null) {
+ sequence.push(line);
+ } else {
+ this.error("Unexpected data while parsing after");
+ }
+ }
+ }
+ }
+
+ parseDo(do_token) {
+ var line, sequence, token;
+ this.nesting += 1;
+ this.addTerminable(do_token);
+ sequence = [];
+ while (true) {
+ token = this.nextToken();
+ if (token.type === Token.TYPE_END) {
+ this.nesting -= 1;
+ this.endTerminable();
+ return new Program.Do(do_token, sequence, token);
+ } else {
+ this.tokenizer.pushBack(token);
+ line = this.parseLine();
+ if (line != null) {
+ sequence.push(line);
+ } else {
+ this.error("Unexpected data while parsing after");
+ }
+ }
+ }
+ }
+
+ parseSleep(sleep) {
+ var delay, multiplier, token;
+ delay = this.assertExpression();
+ token = this.nextToken();
+ multiplier = null;
+ if (token != null) {
+ if (token.type === Token.TYPE_IDENTIFIER && this.multipliers[token.value]) {
+ multiplier = this.multipliers[token.value];
+ } else {
+ this.tokenizer.pushBack(token);
+ }
+ }
+ return new Program.Sleep(sleep, delay, multiplier);
+ }
+
+ parseDelete(del) {
+ var v;
+ v = this.parseExpression();
+ if ((v == null) || (!(v instanceof Program.Variable) && !(v instanceof Program.Field))) {
+ return this.error("expecting variable name or property access after keyword `delete`");
+ } else {
+ return new Program.Delete(del, v);
+ }
+ }
+
+ };
+
+ Parser.prototype.multipliers = {
+ millisecond: 1,
+ milliseconds: 1,
+ second: 1000,
+ seconds: 1000,
+ minute: 60000,
+ minutes: 60000,
+ hour: 60000 * 60,
+ hours: 60000 * 60,
+ day: 60000 * 60 * 24,
+ days: 60000 * 60 * 24
+ };
+
+ return Parser;
+
+}).call(this);
diff --git a/WebGames-master/WebGames-master/games/cap/processor.js b/WebGames-master/WebGames-master/games/cap/processor.js
new file mode 100644
index 00000000..60ed44c6
--- /dev/null
+++ b/WebGames-master/WebGames-master/games/cap/processor.js
@@ -0,0 +1,1542 @@
+this.Processor = class Processor {
+ constructor(runner) {
+ this.runner = runner;
+ this.locals = [];
+ this.stack = [];
+ this.call_stack = [];
+ this.log = false;
+ this.time_limit = 2e308;
+ this.done = true;
+ }
+
+ load(routine1) {
+ this.routine = routine1;
+ return this.resetState();
+ }
+
+ resetState() {
+ this.local_index = 0;
+ this.stack_index = -1;
+ this.op_index = 0;
+ this.call_stack_index = 0;
+ this.global = null;
+ this.object = this.routine.object || null;
+ this.locals_offset = 0;
+ this.call_super = null;
+ this.call_supername = "";
+ return this.done = false;
+ }
+
+ resolveParentClass(obj, global) {
+ if ((obj.class != null) && typeof obj.class === "string") {
+ if (global[obj.class] != null) {
+ obj.class = global[obj.class];
+ return this.resolveParentClass(obj.class, global);
+ }
+ } else if (obj.class != null) {
+ return this.resolveParentClass(obj.class, global);
+ }
+ }
+
+ applyFunction(args) {}
+
+ routineAsFunction(routine, context) {
+ var f, proc;
+ proc = new Processor(this.runner);
+ f = function() {
+ var a, count, i, j, k, ref, ref1;
+ count = Math.min(routine.num_args, arguments.length);
+ proc.load(routine);
+ for (i = j = 0, ref = count - 1; j <= ref; i = j += 1) {
+ proc.stack[++proc.stack_index] = arguments[i] || 0;
+ }
+ proc.stack[++proc.stack_index] = arguments.length;
+ if (routine.uses_arguments) {
+ a = [...arguments];
+ for (i = k = 0, ref1 = a.length - 1; k <= ref1; i = k += 1) {
+ if (a[i] == null) {
+ a[i] = 0;
+ }
+ }
+ proc.stack[++proc.stack_index] = a;
+ }
+ return proc.run(context);
+ };
+ //res = proc.stack[0]
+ return f;
+ }
+
+ routineAsApplicableFunction(routine, context) {
+ var f, proc;
+ proc = new Processor(this.runner);
+ f = function() {
+ var a, count, i, j, k, ref, ref1, res;
+ count = routine.num_args;
+ proc.load(routine);
+ proc.object = this;
+ for (i = j = 0, ref = count - 1; j <= ref; i = j += 1) {
+ proc.stack[++proc.stack_index] = arguments[i] || 0;
+ }
+ proc.stack[++proc.stack_index] = arguments.length;
+ if (routine.uses_arguments) {
+ a = [...arguments];
+ for (i = k = 0, ref1 = a.length - 1; k <= ref1; i = k += 1) {
+ if (a[i] == null) {
+ a[i] = 0;
+ }
+ }
+ proc.stack[++proc.stack_index] = a;
+ }
+ proc.run(context);
+ return res = proc.stack[0];
+ };
+ return f;
+ }
+
+ argToNative(arg, context) {
+ if (arg instanceof Routine) {
+ return this.routineAsFunction(arg, context);
+ } else {
+ if (arg != null) {
+ return arg;
+ } else {
+ return 0;
+ }
+ }
+ }
+
+ modulo(context, a, b) {
+ var f, obj;
+ if (Array.isArray(a)) {
+ obj = context.global.List;
+ } else if (typeof a === "string") {
+ if (isFinite(a)) {
+ a %= b;
+ if (isFinite(a)) {
+ return a;
+ } else {
+ return 0;
+ }
+ } else {
+ obj = context.global.String;
+ }
+ } else {
+ obj = a;
+ }
+ f = obj["%"];
+ while ((f == null) && (obj.class != null)) {
+ obj = obj.class;
+ f = obj["%"];
+ }
+ if (f == null) {
+ f = context.global.Object["%"];
+ }
+ if ((f != null) && f instanceof Routine) {
+ if (f.as_function == null) {
+ f.as_function = this.routineAsApplicableFunction(f, context);
+ }
+ f = f.as_function;
+ return f.call(context.global, a, b);
+ } else {
+ return 0;
+ }
+ }
+
+ add(context, a, b, self) {
+ var f, obj;
+ if (Array.isArray(a)) {
+ obj = context.global.List;
+ } else if (typeof a === "string") {
+ obj = context.global.String;
+ } else {
+ obj = a;
+ }
+ f = obj["+"];
+ while ((f == null) && (obj.class != null)) {
+ obj = obj.class;
+ f = obj["+"];
+ }
+ if (f == null) {
+ f = context.global.Object["+"];
+ }
+ if (f != null) {
+ if (f instanceof Routine) {
+ if (f.as_function == null) {
+ f.as_function = this.routineAsApplicableFunction(f, context);
+ }
+ f = f.as_function;
+ return f.call(context.global, a, b, self);
+ } else if (typeof f === "function") {
+ return f.call(context.global, a, b, self);
+ }
+ } else {
+ return 0;
+ }
+ }
+
+ sub(context, a, b, self) {
+ var f, obj;
+ if (Array.isArray(a)) {
+ obj = context.global.List;
+ } else if (typeof a === "string") {
+ if (isFinite(a)) {
+ a -= b;
+ if (isFinite(a)) {
+ return a;
+ } else {
+ return 0;
+ }
+ } else {
+ obj = context.global.String;
+ }
+ } else {
+ obj = a;
+ }
+ f = obj["-"];
+ while ((f == null) && (obj.class != null)) {
+ obj = obj.class;
+ f = obj["-"];
+ }
+ if (f == null) {
+ f = context.global.Object["-"];
+ }
+ if (f != null) {
+ if (f instanceof Routine) {
+ if (f.as_function == null) {
+ f.as_function = this.routineAsApplicableFunction(f, context);
+ }
+ f = f.as_function;
+ return f.call(context.global, a, b, self);
+ } else if (typeof f === "function") {
+ return f.call(context.global, a, b, self);
+ }
+ } else {
+ return 0;
+ }
+ }
+
+ negate(context, a) {
+ var f, obj;
+ if (Array.isArray(a)) {
+ obj = context.global.List;
+ } else if (typeof a === "string") {
+ if (isFinite(a)) {
+ return -a;
+ } else {
+ obj = context.global.String;
+ }
+ } else {
+ obj = a;
+ }
+ f = obj["-"];
+ while ((f == null) && (obj.class != null)) {
+ obj = obj.class;
+ f = obj["-"];
+ }
+ if (f == null) {
+ f = context.global.Object["-"];
+ }
+ if (f != null) {
+ if (f instanceof Routine) {
+ if (f.as_function == null) {
+ f.as_function = this.routineAsApplicableFunction(f, context);
+ }
+ f = f.as_function;
+ return f.call(context.global, 0, a);
+ } else if (typeof f === "function") {
+ return f.call(context.global, 0, a);
+ }
+ } else {
+ return 0;
+ }
+ }
+
+ mul(context, a, b, self) {
+ var f, obj;
+ if (Array.isArray(a)) {
+ obj = context.global.List;
+ } else if (typeof a === "string") {
+ if (isFinite(a)) {
+ a *= b;
+ if (isFinite(a)) {
+ return a;
+ } else {
+ return 0;
+ }
+ } else {
+ obj = context.global.String;
+ }
+ } else {
+ obj = a;
+ }
+ f = obj["*"];
+ while ((f == null) && (obj.class != null)) {
+ obj = obj.class;
+ f = obj["*"];
+ }
+ if (f == null) {
+ f = context.global.Object["*"];
+ }
+ if (f != null) {
+ if (f instanceof Routine) {
+ if (f.as_function == null) {
+ f.as_function = this.routineAsApplicableFunction(f, context);
+ }
+ f = f.as_function;
+ return f.call(context.global, a, b, self);
+ } else if (typeof f === "function") {
+ return f.call(context.global, a, b, self);
+ }
+ } else {
+ return 0;
+ }
+ }
+
+ div(context, a, b, self) {
+ var f, obj;
+ if (Array.isArray(a)) {
+ obj = context.global.List;
+ } else if (typeof a === "string") {
+ if (isFinite(a)) {
+ a /= b;
+ if (isFinite(a)) {
+ return a;
+ } else {
+ return 0;
+ }
+ } else {
+ obj = context.global.String;
+ }
+ } else {
+ obj = a;
+ }
+ f = obj["/"];
+ while ((f == null) && (obj.class != null)) {
+ obj = obj.class;
+ f = obj["/"];
+ }
+ if (f == null) {
+ f = context.global.Object["/"];
+ }
+ if (f != null) {
+ if (f instanceof Routine) {
+ if (f.as_function == null) {
+ f.as_function = this.routineAsApplicableFunction(f, context);
+ }
+ f = f.as_function;
+ return f.call(context.global, a, b, self);
+ } else if (typeof f === "function") {
+ return f.call(context.global, a, b, self);
+ }
+ } else {
+ return 0;
+ }
+ }
+
+ band(context, a, b, self) {
+ var f, obj;
+ if (Array.isArray(a)) {
+ obj = context.global.List;
+ } else if (typeof a === "string") {
+ if (isFinite(a)) {
+ a &= b;
+ if (isFinite(a)) {
+ return a;
+ } else {
+ return 0;
+ }
+ } else {
+ obj = context.global.String;
+ }
+ } else {
+ obj = a;
+ }
+ f = obj["&"];
+ while ((f == null) && (obj.class != null)) {
+ obj = obj.class;
+ f = obj["&"];
+ }
+ if (f == null) {
+ f = context.global.Object["&"];
+ }
+ if (f != null) {
+ if (f instanceof Routine) {
+ if (f.as_function == null) {
+ f.as_function = this.routineAsApplicableFunction(f, context);
+ }
+ f = f.as_function;
+ return f.call(context.global, a, b, self);
+ } else if (typeof f === "function") {
+ return f.call(context.global, a, b, self);
+ }
+ } else {
+ return 0;
+ }
+ }
+
+ bor(context, a, b, self) {
+ var f, obj;
+ if (Array.isArray(a)) {
+ obj = context.global.List;
+ } else if (typeof a === "string") {
+ if (isFinite(a)) {
+ a |= b;
+ if (isFinite(a)) {
+ return a;
+ } else {
+ return 0;
+ }
+ } else {
+ obj = context.global.String;
+ }
+ } else {
+ obj = a;
+ }
+ f = obj["|"];
+ while ((f == null) && (obj.class != null)) {
+ obj = obj.class;
+ f = obj["|"];
+ }
+ if (f == null) {
+ f = context.global.Object["|"];
+ }
+ if (f != null) {
+ if (f instanceof Routine) {
+ if (f.as_function == null) {
+ f.as_function = this.routineAsApplicableFunction(f, context);
+ }
+ f = f.as_function;
+ return f.call(context.global, a, b, self);
+ } else if (typeof f === "function") {
+ return f.call(context.global, a, b, self);
+ }
+ } else {
+ return 0;
+ }
+ }
+
+ run(context) {
+ var a, arg1, args, argv, b, c, call_stack, call_stack_index, call_super, call_supername, con, cs, err, f, fc, field, global, i, i1, i2, id, index, ir, iter, iterator, j, k, key, l, len, length, local_index, locals, locals_offset, loop_by, loop_to, m, n, name, o, obj, object, op_count, op_index, opcodes, p, parent, q, r, rc, ref, ref1, ref10, ref11, ref12, ref13, ref14, ref2, ref3, ref4, ref5, ref6, ref7, ref8, ref9, res, restore_op_index, routine, s, sleep_time, src, stack, stack_index, sup, t, token, u, v, value, w;
+ routine = this.routine;
+ opcodes = this.routine.opcodes;
+ arg1 = this.routine.arg1;
+ length = opcodes.length;
+ op_index = this.op_index;
+ stack = this.stack;
+ stack_index = this.stack_index;
+ locals = this.locals;
+ local_index = this.local_index;
+ global = this.global || context.global;
+ object = this.object || global;
+ call_stack = this.call_stack;
+ call_stack_index = this.call_stack_index;
+ call_super = this.call_super || global;
+ call_supername = this.call_supername || "";
+ locals_offset = this.locals_offset;
+ op_count = 0;
+ restore_op_index = -1;
+ while (op_index < length) {
+ switch (opcodes[op_index]) {
+ case 1: // OPCODE_TYPE
+ v = stack[stack_index];
+ switch (typeof v) {
+ case "number":
+ stack[stack_index] = "number";
+ break;
+ case "string":
+ stack[stack_index] = "string";
+ break;
+ case "function":
+ stack[stack_index] = "function";
+ break;
+ case "object":
+ if (Array.isArray(v)) {
+ stack[stack_index] = "list";
+ } else if (v instanceof Routine) {
+ stack[stack_index] = "function";
+ } else {
+ stack[stack_index] = "object";
+ }
+ }
+ op_index++;
+ break;
+ case 2: // OPCODE_TYPE_VARIABLE
+ v = object[arg1[op_index]];
+ if (v == null) {
+ v = global[arg1[op_index]];
+ }
+ if (v == null) {
+ stack[++stack_index] = 0;
+ } else {
+ switch (typeof v) {
+ case "number":
+ stack[++stack_index] = "number";
+ break;
+ case "string":
+ stack[++stack_index] = "string";
+ break;
+ case "function":
+ stack[++stack_index] = "function";
+ break;
+ default:
+ if (Array.isArray(v)) {
+ stack[++stack_index] = "list";
+ } else if (v instanceof Routine) {
+ stack[++stack_index] = "function";
+ } else {
+ stack[++stack_index] = "object";
+ }
+ }
+ }
+ op_index++;
+ break;
+ case 3: // OPCODE_TYPE_PROPERTY
+ v = stack[stack_index - 1][stack[stack_index]];
+ if (v == null) {
+ stack[--stack_index] = 0;
+ } else {
+ switch (typeof v) {
+ case "number":
+ stack[--stack_index] = "number";
+ break;
+ case "string":
+ stack[--stack_index] = "string";
+ break;
+ case "function":
+ stack[--stack_index] = "function";
+ break;
+ default:
+ if (Array.isArray(v)) {
+ stack[--stack_index] = "list";
+ } else if (v instanceof Routine) {
+ stack[--stack_index] = "function";
+ } else {
+ stack[--stack_index] = "object";
+ }
+ }
+ }
+ op_index++;
+ break;
+ case 4: // OPCODE_LOAD_IMPORT
+ stack[++stack_index] = routine.import_values[arg1[op_index++]];
+ break;
+ case 5: // OPCODE_LOAD_THIS
+ stack[++stack_index] = object;
+ op_index++;
+ break;
+ case 6: // OPCODE_LOAD_GLOBAL
+ stack[++stack_index] = global;
+ op_index++;
+ break;
+ case 10: // CODE_LOAD_VALUE
+ stack[++stack_index] = arg1[op_index++];
+ break;
+ case 11: // OPCODE_LOAD_LOCAL
+ stack[++stack_index] = locals[locals_offset + arg1[op_index++]];
+ break;
+ case 12: // OPCODE_LOAD_VARIABLE
+ name = arg1[op_index];
+ v = object[name];
+ if ((v == null) && (object.class != null)) {
+ obj = object;
+ while ((v == null) && (obj.class != null)) {
+ obj = obj.class;
+ v = obj[name];
+ }
+ }
+ if (v == null) {
+ v = global[name];
+ }
+ if ((v == null) && !routine.ref[op_index].nowarning) {
+ token = routine.ref[op_index].token;
+ id = token.tokenizer.filename + "-" + token.line + "-" + token.column;
+ if (!context.warnings.using_undefined_variable[id]) {
+ context.warnings.using_undefined_variable[id] = {
+ file: token.tokenizer.filename,
+ line: token.line,
+ column: token.column,
+ expression: name
+ };
+ }
+ }
+ stack[++stack_index] = v != null ? v : 0;
+ op_index++;
+ break;
+ case 13: // OPCODE_LOAD_LOCAL_OBJECT
+ o = locals[locals_offset + arg1[op_index]];
+ if (typeof o !== "object") {
+ o = locals[locals_offset + arg1[op_index]] = {};
+ token = routine.ref[op_index].token;
+ id = token.tokenizer.filename + "-" + token.line + "-" + token.column;
+ if (!context.warnings.assigning_field_to_undefined[id]) {
+ context.warnings.assigning_field_to_undefined[id] = {
+ file: token.tokenizer.filename,
+ line: token.line,
+ column: token.column,
+ expression: token.value
+ };
+ }
+ }
+ stack[++stack_index] = o;
+ op_index++;
+ break;
+ case 14: // OPCODE_LOAD_VARIABLE_OBJECT
+ name = arg1[op_index];
+ obj = object;
+ v = obj[name];
+ while ((v == null) && (obj.class != null)) {
+ obj = obj.class;
+ v = obj[name];
+ }
+ if ((v == null) && (global[name] != null)) {
+ obj = global;
+ v = global[name];
+ }
+ if ((v == null) || typeof v !== "object") {
+ v = obj[name] = {};
+ token = routine.ref[op_index].token;
+ id = token.tokenizer.filename + "-" + token.line + "-" + token.column;
+ if (!context.warnings.assigning_field_to_undefined[id]) {
+ context.warnings.assigning_field_to_undefined[id] = {
+ file: token.tokenizer.filename,
+ line: token.line,
+ column: token.column,
+ expression: arg1[op_index]
+ };
+ }
+ }
+ stack[++stack_index] = v;
+ op_index++;
+ break;
+ case 15: // OPCODE_POP
+ stack_index--;
+ op_index++;
+ break;
+ case 16: // OPCODE_LOAD_PROPERTY
+ obj = stack[stack_index - 1];
+ name = stack[stack_index];
+ v = obj[name];
+ while ((v == null) && (obj.class != null)) {
+ obj = obj.class;
+ v = obj[name];
+ }
+ if (v == null) {
+ v = 0;
+ if (!routine.ref[op_index].nowarning) {
+ routine.ref[op_index].nowarning = true;
+ if (!Array.isArray(obj)) {
+ token = routine.ref[op_index].token;
+ id = token.tokenizer.filename + "-" + token.line + "-" + token.column;
+ context.warnings.using_undefined_variable[id] = {
+ file: token.tokenizer.filename,
+ line: token.line,
+ column: token.column,
+ expression: name
+ };
+ }
+ }
+ }
+ stack[--stack_index] = v;
+ op_index++;
+ break;
+ case 17: // OPCODE_LOAD_PROPERTY_OBJECT
+ v = stack[stack_index - 1][stack[stack_index]];
+ if (typeof v !== "object") {
+ v = stack[stack_index - 1][stack[stack_index]] = {};
+ token = routine.ref[op_index].token;
+ id = token.tokenizer.filename + "-" + token.line + "-" + token.column;
+ if (!context.warnings.assigning_field_to_undefined[id]) {
+ context.warnings.assigning_field_to_undefined[id] = {
+ file: token.tokenizer.filename,
+ line: token.line,
+ column: token.column,
+ expression: stack[stack_index]
+ };
+ }
+ }
+ stack[--stack_index] = v;
+ op_index++;
+ break;
+ case 18: // OPCODE_CREATE_OBJECT
+ stack[++stack_index] = {};
+ op_index++;
+ break;
+ case 19: // OPCODE_MAKE_OBJECT
+ if (typeof stack[stack_index] !== "object") {
+ stack[stack_index] = {};
+ }
+ op_index++;
+ break;
+ case 20: // OPCODE_CREATE_ARRAY
+ stack[++stack_index] = [];
+ op_index++;
+ break;
+ case 21: // OPCODE_STORE_LOCAL
+ locals[locals_offset + arg1[op_index]] = stack[stack_index];
+ op_index++;
+ break;
+ case 22: // OPCODE_STORE_LOCAL_POP
+ locals[locals_offset + arg1[op_index]] = stack[stack_index--];
+ op_index++;
+ break;
+ case 23: // OPCODE_STORE_VARIABLE
+ object[arg1[op_index++]] = stack[stack_index];
+ break;
+ case 24: // OPCODE_CREATE_PROPERTY
+ obj = stack[stack_index - 2];
+ field = stack[stack_index - 1];
+ obj[field] = stack[stack_index];
+ stack_index -= 2;
+ op_index++;
+ break;
+ case 25: // OPCODE_STORE_PROPERTY
+ obj = stack[stack_index - 2];
+ field = stack[stack_index - 1];
+ stack[stack_index - 2] = obj[field] = stack[stack_index];
+ stack_index -= 2;
+ op_index++;
+ break;
+ case 26: // OPCODE_DELETE
+ obj = stack[stack_index - 1];
+ field = stack[stack_index];
+ delete obj[field];
+ stack[stack_index -= 1] = 0;
+ op_index++;
+ break;
+ case 27: // OPCODE_UPDATE_CLASS
+ name = arg1[op_index];
+ // TODO: set classname to variable name
+ if ((object[name] != null) && typeof object[name] === "object") {
+ obj = object[name];
+ src = stack[stack_index];
+ for (key in src) {
+ value = src[key];
+ obj[key] = value;
+ }
+ } else {
+ object[name] = stack[stack_index];
+ }
+ op_index++;
+ break;
+ case 28: // OPCODE_CREATE_CLASS
+ res = {};
+ parent = stack[stack_index];
+ if (parent) {
+ res.class = parent;
+ } else if (arg1[op_index]) {
+ res.class = arg1[op_index];
+ }
+ stack[stack_index] = res;
+ op_index++;
+ break;
+ case 29: // OPCODE_NEW_CALL
+ c = stack[stack_index];
+ args = arg1[op_index];
+ if (typeof c === "function") {
+ a = [];
+ for (i = j = 0, ref = args - 1; j <= ref; i = j += 1) {
+ a.push(stack[stack_index - args + i]);
+ }
+ stack_index -= args;
+ // NEW CALL is followed by a POP (to get rid of constructor return value)
+ stack[stack_index - 1] = new c(...a);
+ op_index++;
+ } else {
+ this.resolveParentClass(c, global);
+ res = {
+ class: c
+ };
+ con = c.constructor;
+ while (!con && (c.class != null)) {
+ c = c.class;
+ con = c.constructor;
+ }
+ if ((con != null) && con instanceof Routine) {
+ stack[stack_index - args - 1] = res;
+ stack_index--;
+ cs = call_stack[call_stack_index] || (call_stack[call_stack_index] = {});
+ call_stack_index++;
+ cs.routine = routine;
+ cs.object = object;
+ cs.super = call_super;
+ cs.supername = call_supername;
+ cs.op_index = op_index + 1;
+ locals_offset += routine.locals_size;
+ routine = con;
+ opcodes = con.opcodes;
+ arg1 = con.arg1;
+ op_index = 0;
+ length = opcodes.length;
+ object = res;
+ call_super = c;
+ call_supername = "constructor";
+ if (routine.uses_arguments) {
+ argv = stack.slice(stack_index - args + 1, stack_index + 1);
+ }
+ if (args < con.num_args) {
+ for (i = k = ref1 = args + 1, ref2 = con.num_args; k <= ref2; i = k += 1) {
+ stack[++stack_index] = 0;
+ }
+ } else if (args > con.num_args) {
+ stack_index -= args - con.num_args;
+ }
+ stack[++stack_index] = args;
+ if (routine.uses_arguments) {
+ stack[++stack_index] = argv;
+ }
+ } else {
+ stack_index -= args;
+ stack[stack_index - 1] = res;
+ op_index++;
+ }
+ }
+ break;
+ case 30: // OPCODE_ADD
+ b = stack[stack_index--];
+ a = stack[stack_index];
+ if (typeof a === "number") {
+ a += b;
+ stack[stack_index] = isFinite(a) || typeof b === "string" ? a : 0;
+ } else {
+ stack[stack_index] = this.add(context, a, b, arg1[op_index]);
+ }
+ op_index++;
+ break;
+ case 31: // OPCODE_SUB
+ b = stack[stack_index--];
+ a = stack[stack_index];
+ if (typeof a === "number") {
+ a -= b;
+ stack[stack_index] = isFinite(a) ? a : 0;
+ } else {
+ stack[stack_index] = this.sub(context, a, b, arg1[op_index]);
+ }
+ op_index++;
+ break;
+ case 32: // OPCODE_MUL
+ b = stack[stack_index--];
+ a = stack[stack_index];
+ if (typeof a === "number") {
+ a *= b;
+ stack[stack_index] = isFinite(a) ? a : 0;
+ } else {
+ stack[stack_index] = this.mul(context, a, b);
+ }
+ op_index++;
+ break;
+ case 33: // OPCODE_DIV
+ b = stack[stack_index--];
+ a = stack[stack_index];
+ if (typeof a === "number") {
+ a /= b;
+ stack[stack_index] = isFinite(a) ? a : 0;
+ } else {
+ stack[stack_index] = this.div(context, a, b);
+ }
+ op_index++;
+ break;
+ case 34: // OPCODE_MODULO
+ b = stack[stack_index--];
+ a = stack[stack_index];
+ if (typeof a === "number" && typeof b === "number") {
+ a %= b;
+ stack[stack_index] = isFinite(a) ? a : 0;
+ } else {
+ stack[stack_index] = this.modulo(context, a, b);
+ }
+ op_index++;
+ break;
+ case 35: // OPCODE_BINARY_AND
+ b = stack[stack_index--];
+ a = stack[stack_index];
+ if (typeof a === "number") {
+ a &= b;
+ stack[stack_index] = isFinite(a) ? a : 0;
+ } else {
+ stack[stack_index] = this.band(context, a, b);
+ }
+ op_index++;
+ break;
+ case 36: // OPCODE_BINARY_OR
+ b = stack[stack_index--];
+ a = stack[stack_index];
+ if (typeof a === "number") {
+ a |= b;
+ stack[stack_index] = isFinite(a) ? a : 0;
+ } else {
+ stack[stack_index] = this.bor(context, a, b);
+ }
+ op_index++;
+ break;
+ case 37: // OPCODE_SHIFT_LEFT
+ v = stack[stack_index - 1] << stack[stack_index];
+ stack[--stack_index] = isFinite(v) ? v : 0;
+ op_index++;
+ break;
+ case 38: // OPCODE_SHIFT_RIGHT
+ v = stack[stack_index - 1] >> stack[stack_index];
+ stack[--stack_index] = isFinite(v) ? v : 0;
+ op_index++;
+ break;
+ case 39: // OPCODE_NEGATE
+ a = stack[stack_index];
+ if (typeof a === "number") {
+ stack[stack_index] = -a;
+ } else {
+ stack[stack_index] = this.negate(context, a);
+ }
+ op_index++;
+ break;
+ case 50: // OPCODE_NOT
+ stack[stack_index] = stack[stack_index] ? 0 : 1;
+ op_index++;
+ break;
+ case 68: // OPCODE_LOAD_PROPERTY_ATOP
+ obj = stack[stack_index - 1];
+ name = stack[stack_index];
+ v = obj[name];
+ while ((v == null) && (obj.class != null)) {
+ obj = obj.class;
+ v = obj[name];
+ }
+ if (v == null) {
+ v = 0;
+ if (!routine.ref[op_index].nowarning) {
+ routine.ref[op_index].nowarning = true;
+ if (!Array.isArray(obj)) {
+ token = routine.ref[op_index].token;
+ id = token.tokenizer.filename + "-" + token.line + "-" + token.column;
+ context.warnings.using_undefined_variable[id] = {
+ file: token.tokenizer.filename,
+ line: token.line,
+ column: token.column,
+ expression: name
+ };
+ }
+ }
+ }
+ stack[++stack_index] = v;
+ op_index++;
+ break;
+ case 40: // OPCODE_EQ
+ stack[stack_index - 1] = stack[stack_index] === stack[stack_index - 1] ? 1 : 0;
+ stack_index--;
+ op_index++;
+ break;
+ case 41: // OPCODE_NEQ
+ stack[stack_index - 1] = stack[stack_index] !== stack[stack_index - 1] ? 1 : 0;
+ stack_index--;
+ op_index++;
+ break;
+ case 42: // OPCODE_LT
+ stack[stack_index - 1] = stack[stack_index - 1] < stack[stack_index] ? 1 : 0;
+ stack_index--;
+ op_index++;
+ break;
+ case 43: // OPCODE_GT
+ stack[stack_index - 1] = stack[stack_index - 1] > stack[stack_index] ? 1 : 0;
+ stack_index--;
+ op_index++;
+ break;
+ case 44: // OPCODE_LTE
+ stack[stack_index - 1] = stack[stack_index - 1] <= stack[stack_index] ? 1 : 0;
+ stack_index--;
+ op_index++;
+ break;
+ case 45: // OPCODE_GTE
+ stack[stack_index - 1] = stack[stack_index - 1] >= stack[stack_index] ? 1 : 0;
+ stack_index--;
+ op_index++;
+ break;
+ case 95: // FORLOOP_INIT
+ // fix loop_by if not set
+ iter = arg1[op_index][0];
+ loop_to = locals[locals_offset + iter + 1] = stack[stack_index - 1];
+ loop_by = stack[stack_index];
+ iterator = locals[locals_offset + iter];
+ stack[--stack_index] = 0; // unload 2 values and load default value
+ if (loop_by === 0) {
+ locals[locals_offset + iter + 2] = loop_to > iterator ? 1 : -1;
+ op_index++;
+ } else {
+ locals[locals_offset + iter + 2] = loop_by;
+ if ((loop_by > 0 && iterator > loop_to) || (loop_by < 0 && iterator < loop_to)) {
+ op_index = arg1[op_index][1];
+ } else {
+ op_index++;
+ }
+ }
+ break;
+ case 96: // FORLOOP_CONTROL
+ iter = arg1[op_index][0];
+ loop_by = locals[locals_offset + iter + 2];
+ loop_to = locals[locals_offset + iter + 1];
+ iterator = locals[locals_offset + iter];
+ iterator += loop_by;
+ if ((loop_by > 0 && iterator > loop_to) || (loop_by < 0 && iterator < loop_to)) {
+ op_index++;
+ } else {
+ locals[locals_offset + iter] = iterator;
+ op_index = arg1[op_index][1];
+ }
+ if (op_count++ > 100) {
+ op_count = 0;
+ if (Date.now() > this.time_limit) {
+ restore_op_index = op_index;
+ op_index = length; // stop the loop without adding a condition statement
+ }
+ }
+ break;
+ case 97: // FORIN_INIT
+ v = stack[stack_index];
+ stack[stack_index] = 0; // default result
+ iterator = arg1[op_index][0];
+ if (typeof v === "object") {
+ if (Array.isArray(v)) {
+ locals[locals_offset + iterator + 1] = v;
+ } else {
+ v = locals[locals_offset + iterator + 1] = Object.keys(v);
+ }
+ } else if (typeof v === "string") {
+ v = locals[locals_offset + iterator + 1] = v.split("");
+ } else {
+ v = locals[locals_offset + iterator + 1] = [];
+ }
+ if (v.length === 0) {
+ op_index = arg1[op_index][1];
+ } else {
+ value = v[0];
+ // value could be undefined if the array is sparse
+ locals[locals_offset + arg1[op_index][0]] = value != null ? value : 0;
+ locals[locals_offset + iterator + 2] = 0;
+ op_index++;
+ }
+ break;
+ case 98: // FORIN_CONTROL
+ iterator = arg1[op_index][0];
+ index = locals[locals_offset + iterator + 2] += 1;
+ v = locals[locals_offset + iterator + 1];
+ if (index < v.length) {
+ value = v[index];
+ // value could be undefined if the array is sparse
+ locals[locals_offset + iterator] = value != null ? value : 0;
+ op_index = arg1[op_index][1];
+ } else {
+ op_index++;
+ }
+ if (op_count++ > 100) {
+ op_count = 0;
+ if (Date.now() > this.time_limit) {
+ restore_op_index = op_index;
+ op_index = length; // stop the loop without adding a condition statement
+ }
+ }
+ break;
+ case 80: // OPCODE_JUMP
+ op_index = arg1[op_index];
+ if (op_count++ > 100) {
+ op_count = 0;
+ if (Date.now() > this.time_limit) {
+ restore_op_index = op_index;
+ op_index = length; // stop the loop without adding a condition statement
+ }
+ }
+ break;
+ case 81: // OPCODE_JUMPY
+ if (stack[stack_index--]) {
+ op_index = arg1[op_index];
+ } else {
+ op_index++;
+ }
+ break;
+ case 82: // OPCODE_JUMPN
+ if (!stack[stack_index--]) {
+ op_index = arg1[op_index];
+ } else {
+ op_index++;
+ }
+ break;
+ case 83: // OPCODE_JUMPY_NOPOP
+ if (stack[stack_index]) {
+ op_index = arg1[op_index];
+ } else {
+ op_index++;
+ }
+ break;
+ case 84: // OPCODE_JUMPN_NOPOP
+ if (!stack[stack_index]) {
+ op_index = arg1[op_index];
+ } else {
+ op_index++;
+ }
+ break;
+ case 89: // OPCODE_LOAD_ROUTINE
+ r = arg1[op_index++];
+ rc = r.clone();
+ ref3 = r.import_refs;
+ for (l = 0, len = ref3.length; l < len; l++) {
+ ir = ref3[l];
+ if (ir === r.import_self) {
+ rc.import_values.push(rc);
+ } else {
+ rc.import_values.push(locals[locals_offset + ir]);
+ }
+ }
+ rc.object = object;
+ stack[++stack_index] = rc;
+ break;
+ case 90: // OPCODE_FUNCTION_CALL
+ args = arg1[op_index];
+ f = stack[stack_index];
+ if (f instanceof Routine) {
+ stack_index--;
+ cs = call_stack[call_stack_index] || (call_stack[call_stack_index] = {});
+ call_stack_index++;
+ cs.routine = routine;
+ cs.object = object;
+ cs.super = call_super;
+ cs.supername = call_supername;
+ cs.op_index = op_index + 1;
+ locals_offset += routine.locals_size;
+ routine = f;
+ opcodes = f.opcodes;
+ arg1 = f.arg1;
+ op_index = 0;
+ length = opcodes.length;
+ object = routine.object != null ? routine.object : global;
+ call_super = global;
+ call_supername = "";
+ if (routine.uses_arguments) {
+ argv = stack.slice(stack_index - args + 1, stack_index + 1);
+ }
+ if (args < f.num_args) {
+ for (i = m = ref4 = args + 1, ref5 = f.num_args; m <= ref5; i = m += 1) {
+ stack[++stack_index] = 0;
+ }
+ } else if (args > f.num_args) {
+ stack_index -= args - f.num_args;
+ }
+ stack[++stack_index] = args;
+ if (routine.uses_arguments) {
+ stack[++stack_index] = argv;
+ }
+ } else if (typeof f === "function") {
+ switch (args) {
+ case 0:
+ try {
+ v = f();
+ } catch (error) {
+ err = error;
+ console.error(err);
+ v = 0;
+ }
+ stack[stack_index] = v != null ? v : 0;
+ break;
+ case 1:
+ try {
+ v = f(this.argToNative(stack[stack_index - 1], context));
+ } catch (error) {
+ err = error;
+ console.error(err);
+ v = 0;
+ }
+ stack[stack_index - 1] = v != null ? v : 0;
+ stack_index -= 1;
+ break;
+ default:
+ argv = [];
+ stack_index -= args;
+ for (i = n = 0, ref6 = args - 1; n <= ref6; i = n += 1) {
+ argv[i] = this.argToNative(stack[stack_index + i], context);
+ }
+ try {
+ v = f.apply(null, argv);
+ } catch (error) {
+ err = error;
+ console.error(err);
+ v = 0;
+ }
+ stack[stack_index] = v != null ? v : 0;
+ }
+ op_index++;
+ } else {
+ stack_index -= args;
+ stack[stack_index] = f != null ? f : 0;
+ token = routine.ref[op_index].token;
+ id = token.tokenizer.filename + "-" + token.line + "-" + token.column;
+ if (!context.warnings.invoking_non_function[id]) {
+ fc = routine.ref[op_index];
+ i1 = fc.expression.token.start;
+ i2 = fc.token.start + fc.token.length;
+ context.warnings.invoking_non_function[id] = {
+ file: token.tokenizer.filename,
+ line: token.line,
+ column: token.column,
+ expression: fc.token.tokenizer.input.substring(i1, i2)
+ };
+ }
+ op_index++;
+ }
+ break;
+ case 91: // OPCODE_FUNCTION_APPLY_VARIABLE
+ name = stack[stack_index];
+ sup = obj = object;
+ f = obj[name];
+ if (f == null) {
+ while ((f == null) && (sup.class != null)) {
+ sup = sup.class;
+ f = sup[name];
+ }
+ if (f == null) {
+ f = global.Object[name];
+ }
+ if (f == null) {
+ f = global[name];
+ sup = global;
+ obj = global;
+ }
+ }
+ args = arg1[op_index];
+ if (f instanceof Routine) {
+ stack_index -= 1;
+ cs = call_stack[call_stack_index] || (call_stack[call_stack_index] = {});
+ call_stack_index++;
+ cs.routine = routine;
+ cs.object = object;
+ cs.super = call_super;
+ cs.supername = call_supername;
+ cs.op_index = op_index + 1;
+ locals_offset += routine.locals_size;
+ routine = f;
+ opcodes = f.opcodes;
+ arg1 = f.arg1;
+ op_index = 0;
+ length = opcodes.length;
+ object = obj;
+ call_super = sup;
+ call_supername = name;
+ if (routine.uses_arguments) {
+ argv = stack.slice(stack_index - args + 1, stack_index + 1);
+ }
+ if (args < f.num_args) {
+ for (i = p = ref7 = args + 1, ref8 = f.num_args; p <= ref8; i = p += 1) {
+ stack[++stack_index] = 0;
+ }
+ } else if (args > f.num_args) {
+ stack_index -= args - f.num_args;
+ }
+ stack[++stack_index] = args;
+ if (routine.uses_arguments) {
+ stack[++stack_index] = argv;
+ }
+ } else if (typeof f === "function") {
+ switch (args) {
+ case 0:
+ try {
+ v = f.call(obj);
+ } catch (error) {
+ err = error;
+ console.error(err);
+ v = 0;
+ }
+ stack[stack_index] = v != null ? v : 0;
+ break;
+ case 1:
+ try {
+ v = f.call(obj, this.argToNative(stack[stack_index - 1], context));
+ } catch (error) {
+ err = error;
+ console.error(err);
+ v = 0;
+ }
+ stack[--stack_index] = v != null ? v : 0;
+ break;
+ default:
+ argv = [];
+ stack_index -= args;
+ for (i = q = 0, ref9 = args - 1; q <= ref9; i = q += 1) {
+ argv[i] = this.argToNative(stack[stack_index + i], context);
+ }
+ try {
+ v = f.apply(obj, argv);
+ } catch (error) {
+ err = error;
+ console.error(err);
+ v = 0;
+ }
+ stack[stack_index] = v != null ? v : 0;
+ }
+ op_index++;
+ } else {
+ stack_index -= args;
+ stack[stack_index] = f != null ? f : 0;
+ token = routine.ref[op_index].token;
+ id = token.tokenizer.filename + "-" + token.line + "-" + token.column;
+ if (!context.warnings.invoking_non_function[id]) {
+ fc = routine.ref[op_index];
+ i1 = fc.expression.token.start;
+ i2 = fc.token.start + fc.token.length;
+ context.warnings.invoking_non_function[id] = {
+ file: token.tokenizer.filename,
+ line: token.line,
+ column: token.column,
+ expression: fc.token.tokenizer.input.substring(i1, i2)
+ };
+ }
+ op_index++;
+ }
+ break;
+ case 92: // OPCODE_FUNCTION_APPLY_PROPERTY
+ obj = stack[stack_index - 1];
+ sup = obj;
+ name = stack[stack_index];
+ f = obj[name];
+ while ((f == null) && (sup.class != null)) {
+ sup = sup.class;
+ f = sup[name];
+ }
+ args = arg1[op_index];
+ if (f == null) {
+ if (obj instanceof Routine) {
+ f = global.Function[name];
+ } else if (typeof obj === "string") {
+ f = global.String[name];
+ } else if (typeof obj === "number") {
+ f = global.Number[name];
+ } else if (Array.isArray(obj)) {
+ f = global.List[name];
+ } else if (typeof obj === "object") {
+ f = global.Object[name];
+ }
+ }
+ if (f instanceof Routine) {
+ stack_index -= 2;
+ cs = call_stack[call_stack_index] || (call_stack[call_stack_index] = {});
+ call_stack_index++;
+ cs.object = object;
+ cs.super = call_super;
+ cs.supername = call_supername;
+ cs.routine = routine;
+ cs.op_index = op_index + 1;
+ locals_offset += routine.locals_size;
+ routine = f;
+ opcodes = f.opcodes;
+ arg1 = f.arg1;
+ op_index = 0;
+ length = opcodes.length;
+ object = obj;
+ call_super = sup;
+ call_supername = name;
+ if (routine.uses_arguments) {
+ argv = stack.slice(stack_index - args + 1, stack_index + 1);
+ }
+ if (args < f.num_args) {
+ for (i = s = ref10 = args + 1, ref11 = f.num_args; s <= ref11; i = s += 1) {
+ stack[++stack_index] = 0;
+ }
+ } else if (args > f.num_args) {
+ stack_index -= args - f.num_args;
+ }
+ stack[++stack_index] = args;
+ if (routine.uses_arguments) {
+ stack[++stack_index] = argv;
+ }
+ } else if (typeof f === "function") {
+ switch (args) {
+ case 0:
+ try {
+ v = f.call(obj);
+ } catch (error) {
+ err = error;
+ console.error(err);
+ v = 0;
+ }
+ stack[--stack_index] = v != null ? v : 0;
+ break;
+ case 1:
+ try {
+ v = f.call(obj, this.argToNative(stack[stack_index - 2], context));
+ } catch (error) {
+ err = error;
+ console.error(err);
+ v = 0;
+ }
+ stack[stack_index - 2] = v != null ? v : 0;
+ stack_index -= 2;
+ break;
+ default:
+ argv = [];
+ stack_index -= args + 1;
+ for (i = u = 0, ref12 = args - 1; u <= ref12; i = u += 1) {
+ argv[i] = this.argToNative(stack[stack_index + i], context);
+ }
+ try {
+ v = f.apply(obj, argv);
+ } catch (error) {
+ err = error;
+ console.error(err);
+ v = 0;
+ }
+ stack[stack_index] = v != null ? v : 0;
+ }
+ op_index++;
+ } else {
+ stack_index -= args + 1;
+ stack[stack_index] = f != null ? f : 0;
+ token = routine.ref[op_index].token;
+ id = token.tokenizer.filename + "-" + token.line + "-" + token.column;
+ if (!context.warnings.invoking_non_function[id]) {
+ fc = routine.ref[op_index];
+ i1 = fc.expression.token.start;
+ i2 = fc.token.start + fc.token.length;
+ context.warnings.invoking_non_function[id] = {
+ file: token.tokenizer.filename,
+ line: token.line,
+ column: token.column,
+ expression: fc.token.tokenizer.input.substring(i1, i2)
+ };
+ }
+ op_index++;
+ }
+ break;
+ case 93: // OPCODE_SUPER_CALL
+ if ((call_super != null) && (call_supername != null)) {
+ sup = call_super;
+ f = null;
+ while ((f == null) && (sup.class != null)) {
+ sup = sup.class;
+ f = sup[call_supername];
+ }
+ if ((f != null) && f instanceof Routine) {
+ args = arg1[op_index];
+ cs = call_stack[call_stack_index] || (call_stack[call_stack_index] = {});
+ call_stack_index++;
+ cs.object = object;
+ cs.super = call_super;
+ cs.supername = call_supername;
+ cs.routine = routine;
+ cs.op_index = op_index + 1;
+ locals_offset += routine.locals_size;
+ routine = f;
+ opcodes = f.opcodes;
+ arg1 = f.arg1;
+ op_index = 0;
+ length = opcodes.length;
+ call_super = sup;
+ if (routine.uses_arguments) {
+ argv = stack.slice(stack_index - args + 1, stack_index + 1);
+ }
+ if (args < f.num_args) {
+ for (i = w = ref13 = args + 1, ref14 = f.num_args; w <= ref14; i = w += 1) {
+ stack[++stack_index] = 0;
+ }
+ } else if (args > f.num_args) {
+ stack_index -= args - f.num_args;
+ }
+ stack[++stack_index] = args;
+ if (routine.uses_arguments) {
+ stack[++stack_index] = argv;
+ }
+ } else {
+ args = arg1[op_index];
+ stack_index -= args;
+ stack[++stack_index] = 0;
+ op_index++;
+ }
+ } else {
+ args = arg1[op_index];
+ stack_index -= args;
+ stack[++stack_index] = 0;
+ op_index++;
+ }
+ break;
+ case 94: // OPCODE_RETURN
+ local_index -= arg1[op_index];
+ if (call_stack_index <= 0) {
+ op_index = length;
+ } else {
+ cs = call_stack[--call_stack_index];
+ object = cs.object;
+ call_super = cs.super;
+ call_supername = cs.supername;
+ routine = cs.routine;
+ op_index = cs.op_index;
+ opcodes = routine.opcodes;
+ arg1 = routine.arg1;
+ locals_offset -= routine.locals_size;
+ length = opcodes.length;
+ }
+ break;
+ case 100: // OPCODE_UNARY_FUNC
+ v = arg1[op_index](stack[stack_index]);
+ stack[stack_index] = isFinite(v) ? v : 0;
+ op_index++;
+ break;
+ case 101: // OPCODE_BINARY_FUNC
+ v = arg1[op_index](stack[stack_index - 1], stack[stack_index]);
+ stack[--stack_index] = isFinite(v) ? v : 0;
+ op_index++;
+ break;
+ case 110: // OPCODE_AFTER
+ t = this.runner.createThread(stack[stack_index - 1], stack[stack_index], false);
+ stack[--stack_index] = t;
+ op_index += 1;
+ break;
+ // add thread to the runner thread list
+ case 111: // OPCODE_EVERY
+ t = this.runner.createThread(stack[stack_index - 1], stack[stack_index], true);
+ stack[--stack_index] = t;
+ op_index += 1;
+ break;
+ // add thread to the runner thread list
+ case 112: // OPCODE_DO
+ t = this.runner.createThread(stack[stack_index], 0, false);
+ stack[stack_index] = t;
+ op_index += 1;
+ break;
+ // add thread to the runner thread list
+ case 113: // OPCODE_SLEEP
+ sleep_time = isFinite(stack[stack_index]) ? stack[stack_index] : 0;
+ this.runner.sleep(sleep_time);
+ op_index += 1;
+ restore_op_index = op_index;
+ op_index = length; // stop the thread
+ break;
+ case 200: // COMPILED
+ stack_index = arg1[op_index](stack, stack_index, locals, locals_offset, object, global);
+ op_index++;
+ break;
+ default:
+ throw `Unsupported operation: ${opcodes[op_index]}`;
+ }
+ }
+ if (restore_op_index >= 0) {
+ this.op_index = restore_op_index;
+ this.routine = routine;
+ this.stack_index = stack_index;
+ this.local_index = local_index;
+ this.object = object;
+ this.call_stack_index = call_stack_index;
+ this.call_super = call_super;
+ this.call_supername = call_supername;
+ this.locals_offset = locals_offset;
+ this.done = false;
+ } else {
+ this.op_index = 0;
+ this.done = true;
+ if (this.routine.callback != null) {
+ this.routine.callback(stack[stack_index]);
+ this.routine.callback = null;
+ }
+ }
+ // console.info """stack_index: #{stack_index}"""
+ // console.info stack
+ if (this.log) {
+ console.info("total operations: " + op_count);
+ console.info(`stack_index: ${stack_index}`);
+ console.info(`result: ${stack[stack_index]}`);
+ }
+ return stack[stack_index];
+ }
+
+};
diff --git a/WebGames-master/WebGames-master/games/cap/program.js b/WebGames-master/WebGames-master/games/cap/program.js
new file mode 100644
index 00000000..784c1d66
--- /dev/null
+++ b/WebGames-master/WebGames-master/games/cap/program.js
@@ -0,0 +1,371 @@
+this.Program = class Program {
+ constructor() {
+ this.statements = [];
+ }
+
+ add(statement) {
+ return this.statements.push(statement);
+ }
+
+ isAssignment() {
+ return this.statements.length > 0 && this.statements[this.statements.length - 1] instanceof Program.Assignment;
+ }
+
+};
+
+this.Program.Expression = class Expression {
+ constructor() {}
+
+};
+
+this.Program.Assignment = class Assignment {
+ constructor(token1, field1, expression1, local) {
+ this.token = token1;
+ this.field = field1;
+ this.expression = expression1;
+ this.local = local;
+ }
+
+};
+
+this.Program.SelfAssignment = class SelfAssignment {
+ constructor(token1, field1, operation, expression1) {
+ this.token = token1;
+ this.field = field1;
+ this.operation = operation;
+ this.expression = expression1;
+ }
+
+};
+
+this.Program.Value = (function() {
+ class Value {
+ constructor(token1, type, value1) {
+ this.token = token1;
+ this.type = type;
+ this.value = value1;
+ }
+
+ };
+
+ Value.TYPE_NUMBER = 1;
+
+ Value.TYPE_STRING = 2;
+
+ Value.TYPE_ARRAY = 3;
+
+ Value.TYPE_OBJECT = 4;
+
+ Value.TYPE_FUNCTION = 5;
+
+ Value.TYPE_CLASS = 6;
+
+ return Value;
+
+}).call(this);
+
+this.Program.CreateFieldAccess = function(token, expression, field) {
+ if (expression instanceof Program.Field) {
+ expression.appendField(field);
+ return expression;
+ } else {
+ return new Program.Field(token, expression, [field]);
+ }
+};
+
+this.Program.Variable = class Variable {
+ constructor(token1, identifier) {
+ this.token = token1;
+ this.identifier = identifier;
+ }
+
+};
+
+this.Program.Field = class Field {
+ constructor(token1, expression1, chain) {
+ this.token = token1;
+ this.expression = expression1;
+ this.chain = chain;
+ this.token = this.expression.token;
+ }
+
+ appendField(field) {
+ return this.chain.push(field);
+ }
+
+};
+
+this.Program.BuildOperations = function(ops, terms) {
+ var i, o, o1, o2, prec, t1, t2;
+ while (ops.length > 1) {
+ i = 0;
+ prec = 0;
+ while (i < ops.length - 1) {
+ o1 = ops[i];
+ o2 = ops[i + 1];
+ if (Program.Precedence[o2.operation] <= Program.Precedence[o1.operation]) {
+ break;
+ }
+ i++;
+ }
+ t1 = terms[i];
+ t2 = terms[i + 1];
+ o = new Program.Operation(ops[i].token, ops[i].operation, t1, t2);
+ terms.splice(i, 2, o);
+ ops.splice(i, 1);
+ }
+ return new Program.Operation(ops[0].token, ops[0].operation, terms[0], terms[1]);
+};
+
+this.Program.Operation = class Operation {
+ constructor(token1, operation, term1, term2) {
+ this.token = token1;
+ this.operation = operation;
+ this.term1 = term1;
+ this.term2 = term2;
+ }
+
+};
+
+this.Program.Negate = class Negate {
+ constructor(token1, expression1) {
+ this.token = token1;
+ this.expression = expression1;
+ }
+
+};
+
+this.Program.Not = class Not {
+ constructor(token1, expression1) {
+ this.token = token1;
+ this.expression = expression1;
+ }
+
+};
+
+this.Program.Braced = class Braced {
+ constructor(token1, expression1) {
+ this.token = token1;
+ this.expression = expression1;
+ }
+
+};
+
+this.Program.Return = class Return {
+ constructor(token1, expression1) {
+ this.token = token1;
+ this.expression = expression1;
+ }
+
+};
+
+this.Program.Condition = class Condition {
+ constructor(token1, chain) {
+ this.token = token1;
+ this.chain = chain;
+ }
+
+};
+
+this.Program.For = class For {
+ constructor(token1, iterator, range_from, range_to, range_by, sequence) {
+ this.token = token1;
+ this.iterator = iterator;
+ this.range_from = range_from;
+ this.range_to = range_to;
+ this.range_by = range_by;
+ this.sequence = sequence;
+ }
+
+};
+
+this.Program.ForIn = class ForIn {
+ constructor(token1, iterator, list, sequence) {
+ this.token = token1;
+ this.iterator = iterator;
+ this.list = list;
+ this.sequence = sequence;
+ }
+
+};
+
+this.Program.toString = function(value, nesting = 0) {
+ var i, j, k, key, len, pref, ref, s, v;
+ if (value instanceof Routine) {
+ if (nesting === 0) {
+ return value.source || "[function]";
+ } else {
+ return "[function]";
+ }
+ } else if (typeof value === "function") {
+ return "[native function]";
+ } else if (typeof value === "string") {
+ return `"${value}"`;
+ } else if (Array.isArray(value)) {
+ if (nesting >= 1) {
+ return "[list]";
+ }
+ s = "[";
+ for (i = j = 0, len = value.length; j < len; i = ++j) {
+ v = value[i];
+ s += Program.toString(v, nesting + 1) + (i < value.length - 1 ? "," : "");
+ }
+ return s + "]";
+ } else if (typeof value === "object") {
+ if (nesting >= 1) {
+ return "[object]";
+ }
+ s = "object\n";
+ pref = "";
+ for (i = k = 1, ref = nesting; k <= ref; i = k += 1) {
+ pref += " ";
+ }
+ for (key in value) {
+ v = value[key];
+ s += pref + ` ${key} = ${Program.toString(v, nesting + 1)}\n`;
+ }
+ return s + pref + "end";
+ }
+ return value || 0;
+};
+
+this.Program.While = class While {
+ constructor(token1, condition, sequence) {
+ this.token = token1;
+ this.condition = condition;
+ this.sequence = sequence;
+ }
+
+};
+
+this.Program.Break = class Break {
+ constructor(token1) {
+ this.token = token1;
+ this.nopop = true;
+ }
+
+};
+
+this.Program.Continue = class Continue {
+ constructor(token1) {
+ this.token = token1;
+ this.nopop = true;
+ }
+
+};
+
+this.Program.Function = class Function {
+ constructor(token1, args, sequence, end) {
+ this.token = token1;
+ this.args = args;
+ this.sequence = sequence;
+ this.source = "function" + this.token.tokenizer.input.substring(this.token.index, end.index + 2);
+ }
+
+};
+
+this.Program.FunctionCall = class FunctionCall {
+ constructor(token1, expression1, args) {
+ this.token = token1;
+ this.expression = expression1;
+ this.args = args;
+ }
+
+};
+
+this.Program.CreateObject = class CreateObject {
+ constructor(token1, fields) {
+ this.token = token1;
+ this.fields = fields;
+ }
+
+};
+
+this.Program.CreateClass = class CreateClass {
+ constructor(token1, ext, fields) {
+ this.token = token1;
+ this.ext = ext;
+ this.fields = fields;
+ }
+
+};
+
+this.Program.NewCall = class NewCall {
+ constructor(token1, expression1) {
+ this.token = token1;
+ this.expression = expression1;
+ if (!(this.expression instanceof Program.FunctionCall)) {
+ this.expression = new Program.FunctionCall(this.token, this.expression, []);
+ }
+ }
+
+};
+
+this.Program.After = class After {
+ constructor(token1, delay, sequence, end, multiplier) {
+ this.token = token1;
+ this.delay = delay;
+ this.sequence = sequence;
+ this.multiplier = multiplier;
+ this.source = "after " + this.token.tokenizer.input.substring(this.token.index, end.index + 2);
+ }
+
+};
+
+this.Program.Every = class Every {
+ constructor(token1, delay, sequence, end, multiplier) {
+ this.token = token1;
+ this.delay = delay;
+ this.sequence = sequence;
+ this.multiplier = multiplier;
+ this.source = "every " + this.token.tokenizer.input.substring(this.token.index, end.index + 2);
+ }
+
+};
+
+this.Program.Do = class Do {
+ constructor(token1, sequence, end) {
+ this.token = token1;
+ this.sequence = sequence;
+ this.source = "do " + this.token.tokenizer.input.substring(this.token.index, end.index + 2);
+ }
+
+};
+
+this.Program.Sleep = class Sleep {
+ constructor(token1, delay, multiplier) {
+ this.token = token1;
+ this.delay = delay;
+ this.multiplier = multiplier;
+ }
+
+};
+
+this.Program.Delete = class Delete {
+ constructor(token1, field1) {
+ this.token = token1;
+ this.field = field1;
+ }
+
+};
+
+this.Program.Precedence = {
+ "^": 21,
+ "/": 20,
+ "*": 19,
+ "%": 18,
+ "+": 17,
+ "-": 17,
+ "<": 16,
+ "<=": 15,
+ ">": 14,
+ ">=": 13,
+ "==": 12,
+ "!=": 11,
+ "<<": 10,
+ ">>": 9,
+ "&": 8,
+ "|": 7,
+ "and": 6,
+ "or": 5
+};
diff --git a/WebGames-master/WebGames-master/games/cap/routine.js b/WebGames-master/WebGames-master/games/cap/routine.js
new file mode 100644
index 00000000..9d0b5540
--- /dev/null
+++ b/WebGames-master/WebGames-master/games/cap/routine.js
@@ -0,0 +1,530 @@
+this.Routine = class Routine {
+ constructor(num_args) {
+ this.num_args = num_args;
+ this.ops = [];
+ this.opcodes = [];
+ this.arg1 = [];
+ this.ref = [];
+ this.label_count = 0;
+ this.labels = {};
+ this.transpile = false;
+ this.import_refs = [];
+ this.import_values = [];
+ this.import_self = -1;
+ }
+
+ clone() {
+ var r;
+ r = new Routine(this.num_args);
+ r.opcodes = this.opcodes;
+ r.arg1 = this.arg1;
+ r.ref = this.ref;
+ r.locals_size = this.locals_size;
+ r.uses_arguments = this.uses_arguments;
+ return r;
+ }
+
+ createLabel(str = "label") {
+ var name;
+ return name = ":" + str + "_" + this.label_count++;
+ }
+
+ setLabel(name) {
+ return this.labels[name] = this.opcodes.length;
+ }
+
+ optimize() {
+ if (this.transpile) {
+ new Transpiler().transpile(this);
+ }
+ }
+
+ removeable(index) {
+ var label, ref1, value;
+ ref1 = this.labels;
+ for (label in ref1) {
+ value = ref1[label];
+ if (value === index) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ remove(index) {
+ var label, ref1, value;
+ ref1 = this.labels;
+ for (label in ref1) {
+ value = ref1[label];
+ if (value === index) {
+ return false;
+ } else if (value > index) {
+ this.labels[label] -= 1;
+ }
+ }
+ this.opcodes.splice(index, 1);
+ this.arg1.splice(index, 1);
+ this.ref.splice(index, 1);
+ return true;
+ }
+
+ resolveLabels() {
+ var i, j, ref1, ref2, ref3, results;
+ results = [];
+ for (i = j = 0, ref1 = this.opcodes.length - 1; (0 <= ref1 ? j <= ref1 : j >= ref1); i = 0 <= ref1 ? ++j : --j) {
+ if ((ref2 = this.opcodes[i]) === OPCODES.JUMP || ref2 === OPCODES.JUMPY || ref2 === OPCODES.JUMPN || ref2 === OPCODES.JUMPY_NOPOP || ref2 === OPCODES.JUMPN_NOPOP) {
+ if (this.labels[this.arg1[i]]) {
+ results.push(this.arg1[i] = this.labels[this.arg1[i]]);
+ } else {
+ results.push(void 0);
+ }
+ } else if ((ref3 = this.opcodes[i]) === OPCODES.FORLOOP_CONTROL || ref3 === OPCODES.FORLOOP_INIT || ref3 === OPCODES.FORIN_CONTROL || ref3 === OPCODES.FORIN_INIT) {
+ if (this.labels[this.arg1[i][1]]) {
+ results.push(this.arg1[i][1] = this.labels[this.arg1[i][1]]);
+ } else {
+ results.push(void 0);
+ }
+ } else {
+ results.push(void 0);
+ }
+ }
+ return results;
+ }
+
+ OP(code, ref, v1 = 0) {
+ this.opcodes.push(code);
+ this.arg1.push(v1);
+ return this.ref.push(ref);
+ }
+
+ OP_INSERT(code, ref, v1 = 0, index) {
+ var label, ref1, value;
+ this.opcodes.splice(index, 0, code);
+ this.arg1.splice(index, 0, v1);
+ this.ref.splice(index, 0, ref);
+ ref1 = this.labels;
+ for (label in ref1) {
+ value = ref1[label];
+ if (value >= index) {
+ this.labels[label] += 1;
+ }
+ }
+ }
+
+ TYPE(ref) {
+ return this.OP(OPCODES.TYPE, ref);
+ }
+
+ VARIABLE_TYPE(variable, ref) {
+ return this.OP(OPCODES.VARIABLE_TYPE, ref, variable);
+ }
+
+ PROPERTY_TYPE(ref) {
+ return this.OP(OPCODES.PROPERTY_TYPE, ref);
+ }
+
+ LOAD_THIS(ref) {
+ return this.OP(OPCODES.LOAD_THIS, ref);
+ }
+
+ LOAD_GLOBAL(ref) {
+ return this.OP(OPCODES.LOAD_GLOBAL, ref);
+ }
+
+ LOAD_VALUE(value, ref) {
+ return this.OP(OPCODES.LOAD_VALUE, ref, value);
+ }
+
+ LOAD_LOCAL(index, ref) {
+ return this.OP(OPCODES.LOAD_LOCAL, ref, index);
+ }
+
+ LOAD_VARIABLE(variable, ref) {
+ return this.OP(OPCODES.LOAD_VARIABLE, ref, variable);
+ }
+
+ LOAD_LOCAL_OBJECT(index, ref) {
+ return this.OP(OPCODES.LOAD_LOCAL_OBJECT, ref, index);
+ }
+
+ LOAD_VARIABLE_OBJECT(variable, ref) {
+ return this.OP(OPCODES.LOAD_VARIABLE_OBJECT, ref, variable);
+ }
+
+ POP(ref) {
+ return this.OP(OPCODES.POP, ref);
+ }
+
+ LOAD_PROPERTY(ref) {
+ return this.OP(OPCODES.LOAD_PROPERTY, ref);
+ }
+
+ LOAD_PROPERTY_OBJECT(ref) {
+ return this.OP(OPCODES.LOAD_PROPERTY_OBJECT, ref);
+ }
+
+ CREATE_OBJECT(ref) {
+ return this.OP(OPCODES.CREATE_OBJECT, ref);
+ }
+
+ MAKE_OBJECT(ref) {
+ return this.OP(OPCODES.MAKE_OBJECT, ref);
+ }
+
+ CREATE_ARRAY(ref) {
+ return this.OP(OPCODES.CREATE_ARRAY, ref);
+ }
+
+ CREATE_CLASS(parent_var, ref) {
+ return this.OP(OPCODES.CREATE_CLASS, ref, parent_var);
+ }
+
+ UPDATE_CLASS(variable, ref) {
+ return this.OP(OPCODES.UPDATE_CLASS, ref, variable);
+ }
+
+ NEW_CALL(args, ref) {
+ return this.OP(OPCODES.NEW_CALL, ref, args);
+ }
+
+ ADD(ref, self = 0) {
+ return this.OP(OPCODES.ADD, ref, self);
+ }
+
+ SUB(ref, self = 0) {
+ return this.OP(OPCODES.SUB, ref, self);
+ }
+
+ MUL(ref) {
+ return this.OP(OPCODES.MUL, ref);
+ }
+
+ DIV(ref) {
+ return this.OP(OPCODES.DIV, ref);
+ }
+
+ MODULO(ref) {
+ return this.OP(OPCODES.MODULO, ref);
+ }
+
+ BINARY_AND(ref) {
+ return this.OP(OPCODES.BINARY_AND, ref);
+ }
+
+ BINARY_OR(ref) {
+ return this.OP(OPCODES.BINARY_OR, ref);
+ }
+
+ SHIFT_LEFT(ref) {
+ return this.OP(OPCODES.SHIFT_LEFT, ref);
+ }
+
+ SHIFT_RIGHT(ref) {
+ return this.OP(OPCODES.SHIFT_RIGHT, ref);
+ }
+
+ NEGATE(ref) {
+ return this.OP(OPCODES.NEGATE, ref);
+ }
+
+ LOAD_PROPERTY_ATOP(ref) {
+ return this.OP(OPCODES.LOAD_PROPERTY_ATOP, ref);
+ }
+
+ EQ(ref) {
+ return this.OP(OPCODES.EQ, ref);
+ }
+
+ NEQ(ref) {
+ return this.OP(OPCODES.NEQ, ref);
+ }
+
+ LT(ref) {
+ return this.OP(OPCODES.LT, ref);
+ }
+
+ GT(ref) {
+ return this.OP(OPCODES.GT, ref);
+ }
+
+ LTE(ref) {
+ return this.OP(OPCODES.LTE, ref);
+ }
+
+ GTE(ref) {
+ return this.OP(OPCODES.GTE, ref);
+ }
+
+ NOT(ref) {
+ return this.OP(OPCODES.NOT, ref);
+ }
+
+ FORLOOP_INIT(iterator, ref) {
+ return this.OP(OPCODES.FORLOOP_INIT, ref, iterator);
+ }
+
+ FORLOOP_CONTROL(args, ref) {
+ return this.OP(OPCODES.FORLOOP_CONTROL, ref, args);
+ }
+
+ FORIN_INIT(args, ref) {
+ return this.OP(OPCODES.FORIN_INIT, ref, args);
+ }
+
+ FORIN_CONTROL(args, ref) {
+ return this.OP(OPCODES.FORIN_CONTROL, ref, args);
+ }
+
+ JUMP(index, ref) {
+ return this.OP(OPCODES.JUMP, ref, index);
+ }
+
+ JUMPY(index, ref) {
+ return this.OP(OPCODES.JUMPY, ref, index);
+ }
+
+ JUMPN(index, ref) {
+ return this.OP(OPCODES.JUMPN, ref, index);
+ }
+
+ JUMPY_NOPOP(index, ref) {
+ return this.OP(OPCODES.JUMPY_NOPOP, ref, index);
+ }
+
+ JUMPN_NOPOP(index, ref) {
+ return this.OP(OPCODES.JUMPN_NOPOP, ref, index);
+ }
+
+ STORE_LOCAL(index, ref) {
+ return this.OP(OPCODES.STORE_LOCAL, ref, index);
+ }
+
+ STORE_VARIABLE(field, ref) {
+ return this.OP(OPCODES.STORE_VARIABLE, ref, field);
+ }
+
+ CREATE_PROPERTY(ref) {
+ return this.OP(OPCODES.CREATE_PROPERTY, ref);
+ }
+
+ STORE_PROPERTY(ref) {
+ return this.OP(OPCODES.STORE_PROPERTY, ref);
+ }
+
+ LOAD_ROUTINE(value, ref) {
+ return this.OP(OPCODES.LOAD_ROUTINE, ref, value);
+ }
+
+ FUNCTION_CALL(args, ref) {
+ return this.OP(OPCODES.FUNCTION_CALL, ref, args);
+ }
+
+ FUNCTION_APPLY_VARIABLE(args, ref) {
+ return this.OP(OPCODES.FUNCTION_APPLY_VARIABLE, ref, args);
+ }
+
+ FUNCTION_APPLY_PROPERTY(args, ref) {
+ return this.OP(OPCODES.FUNCTION_APPLY_PROPERTY, ref, args);
+ }
+
+ SUPER_CALL(args, ref) {
+ return this.OP(OPCODES.SUPER_CALL, ref, args);
+ }
+
+ RETURN(ref) {
+ return this.OP(OPCODES.RETURN, ref);
+ }
+
+ AFTER(ref) {
+ return this.OP(OPCODES.AFTER, ref);
+ }
+
+ EVERY(ref) {
+ return this.OP(OPCODES.EVERY, ref);
+ }
+
+ DO(ref) {
+ return this.OP(OPCODES.DO, ref);
+ }
+
+ SLEEP(ref) {
+ return this.OP(OPCODES.SLEEP, ref);
+ }
+
+ DELETE(ref) {
+ return this.OP(OPCODES.DELETE, ref);
+ }
+
+ UNARY_OP(f, ref) {
+ return this.OP(OPCODES.UNARY_OP, ref, f);
+ }
+
+ BINARY_OP(f, ref) {
+ return this.OP(OPCODES.BINARY_OP, ref, f);
+ }
+
+ toString() {
+ var i, j, len, op, ref1, s;
+ s = "";
+ ref1 = this.opcodes;
+ for (i = j = 0, len = ref1.length; j < len; i = ++j) {
+ op = ref1[i];
+ s += OPCODES[op];
+ if (this.arg1[i] != null) {
+ //if typeof @arg1[i] != "function"
+ s += ` ${this.arg1[i]}`;
+ }
+ s += "\n";
+ }
+ return s;
+ }
+
+ exportArg(arg) {
+ if (arg == null) {
+ return 0;
+ } else if (arg instanceof Routine) {
+ return arg.export();
+ } else if (typeof arg === "function") {
+ return arg.name;
+ } else {
+ return arg;
+ }
+ }
+
+ export() {
+ var args, i, j, ref1, res;
+ args = [];
+ for (i = j = 0, ref1 = this.arg1.length - 1; j <= ref1; i = j += 1) {
+ args[i] = this.exportArg(this.arg1[i]);
+ }
+ res = {
+ num_args: this.num_args,
+ ops: this.opcodes,
+ args: args,
+ import_refs: this.import_refs,
+ import_values: this.import_values,
+ import_self: this.import_self,
+ locals_size: this.locals_size
+ };
+ return res;
+ }
+
+ import(src) {
+ var i, j, ref, ref1, token;
+ this.num_args = src.num_args;
+ this.opcodes = src.ops;
+ this.arg1 = src.args;
+ this.import_refs = src.import_refs;
+ this.import_values = src.import_values;
+ this.import_self = src.import_self;
+ this.locals_size = src.locals_size;
+ token = {
+ line: 0,
+ column: 0,
+ start: 0,
+ length: 0,
+ index: 0,
+ tokenizer: {
+ filename: "filename",
+ input: ""
+ }
+ };
+ ref = {
+ expression: {
+ token: token
+ },
+ token: token
+ };
+ for (i = j = 0, ref1 = this.opcodes.length - 1; j <= ref1; i = j += 1) {
+ if (this.opcodes[i] === 100) {
+ this.arg1[i] = Compiler.predefined_unary_functions[this.arg1[i]];
+ } else if (this.opcodes[i] === 101) {
+ this.arg1[i] = Compiler.predefined_binary_functions[this.arg1[i]];
+ } else if (typeof this.arg1[i] === "object" && !Array.isArray(this.arg1[i])) {
+ this.arg1[i] = new Routine(0).import(this.arg1[i]);
+ }
+ this.ref[i] = ref;
+ }
+ return this;
+ }
+
+};
+
+this.OPCODES_CLASS = class OPCODES_CLASS {
+ constructor() {
+ this.table = {};
+ this.set("TYPE", 1);
+ this.set("VARIABLE_TYPE", 2);
+ this.set("PROPERTY_TYPE", 3);
+ this.set("LOAD_IMPORT", 4);
+ this.set("LOAD_THIS", 5);
+ this.set("LOAD_GLOBAL", 6);
+ this.set("LOAD_VALUE", 10);
+ this.set("LOAD_LOCAL", 11);
+ this.set("LOAD_VARIABLE", 12);
+ this.set("LOAD_LOCAL_OBJECT", 13);
+ this.set("LOAD_VARIABLE_OBJECT", 14);
+ this.set("POP", 15);
+ this.set("LOAD_PROPERTY", 16);
+ this.set("LOAD_PROPERTY_OBJECT", 17);
+ this.set("CREATE_OBJECT", 18);
+ this.set("MAKE_OBJECT", 19);
+ this.set("CREATE_ARRAY", 20);
+ this.set("STORE_LOCAL", 21);
+ this.set("STORE_VARIABLE", 23);
+ this.set("CREATE_PROPERTY", 24);
+ this.set("STORE_PROPERTY", 25);
+ this.set("DELETE", 26);
+ this.set("UPDATE_CLASS", 27);
+ this.set("CREATE_CLASS", 28);
+ this.set("NEW_CALL", 29);
+ this.set("ADD", 30);
+ this.set("SUB", 31);
+ this.set("MUL", 32);
+ this.set("DIV", 33);
+ this.set("MODULO", 34);
+ this.set("BINARY_AND", 35);
+ this.set("BINARY_OR", 36);
+ this.set("SHIFT_LEFT", 37);
+ this.set("SHIFT_RIGHT", 38);
+ this.set("NEGATE", 39);
+ this.set("EQ", 40);
+ this.set("NEQ", 41);
+ this.set("LT", 42);
+ this.set("GT", 43);
+ this.set("LTE", 44);
+ this.set("GTE", 45);
+ this.set("NOT", 50);
+ this.set("LOAD_PROPERTY_ATOP", 68);
+ this.set("JUMP", 80);
+ this.set("JUMPY", 81);
+ this.set("JUMPN", 82);
+ this.set("JUMPY_NOPOP", 83);
+ this.set("JUMPN_NOPOP", 84);
+ this.set("LOAD_ROUTINE", 89);
+ this.set("FUNCTION_CALL", 90);
+ this.set("FUNCTION_APPLY_VARIABLE", 91);
+ this.set("FUNCTION_APPLY_PROPERTY", 92);
+ this.set("SUPER_CALL", 93);
+ this.set("RETURN", 94);
+ this.set("FORLOOP_INIT", 95);
+ this.set("FORLOOP_CONTROL", 96);
+ this.set("FORIN_INIT", 97);
+ this.set("FORIN_CONTROL", 98);
+ this.set("UNARY_OP", 100);
+ this.set("BINARY_OP", 101);
+ this.set("COMPILED", 200);
+ this.set("AFTER", 110);
+ this.set("EVERY", 111);
+ this.set("DO", 112);
+ this.set("SLEEP", 113);
+ }
+
+ set(op, code) {
+ this[op] = code;
+ return this[code] = op;
+ }
+
+};
+
+this.OPCODES = new this.OPCODES_CLASS;
diff --git a/WebGames-master/WebGames-master/games/cap/runner.js b/WebGames-master/WebGames-master/games/cap/runner.js
new file mode 100644
index 00000000..a4cde560
--- /dev/null
+++ b/WebGames-master/WebGames-master/games/cap/runner.js
@@ -0,0 +1,385 @@
+this.Runner = class Runner {
+ constructor(microvm) {
+ this.microvm = microvm;
+ }
+
+ init() {
+ this.initialized = true;
+ this.system = this.microvm.context.global.system;
+ this.system.preemptive = 1;
+ this.system.threads = [];
+ this.main_thread = new Thread(this);
+ this.threads = [this.main_thread];
+ this.current_thread = this.main_thread;
+ this.thread_index = 0;
+ this.microvm.context.global.print = this.microvm.context.meta.print;
+ this.microvm.context.global.random = new Random(0);
+ this.microvm.context.global.Function = {
+ bind: function(obj) {
+ var rc;
+ if (this instanceof Routine) {
+ rc = this.clone();
+ rc.object = obj;
+ return rc;
+ } else {
+ return this;
+ }
+ }
+ };
+ this.microvm.context.global.List = {
+ sortList: (f) => {
+ var funk;
+ if ((f != null) && f instanceof Program.Function) {
+ funk = function(a, b) {
+ return f.call(this.microvm.context.global, [a, b], true);
+ };
+ } else if ((f != null) && typeof f === "function") {
+ funk = f;
+ }
+ return this.sort(funk);
+ },
+ "+": function(a, b, self) {
+ if (!self) { // not +=, clone array a
+ a = [...a];
+ }
+ if (Array.isArray(b)) {
+ return a.concat(b);
+ } else {
+ a.push(b);
+ return a;
+ }
+ },
+ "-": function(a, b, self) {
+ var index;
+ if (!self) { // not -=, clone array a
+ a = [...a];
+ }
+ index = a.indexOf(b);
+ if (index >= 0) {
+ a.splice(index, 1);
+ }
+ return a;
+ }
+ };
+ this.microvm.context.global.Object = {};
+ this.microvm.context.global.String = {
+ fromCharCode: function(...args) { return String.fromCharCode(...args) },
+ "+": function(a, b) {
+ return a + b;
+ }
+ };
+ this.microvm.context.global.Number = {
+ parse: function(s) {
+ var res;
+ res = Number.parseFloat(s);
+ if (isFinite(res)) {
+ return res;
+ } else {
+ return 0;
+ }
+ },
+ toString: function() {
+ return this.toString();
+ }
+ };
+ this.fps = 60;
+ this.fps_max = 60;
+ this.cpu_load = 0;
+ this.microvm.context.meta.print("microScript 2.0");
+ return this.triggers_controls_update = true;
+ }
+
+ run(src, filename, callback) {
+ var compiler, err, id, j, len, parser, program, ref, result, w;
+ if (!this.initialized) {
+ this.init();
+ }
+ parser = new Parser(src, filename);
+ parser.parse();
+ if (parser.error_info != null) {
+ err = parser.error_info;
+ err.type = "compile";
+ throw err;
+ }
+ if (parser.warnings.length > 0) {
+ ref = parser.warnings;
+ for (j = 0, len = ref.length; j < len; j++) {
+ w = ref[j];
+ id = filename + "-" + w.line + "-" + w.column;
+ switch (w.type) {
+ case "assigning_api_variable":
+ if (this.microvm.context.warnings.assigning_api_variable[id] == null) {
+ this.microvm.context.warnings.assigning_api_variable[id] = {
+ file: filename,
+ line: w.line,
+ column: w.column,
+ expression: w.identifier
+ };
+ }
+ break;
+ case "assignment_as_condition":
+ if (this.microvm.context.warnings.assignment_as_condition[id] == null) {
+ this.microvm.context.warnings.assignment_as_condition[id] = {
+ file: filename,
+ line: w.line,
+ column: w.column
+ };
+ }
+ }
+ }
+ }
+ program = parser.program;
+ compiler = new Compiler(program);
+ result = null;
+ compiler.routine.callback = function(res) {
+ if (callback != null) {
+ return callback(Program.toString(res));
+ } else {
+ return result = res;
+ }
+ };
+ this.main_thread.addCall(compiler.routine);
+ this.tick();
+ return result;
+ }
+
+ call(name, args) {
+ var f, routine;
+ if (name === "draw" || name === "update" || name === "serverUpdate") {
+ if (this.microvm.context.global[name] != null) {
+ this.main_thread.addCall(`${name}()`);
+ }
+ return;
+ }
+ if (this.microvm.context.global[name] != null) {
+ if ((args == null) || !args.length) {
+ return this.main_thread.addCall(`${name}()`);
+ } else {
+ routine = this.microvm.context.global[name];
+ if (routine instanceof Routine) {
+ f = this.main_thread.processor.routineAsFunction(routine, this.microvm.context);
+ return f(...args);
+ } else if (typeof routine === "function") {
+ return routine(...args);
+ }
+ }
+ } else {
+ return 0;
+ }
+ }
+
+ toString(obj) {
+ return Program.toString(obj);
+ }
+
+ process(thread, time_limit) {
+ var processor;
+ processor = thread.processor;
+ processor.time_limit = time_limit;
+ this.current_thread = thread;
+ return processor.run(this.microvm.context);
+ }
+
+ tick() {
+ var dt, frame_time, i, index, j, k, len, load, margin, processing, processor, ref, ref1, t, time, time_limit, time_out;
+ if (this.system.fps != null) {
+ this.fps = this.fps * .9 + this.system.fps * .1;
+ }
+ this.fps_max = Math.max(this.fps, this.fps_max);
+ frame_time = Math.min(16, Math.floor(1000 / this.fps_max));
+ if (this.fps < 59) {
+ margin = 10;
+ } else {
+ margin = Math.floor(1000 / this.fps * .8);
+ }
+ time = Date.now();
+ time_limit = time + 100; // allow more time to prevent interrupting main_thread in the middle of a draw()
+ time_out = this.system.preemptive ? time_limit : 2e308;
+ processor = this.main_thread.processor;
+ if (!processor.done) {
+ if (this.main_thread.sleep_until != null) {
+ if (Date.now() >= this.main_thread.sleep_until) {
+ delete this.main_thread.sleep_until;
+ this.process(this.main_thread, time_out);
+ }
+ } else {
+ this.process(this.main_thread, time_out);
+ }
+ }
+ while (processor.done && Date.now() < time_out && this.main_thread.loadNext()) {
+ this.process(this.main_thread, time_out);
+ }
+ time_limit = time + margin; // secondary threads get remaining time
+ time_out = this.system.preemptive ? time_limit : 2e308;
+ processing = true;
+ while (processing) {
+ processing = false;
+ ref = this.threads;
+ for (j = 0, len = ref.length; j < len; j++) {
+ t = ref[j];
+ if (t !== this.main_thread) {
+ if (t.paused || t.terminated) {
+ continue;
+ }
+ processor = t.processor;
+ if (!processor.done) {
+ if (t.sleep_until != null) {
+ if (Date.now() >= t.sleep_until) {
+ delete t.sleep_until;
+ this.process(t, time_out);
+ processing = true;
+ }
+ } else {
+ this.process(t, time_out);
+ processing = true;
+ }
+ } else if (t.start_time != null) {
+ if (t.repeat) {
+ while (time >= t.start_time && !(t.paused || t.terminated)) {
+ if (time >= t.start_time + 150) {
+ t.start_time = time + t.delay;
+ } else {
+ t.start_time += t.delay;
+ }
+ processor.load(t.routine);
+ this.process(t, time_out);
+ processing = true;
+ }
+ } else {
+ if (time >= t.start_time) {
+ delete t.start_time;
+ processor.load(t.routine);
+ this.process(t, time_out);
+ processing = true;
+ }
+ }
+ } else {
+ t.terminated = true;
+ }
+ }
+ }
+ if (Date.now() > time_limit) {
+ break;
+ }
+ }
+ for (i = k = ref1 = this.threads.length - 1; k >= 1; i = k += -1) {
+ t = this.threads[i];
+ if (t.terminated) {
+ this.threads.splice(i, 1);
+ index = this.system.threads.indexOf(t.interface);
+ if (index >= 0) {
+ this.system.threads.splice(index, 1);
+ }
+ }
+ }
+ t = Date.now() - time;
+ dt = time_limit - time;
+ load = t / dt * 100;
+ this.cpu_load = this.cpu_load * .9 + load * .1;
+ this.system.cpu_load = Math.min(100, Math.round(this.cpu_load));
+ }
+
+ createThread(routine, delay, repeat) {
+ var i, j, ref, t;
+ t = new Thread(this);
+ t.routine = routine;
+ this.threads.push(t);
+ t.start_time = Date.now() + delay - 1000 / this.fps;
+ if (repeat) {
+ t.repeat = repeat;
+ t.delay = delay;
+ }
+ this.system.threads.push(t.interface);
+ for (i = j = 0, ref = routine.import_values.length - 1; j <= ref; i = j += 1) {
+ if (routine.import_values[i] === routine) {
+ routine.import_values[i] = t.interface;
+ }
+ }
+ return t.interface;
+ }
+
+ sleep(value) {
+ if (this.current_thread != null) {
+ return this.current_thread.sleep_until = Date.now() + Math.max(0, value);
+ }
+ }
+
+};
+
+this.Thread = class Thread {
+ constructor(runner) {
+ this.runner = runner;
+ this.loop = false;
+ this.processor = new Processor(this.runner);
+ this.paused = false;
+ this.terminated = false;
+ this.next_calls = [];
+ this.interface = {
+ pause: () => {
+ return this.pause();
+ },
+ resume: () => {
+ return this.resume();
+ },
+ stop: () => {
+ return this.stop();
+ },
+ status: "running"
+ };
+ }
+
+ addCall(call) {
+ if (this.next_calls.indexOf(call) < 0) {
+ return this.next_calls.push(call);
+ }
+ }
+
+ loadNext() {
+ var compiler, f, parser, program;
+ if (this.next_calls.length > 0) {
+ f = this.next_calls.splice(0, 1)[0];
+ if (f instanceof Routine) {
+ this.processor.load(f);
+ } else {
+ parser = new Parser(f, "");
+ parser.parse();
+ program = parser.program;
+ compiler = new Compiler(program);
+ this.processor.load(compiler.routine);
+ if ((f === "update()" || f === "serverUpdate()") && (this.runner.updateControls != null)) {
+ this.runner.updateControls();
+ }
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ pause() {
+ if (this.interface.status === "running") {
+ this.interface.status = "paused";
+ this.paused = true;
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+
+ resume() {
+ if (this.interface.status === "paused") {
+ this.interface.status = "running";
+ this.paused = false;
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+
+ stop() {
+ this.interface.status = "stopped";
+ this.terminated = true;
+ return 1;
+ }
+
+};
diff --git a/WebGames-master/WebGames-master/games/cap/sounds/death.wav b/WebGames-master/WebGames-master/games/cap/sounds/death.wav
new file mode 100644
index 00000000..65c7153e
Binary files /dev/null and b/WebGames-master/WebGames-master/games/cap/sounds/death.wav differ
diff --git a/WebGames-master/WebGames-master/games/cap/sounds/jump.wav b/WebGames-master/WebGames-master/games/cap/sounds/jump.wav
new file mode 100644
index 00000000..ac5d6cf6
Binary files /dev/null and b/WebGames-master/WebGames-master/games/cap/sounds/jump.wav differ
diff --git a/WebGames-master/WebGames-master/games/cap/sprites/bas.png b/WebGames-master/WebGames-master/games/cap/sprites/bas.png
new file mode 100644
index 00000000..b30f9235
Binary files /dev/null and b/WebGames-master/WebGames-master/games/cap/sprites/bas.png differ
diff --git a/WebGames-master/WebGames-master/games/cap/sprites/blade.png b/WebGames-master/WebGames-master/games/cap/sprites/blade.png
new file mode 100644
index 00000000..8919ba4e
Binary files /dev/null and b/WebGames-master/WebGames-master/games/cap/sprites/blade.png differ
diff --git a/WebGames-master/WebGames-master/games/cap/sprites/cage.png b/WebGames-master/WebGames-master/games/cap/sprites/cage.png
new file mode 100644
index 00000000..1ac51134
Binary files /dev/null and b/WebGames-master/WebGames-master/games/cap/sprites/cage.png differ
diff --git a/WebGames-master/WebGames-master/games/cap/sprites/chick.png b/WebGames-master/WebGames-master/games/cap/sprites/chick.png
new file mode 100644
index 00000000..88eb3627
Binary files /dev/null and b/WebGames-master/WebGames-master/games/cap/sprites/chick.png differ
diff --git a/WebGames-master/WebGames-master/games/cap/sprites/columnblade.png b/WebGames-master/WebGames-master/games/cap/sprites/columnblade.png
new file mode 100644
index 00000000..b6d38cf1
Binary files /dev/null and b/WebGames-master/WebGames-master/games/cap/sprites/columnblade.png differ
diff --git a/WebGames-master/WebGames-master/games/cap/sprites/columnempty.png b/WebGames-master/WebGames-master/games/cap/sprites/columnempty.png
new file mode 100644
index 00000000..9f6ec623
Binary files /dev/null and b/WebGames-master/WebGames-master/games/cap/sprites/columnempty.png differ
diff --git a/WebGames-master/WebGames-master/games/cap/sprites/cube.png b/WebGames-master/WebGames-master/games/cap/sprites/cube.png
new file mode 100644
index 00000000..d4bd7765
Binary files /dev/null and b/WebGames-master/WebGames-master/games/cap/sprites/cube.png differ
diff --git a/WebGames-master/WebGames-master/games/cap/sprites/cube_ghost.png b/WebGames-master/WebGames-master/games/cap/sprites/cube_ghost.png
new file mode 100644
index 00000000..58ee9ed3
Binary files /dev/null and b/WebGames-master/WebGames-master/games/cap/sprites/cube_ghost.png differ
diff --git a/WebGames-master/WebGames-master/games/cap/sprites/icon.png b/WebGames-master/WebGames-master/games/cap/sprites/icon.png
new file mode 100644
index 00000000..7c9f14e2
Binary files /dev/null and b/WebGames-master/WebGames-master/games/cap/sprites/icon.png differ
diff --git a/WebGames-master/WebGames-master/games/cap/sprites/mockup_bas.png b/WebGames-master/WebGames-master/games/cap/sprites/mockup_bas.png
new file mode 100644
index 00000000..63b95f45
Binary files /dev/null and b/WebGames-master/WebGames-master/games/cap/sprites/mockup_bas.png differ
diff --git a/WebGames-master/WebGames-master/games/cap/sprites/piece.png b/WebGames-master/WebGames-master/games/cap/sprites/piece.png
new file mode 100644
index 00000000..9d9277c4
Binary files /dev/null and b/WebGames-master/WebGames-master/games/cap/sprites/piece.png differ
diff --git a/WebGames-master/WebGames-master/games/cap/sprites/poster.png b/WebGames-master/WebGames-master/games/cap/sprites/poster.png
new file mode 100644
index 00000000..bfa655c4
Binary files /dev/null and b/WebGames-master/WebGames-master/games/cap/sprites/poster.png differ
diff --git a/WebGames-master/WebGames-master/games/cap/sprites/spike.png b/WebGames-master/WebGames-master/games/cap/sprites/spike.png
new file mode 100644
index 00000000..eeefd869
Binary files /dev/null and b/WebGames-master/WebGames-master/games/cap/sprites/spike.png differ
diff --git a/WebGames-master/WebGames-master/games/cap/sprites/tower.png b/WebGames-master/WebGames-master/games/cap/sprites/tower.png
new file mode 100644
index 00000000..4e2d1c8f
Binary files /dev/null and b/WebGames-master/WebGames-master/games/cap/sprites/tower.png differ
diff --git a/WebGames-master/WebGames-master/games/cap/sprites/tower1.png b/WebGames-master/WebGames-master/games/cap/sprites/tower1.png
new file mode 100644
index 00000000..95f717dc
Binary files /dev/null and b/WebGames-master/WebGames-master/games/cap/sprites/tower1.png differ
diff --git a/WebGames-master/WebGames-master/games/cap/sprites/tower2.png b/WebGames-master/WebGames-master/games/cap/sprites/tower2.png
new file mode 100644
index 00000000..0e4262db
Binary files /dev/null and b/WebGames-master/WebGames-master/games/cap/sprites/tower2.png differ
diff --git a/WebGames-master/WebGames-master/games/cap/token.js b/WebGames-master/WebGames-master/games/cap/token.js
new file mode 100644
index 00000000..e9d14b85
--- /dev/null
+++ b/WebGames-master/WebGames-master/games/cap/token.js
@@ -0,0 +1,201 @@
+this.Token = class Token {
+ constructor(tokenizer, type, value, string_value) {
+ this.tokenizer = tokenizer;
+ this.type = type;
+ this.value = value;
+ this.string_value = string_value;
+ this.line = this.tokenizer.line;
+ this.column = this.tokenizer.column;
+ this.start = this.tokenizer.token_start;
+ this.length = this.tokenizer.index - this.start;
+ this.index = this.tokenizer.index;
+ if (this.type === Token.TYPE_IDENTIFIER && Token.predefined.hasOwnProperty(this.value)) {
+ this.type = Token.predefined[this.value];
+ this.reserved_keyword = true;
+ }
+ this.is_binary_operator = (this.type >= 30 && this.type <= 39) || (this.type >= 200 && this.type <= 201) || (this.type >= 2 && this.type <= 7);
+ }
+
+ toString() {
+ return this.value + " : " + this.type;
+ }
+
+};
+
+this.Token.TYPE_EQUALS = 1;
+
+this.Token.TYPE_DOUBLE_EQUALS = 2;
+
+this.Token.TYPE_GREATER = 3;
+
+this.Token.TYPE_GREATER_OR_EQUALS = 4;
+
+this.Token.TYPE_LOWER = 5;
+
+this.Token.TYPE_LOWER_OR_EQUALS = 6;
+
+this.Token.TYPE_UNEQUALS = 7;
+
+this.Token.TYPE_IDENTIFIER = 10;
+
+this.Token.TYPE_NUMBER = 11;
+
+this.Token.TYPE_STRING = 12;
+
+this.Token.TYPE_OPEN_BRACE = 20;
+
+this.Token.TYPE_CLOSED_BRACE = 21;
+
+// @Token.TYPE_OPEN_CURLY_BRACE = 22
+// @Token.TYPE_CLOSED_CURLY_BRACE = 23
+this.Token.TYPE_OPEN_BRACKET = 24;
+
+this.Token.TYPE_CLOSED_BRACKET = 25;
+
+this.Token.TYPE_COMMA = 26;
+
+this.Token.TYPE_DOT = 27;
+
+this.Token.TYPE_PLUS = 30;
+
+this.Token.TYPE_MINUS = 31;
+
+this.Token.TYPE_MULTIPLY = 32;
+
+this.Token.TYPE_DIVIDE = 33;
+
+this.Token.TYPE_POWER = 34;
+
+this.Token.TYPE_MODULO = 35;
+
+this.Token.TYPE_BINARY_AND = 36;
+
+this.Token.TYPE_BINARY_OR = 37;
+
+this.Token.TYPE_SHIFT_LEFT = 38;
+
+this.Token.TYPE_SHIFT_RIGHT = 39;
+
+this.Token.TYPE_PLUS_EQUALS = 40;
+
+this.Token.TYPE_MINUS_EQUALS = 41;
+
+this.Token.TYPE_MULTIPLY_EQUALS = 42;
+
+this.Token.TYPE_DIVIDE_EQUALS = 43;
+
+this.Token.TYPE_MODULO_EQUALS = 44;
+
+this.Token.TYPE_AND_EQUALS = 45;
+
+this.Token.TYPE_OR_EQUALS = 46;
+
+this.Token.TYPE_RETURN = 50;
+
+this.Token.TYPE_BREAK = 51;
+
+this.Token.TYPE_CONTINUE = 52;
+
+this.Token.TYPE_FUNCTION = 60;
+
+this.Token.TYPE_AFTER = 61;
+
+this.Token.TYPE_EVERY = 62;
+
+this.Token.TYPE_DO = 63;
+
+this.Token.TYPE_SLEEP = 64;
+
+this.Token.TYPE_LOCAL = 70;
+
+this.Token.TYPE_OBJECT = 80;
+
+this.Token.TYPE_CLASS = 90;
+
+this.Token.TYPE_EXTENDS = 91;
+
+this.Token.TYPE_NEW = 92;
+
+this.Token.TYPE_FOR = 100;
+
+this.Token.TYPE_TO = 101;
+
+this.Token.TYPE_BY = 102;
+
+this.Token.TYPE_IN = 103;
+
+this.Token.TYPE_WHILE = 104;
+
+this.Token.TYPE_IF = 105;
+
+this.Token.TYPE_THEN = 106;
+
+this.Token.TYPE_ELSE = 107;
+
+this.Token.TYPE_ELSIF = 108;
+
+this.Token.TYPE_END = 120;
+
+this.Token.TYPE_AND = 200;
+
+this.Token.TYPE_OR = 201;
+
+this.Token.TYPE_NOT = 202;
+
+this.Token.TYPE_ERROR = 404;
+
+this.Token.predefined = {};
+
+this.Token.predefined["return"] = this.Token.TYPE_RETURN;
+
+this.Token.predefined["break"] = this.Token.TYPE_BREAK;
+
+this.Token.predefined["continue"] = this.Token.TYPE_CONTINUE;
+
+this.Token.predefined["function"] = this.Token.TYPE_FUNCTION;
+
+this.Token.predefined["for"] = this.Token.TYPE_FOR;
+
+this.Token.predefined["to"] = this.Token.TYPE_TO;
+
+this.Token.predefined["by"] = this.Token.TYPE_BY;
+
+this.Token.predefined["in"] = this.Token.TYPE_IN;
+
+this.Token.predefined["while"] = this.Token.TYPE_WHILE;
+
+this.Token.predefined["if"] = this.Token.TYPE_IF;
+
+this.Token.predefined["then"] = this.Token.TYPE_THEN;
+
+this.Token.predefined["else"] = this.Token.TYPE_ELSE;
+
+this.Token.predefined["elsif"] = this.Token.TYPE_ELSIF;
+
+this.Token.predefined["end"] = this.Token.TYPE_END;
+
+this.Token.predefined["object"] = this.Token.TYPE_OBJECT;
+
+this.Token.predefined["class"] = this.Token.TYPE_CLASS;
+
+this.Token.predefined["extends"] = this.Token.TYPE_EXTENDS;
+
+this.Token.predefined["new"] = this.Token.TYPE_NEW;
+
+this.Token.predefined["and"] = this.Token.TYPE_AND;
+
+this.Token.predefined["or"] = this.Token.TYPE_OR;
+
+this.Token.predefined["not"] = this.Token.TYPE_NOT;
+
+this.Token.predefined["after"] = this.Token.TYPE_AFTER;
+
+this.Token.predefined["every"] = this.Token.TYPE_EVERY;
+
+this.Token.predefined["do"] = this.Token.TYPE_DO;
+
+this.Token.predefined["sleep"] = this.Token.TYPE_SLEEP;
+
+this.Token.predefined["delete"] = this.Token.TYPE_DELETE;
+
+this.Token.predefined["local"] = this.Token.TYPE_LOCAL;
diff --git a/WebGames-master/WebGames-master/games/cap/tokenizer.js b/WebGames-master/WebGames-master/games/cap/tokenizer.js
new file mode 100644
index 00000000..37b7ffe4
--- /dev/null
+++ b/WebGames-master/WebGames-master/games/cap/tokenizer.js
@@ -0,0 +1,343 @@
+this.Tokenizer = (function() {
+ function Tokenizer(input, filename) {
+ this.input = input;
+ this.filename = filename;
+ this.index = 0;
+ this.line = 1;
+ this.column = 0;
+ this.last_column = 0;
+ this.buffer = [];
+ this.chars = {};
+ this.chars["("] = Token.TYPE_OPEN_BRACE;
+ this.chars[")"] = Token.TYPE_CLOSED_BRACE;
+ this.chars["["] = Token.TYPE_OPEN_BRACKET;
+ this.chars["]"] = Token.TYPE_CLOSED_BRACKET;
+ this.chars["{"] = Token.TYPE_OPEN_CURLY_BRACE;
+ this.chars["}"] = Token.TYPE_CLOSED_CURLY_BRACE;
+ this.chars["^"] = Token.TYPE_POWER;
+ this.chars[","] = Token.TYPE_COMMA;
+ this.chars["."] = Token.TYPE_DOT;
+ this.doubles = {};
+ this.doubles[">"] = [Token.TYPE_GREATER, Token.TYPE_GREATER_OR_EQUALS];
+ this.doubles["<"] = [Token.TYPE_LOWER, Token.TYPE_LOWER_OR_EQUALS];
+ this.doubles["="] = [Token.TYPE_EQUALS, Token.TYPE_DOUBLE_EQUALS];
+ this.doubles["+"] = [Token.TYPE_PLUS, Token.TYPE_PLUS_EQUALS];
+ this.doubles["-"] = [Token.TYPE_MINUS, Token.TYPE_MINUS_EQUALS];
+ this.doubles["*"] = [Token.TYPE_MULTIPLY, Token.TYPE_MULTIPLY_EQUALS];
+ this.doubles["/"] = [Token.TYPE_DIVIDE, Token.TYPE_DIVIDE_EQUALS];
+ this.doubles["%"] = [Token.TYPE_MODULO, Token.TYPE_MODULO_EQUALS];
+ this.doubles["&"] = [Token.TYPE_BINARY_AND, Token.TYPE_AND_EQUALS];
+ this.doubles["|"] = [Token.TYPE_BINARY_OR, Token.TYPE_OR_EQUALS];
+ this.shifts = {
+ "<": Token.TYPE_SHIFT_LEFT,
+ ">": Token.TYPE_SHIFT_RIGHT
+ };
+ this.letter_regex = RegExp(/^\p{L}/, 'u');
+ }
+
+ Tokenizer.prototype.pushBack = function(token) {
+ return this.buffer.splice(0, 0, token);
+ };
+
+ Tokenizer.prototype.finished = function() {
+ return this.index >= this.input.length && this.buffer.length === 0;
+ };
+
+ Tokenizer.prototype.nextChar = function(ignore_comments) {
+ var c, endseq;
+ if (ignore_comments == null) {
+ ignore_comments = false;
+ }
+ c = this.input.charAt(this.index++);
+ if (c === "\n") {
+ this.line += 1;
+ this.last_column = this.column;
+ this.column = 0;
+ } else if (c === "/" && !ignore_comments) {
+ if (this.input.charAt(this.index) === "/") {
+ while (true) {
+ c = this.input.charAt(this.index++);
+ if (c === "\n" || this.index >= this.input.length) {
+ break;
+ }
+ }
+ this.line += 1;
+ this.last_column = this.column;
+ this.column = 0;
+ return this.nextChar();
+ } else if (this.input.charAt(this.index) === "*") {
+ endseq = 0;
+ while (true) {
+ c = this.input.charAt(this.index++);
+ if (c === "\n") {
+ this.line += 1;
+ this.last_column = this.column;
+ this.column = 0;
+ endseq = 0;
+ } else if (c === "*") {
+ endseq = 1;
+ } else if (c === "/" && endseq === 1) {
+ break;
+ } else {
+ endseq = 0;
+ }
+ if (this.index >= this.input.length) {
+ break;
+ }
+ }
+ return this.nextChar();
+ }
+ } else {
+ this.column += 1;
+ }
+ return c;
+ };
+
+ Tokenizer.prototype.rewind = function() {
+ this.index -= 1;
+ this.column -= 1;
+ if (this.input.charAt(this.index) === "\n") {
+ this.line -= 1;
+ return this.column = this.last_column;
+ }
+ };
+
+ Tokenizer.prototype.next = function() {
+ var c, code;
+ if (this.buffer.length > 0) {
+ return this.buffer.splice(0, 1)[0];
+ }
+ while (true) {
+ if (this.index >= this.input.length) {
+ return null;
+ }
+ c = this.nextChar();
+ code = c.charCodeAt(0);
+ if (code > 32 && code !== 160) {
+ break;
+ }
+ }
+ this.token_start = this.index - 1;
+ if (this.doubles[c] != null) {
+ return this.parseDouble(c, this.doubles[c]);
+ }
+ if (this.chars[c] != null) {
+ return new Token(this, this.chars[c], c);
+ }
+ if (c === "!") {
+ return this.parseUnequals(c);
+ } else if (code >= 48 && code <= 57) {
+ return this.parseNumber(c);
+ } else if ((code >= 65 && code <= 90) || (code >= 97 && code <= 122) || code === 95 || this.letter_regex.test(c)) {
+ return this.parseIdentifier(c);
+ } else if (c === '"') {
+ return this.parseString(c, '"');
+ } else if (c === "'") {
+ return this.parseString(c, "'");
+ } else {
+ return this.error("Syntax Error");
+ }
+ };
+
+ Tokenizer.prototype.changeNumberToIdentifier = function() {
+ var i, j, ref, results, token, v;
+ token = this.next();
+ if ((token != null) && token.type === Token.TYPE_NUMBER) {
+ v = token.string_value.split(".");
+ results = [];
+ for (i = j = ref = v.length - 1; j >= 0; i = j += -1) {
+ if (v[i].length > 0) {
+ this.pushBack(new Token(this, Token.TYPE_IDENTIFIER, v[i]));
+ }
+ if (i > 0) {
+ results.push(this.pushBack(new Token(this, Token.TYPE_DOT, ".")));
+ } else {
+ results.push(void 0);
+ }
+ }
+ return results;
+ } else if ((token != null) && token.type === Token.TYPE_STRING) {
+ return this.pushBack(new Token(this, Token.TYPE_IDENTIFIER, token.value));
+ } else {
+ return this.pushBack(token);
+ }
+ };
+
+ Tokenizer.prototype.parseDouble = function(c, d) {
+ if ((this.shifts[c] != null) && this.index < this.input.length && this.input.charAt(this.index) === c) {
+ this.nextChar();
+ return new Token(this, this.shifts[c], c + c);
+ } else if (this.index < this.input.length && this.input.charAt(this.index) === "=") {
+ this.nextChar();
+ return new Token(this, d[1], c + "=");
+ } else {
+ return new Token(this, d[0], c);
+ }
+ };
+
+ Tokenizer.prototype.parseEquals = function(c) {
+ if (this.index < this.input.length && this.input.charAt(this.index) === "=") {
+ this.nextChar();
+ return new Token(this, Token.TYPE_DOUBLE_EQUALS, "==");
+ } else {
+ return new Token(this, Token.TYPE_EQUALS, "=");
+ }
+ };
+
+ Tokenizer.prototype.parseGreater = function(c) {
+ if (this.index < this.input.length && this.input.charAt(this.index) === "=") {
+ this.nextChar();
+ return new Token(this, Token.TYPE_GREATER_OR_EQUALS, ">=");
+ } else {
+ return new Token(this, Token.TYPE_GREATER_OR_EQUALS, ">");
+ }
+ };
+
+ Tokenizer.prototype.parseLower = function(c) {
+ if (this.index < this.input.length && this.input.charAt(this.index) === "=") {
+ this.nextChar();
+ return new Token(this, Token.TYPE_LOWER_OR_EQUALS, "<=");
+ } else {
+ return new Token(this, Token.TYPE_LOWER, "<");
+ }
+ };
+
+ Tokenizer.prototype.parseUnequals = function(c) {
+ if (this.index < this.input.length && this.input.charAt(this.index) === "=") {
+ this.nextChar();
+ return new Token(this, Token.TYPE_UNEQUALS, "!=");
+ } else {
+ return this.error("Expected inequality !=");
+ }
+ };
+
+ Tokenizer.prototype.parseIdentifier = function(s) {
+ var c, code;
+ while (true) {
+ if (this.index >= this.input.length) {
+ return new Token(this, Token.TYPE_IDENTIFIER, s);
+ }
+ c = this.nextChar();
+ code = c.charCodeAt(0);
+ if ((code >= 65 && code <= 90) || (code >= 97 && code <= 122) || code === 95 || (code >= 48 && code <= 57) || this.letter_regex.test(c)) {
+ s += c;
+ } else {
+ this.rewind();
+ return new Token(this, Token.TYPE_IDENTIFIER, s);
+ }
+ }
+ };
+
+ Tokenizer.prototype.parseNumber = function(s) {
+ var c, code, exp, pointed;
+ pointed = false;
+ exp = false;
+ while (true) {
+ if (this.index >= this.input.length) {
+ return new Token(this, Token.TYPE_NUMBER, Number.parseFloat(s), s);
+ }
+ c = this.nextChar();
+ code = c.charCodeAt(0);
+ if (c === "." && !pointed && !exp) {
+ pointed = true;
+ s += c;
+ } else if (code >= 48 && code <= 57) {
+ s += c;
+ } else if ((c === "e" || c === "E") && !exp && this.index < this.input.length) {
+ exp = true;
+ s += c;
+ c = this.nextChar();
+ if (c === "+" || c === "-") {
+ s += c;
+ } else {
+ this.rewind();
+ }
+ } else if ((c === "x" || c === "X") && s === "0") {
+ return this.parseHexNumber("0x");
+ } else {
+ this.rewind();
+ return new Token(this, Token.TYPE_NUMBER, Number.parseFloat(s), s);
+ }
+ }
+ };
+
+ Tokenizer.prototype.parseHexNumber = function(s) {
+ var c;
+ while (true) {
+ if (this.index >= this.input.length) {
+ return new Token(this, Token.TYPE_NUMBER, Number.parseInt(s), s);
+ }
+ c = this.nextChar();
+ if (/[a-fA-F0-9]/.test(c)) {
+ s += c;
+ } else {
+ this.rewind();
+ return new Token(this, Token.TYPE_NUMBER, Number.parseInt(s), s);
+ }
+ }
+ };
+
+ Tokenizer.prototype.parseString = function(s, close) {
+ var c, code, count_close, n;
+ if (close == null) {
+ close = '"';
+ }
+ if (close === '"') {
+ if (this.input.charAt(this.index) === '"' && this.input.charAt(this.index + 1) === '"' && this.input.charAt(this.index + 2) !== '"') {
+ close = '"""';
+ this.nextChar(true);
+ this.nextChar(true);
+ }
+ }
+ count_close = 0;
+ while (true) {
+ if (this.index >= this.input.length) {
+ return this.error("Unclosed string value");
+ }
+ c = this.nextChar(true);
+ code = c.charCodeAt(0);
+ if (c === "\\") {
+ n = this.nextChar(true);
+ switch (n) {
+ case "n":
+ s += "\n";
+ break;
+ case "\\":
+ s += "\\";
+ break;
+ case close:
+ s += close;
+ break;
+ default:
+ s += "\\" + n;
+ }
+ } else if (c === close) {
+ n = this.nextChar(true);
+ if (n === close) {
+ s += c;
+ } else {
+ this.rewind();
+ s += c;
+ return new Token(this, Token.TYPE_STRING, s.substring(1, s.length - 1));
+ }
+ } else {
+ if (close === '"""' && c === '"') {
+ count_close += 1;
+ if (count_close === 3) {
+ return new Token(this, Token.TYPE_STRING, s.substring(1, s.length - 2));
+ }
+ } else {
+ count_close = 0;
+ }
+ s += c;
+ }
+ }
+ };
+
+ Tokenizer.prototype.error = function(s) {
+ throw s;
+ };
+
+ return Tokenizer;
+
+})();
diff --git a/WebGames-master/WebGames-master/games/cap/transpiler.js b/WebGames-master/WebGames-master/games/cap/transpiler.js
new file mode 100644
index 00000000..8395cfc1
--- /dev/null
+++ b/WebGames-master/WebGames-master/games/cap/transpiler.js
@@ -0,0 +1,244 @@
+var Transpiler;
+
+Transpiler = (function() {
+ function Transpiler() {}
+
+ Transpiler.prototype.transpile = function(r) {
+ var i, j, l, op, ref, results;
+ results = [];
+ for (i = l = 0, ref = r.opcodes.length - 1; l <= ref; i = l += 1) {
+ op = OPCODES[r.opcodes[i]];
+ if (this.transpilable(op, r.arg1[i])) {
+ j = i + 1;
+ while (j < r.opcodes.length && r.removeable(j) && this.transpilable(OPCODES[r.opcodes[j]], r.arg1[j])) {
+ j += 1;
+ }
+ j -= 1;
+ if (j - i >= 2) {
+ results.push(this.transpileSegment(r, i, j));
+ } else {
+ results.push(void 0);
+ }
+ } else {
+ results.push(void 0);
+ }
+ }
+ return results;
+ };
+
+ Transpiler.prototype.transpileSegment = function(r, i, j) {
+ var comp, err, index, k, l, m, ref, ref1, ref2, ref3, s;
+ this.vcount = 0;
+ this.stack = new Stack();
+ this.locals = {};
+ this.variables = {};
+ s = "f = function(stack,stack_index,locals,locals_offset,object,global) {\n";
+ for (k = l = ref = i, ref1 = j; l <= ref1; k = l += 1) {
+ console.info(OPCODES[r.opcodes[k]] + " " + r.arg1[k]);
+ comp = this[OPCODES[r.opcodes[k]]](r.arg1[k]);
+ if (comp) {
+ s += comp + "\n";
+ }
+ }
+ for (index in this.stack.touched) {
+ if (this.stack.touched[index]) {
+ if (index < 0) {
+ s += "stack[stack_index-" + (Math.abs(index)) + "] = " + this.stack.stack[index] + " ;\n";
+ } else if (index > 0) {
+ s += "stack[stack_index+" + index + "] = " + this.stack.stack[index] + " ;\n";
+ } else {
+ s += "stack[stack_index] = " + this.stack.stack[index] + " ;\n";
+ }
+ }
+ }
+ if (this.stack.index < 0) {
+ s += "stack_index -= " + (Math.abs(this.stack.index)) + " ;\n";
+ } else if (this.stack.index > 0) {
+ s += "stack_index += " + this.stack.index + " ;\n";
+ }
+ s += "return stack_index ;\n}";
+ console.info(s);
+ try {
+ eval(s);
+ } catch (error) {
+ err = error;
+ console.error(s);
+ console.error(err);
+ }
+ r.opcodes[i] = 200;
+ r.arg1[i] = f;
+ for (k = m = ref2 = i + 1, ref3 = j; m <= ref3; k = m += 1) {
+ r.remove(i + 1);
+ }
+ };
+
+ Transpiler.prototype.createVariable = function() {
+ return "v" + (this.vcount++);
+ };
+
+ Transpiler.prototype.transpilable = function(op, arg) {
+ var ref;
+ if (op === "LOAD_VALUE") {
+ return (ref = typeof arg) === "string" || ref === "number";
+ } else {
+ return this[op] != null;
+ }
+ };
+
+ Transpiler.prototype.LOAD_VALUE = function(arg) {
+ if (typeof arg === "string") {
+ this.stack.push(" \"" + (arg.replace(/"/g, "\\\"")) + "\" ");
+ } else if (typeof arg === "number") {
+ this.stack.push(arg + "");
+ }
+ return "";
+ };
+
+ Transpiler.prototype.LOAD_LOCAL = function(arg) {
+ var v;
+ v = this.createVariable();
+ this.stack.push(v);
+ return "let " + v + " = locals[locals_offset+" + arg + "] ; // LOAD_LOCAL";
+ };
+
+ Transpiler.prototype.LOAD_LOCAL_OBJECT = function(arg) {
+ var res, v;
+ if (this.locals[arg] != null) {
+ v = this.locals[arg];
+ this.stack.push(v);
+ return "if (typeof " + v + " != \"object\") { " + v + " = locals[locals_offset+" + arg + "] = {} } ;";
+ } else {
+ v = this.createVariable();
+ res = "let " + v + " = locals[locals_offset+" + arg + "] ;\nif (typeof " + v + " != \"object\") { " + v + " = locals[locals_offset+" + arg + "] = {} } ;";
+ this.stack.push(v);
+ this.locals[arg] = v;
+ return res;
+ }
+ };
+
+ Transpiler.prototype.STORE_LOCAL = function(arg) {
+ var v;
+ v = this.stack.get();
+ return "locals[locals_offset+" + arg + "] = " + v + " ; // STORE_LOCAL";
+ };
+
+ Transpiler.prototype.POP = function() {
+ this.stack.pop();
+ return "";
+ };
+
+ Transpiler.prototype.CREATE_PROPERTY = function(arg) {
+ var res;
+ res = (this.stack.get(-2)) + "[" + (this.stack.get(-1)) + "] = " + (this.stack.get()) + " ;";
+ this.stack.pop();
+ this.stack.pop();
+ return res;
+ };
+
+ Transpiler.prototype.LOAD_PROPERTY = function(arg) {
+ var res, v;
+ v = this.createVariable();
+ res = "let " + v + " = " + (this.stack.get(-1)) + "[" + (this.stack.get()) + "] ; // LOAD_PROPERTY\nif (" + v + " == null) { " + v + " = 0 ; }";
+ this.stack.pop();
+ this.stack.pop();
+ this.stack.push(v);
+ return res;
+ };
+
+ Transpiler.prototype.LOAD_PROPERTY_ATOP = function(arg) {
+ var res, v;
+ v = this.createVariable();
+ res = "let " + v + " = " + (this.stack.get(-1)) + "[" + (this.stack.get()) + "] ; // LOAD_PROPERTY_ATOP\nif (" + v + " == null) { " + v + " = 0 ; }";
+ this.stack.push(v);
+ return res;
+ };
+
+ Transpiler.prototype.NEW_OBJECT = function() {
+ var v;
+ v = this.createVariable();
+ this.stack.push(v);
+ return "let " + v + " = {} ;";
+ };
+
+ Transpiler.prototype.NEW_ARRAY = function() {
+ var v;
+ v = this.createVariable();
+ this.stack.push(v);
+ return "let " + v + " = [] ;";
+ };
+
+ Transpiler.prototype.MAKE_OBJECT = function() {
+ var res, v;
+ v = this.createVariable();
+ res = "let " + v + " = " + (this.stack.get()) + " ;\nif (typeof " + v + " != \"object\") " + v + " = {} ; ";
+ this.stack.pop();
+ this.stack.push(v);
+ return res;
+ };
+
+ Transpiler.prototype.STORE_VARIABLE = function(arg) {
+ if (this.variables[arg] != null) {
+ return this.variables[arg] + " = object[\"" + arg + "\"] = " + (this.stack.get()) + " ; // STORE_VARIABLE";
+ } else {
+ return "object[\"" + arg + "\"] = " + (this.stack.get()) + " ; // STORE_VARIABLE";
+ }
+ };
+
+ Transpiler.prototype.STORE_PROPERTY = function(arg) {
+ var res, v;
+ v = this.createVariable();
+ res = "let " + v + " = " + (this.stack.get(-2)) + "[" + (this.stack.get(-1)) + "] = " + (this.stack.get(0)) + " ; // STORE_PROPERTY";
+ this.stack.pop();
+ this.stack.pop();
+ this.stack.pop();
+ this.stack.push(v);
+ return res;
+ };
+
+ return Transpiler;
+
+})();
+
+this.Stack = (function() {
+ function Stack() {
+ this.stack = ["stack[stack_index]"];
+ this.index = 0;
+ this.touched = {};
+ }
+
+ Stack.prototype.push = function(value) {
+ this.stack[++this.index] = value;
+ return this.touched[this.index] = true;
+ };
+
+ Stack.prototype.pop = function() {
+ var res;
+ if (this.index >= 0) {
+ res = this.stack.splice(this.index, 1)[0];
+ } else if (this.stack[this.index] != null) {
+ res = this.stack[this.index];
+ } else {
+ res = "stack[stack_index-" + this.index + "]";
+ }
+ this.index -= 1;
+ return res;
+ };
+
+ Stack.prototype.get = function(index) {
+ var i;
+ if (index == null) {
+ index = 0;
+ }
+ i = this.index + index;
+ if (i >= 0) {
+ return this.stack[i];
+ } else if (this.stack[i] != null) {
+ return this.stack[i];
+ } else {
+ return "stack[stack_index-" + (-i) + "]";
+ }
+ };
+
+ return Stack;
+
+})();
diff --git a/ba.html b/ba.html
index afa97f15..70416680 100644
--- a/ba.html
+++ b/ba.html
@@ -8,6 +8,10 @@
else { window.location="https://fun-miles-4jub.onrender.com/404";
}
-this is for the bata testers
+
+ new test
+ Gladihoppers-gh
+
this wont look good because its beta testers eyes only
+