6624 lines
194 KiB
JavaScript
6624 lines
194 KiB
JavaScript
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;i<seq.length;i++)\n {\n let note = seq[i] ;\n if (i>0)\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;i<output.length;i++)\n {\n var channel = output[i] ;\n if (i>0)\n {\n for (var j=0;j<channel.length;j++)\n {\n channel[j] = output[0][j]\n }\n }\n else\n {\n for (var j=0;j<channel.length;j++)\n {\n let sig = 0 ;\n for (var k=this.beeps.length-1;k>=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);
|
|
}
|
|
|
|
};
|
|
|