/**
* Handles event dispatching, engine initialization and main loop execution.
* @global
*/
var System = new function() {
var that = this;
/**
* Represents a phase of execution (e.g. init, run...).
* @constructor
* @abstract
*
* Phase life-cycle is as follows:
* begin(oldPhase);
* - called after previous phase ends but before this phase is active.
* wake();
* - called after this phase is activated (i.e. System.oldPhase = this).
* while (System.phase == this) {
* update(dt);
* - called on every main loop iteration, dt = time since last call.
* }
* end();
* - called when phase is ending but before next phase begins.
*/
function Phase() {
/**
* Called when this phase is activating.
*
* @param {Phase} oldPhase - The previous phase (null if none).
*/
this.begin = function(oldPhase) {};
/** Called when this phase is ending, before the next phase activates. */
this.end = function() {};
/** Called when this phase has activated but before the first update. */
this.wake = function() {};
/**
* Default NO-OP global event handler.
* @callback
* @param {InputState} s - The updated input state.
*/
var defaultHandler = function(s) {
return false;
};
/** Handle a 'character typed' event. */
this.charTyped = defaultHandler;
/** Handle a 'mouse scrolled' event. */
this.mouseWheel = defaultHandler;
/** Handle a 'mouse button released' event. */
this.mouseRelease = defaultHandler;
/** Handle a 'mouse button pressed' event. */
this.mousePress = defaultHandler;
/** Handle a 'mouse moved' event. */
this.mouseMove = defaultHandler;
/** Handle a 'key released' event. */
this.keyRelease = defaultHandler;
/** Handle a 'key pressed' event. */
this.keyPress = defaultHandler;
/**
* Called on every main loop iteration whilst this phase is activated.
*/
this.update = function(dt) {
return false;
};
}
this.Phase = Phase;
/**
* @name Vector2
* Represents a 2-vector.
* @constructor
*
* Initialized to (0,0).
*/
/**
* @name Vector2
* Copies a 2-vector.
* @constructor
*
* @param {Vector2} x - The vector to copy coordinates from.
*/
/**
* Represents a 2-vector.
*
* @constructor
* @param {number} x - The initial x-coordinate of the vector.
* @param {number} y - The initial y-coordinate of the vector.
*/
function Vector2(x, y) {
var that = this;
if (arguments.length >= 2) {
this.x = x;
this.y = y;
} else if (arguments.length == 1) {
this.x = x.x;
this.y = x.y;
} else {
this.x = this.y = 0;
}
this.toString = function() {
return "{x:" + that.x + ",y:" + that.y + "}";
};
}
this.Vector2 = Vector2;
/**
* Represents a sample of input states.
* @constructor
*
* @param {InputState} [obj] - The InputState object to copy, if specified.
*
* If no InputState object is given, the state properties are initialized to
* 0/false.
*
* @member {Vector2} pagePos - Position of mouse in page coordinates.
* @member {Vector2} mousePos - Position of mouse in canvas coordinates.
* @member {Vector2} mouseMov - Distance moved since list mousemove event.
* @member {number} mouseWheel - 1 if last scrolled down, -1 if last scrolled up.
* @member {number} mouseButton - Bit-flags indicating currently pressed mouse buttons.
* @member {number} keyCode - key-code of last pressed key (see KeyboardEvent.keyCode).
* @member {number} charCode - char-code of last pressed key (see KeyboardEvent.charCode).
* @member {boolean} ctrlPressed - Flag indicating whether CTRL is pressed.
* @member {boolean} altPressed - Flag indicating whether ALT is pressed.
* @member {boolean} shiftPressed - Flag indicating whether SHIFT is pressed.
*/
function InputState(obj) {
if (arguments.length > 0) {
this.pagePos = new Vector2(obj.pagePos);
this.mousePos = new Vector2(obj.mousePos);
this.mouseMov = new Vector2(obj.mouseMov);
this.mouseWheel = obj.mouseWheel;
this.mouseButton = obj.mouseButton;
this.keyCode = obj.keyCode;
this.charCode = obj.charCode;
this.ctrlPressed = obj.ctrlPressed;
this.altPressed = obj.altPressed;
this.shiftPressed = obj.shiftPressed;
} else {
this.pagePos = new Vector2();
this.mousePos = new Vector2();
this.mouseMov = new Vector2();
this.charCode = this.keyCode = this.mouseWheel = this.mouseButton = 0;
this.shiftPressed = this.altPressed = this.ctrlPressed = false;
}
}
this.InputState = InputState;
/**
* Update the input state with the current modifier key states.
*
* @param {Event} evt - The current DOM event.
*/
function updateModifiers(evt) {
inputState.ctrlPressed = evt.ctrlKey;
inputState.altPressed = evt.altKey;
inputState.shiftPressed = evt.shiftKey;
}
/**
* Initialize input callbacks and start engine.
*/
function init() {
if (canvasLoaded) {
that.phase = new Phase();
oldPhase = null;
// mousewheel handler
var mousewheelHandler = function(evt) {
try {
updateModifiers(evt);
// Get direction of scroll (1 = down, -1 = up)
inputState.mouseWheel = (0 < (evt.detail ? evt.detail : -evt.wheelDelta) ? 1 : -1);
if (that.phase !== null) {
that.phase.mouseWheel(inputState);
}
} catch (err) {}
evt.preventDefault();
};
document.addEventListener("DOMMouseScroll", mousewheelHandler, false);
document.addEventListener("mousewheel", mousewheelHandler, false);
// mousemove handler
window.addEventListener("mousemove", function(evt) {
updateModifiers(evt);
var canvasRect = canvas.getBoundingClientRect();
inputState.mousePos.x = Math.floor((inputState.pagePos.x = evt.pageX) - canvasRect.left);
inputState.mousePos.y = Math.floor((inputState.pagePos.y = evt.pageY) - canvasRect.top);
if (evt.movementX !== 0) {
inputState.mouseMov.x = evt.movementX;
inputState.mouseMov.y = evt.movementY;
} else if (evt.mozMovementX !== 0) {
inputState.mouseMov.x = evt.mozMovementX;
inputState.mouseMov.y = evt.mozMovementY;
} else if (evt.webkitMovementX !== 0) {
inputState.mouseMov.x = evt.webkitMovementX;
inputState.mouseMov.y = evt.webkitMovementY;
}
if (that.phase !== null) {
that.phase.mouseMove(inputState);
}
evt.preventDefault();
}, false);
// mousedown handler
canvas.addEventListener("mousedown", function(evt) {
updateModifiers(evt);
evt.preventDefault();
document.activeElement.blur();
inputState.mouseButton |= 1 << evt.button;
if (that.phase !== null) {
that.phase.mousePress(inputState);
}
}, false);
// contextmenu handler
bodyElement.oncontextmenu = function() {
return contextMenuAllowed;
};
// mouseup handler
window.addEventListener("mouseup", function(evt) {
updateModifiers(evt);
evt.preventDefault();
inputState.mouseButton &= ~(1 << evt.button);
if (that.phase !== null) {
that.phase.mouseRelease(inputState);
}
}, false);
// keydown handler
document.addEventListener("keydown", function(evt) {
updateModifiers(evt);
inputState.keyCode = evt.keyCode;
// Prevent tab/backspace from doing their default actions
if (evt.keyCode === 8 || evt.keyCode === 9) {
evt.preventDefault();
}
if (that.phase !== null) {
that.phase.keyPress(inputState);
}
}, false);
// keypress handler
document.addEventListener("keypress", function(evt) {
updateModifiers(evt);
inputState.keyCode = evt.keyCode;
inputState.charCode = evt.charCode;
if (that.phase !== null) {
that.phase.charTyped(inputState);
}
evt.preventDefault();
}, false);
// keyup handler
document.addEventListener("keyup", function(evt) {
updateModifiers(evt);
inputState.keyCode = evt.keyCode;
if (that.phase !== null) {
that.phase.keyRelease(inputState);
}
evt.preventDefault();
}, false);
postInit();
that.update()
}
}
/**
* Call onInit handlers and prevent further attempts to initialize.
*/
function postInit() {
for (var i = 0; i < initHandlers.length; i++) {
try {
initHandlers[i](systemConfig);
} catch (err) {
that.err("postInit routine #" + i, err)
}
}
initDone = true;
}
/**
* Execute a loop of the engine.
*
* @param {DOMHighResTimeStamp} timestamp - The current time.
* @callback Window.requestAnimationFrame
*/
function mainLoop(timestamp) {
if (realtimeEnabled) {
// Schedule update ASAP
window.requestAnimationFrame(mainLoop);
}
var dt = 0;
if (prevTimestamp != 0) {
dt = timestamp - prevTimestamp;
}
prevTimestamp = timestamp;
try {
if (that.phase !== oldPhase) {
if (oldPhase !== null) {
oldPhase.end()
}
if (that.phase != null) {
that.phase.begin(oldPhase);
oldPhase = that.phase;
that.phase.wake();
}
}
if (that.phase != null) {
that.phase.update(dt);
}
} catch (err) {
that.err("mainLoop()", err)
}
}
/** Skullcode version? */
this.version = 1408337099853;
/** @constant {number} */
this.TAU = 6.283185307179586;
/** @constant {number} */
this.RAD2DEG = 57.2957795131;
/** @constant {number} */
this.DEG2RAD = 0.01745329251;
/** @constant {number} */
this.VIEW2D = 0;
/** @constant {number} */
this.VIEW3D = 1;
/** @constant {number} */
this.NEAREST = 0;
/** @constant {number} */
this.LINEAR = 1;
/** @constant {number} */
this.DRAW = 1;
/** @constant {number} */
this.CACHE = 2;
/** @constant {number} */
this.DRAW_CACHE = this.DRAW | this.CACHE;
/** Currently active phase. */
this.phase = null;
var realtimeEnabled = true,
bodyElement = null,
oldPhase = null,
canvas = null,
initHandlers = [],
initDone = false,
canvasLoaded = false,
systemConfig = null,
intervalID = null,
inputState = new InputState(),
prevTimestamp = 0,
contextMenuAllowed = false;
/**
* Set whether the context menu is enabled.
*
* @param {boolean} enable - If true, allow the context menu to appear.
*/
this.allowContextMenu = function(enable) {
contextMenuAllowed = enable ? true : false;
};
/**
* Log a given message (triggers a window.alert()).
*
* @param {string} msg - The message to log.
*/
this.log = function(msg) {
window.alert(msg);
};
/**
* Log a given error.
*
* @param {string} msg - A string describing the error.
* @param {exception} [exc] - An exception associated with the error.
*/
this.err = function(msg, exc) {
try {
if (arguments.length < 2) {
this.log("ERROR: " + msg);
} else {
this.log("ERROR: " + msg + " : " + exc.toString() + " : line " +
exc.lineNumber + " of file: " + exc.fileName);
}
} catch (err) {}
};
/**
* Log a given warning.
*
* @param {string} msg - A string describing the warning.
* @param {exception} [exc] - An exception associated with the warning.
*/
this.warn = function(msg, exc) {
try {
if (arguments.length < 2) {
this.log("WARNING: " + msg);
} else {
this.log("WARNING: " + msg + " : " + exc.toString() + " : line " +
exc.lineNumber + " of file: " + exc.fileName);
}
} catch (err) {}
};
/**
* Add a callback to the list of onInit handlers.
*
* @param {function(systemConfig)} f - The function to call on initialization.
*/
this.onInit = function(f) {
if (!initDone) {
initHandlers.push(f);
} else {
this.err("Function not added via onInit(), already initialized");
}
};
/**
* Configure and initialize the engine.
*
* @param {dictionary} config - The configuration of the engine.
*
* Supported configuration options are:
* realtime - ?
* canvas - ID/DOM object of canvas to render to.
*/
this.start = function(config) {
if (systemConfig != null) {
this.err("start() called while engine is already running.");
return false;
}
systemConfig = {
realtime: true,
canvas: "viewport"
};
if (typeof config != "undefined" && config !== null) try {
systemConfig.realtime = config.realtime ? true : false;
if (typeof config.canvas != "undefined") {
systemConfig.canvas = config.canvas;
}
} catch (err) {
return this.err("setup object invalid ", err), false
}
return init();
};
/**
* Enable or disable realtime execution.
*
* @param {boolean} enable - If true, VM updates will occur as soon as possible.
*/
this.setRealtime = function(enable) {
if (enable && realtimeEnabled != enable) {
window.requestAnimationFrame(mainLoop);
}
realtimeEnabled = enable;
};
/**
* Enable or disable image smoothing.
*
* @param {CanvasRenderingContext2D} context - The context to set image smoothing state on.
* @param {boolean} enable
*/
this.scaleSmoothing = function(context, enable) {
enable = enable ? true : false;
context.imageSmoothingEnabled = enable;
context.mozImageSmoothingEnabled = enable;
context.webkitImageSmoothingEnabled = enable;
};
/**
* Enter or leave full-screen mode.
*
* @param {boolean} enable
*/
this.setFullScreen = function(enable) {
this.log("Setting screen mode: " + enable);
if (enable) {
if (canvas.requestFullscreen) {
canvas.requestFullscreen();
} else if (canvas.msRequestFullscreen) {
canvas.msRequestFullscreen();
} else if (canvas.mozRequestFullScreen) {
canvas.mozRequestFullScreen();
} else if (canvas.webkitRequestFullscreen) {
canvas.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
} else {
this.log("Fullscreen not supported.")
}
} else {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.msExitFullscreen) {
document.msExitFullscreen();
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
} else {
this.log("Fullscreen not supported.");
}
}
};
/**
* Enable or disable pointer lock.
*
* @param {boolean} enable
*/
this.setPointerLock = function(enable) {
this.log("Setting pointer lock: " + enable);
if (enable) {
if (canvas.requestPointerLock) {
canvas.requestPointerLock();
} else if (canvas.mozRequestPointerLock) {
canvas.mozRequestPointerLock();
} else if (canvas.webkitRequestPointerLock) {
canvas.webkitRequestPointerLock();
} else {
this.log("Pointer lock not supported.")
}
} else {
if (canvas.exitPointerLock) {
canvas.exitPointerLock();
} else if (canvas.mozExitPointerLock) {
canvas.mozExitPointerLock();
} else if (canvas.webkitExitPointerLock) {
canvas.webkitExitPointerLock();
} else {
this.log("Pointer lock not supported.");
}
}
};
/**
* Run a single iteration of the main engine loop.
*/
this.update = function() {
window.requestAnimationFrame(mainLoop);
};
// Wait for canvas to load before initializing.
intervalID = window.setInterval(function preInit() {
try {
if (!bodyElement) {
bodyElement = document.getElementsByTagName("body")[0];
}
if (systemConfig !== null && canvas === null)
if ("string" == typeof systemConfig.canvas) {
canvas = document.getElementById(systemConfig.canvas);
if (canvas) {
systemConfig.canvas = canvas;
}
} else {
canvas = systemConfig.canvas;
}
if (bodyElement && canvas) {
window.clearInterval(intervalID);
intervalID = null;
canvasLoaded = true;
if (systemConfig != null) {
// System is configured, make sure it is initialized.
init();
}
}
} catch (err) {
that.err("preInit() failed", err);
}
}, 250);
};
new function() {
var sys = System;
function h(f) {
var a = this,
e = a.value = 0;
a.advance = function(c) {
e += c;
return 0 >= e ? a.value = e = 0 : e >= f ? (e = f, a.value = 1) : a.value = e / f
};
a.reset = function(c) {
e = a.value = 0;
0 < arguments.length && (f = c)
}
}
sys.LinearInterp = h;
/**
* @name Vector3
* Represents a 3-vector.
* @constructor
*
* Initialized to (0,0,0).
*/
/**
* @name Vector3
* Copies a 3-vector.
* @constructor
*
* @param {Vector3} x - The vector to copy coordinates from.
*/
/**
* Represents a 3-vector.
*
* @constructor
* @param {number} x - The initial x-coordinate of the vector.
* @param {number} y - The initial y-coordinate of the vector.
* @param {number} z - The initial z-coordinate of the vector.
*/
function Vector3(x, y, z) {
var that = this;
if (arguments.length >= 2) {
this.x = x;
this.y = y;
this.z = z;
} else if (arguments.length == 1) {
this.x = x.x;
this.y = x.y;
this.z = x.z;
} else {
this.x = this.y = this.z = 0;
}
this.toString = function() {
return "{x:" + that.x + ",y:" + that.y + ",z:" + that.z + "}";
}
}
sys.Vector3 = Vector3;
/**
* Represents a linked list of objects.
* @constructor
*
* Note: 'prior' and 'next' properties are added to objects that are
* added to this linked list, and can be used to navigate it.
*/
sys.LinkedList = function() {
var _first = null,
_last = null;
/** @returns {object} The first object in the list. */
this.first = function() {
return _first;
};
/** @returns {object} The last object in the list. */
this.last = function() {
return _last;
};
/**
* Add an object to the end of the list.
*
* @param {object} elem - The object to add.
*/
this.add = function(elem) {
if (_first == null) {
_first = elem;
} else {
_last.next = elem;
}
elem.prior = _last;
_last = elem;
};
/**
* Remove an object from the list (next and prior are set to null).
*
* @param {object} elem - The object to remove.
*/
this.unlink = function(elem) {
if (elem.next == null) {
_last = elem.prior;
} else {
elem.next.prior = elem.prior;
}
if (elem.prior == null) {
_first = elem.next;
} else {
elem.prior.next = elem.next;
}
elem.prior = elem.next = null;
};
/**
* Insert an object after an element.
*
* @param {object} elem - The object to insert.
* @param {object} [target] - The object to insert before (defaults to this.first)
*/
this.insert = function(elem, target) {
if (null == target) {
target = _first;
}
if (null == target) {
_last = _first = elem;
} else {
if (target === _first) {
_first = elem;
} else {
target.prior.next = elem;
}
elem.prior = target.prior;
target.prior = elem;
elem.next = target;
}
};
/**
* Clear the contents of this list (note: does not reset elements).
*/
this.empty = function() {
_first = _last = null;
};
/**
* Attach a list to the end of this list.
*
* @param {LinkedList} list - The list to attach (will be emptied afterwards).
*/
this.attach = function(list) {
if (_first == null) {
_first = list.first();
_last = list.last();
} else {
_last.next = list.first();
if (_last.next != null) {
_last.next.prior = _last;
_last = list.last();
}
}
list.empty();
}
};
sys.LCPRNG = function(f, a) {
var e = this,
c = [],
b = 0;
e.seed = function(l) {
if (0 < arguments.length) {
c[0] = f = l | 0;
for (var g = a - 1, d = 1; d < g; ++d) c[d] = 16807 * c[d - 1] & 2147483647;
c[g] = c[0];
c[0] = c[1];
c[1] = c[2];
b = 2;
g = a << 4;
for (d = 0; d < g; ++d) e.rand()
}
return f
};
e.rand = function() {
var e = b;
b = (b + 1) % a;
return c[e] = c[b] + c[(b + 29) % a] >> 0
};
e.toString = function() {
return e.seed()
};
1 > arguments.length && (f = 1);
2 > arguments.length && (a = 32);
e.seed(f)
};
sys.SineInterp = function(f) {
var a = this;
a.value = 0;
var e = new h(f),
c = Math.PI / 2;
a.advance = function(b) {
b = e.advance(b);
return 1 == b ? a.value = 1 : 0 == b ? a.value = 0 : a.value = Math.sin(b * c)
};
a.reset = function(b) {
a.value = 0;
0 < arguments.length ? e.reset(b) : e.reset()
}
};
sys.CosineInterp = function(f) {
var a = this;
a.value = 0;
var e = new h(f),
c = Math.PI;
a.advance = function(b) {
b = e.advance(b);
return 1 == b ? a.value = 1 : 0 == b ? a.value = 0 : a.value = 0.5 * (1 - Math.cos(b * c))
};
a.reset = function(b) {
a.value = 0;
0 < arguments.length ? e.reset(b) : e.reset()
}
};
sys.Box3 = function(f, a, e, c, b, l) {
var n = this;
5 <= arguments.length ? (n.a = new Vector3(f, a, e), n.b = new Vector3(c, b, l)) : 1 < arguments.length ? (n.a = new Vector3(f), n.b = new Vector3(a)) : 1 == arguments.length ? (n.a = new Vector3(f.a), n.b = new Vector3(f.b)) : (n.a = new Vector3, n.b = new Vector3);
this.toString = function() {
return "{a:" + n.a + ",b:" + n.b + "}"
}
};
/**
* Calculates the cross product of two Vector3 instances.
*
* @param {Vector3} a - The left parameter to the cross product.
* @param {Vector3} b - The right parameter to the cross product.
* @param {Vector3} c - The Vector3 to set to the result.
*/
sys.cross = function(a, b, c) {
c.x = a.y * b.z - a.z * b.y;
c.y = a.z * b.x - a.x * b.z;
c.z = a.x * b.y - a.y * b.x
}
};
new function() {
function h(f, a) {
function e(b) {
if (!b.isLoaded) {
b.isLoaded = true;
try {
var d = eval(l.responseText);
a(d)
} catch (c) {
a(null)
}
}
}
var c = document.getElementsByTagName("body")[0];
if (!c) return false;
if (k) {
_JSE_ = null;
var b = document.createElement("script");
b.onload = function() {
a(_JSE_);
c.removeChild(b)
};
b.onerror = function() {
g.log("fetchObj() failed to load: " + f);
c.removeChild(b);
a(null)
};
b.src = f;
c.appendChild(b)
} else {
var l = new XMLHttpRequest;
l.isLoaded = false;
l.onreadystatechange = function() {
4 === l.readyState && e(l)
};
l.onload = function() {
e(l)
};
l.ontimeout = function() {
g.log("fetchObj() failed to download: " + f);
a(null)
};
l.open("GET", f, true);
l.send(null)
}
}
var g = System,
k = "file:" == window.location.protocol;
g.fetchObject = h;
g.ImageLoader = function(f, a) {
this.fails = this.loaded = this.count = 0;
this.queue = function(b, l) {
var g = new Image;
b = f + b;
g.onload = function() {
var d = b;
try {
e.loaded++, a && a(g, true, d, l)
} catch (c) {}
};
g.onerror = function() {
var d = b;
try {
e.fails++, a && a(g, false, d, l)
} catch (c) {}
};
g.src = b;
c[c.length] = g;
e.count = c.length
};
var e = this,
c = [];
void 0 == f && (f = "")
};
g.Asset = function(f, a, e, c, b, l) {
function g(a, b) {
null != a && (d.flag = a ? d.flag | b : d.flag & ~b);
return 0 < (d.flag & b) ? true : false
}
var d = this;
d.type = f ? f : "unknown";
d.name = a ? a : "";
d.path = e ? e : "";
d.flag = c ? c : 0;
d.rev = l ? l : 0;
5 <= arguments.length ? d.id = b : (d.id = assets.length, d.flag |= 6);
assets[d.id] = d;
d.loaded = function(a) {
return g(1 > arguments.length ? null : a, 1)
};
d.stow = function(a) {
return g(1 > arguments.length ? null : a, 2)
};
d.updated = function(a) {
return g(1 > arguments.length ? null : a, 4)
};
d.customJSE = function() {
return null
};
d.toString = function() {
var a = d.customJSE(),
b = d.flags;
d.loaded(false);
d.updated(false);
a = "{\tid :\t" + d.id + ",\n\trev :\t" + d.rev + ",\n\tflag :\t" + d.flag + ",\n\ttype :\t" + JSON.stringify(d.type) + ",\n\tname :\t" + JSON.stringify(d.name) + ",\n\tpath :\t" + JSON.stringify(d.path) + (null == a ? "" : ",\n\t" + a) + "\n}";
d.flags = b;
return a
}
};
g.AssetManager = function(f) {
var a = this,
e = {},
c = {},
b = {};
f = 1 > arguments.length ? "" : f.toString();
a.register = function(a, c) {
b[a] = c
};
a.storeAll = function(b, c, d) {
var f = 0,
g;
for (g in e) {
var h = e[g];
null == h || b && "function" == typeof h.updated && !h.updated() || (++f, a.store(h, c, d))
}
return f
};
a.store = function(a, b, d) {
if (d) {
g.log("Error: AssetManager.store(): Remote storage unimplemented.", "#911");
try {
b(a, 0)
} catch (c) {
g.log("Error: AssetManager.store() callback(data,0): " + c)
}
} else if (localStorage) try {
localStorage.setItem(a.path, "_JSE_=" + a.toString());
try {
b(a, 1)
} catch (e) {
g.log("Error: AssetManager.store() callback(data,1): " + e)
}
} catch (f) {
g.log("Error: AssetManager.store() localStorage.setItem(): " + f);
try {
b(a, 0)
} catch (h) {
g.log("Error: AssetManager.store() callback(data,0): " + h)
}
} else {
g.log("Error: AssetManager.store(): No localStorage");
try {
b(a, 0)
} catch (k) {
g.log("Error: AssetManager.store() callback(data,0): " + k)
}
}
};
a.fetch = function(a, k, d) {
3 > arguments.length && (d = false);
var p = e[a];
if (p) {
try {
g.log("AM: already loaded: " + a), k(p, a)
} catch (r) {
return g.log("AssetManager callback error '" + f + a + "': " + r, "#911"), -1
}
return 0
}
var u = c[a];
if (u) return d || u.push(func), 3;
var u = c[a] = [k],
v = function(d) {
if (null == d)
for (var h in u) try {
u[h](null, a)
} catch (k) {
g.log("AssetManager callback error '" + f + a + "': " + k, "#911")
} else {
if (d.type) {
var n = b[d.type];
if (n) try {
d = n(d, a)
} catch (p) {
g.log("AssetManager creation error '" + f + a + "': " + p, "#911");
for (h in u) try {
var r = u[h];
r && r(null, a)
} catch (G) {
g.log("AssetManager callback error '" + f + a + "': " + G, "#911")
}
delete c[a];
return
}
}
e[a] = d;
for (h in u) try {
(r = u[h]) && r(d, a)
} catch (T) {
g.log("AssetManager callback error '" + f + a + "': " + T, "#911")
}
}
delete c[a]
};
if (localStorage && (p = localStorage.getItem(a), null != p)) try {
return v(eval(p)), 1
} catch (A) {
g.log("AssetManager localStorage eval() error '" + a + "': " + A + "\n" + p.toString(), "#911")
}
h(f + a, v);
return 2
};
a.getAsset = function(a) {
a = e[a];
return void 0 != typeof a ? a : null
};
a.setAsset = function(a, b) {
null === b ? delete e[a] : e[a] = b
}
};
g.getAsset = function(f) {
f = assets[f];
return void 0 == typeof f ? null : f
}
};
var M = "<snip - see vm.js>";
new function() {
function h(a) {
this.data = null;
this.direct = false;
this.size = this.pos = this.id = this.host = null;
0 < arguments.length && (this.data = a.data, this.direct = a.direct, this.host = a.host, this.id = a.id, this.pos = a.pos, this.size = a.size)
}
function g() {
this.skull = this.id = null;
this.bind = function(a, e) {
return null
};
this.connect = function(a, e, c) {
k.log("sc.connect( " + a + ", " + e + ", " + c + " )");
return true
}
}
var k = System,
f = M;
M = "";
k.Protocol = h;
k.Machine = g;
Math.imul || (Math.imul = function(a, e) {
var c = a & 65535,
b = e & 65535;
return c * b + ((a >>> 16 & 65535) * b + c * (e >>> 16 & 65535) << 16 >>> 0) | 0
});
Math.fround || (Math.fround = function() {
var a = new Float32Array(1);
return function(e) {
a[0] = +e;
return a[0]
}
}());
k.Environment = function() {
function a(a) {
if ("number" != typeof a) try {
return a.toString()
} catch (b) {
a = v
}
a |= 0;
return 0 > a || a >= m.length ? "Unknown Error." : m[a]
}
function e(a) {
throw a >>> 0;
}
function c() {
var a;
do a = (+new Date ^ 65536 * Math.random() ^ 65536 * Math.random() << 16) >>> 0 | 0; while (void 0 !== w[a]);
return a
}
function b() {
var a;
do a = (+new Date ^ 65536 * Math.random() ^ 65536 * Math.random() << 16) >>> 0 | 0; while (void 0 !== C[a]);
return a
}
function l(b) {
if ("number" == typeof b) return 0 < b ? (k.log("sc error " + b + ", 0x" + b.toString(16) + ": " + a(b)), b) : b - 1;
k.log("sc error ?: " + a(b));
k.log(b);
return A
}
function n(a) {
k.log("sc.logs: " + a)
}
function d(a) {
k.log("sc.logv: " + (a >>> 0).toString(16) + " : " + a)
}
function p(a) {
a |= 0;
0 > a && (a = 0);
throw -a;
}
function r() {
return Date.now()
}
function u(a) {
this.inherit = g;
this.inherit();
a = (a | 0) >>> 13;
++D;
this.id = c();
a <<= 13;
var b = new ArrayBuffer(a);
new Uint8Array(b);
var l = new Uint32Array(b);
this.connect = function(a, b, d) {
return false
};
this.bind = function(a, b) {
return l.subarray(a >> 2, (a >> 2) + (b >> 2))
};
this.brain = (new Function("std", "foriegn", "heap", f))(window, {
error: e,
imul: Math.imul,
logs: n,
logv: d,
wait: p,
time: r
}, b);
this.size = a;
this.heap = b
}
var v = 6,
A = 7,
m = "OK.;Permission Required.;Out of memory.;Invalid operation.;Invalid memory access.;Invalid access alignment.;Unknown error.;Host environment exception.;Halted.;Operation not supported.".split(";"),
s = void 0;
this.LSB = s;
var D = 0,
w = [],
C = [];
this.explain = a;
this.cycle = function(a, b) {
try {
return w[a].brain.cycle(b | 0)
} catch (d) {
return l(d)
}
};
this.init = function(a, b, d, c, e, f, g) {
try {
w[a].brain.init(w[a].size - 1, b, d, c, e, f, g)
} catch (h) {
return l(h)
}
};
this.load = function(b, d, c) {
try {
if ("string" == typeof d) throw a(9);
var e = w[b].bind(c, d.length << 2);
for (b = 0; b < d.length && b < e.length; ++b) e[b] = d[b];
k.log("Loaded " + b + " words.")
} catch (f) {
return l(f)
}
};
Date.now || (Date.now = function() {
return (new Date).getTime()
});
try {
s = function() {
var a = new ArrayBuffer(4);
(new DataView(a)).setUint32(0, 1718303319, true);
switch ((new Int32Array(a))[0]) {
case 1463446374:
return false;
case 1718303319:
return true;
default:
return null
}
}()
} catch (y) {
k.log("sc: can't test LSB: " + y)
}
this.LSB = s;
this.build = function(a) {
a = new u(a);
if (!a) throw 3;
w[a.id] = a;
return a.id
};
this.dump = function(a) {
return w[a].heap
};
this.support = function(a) {
var d = new h(a);
d.id = b();
C[d.id] = d;
return a.id = d.id
};
this.register = function(a) {
var b = c();
w[b] = a;
return b
};
this.connect = function(a, d, c) {
var e = w[a];
c = w[c];
var f = C[d];
if (!e || !c || !f) throw 3;
try {
if (f = new h(f), f.host = e, f.client = c, f.data = e.bind(f.pos, f.size), f.id = b(), f.direct) try {
C[f.id] = f, c.connect(a, d, f.data)
} catch (g) {
throw delete C[f.id], A;
} else C[f.id] = f
} catch (l) {
throw A;
}
return f.id
}
}
};
new function() {
var h = System,
g = "#000 #00a #0a0 #0aa #a00 #a0a #a50 #aaa #555 #55f #5f5 #5ff #f55 #f5f #ff5 #fff".split(" "),
k = "#000000 #000084 #008400 #008080 #840000 #800080 #804000 #808080 #404040 #4040ff #38ff38 #40ffff #ff4040 #ff40ff #ffff40 #ffffff".split(" "),
f = "#000000 #000099 #009900 #009292 #9b0000 #940094 #964b00 #939393 #4b4b4b #4c4ce0 #39e339 #40e2df #e34b4b #e34ae3 #e0e048 #e2e2e2".split(" ");
h.InputDevice = function(a) {
function e(b) {
c[g] = (b.shiftPressed ? 1 : 0) | (b.ctrlPressed ? 2 : 0) | (b.altPressed ? 4 : 0);
a(-1)
}
this.inherit = h.Phase;
this.inherit();
this.inherit = h.Machine;
this.inherit();
var c = null,
b = false,
f = 1,
g = 2;
this.setScale = function(a) {
f = 0 + a
};
this.mouseMove = function(a) {
c[5] = a.mousePos.x * f;
c[6] = a.mousePos.y * f;
c[9] += a.mouseMov.x * f;
c[10] += a.mouseMov.y * f;
c[0] |= 1;
e(a)
};
this.mousePress = function(a) {
c[7] = a.mouseButton;
c[0] |= 2;
e(a)
};
this.mouseRelease = function(a) {
c[7] = a.mouseButton;
c[0] |= 4;
e(a)
};
this.mouseWheel = function(a) {
c[8] = a.mouseWheel | 0;
c[0] |= 8;
e(a)
};
this.keyPress = function(a) {
c[0] |= 16;
c[3] = a.keyCode;
e(a)
};
this.keyRelease = function(a) {
c[3] = a.keyCode;
c[0] |= 32;
e(a)
};
this.charTyped = function(a) {
c[0] |= 64;
c[4] = a.charCode;
e(a)
};
this.begin = function() {};
this.end = function() {};
this.update = function(b) {
a(b);
return true
};
this.connect = function(a, e, f) {
if (b) return false;
c = f;
return b = true
}
};
h.TextDisplay = function(a, e, c, b, l) {
function n(a, b) {
var c = b.length;
if (null == N) {
N = Array(c);
for (var d = c; 0 <= --d;) N[d] = document.createElement("canvas")
}
for (d = c; 0 <= --d;) canvas = N[d], canvas.width = a.width, canvas.height = a.height, c = canvas.getContext("2d"), c.globalAlpha = 1, c.globalCompositeOperation = "source-over", c.drawImage(a, 0, 0), c.globalCompositeOperation = "source-atop", c.fillStyle = b[d], c.fillRect(0, 0, canvas.width, canvas.height)
}
var d = this;
d.inherit = h.Machine;
d.inherit();
l = l ? true : false;
b |= 0;
e |= 0;
c |= 0;
var p = e * b,
r = c * b;
a.width = p;
a.height = r;
var u = null,
v = 0,
A = 0,
m = a.getContext("2d"),
s = m,
D = 1 < b && l ? k : g;
1 < b && (u = document.createElement("canvas"), u.width = e, u.height = c, s = u.getContext("2d"), u.ctx = s);
s.fillStyle = D[0];
s.fillRect(0, 0, e, c);
var w = Math.floor(e / 9),
C = c >>> 4,
y = C * w,
G = 4,
T = G + (y >> 1) - 1,
y = new ArrayBuffer(y << 2),
R = new Uint32Array(y),
U = false,
q = 0,
H, L, I, J, U = false,
E = 0,
B = null,
Z = false,
F, V, W, Q;
d.connect = function(a, b, c) {
if (Z) return false;
B = c;
V = +new Date;
W = 666;
Q = 0;
F = false;
G = 4;
L = 13;
H = 1;
I = 7;
J = 2;
E = 0;
q = E << 16 | H << 12 | L << 8 | I << 4 | J | 134217728;
l && (q |= 268435456);
B[0] = q;
B[2] = C << 16 | w;
B[1] = 0;
B[3] = G;
return Z = true
};
d.setScanLines = function(a) {
l = a ? true : false;
n(K[1], l ? k : g);
l && 1 < b ? (viewport.parentElement.style.backgroundColor = f[E], D = k) : (viewport.parentElement.style.backgroundColor = g[E], D = g);
s = 1 < b ? u.ctx : m;
for (a = 0; a < R.length; ++a) R[a] = 0
};
d.render = function() {
if (U) {
h.scaleSmoothing(s, false);
q = B[0];
0 == (q & 2147483648) && (B[0] = q |= 2147483648, B[2] = C << 16 | w);
var k = B[1],
n = k >>> 16 & 65535,
k = k & 65535;
if (0 == (q & 134217728)) F && (q |= 536870912), F = false;
else if (W) {
var t = +new Date;
Q += t - V;
Q >= W && (Q = 0, F = !F, q |= 536870912);
V = t
} else F || (q |= 536870912), F = true;
if (0 != (q & 1610612736)) {
q &= -536870913;
t = q >>> 16 & 15;
H = q >>> 12 & 15;
L = q >>> 8 & 15;
I = q >>> 4 & 15;
J = q & 15;
v = (k + n * w >> 1) + G;
0 != (q & 268435456) != l ? (E = t, d.setScanLines(q & 268435456)) : t != E && (E = t, viewport.parentElement.style.backgroundColor = l ? f[E] : g[E]);
s.globalCompositeOperation = "source-over";
s.globalAlpha = 1;
for (var z = t = 0, y = 0, x = 0, S = 0, O = 0, P = 0, K = 0, y = G; y <= T; ++y) {
x = B[y];
if (x == R[K] && y != v && y != A) {
if (++K, t += 9, t >= e && (z += 16, t = 0, z >= c)) break
} else {
R[K++] = x;
O = x >> 8 & 15;
S = x >> 12 & 15;
P = x & 255;
chx = P & 31;
chy = P >> 5 & 7;
s.fillStyle = D[S];
s.fillRect(t, z, 9, 16);
s.drawImage(N[O], 2 + 12 * chx, 2 + 19 * chy, 9, 16, t, z, 9, 16);
t += 9;
if (t >= e && (z += 16, t = 0, z >= c)) break;
x >>>= 16;
O = x >> 8 & 15;
S = x >> 12 & 15;
P = x & 255;
chx = P & 31;
chy = P >> 5 & 7;
s.fillStyle = D[S];
s.fillRect(t, z, 9, 16);
s.drawImage(N[O], 2 + 12 * chx, 2 + 19 * chy, 9, 16, t, z, 9, 16)
}
t += 9;
if (t >= e && (z += 16, t = 0, z >= c)) break
}
A = v;
F && (k < w && n < C) && (x = B[v], k & 1 && (x >>>= 16), O = x >> 8 & 15, 9 > H && (0 < J && 0 < I) && (9 < H + I && (I = 9 - H), 16 < L + J && (J = 16 - L), s.fillStyle = D[O], s.fillRect(9 * k + H, (n << 4) + L, I, J)));
1 < b && (h.scaleSmoothing(m, false), m.globalAlpha = 1, m.globalCompositeOperation = "source-over", m.drawImage(u, 0, 0, e, c, 0, 0, p, r), l && null != X && (m.fillStyle = X, m.fillRect(0, 0, p, r), m.globalCompositeOperation = "lighter", h.scaleSmoothing(m, true), m.globalAlpha = 0.5, m.drawImage(a, 0, 0, p, r, 1.5, 0, p, r), m.drawImage(a, 0, 0, p, r, -0.25, 1, p, r)));
B[0] = q
}
}
};
var K = [],
N = null,
X = null,
Y = new h.ImageLoader("img/", function(a, b, c, d) {
if (b) {
if (h.log("Loaded texture #" + d + " from: " + c), K[d] = a, Y.count == Y.loaded) {
b = document.createElement("canvas");
K[0] = b;
b.width = 64;
b.height = 64;
c = b.getContext("2d");
c.fillStyle = "#000";
c.globalAlpha = 1;
h.scaleSmoothing(c, false);
for (d = 1; 64 > d; d += 2) c.fillRect(0, d, 64, 1);
X = c.createPattern(b, "repeat");
n(a, l ? k : g);
h.log("Display ready.");
U = true
}
} else h.log("Could not load texture #" + d + " from: " + c)
});
Y.queue("sc-font-9x16.png", 1);
viewport.parentElement.style.backgroundColor = l && 1 < b ? f[E] : g[E];
d.toString = function() {
return "TextDisplay"
}
}
};
new function() {
var h = System;
h.onInit(function() {
try {
h.log = function(a) {
console.log(a)
};
var g = new h.Environment,
k = g.build(2097152),
f = new h.Protocol;
f.pos = 0;
f.size = 64;
f.direct = true;
g.support(f);
var a = new h.Protocol;
a.pos = f.size;
a.size = 16384;
a.direct = true;
g.support(a);
var e = document.getElementById("viewport"),
c = true,
b = new h.InputDevice(function(a) {
c || (0 <= a && (cycleDelay = -g.cycle(k, 32768), l.render()), 0 > cycleDelay && (c = true))
}),
l;
1440 <= e.offsetParent.offsetWidth + 4 && 800 <= e.offsetParent.offsetHeight + 4 ? (l = new h.TextDisplay(e, 720, 400, 2, false), b.setScale(1)) : (l = new h.TextDisplay(e, 720, 400, 1, false), b.setScale(2));
window.setScanLines = l.setScanLines;
var n = g.register(l);
g.connect(k, a.id, n);
var d = g.register(b);
g.connect(k, f.id, d);
var p = a.pos + a.size + 1023 & 268434432,
f = [<snip - bootloader?>];
g.load(k, f, p);
g.init(k, p, p + (f.length << 2), 0, 0, 0, 0);
c = false
} catch (r) {
if ("number" == typeof r) throw g.explain(r);
throw "boot: " + r.toString() + ": line " + r.lineNumber + ": " + r.fileName;
}
h.phase = b
});
h.start({
canvas: "viewport",
realtime: true
})
};