mirror of
https://github.com/hexahigh/games.git
synced 2025-12-11 20:15:38 +01:00
239 lines
5.7 KiB
JavaScript
239 lines
5.7 KiB
JavaScript
|
|
let nes = new Nes();
|
|
let audioHandler = new AudioHandler();
|
|
let paused = false;
|
|
let loaded = false;
|
|
let pausedInBg = false;
|
|
let loopId = 0;
|
|
let loadedName = "";
|
|
|
|
let c = el("output");
|
|
c.width = 256;
|
|
c.height = 240;
|
|
let ctx = c.getContext("2d");
|
|
let imgData = ctx.createImageData(256, 240);
|
|
|
|
let controlsP1 = {
|
|
arrowright: nes.INPUT.RIGHT,
|
|
arrowleft: nes.INPUT.LEFT,
|
|
arrowdown: nes.INPUT.DOWN,
|
|
arrowup: nes.INPUT.UP,
|
|
enter: nes.INPUT.START,
|
|
shift: nes.INPUT.SELECT,
|
|
a: nes.INPUT.B,
|
|
z: nes.INPUT.A
|
|
}
|
|
let controlsP2 = {
|
|
l: nes.INPUT.RIGHT,
|
|
j: nes.INPUT.LEFT,
|
|
k: nes.INPUT.DOWN,
|
|
i: nes.INPUT.UP,
|
|
p: nes.INPUT.START,
|
|
o: nes.INPUT.SELECT,
|
|
t: nes.INPUT.B,
|
|
g: nes.INPUT.A
|
|
}
|
|
|
|
zip.workerScriptsPath = "lib/";
|
|
zip.useWebWorkers = false;
|
|
|
|
el("rom").onchange = function(e) {
|
|
audioHandler.resume();
|
|
let freader = new FileReader();
|
|
freader.onload = function() {
|
|
let buf = freader.result;
|
|
if(e.target.files[0].name.slice(-4) === ".zip") {
|
|
// use zip.js to read the zip
|
|
let blob = new Blob([buf]);
|
|
zip.createReader(new zip.BlobReader(blob), function(reader) {
|
|
reader.getEntries(function(entries) {
|
|
if(entries.length) {
|
|
let found = false;
|
|
for(let i = 0; i < entries.length; i++) {
|
|
let name = entries[i].filename;
|
|
if(name.slice(-4) !== ".nes" && name.slice(-4) !== ".NES") {
|
|
continue;
|
|
}
|
|
found = true;
|
|
log("Loaded \"" + name + "\" from zip");
|
|
entries[i].getData(new zip.BlobWriter(), function(blob) {
|
|
let breader = new FileReader();
|
|
breader.onload = function() {
|
|
let rbuf = breader.result;
|
|
let arr = new Uint8Array(rbuf);
|
|
loadRom(arr, name);
|
|
reader.close(function() {});
|
|
}
|
|
breader.readAsArrayBuffer(blob);
|
|
}, function(curr, total) {});
|
|
break;
|
|
}
|
|
if(!found) {
|
|
log("No .nes file found in zip");
|
|
}
|
|
} else {
|
|
log("Zip file was empty");
|
|
}
|
|
});
|
|
}, function(err) {
|
|
log("Failed to read zip: " + err);
|
|
});
|
|
} else {
|
|
// load rom normally
|
|
let parts = e.target.value.split("\\");
|
|
let name = parts[parts.length - 1];
|
|
let arr = new Uint8Array(buf);
|
|
loadRom(arr, name);
|
|
}
|
|
}
|
|
freader.readAsArrayBuffer(e.target.files[0]);
|
|
}
|
|
|
|
el("pause").onclick = function(e) {
|
|
if(paused && loaded) {
|
|
loopId = requestAnimationFrame(update);
|
|
audioHandler.start();
|
|
paused = false;
|
|
el("pause").innerText = "Pause";
|
|
} else {
|
|
cancelAnimationFrame(loopId);
|
|
audioHandler.stop();
|
|
paused = true;
|
|
el("pause").innerText = "Unpause";
|
|
}
|
|
}
|
|
|
|
el("reset").onclick = function(e) {
|
|
nes.reset(false);
|
|
}
|
|
|
|
el("hardreset").onclick = function(e) {
|
|
nes.reset(true);
|
|
}
|
|
|
|
el("runframe").onclick = function(e) {
|
|
if(loaded) {
|
|
runFrame();
|
|
}
|
|
}
|
|
|
|
document.onvisibilitychange = function(e) {
|
|
if(document.hidden) {
|
|
pausedInBg = false;
|
|
if(!paused && loaded) {
|
|
el("pause").click();
|
|
pausedInBg = true;
|
|
}
|
|
} else {
|
|
if(pausedInBg && loaded) {
|
|
el("pause").click();
|
|
pausedInBg = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
window.onpagehide = function(e) {
|
|
saveBatteryForRom();
|
|
}
|
|
|
|
function loadRom(rom, name) {
|
|
saveBatteryForRom();
|
|
if(nes.loadRom(rom)) {
|
|
// load the roms battery data
|
|
let data = localStorage.getItem(name + "_battery");
|
|
if(data) {
|
|
let obj = JSON.parse(data);
|
|
nes.setBattery(obj);
|
|
log("Loaded battery");
|
|
}
|
|
nes.reset(true);
|
|
if(!loaded && !paused) {
|
|
loopId = requestAnimationFrame(update);
|
|
audioHandler.start();
|
|
}
|
|
loaded = true;
|
|
loadedName = name;
|
|
}
|
|
}
|
|
|
|
function saveBatteryForRom() {
|
|
// save the loadedName's battery data
|
|
if(loaded) {
|
|
let data = nes.getBattery();
|
|
if(data) {
|
|
try {
|
|
localStorage.setItem(loadedName + "_battery", JSON.stringify(data));
|
|
log("Saved battery");
|
|
} catch(e) {
|
|
log("Failed to save battery: " + e);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function update() {
|
|
runFrame();
|
|
loopId = requestAnimationFrame(update);
|
|
}
|
|
|
|
function runFrame() {
|
|
nes.runFrame();
|
|
nes.getSamples(audioHandler.sampleBuffer, audioHandler.samplesPerFrame);
|
|
audioHandler.nextBuffer();
|
|
nes.getPixels(imgData.data);
|
|
ctx.putImageData(imgData, 0, 0);
|
|
}
|
|
|
|
function log(text) {
|
|
el("log").innerHTML += text + "<br>";
|
|
el("log").scrollTop = el("log").scrollHeight;
|
|
}
|
|
|
|
function el(id) {
|
|
return document.getElementById(id);
|
|
}
|
|
|
|
window.onkeydown = function(e) {
|
|
if(controlsP1[e.key.toLowerCase()] !== undefined) {
|
|
nes.setButtonPressed(1, controlsP1[e.key.toLowerCase()]);
|
|
e.preventDefault();
|
|
}
|
|
if(controlsP2[e.key.toLowerCase()] !== undefined) {
|
|
nes.setButtonPressed(2, controlsP2[e.key.toLowerCase()]);
|
|
e.preventDefault();
|
|
}
|
|
}
|
|
|
|
window.onkeyup = function(e) {
|
|
if(controlsP1[e.key.toLowerCase()] !== undefined) {
|
|
nes.setButtonReleased(1, controlsP1[e.key.toLowerCase()]);
|
|
e.preventDefault();
|
|
}
|
|
if(controlsP2[e.key.toLowerCase()] !== undefined) {
|
|
nes.setButtonReleased(2, controlsP2[e.key.toLowerCase()]);
|
|
e.preventDefault();
|
|
}
|
|
if(e.key.toLowerCase() === "m" && loaded) {
|
|
let saveState = nes.getState();
|
|
try {
|
|
localStorage.setItem(loadedName + "_savestate", JSON.stringify(saveState));
|
|
log("Saved state");
|
|
} catch(e) {
|
|
log("Failed to save state: " + e);
|
|
}
|
|
}
|
|
if(e.key.toLowerCase() === "n" && loaded) {
|
|
let data = localStorage.getItem(loadedName + "_savestate");
|
|
if(data) {
|
|
let obj = JSON.parse(data);
|
|
if(nes.setState(obj)) {
|
|
log("Loaded state");
|
|
} else {
|
|
log("Failed to load state");
|
|
}
|
|
} else {
|
|
log("No state saved yet");
|
|
}
|
|
}
|
|
}
|