| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798 |
- const SCREEN_WIDTH = 256;
- const SCREEN_HEIGHT = 240;
- const WORKING_MEMORY = 0x800;
- const SAMPLE_REDUCTION = 4;
- const jsnes = require('jsnes')
- const { Subject } = require('rxjs')
- const chunk = (a, l) => Array(Math.ceil(a.length / l)).fill().map((_, i) => (a.slice ? a.slice(i * l, i * l + l) : a.substr(i * l, i * l + 1)))
- const sample = (a, n) => Array(Math.floor(a.length / n)).fill().map((_, i) => a[i * n])
- class NES {
- constructor(rom) {
- this.nes = new jsnes.NES({
- onFrame: this.onFrame.bind(this)
- })
- this.nes.loadROM(rom)
- this.frameCount = 0
- this.packetBuffer = new ArrayBuffer(256 * 4 + SCREEN_WIDTH * SCREEN_HEIGHT + WORKING_MEMORY)
- this.paletteBuffer = new Uint32Array(this.packetBuffer)
- this.pixelBuffer = new Uint8ClampedArray(this.packetBuffer, 256 * 4)
- this.copyMemoryBuffer = new Uint8Array(this.packetBuffer, 256 * 4 + SCREEN_WIDTH * SCREEN_HEIGHT, WORKING_MEMORY)
- this.frameBuffer = new ArrayBuffer(SCREEN_WIDTH * SCREEN_HEIGHT * 4)
- this.screen32 = new Uint32Array(this.frameBuffer)
- this.nes.ppu.buffer = this.screen32
- this.frameBytes = new Uint8ClampedArray(this.frameBuffer)
- this.frames = new Subject()
- }
- command(data) {
- if (data.type === 'button') {
- const player = data.player || 1
- this.nes.controllers[player].state[data.button] = data.pressed ? 0x41 : 0x40
- }
- }
- onFrame(frameBuffer) {
- //console.log('frames.next' + Date.now())
- const colorMap = new Map()
- for (let i = 0; i < 256; i++) {
- this.paletteBuffer[i] = this.nes.ppu.palTable.curTable[i]
- colorMap.set(this.nes.ppu.palTable.curTable[i], i)
- }
- for (let i = 0; i < this.screen32.length; i++) {
- this.pixelBuffer[i] = colorMap.get(this.screen32[i])
- }
- for (let i = 0; i < WORKING_MEMORY; i++) {
- this.copyMemoryBuffer[i] = this.nes.cpu.mem[i]
- }
- this.frames.next(this.packetBuffer)
- }
- genie(code) {
- const map = { A: 0x0, P: 0x1, Z: 0x2, L: 0x3, G: 0x4, I: 0x5, T: 0x6, Y: 0x7, E: 0x8, O: 0x9, X: 0xA, U: 0xB, K: 0xC, S: 0xD, V: 0xE, N: 0xF }
- const [n0, n1, n2, n3, n4, n5, n6, n7] = code.split('').map(c => map[c])
- let address, data, compare
-
- address = 0x8000 +
- ((n3 & 7) << 12)
- | ((n5 & 7) << 8) | ((n4 & 8) << 8)
- | ((n2 & 7) << 4) | ((n1 & 8) << 4)
- | (n4 & 7) | (n3 & 8)
-
- if (code.length === 6) {
- data = ((n1 & 7) << 4) | ((n0 & 8) << 4) | (n0 & 7) | (n5 & 8)
- compare = null
- } else {
- data = ((n1 & 7) << 4) | ((n0 & 8) << 4) | (n0 & 7) | (n7 & 8)
- compare = ((n7 & 7) << 4) | ((n6 & 8) << 4) | (n6 & 7) | (n5 & 8)
- }
- this.hack(address, data, compare)
- }
- hack(address, data, compare = null) {
- let val = this.nes.cpu.mem[address]
- Object.defineProperty(this.nes.cpu.mem, address, {
- get: () => compare === null || val === compare
- ? data
- : val,
- set: v => (val = v)
- })
- }
- start() {
- if (!this.timer) this.timer = setInterval(() => this.nes.frame(), 1000 / 60)
- }
- stop() {
- if (this.timer) {
- clearInterval(this.timer)
- this.timer = null
- }
- }
- }
- module.exports = NES
|