mirror of
https://github.com/inexorabletash/jsbasic.git
synced 2024-09-07 20:54:32 +00:00
Fixes #32 The RdAltChar (mousetext) is not accurate. Under Virtual II it seems to always return true if the 80 column firmware is active, regardless of which character set is active.
157 lines
4.7 KiB
JavaScript
157 lines
4.7 KiB
JavaScript
|
|
(function () {
|
|
var $ = function (s) { return document.querySelector(s); };
|
|
var $$ = function (s) { return document.querySelectorAll(s); };
|
|
|
|
var ss = $$('script'), cs = ss[ss.length - 1], baseURL = /^.*\/|/.exec(cs.src)[0];
|
|
|
|
document.write('<link rel="stylesheet" href="' + baseURL + 'display.css">');
|
|
|
|
function load(url) { document.write('<script src="' + baseURL + url + '"></script>'); }
|
|
load('https://cdn.rawgit.com/inexorabletash/polyfill/v0.1.25/polyfill.min.js');
|
|
load('https://cdn.rawgit.com/inexorabletash/polyfill/v0.1.25/keyboard.js');
|
|
load('tty.js');
|
|
load('lores.js');
|
|
load('hires.js');
|
|
load('bell.js');
|
|
load('dos.js');
|
|
load('basic.js');
|
|
|
|
function createInstance(src) {
|
|
function ce(element, attributes, children) {
|
|
var e = document.createElement(element);
|
|
if (attributes) {
|
|
Object.keys(attributes).forEach(function(key) {
|
|
e[key] = attributes[key];
|
|
});
|
|
}
|
|
if (children) {
|
|
children.forEach(function(child) {
|
|
e.appendChild(child);
|
|
});
|
|
}
|
|
return e;
|
|
}
|
|
|
|
// DOM
|
|
var lores_elem = ce('div', {className: 'jsb-lores'});
|
|
var hgr1_elem = ce('canvas', {className: 'jsb-hires', width: 560, height: 384});
|
|
var hgr2_elem = ce('canvas', {className: 'jsb-hires', width: 560, height: 384});
|
|
var tty_elem = ce('div', {className: 'jsb-tty'});
|
|
var wrapper_elem = ce('div', {className: 'jsb-wrapper'}, [lores_elem, hgr1_elem, hgr2_elem, tty_elem]);
|
|
var frame = ce('div', {className: 'jsb-frame', tabIndex: 0}, [wrapper_elem]);
|
|
|
|
// JS OM
|
|
var bell = new Bell(baseURL);
|
|
var tty = new TTY(tty_elem, frame, bell.play.bind(bell));
|
|
var dos = new DOS(tty);
|
|
var lores = new LoRes(lores_elem, 40, 48);
|
|
var hires = new HiRes(hgr1_elem, 280, 192);
|
|
var hires2 = new HiRes(hgr2_elem, 280, 192);
|
|
var display = {
|
|
state: { graphics: false, full: true, page1: true, lores: true },
|
|
setState: function (state, value /* ... */) {
|
|
var args = [].slice.call(arguments);
|
|
while (args.length) {
|
|
state = args.shift();
|
|
value = args.shift();
|
|
this.state[state] = value;
|
|
}
|
|
|
|
if (this.state.graphics) {
|
|
lores.show(this.state.lores);
|
|
hires.show(!this.state.lores && this.state.page1);
|
|
hires2.show(!this.state.lores && !this.state.page1);
|
|
tty.splitScreen(tty.getScreenSize().height - (this.state.full ? 0 : 4));
|
|
} else {
|
|
lores.show(false);
|
|
hires.show(false);
|
|
hires2.show(false);
|
|
tty.splitScreen(0);
|
|
}
|
|
},
|
|
getState: function() {
|
|
return Object.assign({}, this.state);
|
|
}
|
|
};
|
|
var pdl = [0, 0, 0, 0];
|
|
|
|
// Mouse-as-Joystick
|
|
wrapper_elem.addEventListener('mousemove', function (e) {
|
|
var rect = wrapper_elem.getBoundingClientRect(),
|
|
x = e.clientX - rect.left, y = e.clientY - rect.top;
|
|
function clamp(n, min, max) { return n < min ? min : n > max ? max : n; }
|
|
pdl[0] = clamp(x / (rect.width - 1), 0, 1);
|
|
pdl[1] = clamp(y / (rect.height - 1), 0, 1);
|
|
});
|
|
|
|
var program;
|
|
dos.reset();
|
|
tty.reset();
|
|
tty.autoScroll = true;
|
|
|
|
try {
|
|
program = basic.compile(src);
|
|
} catch (e) {
|
|
if (e instanceof basic.ParseError) {
|
|
tty.writeString(e.message + '\r');
|
|
tty.writeString('Source line: ' + e.line + ', column: ' + e.column);
|
|
} else {
|
|
tty.writeString(e.message);
|
|
}
|
|
return frame;
|
|
}
|
|
|
|
var stopped = false;
|
|
|
|
program.init({
|
|
tty: tty,
|
|
hires: hires,
|
|
hires2: hires2,
|
|
lores: lores,
|
|
display: display,
|
|
paddle: function (n) { return pdl[n]; }
|
|
});
|
|
setTimeout(driver, 0);
|
|
|
|
var NUM_SYNCHRONOUS_STEPS = 37;
|
|
function driver() {
|
|
var state = basic.STATE_RUNNING;
|
|
var statements = NUM_SYNCHRONOUS_STEPS;
|
|
|
|
while (!stopped && state === basic.STATE_RUNNING && statements > 0) {
|
|
try {
|
|
state = program.step(driver);
|
|
} catch (e) {
|
|
tty.writeString(e.message);
|
|
stopped = true;
|
|
return;
|
|
}
|
|
|
|
statements -= 1;
|
|
}
|
|
|
|
if (state === basic.STATE_STOPPED || stopped) {
|
|
stopped = true;
|
|
} else if (state === basic.STATE_BLOCKED) {
|
|
// Fall out
|
|
} else { // state === basic.STATE_RUNNING
|
|
setTimeout(driver, 0); // Keep going
|
|
}
|
|
}
|
|
|
|
return frame;
|
|
}
|
|
|
|
window.addEventListener('load', function() {
|
|
[].forEach.call($$('script'), function(script) {
|
|
if (script.type === 'text/applesoft-basic') {
|
|
var source = script.innerText || script.textContent;
|
|
var elem = createInstance(source);
|
|
script.parentElement.insertBefore(elem, script.nextSibling);
|
|
}
|
|
});
|
|
});
|
|
|
|
}());
|