Last active
April 3, 2023 18:24
-
-
Save cxx/81b9f45eb5b3cb87b4f3783ccdf8894f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// dotemu2mame.js - convert data of games ported by DotEmu to MAME ROM sets | |
// | |
// Usage: | |
// node dotemu2mame.js [ROM directory] | |
// | |
// Requirements: | |
// - Node.js v6 or later | |
// - [Microsoft Windows] .NET Framework 4.5 or later (included in Windows 8/10) | |
// - [Linux] /usr/bin/zip | |
// | |
// Supported games: | |
// - Double Dragon Trilogy (GOG.com) | |
// * Double Dragon | |
// * Double Dragon 2 | |
// * Double Dragon 3 ("mb7114h.ic38" is missing) | |
// - R-Type (Google Play) | |
// - R-Type II (Google Play) | |
// - Irem Arcade Hits (Mac App Store) | |
// * Air Duel | |
// * Battle Chopper | |
// * Blade Master | |
// * Cosmic Cop | |
// * Dragon Breed | |
// * Gunforce | |
// * Gunforce 2 | |
// * Hammerin' Harry | |
// * Image Fight | |
// * In the Hunt | |
// * Kung-Fu Master ("b-6f-.bin" is missing) | |
// * Legend of Hero Tonma | |
// * Mystic Riders | |
// * Ninja Spirit ("proms" and "plds" ROMs are missing) | |
// * R-Type Leo | |
// * Superior Soldiers | |
// * Undercover Cops | |
// * Vigilante ("plds" ROMs are missing) | |
// - Raiden Legacy (Google Play, GOG.com) | |
// * Raiden | |
// * Raiden Fighters (wrong checksums) | |
// * Raiden Fighters 2 (wrong checksums) | |
// * Raiden Fighters Jet (wrong checksums) | |
// - Neo Geo (Steam, Google Play) (neogeo.zip is incomplete, cannot be run) | |
// * Baseball Stars 2 | |
// * Blazing Star | |
// * The King of Fighters '97 | |
// * The King of Fighters '98 (KOF '98 Ultimate Match is NOT supported) | |
// * Metal Slug | |
// * Metal Slug 2 | |
// * Metal Slug X (wrong checksums) | |
// * Metal Slug 3 | |
// * Samurai Shodown II | |
// * Shock Troopers | |
// * Twinkle Star Sprites | |
// * Fatal Fury Special (not tested, may not work) | |
// * The Last Blade (not tested, may not work) | |
// * Shock Troopers 2nd Squad (not tested, may not work) | |
// | |
// Changelog: | |
// - 2017-12-21: Place dummy files for missing ROMs. | |
// - 2017-12-20: Support Irem Arcade Hits (Mac App Store). | |
// - 2017-06-25: Support R-Type II (Google Play). | |
// - 2017-04-23: Initial release. | |
const child_process = require('child_process'); | |
const crypto = require('crypto'); | |
const fs = require('fs'); | |
const os = require('os'); | |
const path = require('path'); | |
Array.prototype.flatten = function() { | |
return this.reduce((acc, cur) => acc.concat( | |
Array.isArray(cur) ? cur.flatten() : cur | |
), []); | |
}; | |
Array.prototype.flatMap = function(callback) { | |
return this.map(callback).flatten(); | |
}; | |
Array.prototype.sum = function() { | |
return this.reduce((acc, cur) => acc + cur, 0); | |
}; | |
function split(buf, size) | |
{ | |
const ret = []; | |
for (let i = 0; i < buf.length; i += size) | |
ret.push(buf.slice(i, Math.min(i+size,buf.length))); | |
return ret; | |
} | |
function split_at(buf, ...pos) | |
{ | |
const ret = []; | |
pos = [0, ...pos, buf.length]; | |
for (let i = 1; i < pos.length; i++) | |
ret.push(buf.slice(pos[i-1], pos[i])); | |
return ret; | |
} | |
function interleave(buf, pat=[1,1]) | |
{ | |
const step = pat.sum(); | |
return pat.map((n, index) => { | |
const b = Buffer.allocUnsafe(buf.length * n / step); | |
const offset = pat.slice(0, index).sum(); | |
if (n === 1) | |
for (let i = 0; i < b.length; i++) | |
b[i] = buf[i*step+offset]; | |
else { /* n === 2 */ | |
for (let i = 0; i < b.length/2; i++) { | |
b[i*2+0] = buf[i*step+offset+1]; | |
b[i*2+1] = buf[i*step+offset+0]; | |
} | |
} | |
return b; | |
}); | |
} | |
function bitswap(val, ...indices) | |
{ | |
const n = indices.length; | |
let ret = 0; | |
for (let i = 0; i < n; i++) | |
ret |= (val >> indices[i] & 1) << n-1-i; | |
return ret; | |
} | |
function reverse_bitswap(val, ...indices) | |
{ | |
const n = indices.length; | |
let ret = 0; | |
for (let i = 0; i < n; i++) | |
ret |= (val >> n-1-i & 1) << indices[i]; | |
return ret; | |
} | |
function sha1(buf) | |
{ | |
const hash = crypto.createHash('sha1'); | |
hash.update(buf); | |
return hash.digest('hex'); | |
} | |
function encode_gfx(buf, layout) | |
{ | |
const np = layout.planes; | |
const dest = Buffer.alloc(buf.length * np / 8); | |
if (Array.isArray(layout.total)) { | |
const [num, den] = layout.total; | |
layout = Object.assign({}, layout, { | |
total: dest.length * 8 / layout.charincrement * num / den, | |
planeoffset: layout.planeoffset.map(x => { | |
if (Array.isArray(x)) { | |
let [num, den, add] = x; | |
add = add || 0; | |
return dest.length * 8 * num / den + add; | |
} | |
else | |
return x; | |
}) | |
}); | |
} | |
let i = 0; | |
for (let c = 0; c < layout.total; c++) { | |
const charoffset = layout.charincrement * c; | |
for (let y = 0; y < layout.height; y++) { | |
const yoffset = charoffset + layout.yoffset[y]; | |
for (let x = 0; x < layout.width; x++) { | |
const xoffset = yoffset + layout.xoffset[x]; | |
for (let p = 0; p < np; p++) { | |
const offset = xoffset + layout.planeoffset[p]; | |
dest[offset >> 3] |= | |
((buf[i] >> np-1-p) & 1) << (~offset & 7); | |
} | |
i++; | |
} | |
} | |
} | |
return dest; | |
} | |
function zip(name, dir) | |
{ | |
let cmd; | |
if (os.type() === 'Windows_NT') | |
cmd = `powershell Add-Type -AssemblyName System.IO.Compression.FileSystem; [System.IO.Compression.ZipFile]::CreateFromDirectory('${dir}', '${name}.zip')`; | |
else | |
cmd = `zip -j ${name}.zip ${dir}/*`; | |
child_process.execSync(cmd); | |
} | |
function convert_roms(name, srcdir, maps) | |
{ | |
const bins = {}; | |
for (const region in maps) { | |
const map = maps[region]; | |
let bin; | |
if (map.input instanceof Buffer) | |
bin = map.input; | |
else { | |
let file; | |
let layout; | |
if (typeof map.input === 'string') | |
file = map.input; | |
else | |
({file, layout} = map.input); | |
bin = fs.readFileSync(path.join(srcdir, file)); | |
if (layout) | |
bin = encode_gfx(bin, layout); | |
} | |
if (map.transform) | |
bin = map.transform(bin); | |
bins[region] = bin; | |
} | |
const dstdir = fs.mkdtempSync(path.join(os.tmpdir(), name)); | |
for (const region in maps) { | |
let bin = bins[region]; | |
let {output} = maps[region]; | |
if (typeof output === 'string') { | |
output = [output]; | |
bin = [bin]; | |
} | |
if (!Array.isArray(bin)) | |
bin = split(bin, bin.length/output.length); | |
for (let i = 0; i < output.length; i++) | |
fs.writeFileSync(path.join(dstdir, output[i]), bin[i]); | |
} | |
zip(name, dstdir); | |
for (const f of fs.readdirSync(dstdir)) | |
fs.unlinkSync(path.join(dstdir, f)); | |
fs.rmdirSync(dstdir); | |
console.log(`saved as ${name}.zip.`); | |
} | |
// from https://github.com/mamedev/mame/blob/ddb290d5f615019c33c42b8d94e5a5254cabcf33/src/mame/video/vigilant.cpp | |
// license:BSD-3-Clause | |
// copyright-holders:Mike Balfour | |
function vigilant_reorder(src) | |
{ | |
const pages = 4; | |
const width = 512; | |
const height = 256; | |
var dst = Buffer.alloc(src.length/2); | |
var i = 0; | |
for (var p = 0; p < pages; p++) | |
for (var y = 0; y < height; y++) { | |
var j = (width*pages*y + width*p) * 2; | |
for (var x = 0; x < width; x++) { | |
dst[i] = src[j] & 0xf; | |
i++; | |
j += 2; | |
} | |
} | |
return dst; | |
} | |
const SPI = (function() { | |
// from https://github.com/mamedev/mame/blob/ddb290d5f615019c33c42b8d94e5a5254cabcf33/src/mame/machine/seibuspi.cpp | |
// license:BSD-3-Clause | |
// copyright-holders:Ville Linde, hap, Nicola Salmoria | |
function partial_borrow_diff(minu, sub, carry_mask, bits) | |
{ | |
let res = 0; | |
let borrow = 0; | |
for (let i = 0; i < bits; i++) { | |
bit = (minu >> i & 1) - (sub >> i & 1) - borrow; | |
res |= (bit & 1) << i; | |
borrow = (carry_mask >> i & 1) & (bit >> 1); | |
} | |
return res ^ borrow; | |
} | |
const KEY_TABLE = [ | |
0x3ad7,0x54b1,0x2d41,0x8ca0,0xa69b,0x9018,0x9db9,0x6559, | |
0xe9a7,0xb087,0x8a5e,0x821c,0xaafc,0x2ae7,0x557b,0xcd80, | |
0xcfee,0x653e,0x9b31,0x7ab5,0x8b2a,0xbda8,0x707a,0x3c83, | |
0xcbb7,0x7157,0x8226,0x5c4a,0x8bf2,0x6397,0x13e2,0x3102, | |
0x8093,0x44cd,0x5f2d,0x7639,0xa7a4,0x9974,0x5263,0x8318, | |
0xb78c,0xa120,0xafb4,0x615f,0x6e0b,0x1d7d,0x8c29,0x4466, | |
0x3f35,0x794e,0xaea6,0x601c,0xe478,0xcf6e,0x4ee3,0xa009, | |
0x4b99,0x51d3,0x3474,0x3e4d,0xe5b7,0x9088,0xb5c0,0xba9f, | |
0x5646,0xa0af,0x970b,0xb14f,0x8216,0x2386,0x496d,0x9245, | |
0x7e4c,0xad5f,0x89d9,0xb801,0xdf64,0x8ca8,0xe019,0xde9b, | |
0x6836,0x70e2,0x7dcd,0x7ac1,0x98ef,0x71aa,0x7d6f,0x70bd, | |
0x9e14,0x75b6,0x8153,0xab6c,0x1f85,0x79cd,0xb2a1,0x934a, | |
0x6f74,0x37d7,0xa05a,0x6563,0x1972,0x2dcd,0x7e59,0x6a60, | |
0x5163,0x84c4,0xc451,0x8d80,0x4287,0x57e8,0xacc9,0x539d, | |
0xbe71,0xdb7c,0x9424,0xb224,0xcc0f,0xe3dd,0xb79c,0x461e, | |
0x96a9,0x4c7c,0x5443,0x6b2b,0x3cdc,0xbee8,0x2602,0x3282, | |
0x7f9c,0x59c3,0xc69a,0x39f4,0x5138,0xb7ca,0x6ca7,0x62e7, | |
0xc455,0x56cf,0x8a9a,0x695c,0x5af2,0xdebf,0x4dbb,0xdaec, | |
0xb564,0xc89c,0x7d2d,0x6dc3,0xa15a,0x6584,0xb8ea,0xb7ac, | |
0x88d8,0xc5aa,0x98c5,0xc506,0xc13c,0x7f59,0xab65,0x8fc8, | |
0x3a3c,0xd5f6,0x554d,0x5682,0x8ce7,0x40fc,0x8fd7,0x535c, | |
0x6aa0,0x52fe,0x8834,0x5316,0x6c27,0x80a9,0x9e6f,0x2c08, | |
0x4092,0xc7c1,0xc468,0x9520,0xbc4d,0xb621,0x3cdb,0xdce8, | |
0x481f,0xd0bd,0x3a57,0x807e,0x3025,0x5aa0,0x5e49,0xa29b, | |
0xd2d6,0x7bee,0x97f0,0xe28e,0x2fff,0x48e4,0x6367,0x933f, | |
0x57c5,0x28d4,0x68a0,0xd22e,0x39a6,0x9d2b,0x7a64,0x7e72, | |
0x5379,0xe86c,0x7554,0x8fbb,0xc06a,0x9533,0x7eec,0x4d52, | |
0xa800,0x5d35,0xa47d,0xe515,0x8d19,0x703b,0x5a2e,0x627c, | |
0x7cea,0x1b2c,0x5a05,0x8598,0x9e00,0xcf01,0x62d9,0x7a10, | |
0x1f42,0x87ce,0x575d,0x6e23,0x86ef,0x93c2,0x3d1a,0x89aa, | |
0xe199,0xba1d,0x1b72,0x4513,0x5131,0xc23c,0xba9f,0xa069, | |
0xfbfb,0xda92,0x42b2,0x3a48,0xdb96,0x5fad,0xba96,0xc6eb | |
]; | |
const SPI_BITSWAP = [ | |
[15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0], | |
[ 7, 6, 5,14, 0,15, 4, 3, 2, 8, 9,10,11,12,13, 1], | |
[ 9,15,14,13,12, 0, 1, 2,10, 8, 7, 6, 5, 4, 3,11], | |
[ 5, 4, 3, 2, 9,14,13,12,11, 6, 7, 8, 1,15, 0,10], | |
[12,11, 0, 7, 8, 5, 6,15,10,13,14, 1, 2, 3, 4, 9], | |
[14, 0, 1, 2, 3, 9, 8, 7,15, 5, 6,13,12,11,10, 4], | |
[13,12,11,10, 2, 7, 8, 9, 0,14,15, 3, 4, 5, 6, 1], | |
[ 2, 9,10,11,12, 7, 6, 5,14, 3, 4, 0,15, 1, 8,13], | |
[ 8, 7, 4, 3, 2,13,12,11, 0, 9,10,14,15, 6, 5, 1], | |
[ 3, 2,10,11,12, 5,14, 0, 1, 4,15, 6, 7, 8, 9,13], | |
[ 2,10, 6, 5, 4,14,13,12,11, 1, 0,15, 9, 8, 7, 3], | |
[12,11, 8, 1,15, 3, 2, 9,10,13,14, 4, 5, 6, 7, 0], | |
[ 8, 7, 0,11,12, 5, 6,15,14, 9,10, 1, 2, 3, 4,13], | |
[ 3, 2, 1, 0,14, 9, 8, 7, 6, 4,15,13,12,11,10, 5], | |
[ 2,10,11,12,13, 7, 8, 9,15, 1, 0, 3, 4, 5, 6,14], | |
[12,11,10, 9, 2, 7, 6, 5, 4,13,14, 0,15, 1, 8, 3] | |
]; | |
function key(table, addr) | |
{ | |
const xorbit = 8 + ((table & 0xc) >> 2); | |
return ((KEY_TABLE[addr & 0xff] >> 4) >> table & 1) ^ (addr >> xorbit & 1); | |
} | |
function seibuspi_sprite_encrypt(src) | |
{ | |
const rom_size = src.length / 3; | |
for (let i = 0; i < rom_size/2; i++) { | |
const addr = i >> 8; | |
const plane5 = src[2*i+0*rom_size+0]; | |
const plane4 = src[2*i+0*rom_size+1]; | |
const plane3 = src[2*i+1*rom_size+0]; | |
const plane2 = src[2*i+1*rom_size+1]; | |
const plane1 = src[2*i+2*rom_size+0]; | |
const plane0 = src[2*i+2*rom_size+1]; | |
let s1 = 0; | |
let s2 = 0; | |
for (let j = 0; j < 8; j++) { | |
s1 |= (plane5 >> j & 1) << 2*j+1 | | |
(plane4 >> j & 1) << 2*j+0; | |
s2 |= (plane3 >> j & 1) << 4*j+3 | | |
(plane2 >> j & 1) << 4*j+2 | | |
(plane1 >> j & 1) << 4*j+1 | | |
(plane0 >> j & 1) << 4*j+0; | |
} | |
const sub1 = (addr >> 11 & 1) << 0 | | |
(addr >> 10 & 1) << 1 | | |
key(10, addr) << 2 | | |
key( 5, addr) << 3 | | |
key( 4, addr) << 4 | | |
(addr >> 11 & 1) << 5 | | |
(addr >> 11 & 1) << 6 | | |
key( 7, addr) << 7 | | |
key( 6, addr) << 8 | | |
key( 1, addr) << 9 | | |
key( 0, addr) << 10 | | |
(addr >> 11 & 1) << 11 | | |
key( 9, addr) << 12 | | |
key( 8, addr) << 13 | | |
key( 3, addr) << 14 | | |
key( 2, addr) << 15; | |
const sub2 = key( 0, addr) << 0 | | |
key( 1, addr) << 1 | | |
key( 2, addr) << 2 | | |
key( 3, addr) << 3 | | |
key( 4, addr) << 4 | | |
key( 5, addr) << 5 | | |
key( 6, addr) << 6 | | |
key( 7, addr) << 7 | | |
key( 8, addr) << 8 | | |
key( 9, addr) << 9 | | |
key(10, addr) << 10 | | |
(addr >> 10 & 1) << 11 | | |
(addr >> 11 & 1) << 12 | | |
(addr >> 11 & 1) << 13 | | |
(addr >> 11 & 1) << 14 | | |
(addr >> 11 & 1) << 15 | | |
(addr >> 11 & 1) << 16 | | |
key( 7, addr) << 17 | | |
(addr >> 11 & 1) << 18 | | |
key( 6, addr) << 19 | | |
(addr >> 11 & 1) << 20 | | |
key( 5, addr) << 21 | | |
(addr >> 11 & 1) << 22 | | |
key( 4, addr) << 23 | | |
(addr >> 10 & 1) << 24 | | |
key( 3, addr) << 25 | | |
key(10, addr) << 26 | | |
key( 2, addr) << 27 | | |
key( 9, addr) << 28 | | |
key( 1, addr) << 29 | | |
key( 8, addr) << 30 | | |
key( 0, addr) << 31; | |
s1 = partial_borrow_diff(s1 ^ 0x843a, sub1, 0x3a59, 16); | |
s2 = partial_borrow_diff(s2 ^ 0xc8e29f84, sub2, 0x28d49cac, 32); | |
let y1 = (s2 >> 22 & 1) << 0 | | |
(s1 >> 6 & 1) << 1 | | |
(s2 >> 6 & 1) << 2 | | |
(s2 >> 16 & 1) << 3 | | |
(s1 >> 0 & 1) << 4 | | |
(s2 >> 0 & 1) << 5 | | |
(s2 >> 11 & 1) << 6 | | |
(s1 >> 11 & 1) << 7 | | |
(s2 >> 27 & 1) << 8 | | |
(s2 >> 21 & 1) << 9 | | |
(s1 >> 5 & 1) << 10 | | |
(s2 >> 5 & 1) << 11 | | |
(s2 >> 15 & 1) << 12 | | |
(s1 >> 15 & 1) << 13 | | |
(s2 >> 31 & 1) << 14 | | |
(s2 >> 10 & 1) << 15; | |
let y2 = (s1 >> 10 & 1) << 0 | | |
(s2 >> 26 & 1) << 1 | | |
(s2 >> 20 & 1) << 2 | | |
(s1 >> 4 & 1) << 3 | | |
(s2 >> 4 & 1) << 4 | | |
(s2 >> 14 & 1) << 5 | | |
(s1 >> 14 & 1) << 6 | | |
(s2 >> 30 & 1) << 7 | | |
(s2 >> 9 & 1) << 8 | | |
(s1 >> 9 & 1) << 9 | | |
(s2 >> 25 & 1) << 10 | | |
(s2 >> 19 & 1) << 11 | | |
(s1 >> 3 & 1) << 12 | | |
(s2 >> 3 & 1) << 13 | | |
(s2 >> 13 & 1) << 14 | | |
(s1 >> 13 & 1) << 15; | |
let y3 = (s2 >> 1 & 1) << 0 | | |
(s2 >> 24 & 1) << 1 | | |
(s1 >> 8 & 1) << 2 | | |
(s2 >> 8 & 1) << 3 | | |
(s2 >> 29 & 1) << 4 | | |
(s2 >> 2 & 1) << 5 | | |
(s1 >> 2 & 1) << 6 | | |
(s1 >> 1 & 1) << 7 | | |
(s2 >> 17 & 1) << 8 | | |
(s2 >> 7 & 1) << 9 | | |
(s2 >> 23 & 1) << 10 | | |
(s2 >> 12 & 1) << 11 | | |
(s1 >> 12 & 1) << 12 | | |
(s2 >> 28 & 1) << 13 | | |
(s1 >> 7 & 1) << 14 | | |
(s2 >> 18 & 1) << 15; | |
y3 = reverse_bitswap(y3, ...SPI_BITSWAP[KEY_TABLE[addr & 0xff] & 0xf]); | |
src[2*i+0*rom_size+0] = y1 >> 0 & 0xff; | |
src[2*i+0*rom_size+1] = y1 >> 8 & 0xff; | |
src[2*i+1*rom_size+0] = y2 >> 0 & 0xff; | |
src[2*i+1*rom_size+1] = y2 >> 8 & 0xff; | |
src[2*i+2*rom_size+0] = y3 >> 0 & 0xff; | |
src[2*i+2*rom_size+1] = y3 >> 8 & 0xff; | |
} | |
return src; | |
} | |
function sprite_reorder(buf) | |
{ | |
const tmp = Buffer.allocUnsafe(64); | |
for (let i = 0; i < buf.length; i += 64) { | |
for (let j = 0; j < 16; j++) { | |
tmp[2*j+ 0] = buf[i+4*j+0]; | |
tmp[2*j+ 1] = buf[i+4*j+1]; | |
tmp[2*j+32] = buf[i+4*j+2]; | |
tmp[2*j+33] = buf[i+4*j+3]; | |
} | |
tmp.copy(buf, i); | |
} | |
} | |
function seibuspi_rise10_sprite_encrypt(rom) | |
{ | |
const size = rom.length / 3; | |
sprite_reorder(rom); | |
for (let i = 0; i < size/2; i++) { | |
let plane54 = rom[0*size+2*i+0] << 8 | | |
rom[0*size+2*i+1] << 0; | |
let plane3210 = rom[1*size+2*i+0] << 24 | | |
rom[1*size+2*i+1] << 16 | | |
rom[2*size+2*i+0] << 8 | | |
rom[2*size+2*i+1] << 0; | |
plane54 = partial_borrow_diff(plane54 ^ 0x6699, 0xabcb, 0x55aa, 16); | |
plane3210 = partial_borrow_diff(plane3210 ^ 0x0ca352a9, | |
0x654321d9 ^ 0x42, 0x1d463748, 32); | |
plane3210 = reverse_bitswap( | |
plane3210, 23,13,24,4,16,12,25,30, 3,5,29,17,14,22,2,11, | |
27,6,15,21,1,28,10,20, 7,31,26,0,18,9,19,8 | |
); | |
rom[0*size+2*i+0] = plane54 >> 0 & 0xff; | |
rom[0*size+2*i+1] = plane54 >> 8 & 0xff; | |
rom[1*size+2*i+0] = plane3210 >> 0 & 0xff; | |
rom[1*size+2*i+1] = plane3210 >> 8 & 0xff; | |
rom[2*size+2*i+0] = plane3210 >> 16 & 0xff; | |
rom[2*size+2*i+1] = plane3210 >> 24 & 0xff; | |
} | |
} | |
function seibuspi_rise11_sprite_encrypt(rom, k1, k2, k3, k4, k5) | |
{ | |
const size = rom.length / 3; | |
sprite_reorder(rom); | |
for (let i = 0; i < size/2; i++) { | |
let plane543 = rom[0*size+2*i+0] << 16 | | |
rom[0*size+2*i+1] << 8 | | |
rom[1*size+2*i+0] << 0; | |
let plane210 = rom[1*size+2*i+1] << 16 | | |
rom[2*size+2*i+0] << 8 | | |
rom[2*size+2*i+1] << 0; | |
plane543 = partial_borrow_diff(plane543 ^ k3, k1, k2, 32); | |
plane210 = partial_borrow_diff(plane210 ^ k5, i, k4, 24); | |
rom[0*size+2*i+0] = (plane210 >> 12 & 1) << 0 | | |
(plane210 >> 1 & 1) << 1 | | |
(plane543 >> 9 & 1) << 2 | | |
(plane543 >> 16 & 1) << 3 | | |
(plane543 >> 21 & 1) << 4 | | |
(plane210 >> 22 & 1) << 5 | | |
(plane543 >> 1 & 1) << 6 | | |
(plane210 >> 4 & 1) << 7; | |
rom[0*size+2*i+1] = (plane210 >> 16 & 1) << 0 | | |
(plane543 >> 11 & 1) << 1 | | |
(plane210 >> 19 & 1) << 2 | | |
(plane543 >> 7 & 1) << 3 | | |
(plane543 >> 8 & 1) << 4 | | |
(plane210 >> 2 & 1) << 5 | | |
(plane210 >> 0 & 1) << 6 | | |
(plane543 >> 18 & 1) << 7; | |
rom[1*size+2*i+0] = (plane543 >> 23 & 1) << 0 | | |
(plane210 >> 9 & 1) << 1 | | |
(plane543 >> 13 & 1) << 2 | | |
(plane210 >> 21 & 1) << 3 | | |
(plane210 >> 6 & 1) << 4 | | |
(plane543 >> 10 & 1) << 5 | | |
(plane210 >> 11 & 1) << 6 | | |
(plane543 >> 17 & 1) << 7; | |
rom[1*size+2*i+1] = (plane210 >> 14 & 1) << 0 | | |
(plane210 >> 7 & 1) << 1 | | |
(plane543 >> 14 & 1) << 2 | | |
(plane543 >> 0 & 1) << 3 | | |
(plane543 >> 4 & 1) << 4 | | |
(plane543 >> 20 & 1) << 5 | | |
(plane210 >> 5 & 1) << 6 | | |
(plane210 >> 20 & 1) << 7; | |
rom[2*size+2*i+0] = (plane210 >> 3 & 1) << 0 | | |
(plane543 >> 12 & 1) << 1 | | |
(plane543 >> 22 & 1) << 2 | | |
(plane543 >> 3 & 1) << 3 | | |
(plane543 >> 6 & 1) << 4 | | |
(plane543 >> 15 & 1) << 5 | | |
(plane210 >> 18 & 1) << 6 | | |
(plane210 >> 10 & 1) << 7; | |
rom[2*size+2*i+1] = (plane210 >> 8 & 1) << 0 | | |
(plane543 >> 19 & 1) << 1 | | |
(plane210 >> 17 & 1) << 2 | | |
(plane210 >> 13 & 1) << 3 | | |
(plane543 >> 2 & 1) << 4 | | |
(plane210 >> 15 & 1) << 5 | | |
(plane543 >> 5 & 1) << 6 | | |
(plane210 >> 23 & 1) << 7; | |
} | |
} | |
function seibuspi_rise11_sprite_encrypt_rfjet(rom) | |
{ | |
seibuspi_rise11_sprite_encrypt(rom, 0xabcb64, 0x55aadd, | |
0xab6a4c, 0xd6375b, 0x8bf23b); | |
return rom; | |
} | |
// from https://github.com/mamedev/mame/blob/6c23897483a0201dd0b65b450253fd9bf8fb8723/src/mame/video/seibuspi.cpp | |
// license:BSD-3-Clause | |
// copyright-holders:Ville Linde, hap, Nicola Salmoria | |
function encrypt_tile(val, tileno, key1, key2, key3) | |
{ | |
val = partial_borrow_diff(val ^ key3, tileno + key1, key2, 24); | |
return reverse_bitswap( | |
val, 18,19,9,5,10,17,16,20, 21,22,6,11,15,14,4,23, 0,1,7,8,13,12,3,2 | |
); | |
} | |
function encrypt_text(rom, key1, key2, key3) | |
{ | |
for (let i = 0; i < 0x10000; i++) { | |
let w = rom[i*3+0] << 16 | rom[i*3+1] << 8 | rom[i*3+2]; | |
w = encrypt_tile(w, i >> 4, key1, key2, key3); | |
rom[i*3+0] = w >> 16 & 0xff; | |
rom[i*3+1] = w >> 8 & 0xff; | |
rom[i*3+2] = w >> 0 & 0xff; | |
} | |
} | |
function encrypt_bg(rom, key1, key2, key3) | |
{ | |
for (let j = 0; j < rom.length; j += 0xc0000) { | |
for (let i = 0; i < 0x40000; i++) { | |
let w = rom[j+i*3+0] << 16 | rom[j+i*3+1] << 8 | rom[j+i*3+2]; | |
w = encrypt_tile(w, i >> 6, key1, key2, key3); | |
rom[j+i*3+0] = w >> 16 & 0xff; | |
rom[j+i*3+1] = w >> 8 & 0xff; | |
rom[j+i*3+2] = w >> 0 & 0xff; | |
} | |
} | |
} | |
function seibuspi_text_encrypt(rom) | |
{ | |
encrypt_text(rom, 0x5a3845, 0x77cf5b, 0x1378df); | |
return rom; | |
} | |
function seibuspi_bg_encrypt(rom) | |
{ | |
encrypt_bg(rom, 0x5a3845, 0x77cf5b, 0x1378df); | |
return rom; | |
} | |
function rdft2_text_encrypt(rom) | |
{ | |
encrypt_text(rom, 0x823146, 0x4de2f8, 0x157adc); | |
return rom; | |
} | |
function rdft2_bg_encrypt(rom) | |
{ | |
encrypt_bg(rom, 0x823146, 0x4de2f8, 0x157adc); | |
return rom; | |
} | |
function rfjet_text_encrypt(rom) | |
{ | |
encrypt_text(rom, 0xaea754, 0xfe8530, 0xccb666); | |
return rom; | |
} | |
function rfjet_bg_encrypt(rom) | |
{ | |
encrypt_bg(rom, 0xaea754, 0xfe8530, 0xccb666); | |
return rom; | |
} | |
return { | |
seibuspi_text_encrypt: seibuspi_text_encrypt, | |
seibuspi_bg_encrypt: seibuspi_bg_encrypt, | |
seibuspi_sprite_encrypt: seibuspi_sprite_encrypt, | |
rdft2_text_encrypt: rdft2_text_encrypt, | |
rdft2_bg_encrypt: rdft2_bg_encrypt, | |
seibuspi_rise10_sprite_encrypt: seibuspi_rise10_sprite_encrypt, | |
rfjet_text_encrypt: rfjet_text_encrypt, | |
rfjet_bg_encrypt: rfjet_bg_encrypt, | |
seibuspi_rise11_sprite_encrypt_rfjet: seibuspi_rise11_sprite_encrypt_rfjet | |
}; | |
})(); | |
const NeoGeo = (function() { | |
// from http://i486.mods.jp/ichild/?page_id=62 | |
// Original author: Imaha486 | |
function deoptimize_sprites(buf) | |
{ | |
const tmp = Buffer.allocUnsafe(0x80); | |
for (let i = 0; i < buf.length; i += 0x80) { | |
tmp.fill(0); | |
for (let y = 0; y < 0x10; y++) { | |
let dstData; | |
dstData = buf[i+(y*8)+0] << 0 | | |
buf[i+(y*8)+1] << 8 | | |
buf[i+(y*8)+2] << 16 | | |
buf[i+(y*8)+3] << 24; | |
for (let x = 0; x < 8; x++) { | |
tmp[0x43 | y << 2] |= (dstData >> x*4+3 & 1) << 7-x; | |
tmp[0x41 | y << 2] |= (dstData >> x*4+2 & 1) << 7-x; | |
tmp[0x42 | y << 2] |= (dstData >> x*4+1 & 1) << 7-x; | |
tmp[0x40 | y << 2] |= (dstData >> x*4+0 & 1) << 7-x; | |
} | |
dstData = buf[i+(y*8)+4] << 0 | | |
buf[i+(y*8)+5] << 8 | | |
buf[i+(y*8)+6] << 16 | | |
buf[i+(y*8)+7] << 24; | |
for (let x = 0; x < 8; x++) { | |
tmp[0x03 | y << 2] |= (dstData >> x*4+3 & 1) << 7-x; | |
tmp[0x01 | y << 2] |= (dstData >> x*4+2 & 1) << 7-x; | |
tmp[0x02 | y << 2] |= (dstData >> x*4+1 & 1) << 7-x; | |
tmp[0x00 | y << 2] |= (dstData >> x*4+0 & 1) << 7-x; | |
} | |
} | |
tmp.copy(buf, i); | |
} | |
return buf; | |
} | |
function sfix_reorder(bin) | |
{ | |
const tmp = Buffer.allocUnsafe(32); | |
for (let i = 0; i < bin.length; i += 32) { | |
for (let j = 0; j < 8; j++) { | |
tmp[j+16] = bin[i+4*j+0]; | |
tmp[j+24] = bin[i+4*j+1]; | |
tmp[j+ 0] = bin[i+4*j+2]; | |
tmp[j+ 8] = bin[i+4*j+3]; | |
} | |
tmp.copy(bin, i); | |
} | |
return bin; | |
} | |
// from https://github.com/mamedev/mame/blob/6c23897483a0201dd0b65b450253fd9bf8fb8723/src/devices/bus/neogeo/prot_sma.cpp | |
// license:BSD-3-Clause | |
// copyright-holders:S. Smith,David Haywood,Fabio Priuli | |
function mslug3_encrypt_68k(buf) | |
{ | |
let rom = buf.slice(0x100000); | |
const tmp = Buffer.allocUnsafe(0x10000); | |
for (let i = 0; i < 0x800000/2; i += 0x10000/2) { | |
rom.copy(tmp, 0, i*2, i*2+0x10000); | |
for (let j = 0; j < 0x10000/2; j++) { | |
const k = bitswap(j, 2,11,0,14,6,4,13,8,9,3,10,7,5,12,1); | |
rom[(i+k)*2+0] = tmp[j*2+0]; | |
rom[(i+k)*2+1] = tmp[j*2+1]; | |
} | |
} | |
rom = buf; | |
for (let i = 0; i < 0x0c0000/2; i++) { | |
const j = bitswap(i, 18,15,2,1,13,3,0,9,6,16,4,11,5,7,12,17,14,10,8); | |
rom[0x5d0000+j*2+0] = rom[i*2+0]; | |
rom[0x5d0000+j*2+1] = rom[i*2+1]; | |
} | |
rom = buf.slice(0x100000); | |
for (let i = 0; i < 0x800000/2; i++) { | |
let w = rom[i*2+0] | rom[i*2+1] << 8; | |
w = reverse_bitswap(w, 4,11,14,3,1,13,0,7,2,8,12,15,10,9,5,6); | |
rom[i*2+0] = w >> 0 & 0xff; | |
rom[i*2+1] = w >> 8 & 0xff; | |
} | |
} | |
// from https://github.com/mamedev/mame/blob/ddb290d5f615019c33c42b8d94e5a5254cabcf33/src/devices/bus/neogeo/prot_cmc.h | |
// license:BSD-3-Clause | |
// copyright-holders:S. Smith,David Haywood,Fabio Priuli | |
const MSLUG3_GFX_KEY = 0xad; | |
// from https://github.com/mamedev/mame/blob/6c23897483a0201dd0b65b450253fd9bf8fb8723/src/devices/bus/neogeo/prot_cmc.cpp | |
// license:BSD-3-Clause | |
// copyright-holders:S. Smith,David Haywood,Fabio Priuli | |
const CMC42_TYPE0_T03 = [ | |
0xfb, 0x86, 0x9d, 0xf1, 0xbf, 0x80, 0xd5, 0x43, 0xab, 0xb3, 0x9f, 0x6a, 0x33, 0xd9, 0xdb, 0xb6, | |
0x66, 0x08, 0x69, 0x88, 0xcc, 0xb7, 0xde, 0x49, 0x97, 0x64, 0x1f, 0xa6, 0xc0, 0x2f, 0x52, 0x42, | |
0x44, 0x5a, 0xf2, 0x28, 0x98, 0x87, 0x96, 0x8a, 0x83, 0x0b, 0x03, 0x61, 0x71, 0x99, 0x6b, 0xb5, | |
0x1a, 0x8e, 0xfe, 0x04, 0xe1, 0xf7, 0x7d, 0xdd, 0xed, 0xca, 0x37, 0xfc, 0xef, 0x39, 0x72, 0xda, | |
0xb8, 0xbe, 0xee, 0x7f, 0xe5, 0x31, 0x78, 0xf3, 0x91, 0x9a, 0xd2, 0x11, 0x19, 0xb9, 0x09, 0x4c, | |
0xfd, 0x6d, 0x2a, 0x4d, 0x65, 0xa1, 0x89, 0xc7, 0x75, 0x50, 0x21, 0xfa, 0x16, 0x00, 0xe9, 0x12, | |
0x74, 0x2b, 0x1e, 0x4f, 0x14, 0x01, 0x70, 0x3a, 0x4e, 0x3f, 0xf5, 0xf4, 0x1d, 0x3d, 0x15, 0x27, | |
0xa7, 0xff, 0x45, 0xe0, 0x6e, 0xf9, 0x54, 0xc8, 0x48, 0xad, 0xa5, 0x0a, 0xf6, 0x2d, 0x2c, 0xe2, | |
0x68, 0x67, 0xd6, 0x85, 0xb4, 0xc3, 0x34, 0xbc, 0x62, 0xd3, 0x5f, 0x84, 0x06, 0x5b, 0x0d, 0x95, | |
0xea, 0x5e, 0x9e, 0xd4, 0xeb, 0x90, 0x7a, 0x05, 0x81, 0x57, 0xe8, 0x60, 0x2e, 0x20, 0x25, 0x7c, | |
0x46, 0x0c, 0x93, 0xcb, 0xbd, 0x17, 0x7e, 0xec, 0x79, 0xb2, 0xc2, 0x22, 0x41, 0xb1, 0x10, 0xac, | |
0xa8, 0xbb, 0x9b, 0x82, 0x4b, 0x9c, 0x8b, 0x07, 0x47, 0x35, 0x24, 0x56, 0x8d, 0xaf, 0xe6, 0x26, | |
0x40, 0x38, 0xc4, 0x5d, 0x1b, 0xc5, 0xd1, 0x0f, 0x6c, 0x7b, 0xb0, 0xe3, 0xa3, 0x23, 0x6f, 0x58, | |
0xc1, 0xba, 0xcf, 0xd7, 0xa2, 0xe7, 0xd0, 0x63, 0x5c, 0xf8, 0x73, 0xa0, 0x13, 0xdc, 0x29, 0xcd, | |
0xc9, 0x76, 0xae, 0x8f, 0xe4, 0x59, 0x30, 0xaa, 0x94, 0x1c, 0x3c, 0x0e, 0x55, 0x92, 0x77, 0x32, | |
0xc6, 0xce, 0x18, 0x36, 0xdf, 0xa9, 0x8c, 0xd8, 0xa4, 0xf0, 0x3b, 0x51, 0x4a, 0x02, 0x3e, 0x53 | |
]; | |
const CMC42_TYPE0_T12 = [ | |
0x1f, 0xac, 0x4d, 0xcd, 0xca, 0x70, 0x02, 0x6b, 0x18, 0x40, 0x62, 0xb2, 0x3f, 0x9b, 0x5b, 0xef, | |
0x69, 0x68, 0x71, 0x3b, 0xcb, 0xd4, 0x30, 0xbc, 0x47, 0x72, 0x74, 0x5e, 0x84, 0x4c, 0x1b, 0xdb, | |
0x6a, 0x35, 0x1d, 0xf5, 0xa1, 0xb3, 0x87, 0x5d, 0x57, 0x28, 0x2f, 0xc4, 0xfd, 0x24, 0x26, 0x36, | |
0xad, 0xbe, 0x61, 0x63, 0x73, 0xaa, 0x82, 0xee, 0x29, 0xd0, 0xdf, 0x8c, 0x15, 0xb5, 0x96, 0xf3, | |
0xdd, 0x7e, 0x3a, 0x37, 0x58, 0x7f, 0x0c, 0xfc, 0x0b, 0x07, 0xe8, 0xf7, 0xf4, 0x14, 0xb8, 0x81, | |
0xb6, 0xd7, 0x1e, 0xc8, 0x85, 0xe6, 0x9d, 0x33, 0x60, 0xc5, 0x95, 0xd5, 0x55, 0x00, 0xa3, 0xb7, | |
0x7d, 0x50, 0x0d, 0xd2, 0xc1, 0x12, 0xe5, 0xed, 0xd8, 0xa4, 0x9c, 0x8f, 0x2a, 0x4f, 0xa8, 0x01, | |
0x52, 0x83, 0x65, 0xea, 0x9a, 0x6c, 0x44, 0x4a, 0xe2, 0xa5, 0x2b, 0x46, 0xe1, 0x34, 0x25, 0xf8, | |
0xc3, 0xda, 0xc7, 0x6e, 0x48, 0x38, 0x7c, 0x78, 0x06, 0x53, 0x64, 0x16, 0x98, 0x3c, 0x91, 0x42, | |
0x39, 0xcc, 0xb0, 0xf1, 0xeb, 0x13, 0xbb, 0x05, 0x32, 0x86, 0x0e, 0xa2, 0x0a, 0x9e, 0xfa, 0x66, | |
0x54, 0x8e, 0xd3, 0xe7, 0x19, 0x20, 0x77, 0xec, 0xff, 0xbd, 0x6d, 0x43, 0x23, 0x03, 0xab, 0x75, | |
0x3d, 0xcf, 0xd1, 0xde, 0x92, 0x31, 0xa7, 0x45, 0x4b, 0xc2, 0x97, 0xf9, 0x7a, 0x88, 0xd9, 0x1c, | |
0xe9, 0xe4, 0x10, 0xc9, 0x22, 0x2d, 0x90, 0x76, 0x17, 0x79, 0x04, 0x51, 0x1a, 0x5a, 0x5f, 0x2c, | |
0x21, 0x6f, 0x3e, 0xe0, 0xf0, 0xbf, 0xd6, 0x94, 0x0f, 0x80, 0x11, 0xa0, 0x5c, 0xa9, 0x49, 0x2e, | |
0xce, 0xaf, 0xa6, 0x9f, 0x7b, 0x99, 0xb9, 0xb4, 0xe3, 0xfb, 0xf6, 0x27, 0xf2, 0x93, 0xfe, 0x08, | |
0x67, 0xae, 0x09, 0x89, 0xdc, 0x4e, 0xc6, 0xc0, 0x8a, 0xb1, 0x59, 0x8b, 0x41, 0x56, 0x8d, 0xba | |
]; | |
const CMC42_TYPE1_T03 = [ | |
0xa9, 0x17, 0xaf, 0x0d, 0x34, 0x6e, 0x53, 0xb6, 0x7f, 0x58, 0xe9, 0x14, 0x5f, 0x55, 0xdb, 0xd4, | |
0x42, 0x80, 0x99, 0x59, 0xa8, 0x3a, 0x57, 0x5d, 0xd5, 0x6f, 0x4c, 0x68, 0x35, 0x46, 0xa6, 0xe7, | |
0x7b, 0x71, 0xe0, 0x93, 0xa2, 0x1f, 0x64, 0x21, 0xe3, 0xb1, 0x98, 0x26, 0xab, 0xad, 0xee, 0xe5, | |
0xbb, 0xd9, 0x1e, 0x2e, 0x95, 0x36, 0xef, 0x23, 0x79, 0x45, 0x04, 0xed, 0x13, 0x1d, 0xf4, 0x85, | |
0x96, 0xec, 0xc2, 0x32, 0xaa, 0x7c, 0x15, 0xd8, 0xda, 0x92, 0x90, 0x9d, 0xb7, 0x56, 0x6a, 0x66, | |
0x41, 0xfc, 0x00, 0xf6, 0x50, 0x24, 0xcf, 0xfb, 0x11, 0xfe, 0x82, 0x48, 0x9b, 0x27, 0x1b, 0x67, | |
0x4e, 0x84, 0x69, 0x97, 0x6d, 0x8c, 0xd2, 0xba, 0x74, 0xf9, 0x8f, 0xa5, 0x54, 0x5c, 0xcd, 0x73, | |
0x07, 0xd1, 0x01, 0x09, 0xf1, 0x19, 0x3b, 0x5e, 0x87, 0x30, 0x76, 0xcc, 0xc0, 0x5a, 0xa7, 0x49, | |
0x22, 0xfa, 0x16, 0x02, 0xdf, 0xa4, 0xff, 0xb3, 0x75, 0x33, 0xbd, 0x88, 0x2f, 0xcb, 0x2a, 0x44, | |
0xb8, 0xbf, 0x1c, 0x0f, 0x81, 0x10, 0x43, 0xb4, 0xc8, 0x7e, 0x9a, 0x25, 0xea, 0x83, 0x4b, 0x38, | |
0x7a, 0xd7, 0x3d, 0x1a, 0x4f, 0x62, 0x51, 0xc9, 0x47, 0x0e, 0xce, 0x3f, 0xc7, 0x4d, 0x2c, 0xa1, | |
0x86, 0xb9, 0xc5, 0xca, 0xdd, 0x6b, 0x70, 0x6c, 0x91, 0x9c, 0xbe, 0x0a, 0x9f, 0xf5, 0x94, 0xbc, | |
0x18, 0x2b, 0x60, 0x20, 0x29, 0xf7, 0xf2, 0x28, 0xc4, 0xa0, 0x0b, 0x65, 0xde, 0x8d, 0x78, 0x12, | |
0x3e, 0xd0, 0x77, 0x08, 0x8b, 0xae, 0x05, 0x31, 0x3c, 0xd6, 0xa3, 0x89, 0x06, 0xdc, 0x52, 0x72, | |
0xb0, 0xb5, 0x37, 0xd3, 0xc3, 0x8a, 0xc6, 0xf0, 0xc1, 0x61, 0xfd, 0x4a, 0x5b, 0x7d, 0x9e, 0xf3, | |
0x63, 0x40, 0x2d, 0xe8, 0xb2, 0xe6, 0x39, 0x03, 0xeb, 0x8e, 0xe1, 0x0c, 0xe4, 0xe2, 0xf8, 0xac | |
]; | |
const CMC42_TYPE1_T12 = [ | |
0xea, 0xe6, 0x5e, 0xa7, 0x8e, 0xac, 0x34, 0x03, 0x30, 0x97, 0x52, 0x53, 0x76, 0xf2, 0x62, 0x0b, | |
0x0a, 0xfc, 0x94, 0xb8, 0x67, 0x36, 0x11, 0xbc, 0xae, 0xca, 0xfa, 0x15, 0x04, 0x2b, 0x17, 0xc4, | |
0x3e, 0x5b, 0x59, 0x01, 0x57, 0xe2, 0xba, 0xb7, 0xd1, 0x3f, 0xf0, 0x6a, 0x9c, 0x2a, 0xcb, 0xa9, | |
0xe3, 0x2c, 0xc0, 0x0f, 0x46, 0x91, 0x8a, 0xd0, 0x98, 0xc5, 0xa6, 0x1b, 0x96, 0x29, 0x12, 0x09, | |
0x63, 0xed, 0xe0, 0xa2, 0x86, 0x77, 0xbe, 0xe5, 0x65, 0xdb, 0xbd, 0x50, 0xb3, 0x9d, 0x1a, 0x4e, | |
0x79, 0x0c, 0x00, 0x43, 0xdf, 0x3d, 0x54, 0x33, 0x8f, 0x89, 0xa8, 0x7b, 0xf9, 0xd5, 0x27, 0x82, | |
0xbb, 0xc2, 0x8c, 0x47, 0x88, 0x6b, 0xb4, 0xc3, 0xf8, 0xaa, 0x06, 0x1e, 0x83, 0x7d, 0x05, 0x78, | |
0x85, 0xf6, 0x6e, 0x2e, 0xec, 0x5a, 0x31, 0x45, 0x38, 0x14, 0x16, 0x8b, 0x02, 0xe4, 0x4f, 0xb0, | |
0xbf, 0xab, 0xa4, 0x9e, 0x48, 0x60, 0x19, 0x35, 0x08, 0xde, 0xdd, 0x66, 0x90, 0x51, 0xcc, 0xa3, | |
0xaf, 0x70, 0x9b, 0x75, 0x95, 0x49, 0x6c, 0x64, 0x72, 0x7e, 0x44, 0xa0, 0x73, 0x25, 0x68, 0x55, | |
0x1f, 0x40, 0x7a, 0x74, 0x0e, 0x8d, 0xdc, 0x1c, 0x71, 0xc8, 0xcf, 0xd7, 0xe8, 0xce, 0xeb, 0x32, | |
0x3a, 0xee, 0x07, 0x61, 0x4d, 0xfe, 0x5c, 0x7c, 0x56, 0x2f, 0x2d, 0x5f, 0x6f, 0x9f, 0x81, 0x22, | |
0x58, 0x4b, 0xad, 0xda, 0xb9, 0x10, 0x18, 0x23, 0xe1, 0xf3, 0x6d, 0xe7, 0xe9, 0x28, 0xd6, 0xd8, | |
0xf4, 0x4c, 0x39, 0x21, 0xb2, 0x84, 0xc1, 0x24, 0x26, 0xf1, 0x93, 0x37, 0xc6, 0x4a, 0xcd, 0x20, | |
0xc9, 0xd9, 0xc7, 0xb1, 0xff, 0x99, 0xd4, 0x5d, 0xb5, 0xa1, 0x87, 0x0d, 0x69, 0x92, 0x13, 0x80, | |
0xd2, 0xd3, 0xfd, 0x1d, 0xf5, 0x3b, 0xa5, 0x7f, 0xef, 0x9a, 0xb6, 0x42, 0xfb, 0x3c, 0xf7, 0x41 | |
]; | |
const CMC42_ADDRESS_8_15_XOR1 = [ | |
0x00, 0xb1, 0x1e, 0xc5, 0x3d, 0x40, 0x45, 0x5e, 0xf2, 0xf8, 0x04, 0x63, 0x36, 0x87, 0x88, 0xbf, | |
0xab, 0xcc, 0x78, 0x08, 0xdd, 0x20, 0xd4, 0x35, 0x09, 0x8e, 0x44, 0xae, 0x33, 0xa9, 0x9e, 0xcd, | |
0xb3, 0xe5, 0xad, 0x41, 0xda, 0xbe, 0xf4, 0x16, 0x57, 0x2e, 0x53, 0x67, 0xaf, 0xdb, 0x8a, 0xd8, | |
0x34, 0x17, 0x3c, 0x01, 0x55, 0x73, 0xcf, 0xe3, 0xe8, 0xc7, 0x0d, 0xe9, 0xa3, 0x13, 0x0c, 0xf6, | |
0x90, 0x4e, 0xfb, 0x97, 0x6d, 0x5f, 0xa8, 0x71, 0x11, 0xfc, 0xd1, 0x95, 0x81, 0xba, 0x8c, 0x1b, | |
0x39, 0xfe, 0xa2, 0x15, 0xa6, 0x52, 0x4d, 0x5b, 0x59, 0xa5, 0xe0, 0x96, 0xd9, 0x8f, 0x7b, 0xed, | |
0x29, 0xd3, 0x1f, 0x0e, 0xec, 0x23, 0x0f, 0xb8, 0x6c, 0x6f, 0x7d, 0x18, 0x46, 0xd6, 0xe4, 0xb5, | |
0x9a, 0x79, 0x02, 0xf5, 0x03, 0xc0, 0x60, 0x66, 0x5c, 0x2f, 0x76, 0x85, 0x9d, 0x54, 0x1a, 0x6a, | |
0x28, 0xce, 0x7f, 0x7c, 0x91, 0x99, 0x4c, 0x83, 0x3e, 0xb4, 0x1d, 0x05, 0xc1, 0xc3, 0xd7, 0x47, | |
0xde, 0xbc, 0x62, 0x6e, 0x86, 0x14, 0x80, 0x77, 0xeb, 0xf3, 0x07, 0x31, 0x56, 0xd2, 0xc2, 0xc6, | |
0x6b, 0xdc, 0xfd, 0x22, 0x92, 0xf0, 0x06, 0x51, 0x2d, 0x38, 0xe6, 0xa0, 0x25, 0xdf, 0xd5, 0x2c, | |
0x1c, 0x94, 0x12, 0x9c, 0xb0, 0x9b, 0xc4, 0x0b, 0xc8, 0xd0, 0xf7, 0x30, 0xcb, 0x27, 0xfa, 0x7a, | |
0x10, 0x61, 0xaa, 0xa4, 0x70, 0xb7, 0x2a, 0x5a, 0xc9, 0xf1, 0x0a, 0x49, 0x65, 0xee, 0x69, 0x4b, | |
0x3a, 0x8d, 0x32, 0x5d, 0x68, 0xb9, 0x9f, 0x75, 0x19, 0x3f, 0xac, 0x37, 0x4f, 0xe7, 0x93, 0x89, | |
0x7e, 0x4a, 0x3b, 0xea, 0x74, 0x72, 0x43, 0xbd, 0x24, 0xef, 0xb6, 0xff, 0x64, 0x58, 0x84, 0x8b, | |
0xa7, 0xbb, 0xb2, 0xe1, 0x26, 0x2b, 0x50, 0xca, 0x21, 0xf9, 0x98, 0xa1, 0xe2, 0x42, 0x82, 0x48 | |
]; | |
const CMC42_ADDRESS_8_15_XOR2 = [ | |
0x9b, 0x9d, 0xc1, 0x3d, 0xa9, 0xb8, 0xf4, 0x6f, 0xf6, 0x25, 0xc7, 0x47, 0xd5, 0x97, 0xdf, 0x6b, | |
0xeb, 0x90, 0xa4, 0xb2, 0x5d, 0xf5, 0x66, 0xb0, 0xb9, 0x8b, 0x93, 0x64, 0xec, 0x7b, 0x65, 0x8c, | |
0xf1, 0x43, 0x42, 0x6e, 0x45, 0x9f, 0xb3, 0x35, 0x06, 0x71, 0x96, 0xdb, 0xa0, 0xfb, 0x0b, 0x3a, | |
0x1f, 0xf8, 0x8e, 0x69, 0xcd, 0x26, 0xab, 0x86, 0xa2, 0x0c, 0xbd, 0x63, 0xa5, 0x7a, 0xe7, 0x6a, | |
0x5f, 0x18, 0x9e, 0xbf, 0xad, 0x55, 0xb1, 0x1c, 0x5c, 0x03, 0x30, 0xc6, 0x37, 0x20, 0xe3, 0xc9, | |
0x52, 0xe8, 0xee, 0x4f, 0x01, 0x70, 0xc4, 0x77, 0x29, 0x2a, 0xba, 0x53, 0x12, 0x04, 0x7d, 0xaf, | |
0x33, 0x8f, 0xa8, 0x4d, 0xaa, 0x5b, 0xb4, 0x0f, 0x92, 0xbb, 0xed, 0xe1, 0x2f, 0x50, 0x6c, 0xd2, | |
0x2c, 0x95, 0xd9, 0xf9, 0x98, 0xc3, 0x76, 0x4c, 0xf2, 0xe4, 0xe5, 0x2b, 0xef, 0x9c, 0x49, 0xb6, | |
0x31, 0x3b, 0xbc, 0xa1, 0xca, 0xde, 0x62, 0x74, 0xea, 0x81, 0x00, 0xdd, 0xa6, 0x46, 0x88, 0x3f, | |
0x39, 0xd6, 0x23, 0x54, 0x24, 0x4a, 0xd8, 0xdc, 0xd7, 0xd1, 0xcc, 0xbe, 0x57, 0x7c, 0xda, 0x44, | |
0x61, 0xce, 0xd3, 0xd4, 0xe9, 0x28, 0x80, 0xe0, 0x56, 0x8a, 0x09, 0x05, 0x9a, 0x89, 0x1b, 0xf7, | |
0xf3, 0x99, 0x6d, 0x5e, 0x48, 0x91, 0xc0, 0xd0, 0xc5, 0x79, 0x78, 0x41, 0x59, 0x21, 0x2e, 0xff, | |
0xc2, 0x4b, 0x38, 0x83, 0x32, 0xe6, 0xe2, 0x7f, 0x1e, 0x17, 0x58, 0x1d, 0x1a, 0xfa, 0x85, 0x82, | |
0x94, 0xc8, 0x72, 0x7e, 0xb7, 0xac, 0x0e, 0xfc, 0xfd, 0x16, 0x27, 0x75, 0x8d, 0xcb, 0x08, 0xfe, | |
0x0a, 0x02, 0x0d, 0x36, 0x11, 0x22, 0x84, 0x40, 0x34, 0x3e, 0x2d, 0x68, 0x5a, 0xa7, 0x67, 0xae, | |
0x87, 0x07, 0x10, 0x60, 0x14, 0x73, 0x3c, 0x51, 0x19, 0xa3, 0xb5, 0xcf, 0x13, 0xf0, 0x15, 0x4e | |
]; | |
const CMC42_ADDRESS_16_23_XOR1 = [ | |
0x00, 0x5f, 0x03, 0x52, 0xce, 0xe3, 0x7d, 0x8f, 0x6b, 0xf8, 0x20, 0xde, 0x7b, 0x7e, 0x39, 0xbe, | |
0xf5, 0x94, 0x18, 0x78, 0x80, 0xc9, 0x7f, 0x7a, 0x3e, 0x63, 0xf2, 0xe0, 0x4e, 0xf7, 0x87, 0x27, | |
0x69, 0x6c, 0xa4, 0x1d, 0x85, 0x5b, 0xe6, 0x44, 0x25, 0x0c, 0x98, 0xc7, 0x01, 0x02, 0xa3, 0x26, | |
0x09, 0x38, 0xdb, 0xc3, 0x1e, 0xcf, 0x23, 0x45, 0x68, 0x76, 0xd6, 0x22, 0x5d, 0x5a, 0xae, 0x16, | |
0x9f, 0xa2, 0xb5, 0xcd, 0x81, 0xea, 0x5e, 0xb8, 0xb9, 0x9d, 0x9c, 0x1a, 0x0f, 0xff, 0xe1, 0xe7, | |
0x74, 0xaa, 0xd4, 0xaf, 0xfc, 0xc6, 0x33, 0x29, 0x5c, 0xab, 0x95, 0xf0, 0x19, 0x47, 0x59, 0x67, | |
0xf3, 0x96, 0x60, 0x1f, 0x62, 0x92, 0xbd, 0x89, 0xee, 0x28, 0x13, 0x06, 0xfe, 0xfa, 0x32, 0x6d, | |
0x57, 0x3c, 0x54, 0x50, 0x2c, 0x58, 0x49, 0xfb, 0x17, 0xcc, 0xef, 0xb2, 0xb4, 0xf9, 0x07, 0x70, | |
0xc5, 0xa9, 0xdf, 0xd5, 0x3b, 0x86, 0x2b, 0x0d, 0x6e, 0x4d, 0x0a, 0x90, 0x43, 0x31, 0xc1, 0xf6, | |
0x88, 0x0b, 0xda, 0x53, 0x14, 0xdc, 0x75, 0x8e, 0xb0, 0xeb, 0x99, 0x46, 0xa1, 0x15, 0x71, 0xc8, | |
0xe9, 0x3f, 0x4a, 0xd9, 0x73, 0xe5, 0x7c, 0x30, 0x77, 0xd3, 0xb3, 0x4b, 0x37, 0x72, 0xc2, 0x04, | |
0x97, 0x08, 0x36, 0xb1, 0x3a, 0x61, 0xec, 0xe2, 0x1c, 0x9a, 0x8b, 0xd1, 0x1b, 0x2e, 0x9e, 0x8a, | |
0xd8, 0x41, 0xe4, 0xc4, 0x40, 0x2f, 0xad, 0xc0, 0xb6, 0x84, 0x51, 0x66, 0xbb, 0x12, 0xe8, 0xdd, | |
0xcb, 0xbc, 0x6f, 0xd0, 0x11, 0x83, 0x56, 0x4c, 0xca, 0xbf, 0x05, 0x10, 0xd7, 0xba, 0xfd, 0xed, | |
0x8c, 0x0e, 0x4f, 0x3d, 0x35, 0x91, 0xb7, 0xac, 0x34, 0x64, 0x2a, 0xf1, 0x79, 0x6a, 0x9b, 0x2d, | |
0x65, 0xf4, 0x42, 0xa0, 0x8d, 0xa7, 0x48, 0x55, 0x21, 0x93, 0x24, 0xd2, 0xa6, 0xa5, 0xa8, 0x82 | |
]; | |
const CMC42_ADDRESS_16_23_XOR2 = [ | |
0x29, 0x97, 0x1a, 0x2c, 0x0b, 0x94, 0x3e, 0x75, 0x01, 0x0d, 0x1b, 0xe1, 0x4d, 0x38, 0x39, 0x8f, | |
0xe7, 0xd0, 0x60, 0x90, 0xb2, 0x0f, 0xbb, 0x70, 0x1f, 0xe6, 0x5b, 0x87, 0xb4, 0x43, 0xfd, 0xf5, | |
0xf6, 0xf9, 0xad, 0xc0, 0x98, 0x17, 0x9f, 0x91, 0x15, 0x51, 0x55, 0x64, 0x6c, 0x18, 0x61, 0x0e, | |
0xd9, 0x93, 0xab, 0xd6, 0x24, 0x2f, 0x6a, 0x3a, 0x22, 0xb1, 0x4f, 0xaa, 0x23, 0x48, 0xed, 0xb9, | |
0x88, 0x8b, 0xa3, 0x6b, 0x26, 0x4c, 0xe8, 0x2d, 0x1c, 0x99, 0xbd, 0x5c, 0x58, 0x08, 0x50, 0xf2, | |
0x2a, 0x62, 0xc1, 0x72, 0x66, 0x04, 0x10, 0x37, 0x6e, 0xfc, 0x44, 0xa9, 0xdf, 0xd4, 0x20, 0xdd, | |
0xee, 0x41, 0xdb, 0x73, 0xde, 0x54, 0xec, 0xc9, 0xf3, 0x4b, 0x2e, 0xae, 0x5a, 0x4a, 0x5e, 0x47, | |
0x07, 0x2b, 0x76, 0xa4, 0xe3, 0x28, 0xfe, 0xb0, 0xf0, 0x02, 0x06, 0xd1, 0xaf, 0x42, 0xc2, 0xa5, | |
0xe0, 0x67, 0xbf, 0x16, 0x8e, 0x35, 0xce, 0x8a, 0xe5, 0x3d, 0x7b, 0x96, 0xd7, 0x79, 0x52, 0x1e, | |
0xa1, 0xfb, 0x9b, 0xbe, 0x21, 0x9c, 0xe9, 0x56, 0x14, 0x7f, 0xa0, 0xe4, 0xc3, 0xc4, 0x46, 0xea, | |
0xf7, 0xd2, 0x1d, 0x31, 0x0a, 0x5f, 0xeb, 0xa2, 0x68, 0x8d, 0xb5, 0xc5, 0x74, 0x0c, 0xdc, 0x82, | |
0x80, 0x09, 0x19, 0x95, 0x71, 0x9a, 0x11, 0x57, 0x77, 0x4e, 0xc6, 0xff, 0x12, 0x03, 0xa7, 0xc7, | |
0xf4, 0xc8, 0xb6, 0x7a, 0x59, 0x36, 0x3c, 0x53, 0xe2, 0x69, 0x8c, 0x25, 0x05, 0x45, 0x63, 0xf8, | |
0x34, 0x89, 0x33, 0x3f, 0x85, 0x27, 0xbc, 0x65, 0xfa, 0xa8, 0x6d, 0x84, 0x5d, 0xba, 0x40, 0x32, | |
0x30, 0xef, 0x83, 0x13, 0xa6, 0x78, 0xcc, 0x81, 0x9e, 0xda, 0xca, 0xd3, 0x7e, 0x9d, 0x6f, 0xcd, | |
0xb7, 0xb3, 0xd8, 0xcf, 0x3b, 0x00, 0x92, 0xb8, 0x86, 0xac, 0x49, 0x7c, 0xf1, 0xd5, 0xcb, 0x7d | |
]; | |
const CMC42_ADDRESS_0_7_XOR = [ | |
0x74, 0xad, 0x5d, 0x1d, 0x9e, 0xc3, 0xfa, 0x4e, 0xf7, 0xdb, 0xca, 0xa2, 0x64, 0x36, 0x56, 0x0c, | |
0x4f, 0xcf, 0x43, 0x66, 0x1e, 0x91, 0xe3, 0xa5, 0x58, 0xc2, 0xc1, 0xd4, 0xb9, 0xdd, 0x76, 0x16, | |
0xce, 0x61, 0x75, 0x01, 0x2b, 0x22, 0x38, 0x55, 0x50, 0xef, 0x6c, 0x99, 0x05, 0xe9, 0xe8, 0xe0, | |
0x2d, 0xa4, 0x4b, 0x4a, 0x42, 0xae, 0xba, 0x8c, 0x6f, 0x93, 0x14, 0xbd, 0x71, 0x21, 0xb0, 0x02, | |
0x15, 0xc4, 0xe6, 0x60, 0xd7, 0x44, 0xfd, 0x85, 0x7e, 0x78, 0x8f, 0x00, 0x81, 0xf1, 0xa7, 0x3b, | |
0xa0, 0x10, 0xf4, 0x9f, 0x39, 0x88, 0x35, 0x62, 0xcb, 0x19, 0x31, 0x11, 0x51, 0xfb, 0x2a, 0x20, | |
0x45, 0xd3, 0x7d, 0x92, 0x1b, 0xf2, 0x09, 0x0d, 0x97, 0xa9, 0xb5, 0x3c, 0xee, 0x5c, 0xaf, 0x7b, | |
0xd2, 0x3a, 0x49, 0x8e, 0xb6, 0xcd, 0xd9, 0xde, 0x8a, 0x29, 0x6e, 0xd8, 0x0b, 0xe1, 0x69, 0x87, | |
0x1a, 0x96, 0x18, 0xcc, 0xdf, 0xe7, 0xc5, 0xc7, 0xf8, 0x52, 0xc9, 0xf0, 0xb7, 0xe5, 0x33, 0xda, | |
0x67, 0x9d, 0xa3, 0x03, 0x0e, 0x72, 0x26, 0x79, 0xe2, 0xb8, 0xfc, 0xaa, 0xfe, 0xb4, 0x86, 0xc8, | |
0xd1, 0xbc, 0x12, 0x08, 0x77, 0xeb, 0x40, 0x8d, 0x04, 0x25, 0x4d, 0x5a, 0x6a, 0x7a, 0x2e, 0x41, | |
0x65, 0x1c, 0x13, 0x94, 0xb2, 0x63, 0x28, 0x59, 0x5e, 0x9a, 0x30, 0x07, 0xc6, 0xbf, 0x17, 0xf5, | |
0x0f, 0x89, 0xf3, 0x1f, 0xea, 0x6d, 0xb3, 0xc0, 0x70, 0x47, 0xf9, 0x53, 0xf6, 0xd6, 0x54, 0xed, | |
0x6b, 0x4c, 0xe4, 0x8b, 0x83, 0x24, 0x90, 0xb1, 0x7c, 0xbb, 0x73, 0xab, 0xd5, 0x2f, 0x5f, 0xec, | |
0x9c, 0x2c, 0xa8, 0x34, 0x46, 0x37, 0x27, 0xa1, 0x0a, 0x06, 0x80, 0x68, 0x82, 0x32, 0x84, 0xff, | |
0x48, 0xac, 0x7f, 0x3f, 0x95, 0xdc, 0x98, 0x9b, 0xbe, 0x23, 0x57, 0x3e, 0x5b, 0xd0, 0x3d, 0xa6 | |
]; | |
function encrypt(src, dst, pos0, pos1, | |
table0hi, table0lo, table1, base, invert, address_0_7_xor) | |
{ | |
const tmp = table1[(base & 0xff) ^ address_0_7_xor[(base >> 8) & 0xff]]; | |
const xor0 = (table0hi[(base >> 8) & 0xff] & 0xfe) | (tmp & 0x01); | |
const xor1 = (tmp & 0xfe) | (table0lo[(base >> 8) & 0xff] & 0x01); | |
if (invert) { | |
dst[pos1] = src[pos0] ^ xor0; | |
dst[pos0] = src[pos1] ^ xor1; | |
} | |
else { | |
dst[pos0] = src[pos0] ^ xor0; | |
dst[pos1] = src[pos1] ^ xor1; | |
} | |
} | |
function gfx_encrypt(rom, extra_xor, | |
type0_t03, type0_t12, type1_t03, type1_t12, | |
address_8_15_xor1, address_8_15_xor2, | |
address_16_23_xor1, address_16_23_xor2, | |
address_0_7_xor) | |
{ | |
const buf = Buffer.allocUnsafe(rom.length); | |
for (let rpos = 0; rpos < rom.length/4; rpos++) { | |
let baser = rpos; | |
baser ^= extra_xor; | |
baser ^= address_8_15_xor1[(baser >> 16) & 0xff] << 8; | |
baser ^= address_8_15_xor2[baser & 0xff] << 8; | |
baser ^= address_16_23_xor1[baser & 0xff] << 16; | |
baser ^= address_16_23_xor2[(baser >> 8) & 0xff] << 16; | |
baser ^= address_0_7_xor[(baser >> 8) & 0xff]; | |
baser &= (rom.length/4)-1; | |
buf[4*baser+0] = rom[4*rpos+0]; | |
buf[4*baser+1] = rom[4*rpos+1]; | |
buf[4*baser+2] = rom[4*rpos+2]; | |
buf[4*baser+3] = rom[4*rpos+3]; | |
} | |
for (let rpos = 0; rpos < rom.length/4; rpos++) { | |
encrypt(buf, rom, 4*rpos+0, 4*rpos+3, | |
type0_t03, type0_t12, type1_t03, rpos, (rpos>>8) & 1, | |
address_0_7_xor); | |
encrypt(buf, rom, 4*rpos+1, 4*rpos+2, | |
type0_t12, type0_t03, type1_t12, rpos, | |
((rpos>>16) ^ address_16_23_xor2[(rpos>>8) & 0xff]) & 1, | |
address_0_7_xor); | |
} | |
} | |
function cmc42_gfx_encrypt(rom, extra_xor) | |
{ | |
gfx_encrypt( | |
rom, extra_xor, | |
CMC42_TYPE0_T03, CMC42_TYPE0_T12, CMC42_TYPE1_T03, CMC42_TYPE1_T12, | |
CMC42_ADDRESS_8_15_XOR1, CMC42_ADDRESS_8_15_XOR2, | |
CMC42_ADDRESS_16_23_XOR1, CMC42_ADDRESS_16_23_XOR2, | |
CMC42_ADDRESS_0_7_XOR | |
); | |
} | |
return { | |
deoptimize_sprites: deoptimize_sprites, | |
sfix_reorder: sfix_reorder, | |
MSLUG3_GFX_KEY: MSLUG3_GFX_KEY, | |
mslug3_encrypt_68k: mslug3_encrypt_68k, | |
cmc42_gfx_encrypt: cmc42_gfx_encrypt | |
}; | |
})(); | |
// from https://github.com/mamedev/mame/blob/32f4e130ee99038854786024acc3e0871a4f7d0c/src/mame/drivers/ddragon.cpp | |
// license:BSD-3-Clause | |
// copyright-holders:Philip Bennett,Carlos A. Lozano, Rob Rosenbrock, Phil Stroffolino, Ernesto Corvi, David Haywood, R. Belmont | |
const DDRAGON_CHAR_LAYOUT = { | |
width: 8, | |
height: 8, | |
total: [1,1], | |
planes: 4, | |
planeoffset: [0, 2, 4, 6], | |
xoffset: [1, 0, 8*8+1, 8*8+0, 16*8+1, 16*8+0, 24*8+1, 24*8+0], | |
yoffset: [0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8], | |
charincrement: 32*8 | |
}; | |
const DDRAGON_TILE_LAYOUT = { | |
width: 16, | |
height: 16, | |
total: [1,2], | |
planes: 4, | |
planeoffset: [[1,2,0], [1,2,4], 0, 4], | |
xoffset: [3, 2, 1, 0, 16*8+3, 16*8+2, 16*8+1, 16*8+0, | |
32*8+3, 32*8+2, 32*8+1, 32*8+0, 48*8+3, 48*8+2, 48*8+1, 48*8+0], | |
yoffset: [0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8, | |
8*8, 9*8, 10*8, 11*8, 12*8, 13*8, 14*8, 15*8], | |
charincrement: 64*8 | |
}; | |
// from https://github.com/mamedev/mame/blob/b888b8c4edaeccea889b97e1c2df6f914ae6e303/src/mame/drivers/ddragon3.cpp | |
// license:BSD-3-Clause | |
// copyright-holders:Bryan McPhail, David Haywood | |
const WWF_TILE_LAYOUT = { | |
width: 16, | |
height: 16, | |
total: [1,2], | |
planes: 4, | |
planeoffset: [8, 0, [1,2,8], [1,2,0]], | |
xoffset: [0, 1, 2, 3, 4, 5, 6, 7, | |
32*8+0, 32*8+1, 32*8+2, 32*8+3, 32*8+4, 32*8+5, 32*8+6, 32*8+7], | |
yoffset: [0*16, 1*16, 2*16, 3*16, 4*16, 5*16, 6*16, 7*16, | |
16*8, 16*9, 16*10, 16*11, 16*12, 16*13, 16*14, 16*15], | |
charincrement: 64*8 | |
}; | |
const WWF_SPRITE_LAYOUT = { | |
width: 16, | |
height: 16, | |
total: [1,4], | |
planes: 4, | |
planeoffset: [[0,4], [1,4], [2,4], [3,4]], | |
xoffset: [0, 1, 2, 3, 4, 5, 6, 7, | |
16*8+0, 16*8+1, 16*8+2, 16*8+3, 16*8+4, 16*8+5, 16*8+6, 16*8+7], | |
yoffset: [0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8, | |
8*8, 9*8, 10*8, 11*8, 12*8, 13*8, 14*8, 15*8], | |
charincrement: 32*8 | |
}; | |
// from https://github.com/mamedev/mame/blob/6c23897483a0201dd0b65b450253fd9bf8fb8723/src/mame/drivers/m72.cpp | |
// license:BSD-3-Clause | |
// copyright-holders:Nicola Salmoria | |
const M72_TILE_LAYOUT = { | |
width: 8, | |
height: 8, | |
total: [1,4], | |
planes: 4, | |
planeoffset: [[3,4], [2,4], [1,4], [0,4]], | |
xoffset: [0, 1, 2, 3, 4, 5, 6, 7], | |
yoffset: [0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8], | |
charincrement: 8*8 | |
}; | |
const M72_SPRITE_LAYOUT = { | |
width: 16, | |
height: 16, | |
total: [1,4], | |
planes: 4, | |
planeoffset: [[3,4], [2,4], [1,4], [0,4]], | |
xoffset: [0, 1, 2, 3, 4, 5, 6, 7, | |
16*8+0, 16*8+1, 16*8+2, 16*8+3, 16*8+4, 16*8+5, 16*8+6, 16*8+7], | |
yoffset: [0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8, | |
8*8, 9*8, 10*8, 11*8, 12*8, 13*8, 14*8, 15*8], | |
charincrement: 32*8 | |
}; | |
// from https://github.com/mamedev/mame/blob/27600407666e5222233ae298c88c9da181266937/src/mame/drivers/vigilant.cpp | |
// license:BSD-3-Clause | |
// copyright-holders:Mike Balfour | |
const VIGILANT_TEXT_LAYOUT = { | |
width: 8, | |
height: 8, | |
total: [1,2], | |
planes: 4, | |
planeoffset: [[1,2], [1,2,4], 0, 4], | |
xoffset: [0,1,2,3, 64+0,64+1,64+2,64+3], | |
yoffset: [0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8], | |
charincrement: 128 | |
}; | |
const VIGILANT_SPRITE_LAYOUT = { | |
width: 16, | |
height: 16, | |
total: [1,2], | |
planes: 4, | |
planeoffset: [[1,2], [1,2,4], 0, 4], | |
xoffset: [ | |
0x00*8+0,0x00*8+1,0x00*8+2,0x00*8+3, | |
0x10*8+0,0x10*8+1,0x10*8+2,0x10*8+3, | |
0x20*8+0,0x20*8+1,0x20*8+2,0x20*8+3, | |
0x30*8+0,0x30*8+1,0x30*8+2,0x30*8+3 | |
], | |
yoffset: [ | |
0x00*8, 0x01*8, 0x02*8, 0x03*8, | |
0x04*8, 0x05*8, 0x06*8, 0x07*8, | |
0x08*8, 0x09*8, 0x0A*8, 0x0B*8, | |
0x0C*8, 0x0D*8, 0x0E*8, 0x0F*8 | |
], | |
charincrement: 0x40*8 | |
}; | |
const VIGILANT_BACK_LAYOUT = { | |
width: 32, | |
height: 1, | |
total: [1,1], | |
planes: 4, | |
planeoffset: [0,2,4,6], | |
xoffset: [ | |
0*8+1, 0*8, 1*8+1, 1*8, 2*8+1, 2*8, 3*8+1, 3*8, 4*8+1, 4*8, 5*8+1, 5*8, | |
6*8+1,6*8, 7*8+1,7*8, 8*8+1,8*8, 9*8+1,9*8, 10*8+1,10*8, 11*8+1,11*8, | |
12*8+1, 12*8, 13*8+1, 13*8, 14*8+1, 14*8, 15*8+1, 15*8 | |
], | |
yoffset: [0], | |
charincrement: 16*8 | |
}; | |
// from https://github.com/mamedev/mame/blob/b888b8c4edaeccea889b97e1c2df6f914ae6e303/src/mame/drivers/raiden.cpp | |
// license:BSD-3-Clause | |
// copyright-holders:Bryan McPhail | |
// thanks-to:Oliver Bergmann,Randy Mongenel (for initial CPU core) | |
const RAIDEN_SPRITE_LAYOUT = { | |
width: 16, | |
height: 16, | |
total: 4096, | |
planes: 4, | |
planeoffset: [12, 8, 4, 0], | |
xoffset: [0,1,2,3, 16,17,18,19, | |
512+0,512+1,512+2,512+3, 512+8+8,512+9+8,512+10+8,512+11+8], | |
yoffset: [0*32, 1*32, 2*32, 3*32, 4*32, 5*32, 6*32, 7*32, | |
8*32, 9*32, 10*32, 11*32, 12*32, 13*32, 14*32, 15*32], | |
charincrement: 1024 | |
}; | |
// from https://github.com/mamedev/mame/blob/6c23897483a0201dd0b65b450253fd9bf8fb8723/src/mame/drivers/seibuspi.cpp | |
// license:BSD-3-Clause | |
// copyright-holders:Ville Linde, hap, Nicola Salmoria | |
const SPI_CHAR_LAYOUT = { | |
width: 8, | |
height: 8, | |
total: 4096, | |
planes: 6, | |
planeoffset: [0, 4, 8, 12, 16, 20], | |
xoffset: [3, 2, 1, 0, 27, 26, 25, 24], | |
yoffset: [0*48, 1*48, 2*48, 3*48, 4*48, 5*48, 6*48, 7*48], | |
charincrement: 6*8*8 | |
}; | |
const SPI_TILE_LAYOUT = { | |
width: 16, | |
height: 16, | |
total: [1,1], | |
planes: 6, | |
planeoffset: [0, 4, 8, 12, 16, 20], | |
xoffset: [3, 2, 1, 0, 27,26,25,24, 51,50,49,48, 75,74,73,72], | |
yoffset: [0*96, 1*96, 2*96, 3*96, 4*96, 5*96, 6*96, 7*96, | |
8*96, 9*96, 10*96, 11*96, 12*96, 13*96, 14*96, 15*96], | |
charincrement: 6*16*16 | |
}; | |
const SPI_SPRITE_LAYOUT = { | |
width: 16, | |
height: 16, | |
total: [1,3], | |
planes: 6, | |
planeoffset: [0,8,[1,3,0],[1,3,8],[2,3,0],[2,3,8]], | |
xoffset: [7,6,5,4,3,2,1,0,23,22,21,20,19,18,17,16], | |
yoffset: [0*32,1*32,2*32,3*32,4*32,5*32,6*32,7*32, | |
8*32,9*32,10*32,11*32,12*32,13*32,14*32,15*32], | |
charincrement: 16*32 | |
}; | |
function ddragon(srcdir) | |
{ | |
convert_roms('ddragon', srcdir, { | |
maincpu: { | |
input: 'ddragon_hd6309.bin', | |
output: ['21j-1-5.26', '21j-2-3.25', '21j-3.24', '21j-4-1.23'] | |
}, | |
sub: { input: 'ddragon_hd63701.bin', output: '21jm-0.ic55' }, | |
soundcpu: { input: 'ddragon_m6809.bin', output: '21j-0-1' }, | |
gfx1: { | |
input: { | |
file: 'ddragon_gfxdata1.bin', layout: DDRAGON_CHAR_LAYOUT | |
}, | |
output: '21j-5' | |
}, | |
gfx2: { | |
input: { | |
file: 'ddragon_gfxdata2.bin', layout: DDRAGON_TILE_LAYOUT | |
}, | |
output: ['21j-a', '21j-b', '21j-c', '21j-d', | |
'21j-e', '21j-f', '21j-g', '21j-h'] | |
}, | |
gfx3: { | |
input: { | |
file: 'ddragon_gfxdata3.bin', layout: DDRAGON_TILE_LAYOUT | |
}, | |
output: ['21j-8', '21j-9', '21j-i', '21j-j'] | |
}, | |
adpcm: { input: 'ddragon_adpcm.bin', output: ['21j-6', '21j-7'] }, | |
proms: { | |
input: 'proms.bin', output: ['21j-k-0', '21j-l-0'], | |
transform: bin => split_at(bin, 0x100) | |
} | |
}); | |
} | |
function ddragon2(srcdir) | |
{ | |
convert_roms('ddragon2', srcdir, { | |
maincpu: { | |
input: 'ddragon2_hd6309.bin', | |
output: ['26a9-04.bin', '26aa-03.bin', '26ab-0.bin', '26ac-0e.63'] | |
}, | |
sub: { input: 'ddragon2_z80sub.bin', output: '26ae-0.bin' }, | |
soundcpu: { input: 'ddragon2_z80sound.bin', output: '26ad-0.bin' }, | |
gfx1: { | |
input: { | |
file: 'ddragon2_gfxdata1.bin', layout: DDRAGON_CHAR_LAYOUT | |
}, | |
output: '26a8-0e.19' | |
}, | |
gfx2: { | |
input: { | |
file: 'ddragon2_gfxdata2.bin', layout: DDRAGON_TILE_LAYOUT | |
}, | |
output: ['26j0-0.bin', '26j1-0.bin', '26af-0.bin', | |
'26j2-0.bin', '26j3-0.bin', '26j10-0.bin'] | |
}, | |
gfx3: { | |
input: { | |
file: 'ddragon2_gfxdata3.bin', layout: DDRAGON_TILE_LAYOUT | |
}, | |
output: ['26j4-0.bin', '26j5-0.bin'] | |
}, | |
oki: { | |
input: 'ddragon2_oki.bin', output: ['26j6-0.bin', '26j7-0.bin'] | |
}, | |
proms: { | |
input: 'proms.bin', output: 'prom.16', | |
transform: bin => bin.slice(0x100) | |
} | |
}); | |
} | |
function ddragon3_mame2000(srcdir) | |
{ | |
convert_roms('ddragon3', srcdir, { | |
cpu1: { | |
input: 'ddragon3_m68k.bin', output: ['30a14', '30a15'], | |
transform: bin => { | |
const a = interleave(bin); | |
return [a[1], a[0].slice(0, 0x20000)]; | |
} | |
}, | |
cpu2: { input: 'ddragon3_z80.bin', output: 'dd3.06' }, | |
gfx1: { | |
input: { file: 'ddragon3_gfxdata1.bin', layout: WWF_TILE_LAYOUT }, | |
output: ['dd3.e', 'dd3.a', 'dd3.f', 'dd3.b'], | |
transform: bin => interleave(bin).flatMap(b => split_at(b, 0x40000)) | |
}, | |
gfx2: { | |
input: { file: 'ddragon3_gfxdata2.bin', layout: WWF_SPRITE_LAYOUT}, | |
output: ['dd3.3e', 'dd3.3d', 'dd3.3c', 'dd3.3b', 'dd3.3a', | |
'dd3.2e', 'dd3.2d', 'dd3.2c', 'dd3.2b', 'dd3.2a', | |
'dd3.1e', 'dd3.1d', 'dd3.1c', 'dd3.1b', 'dd3.1a', | |
'dd3.0e', 'dd3.0d', 'dd3.0c', 'dd3.0b', 'dd3.0a'], | |
transform: bin => | |
split(bin, 0x90000).flatMap(b => split(b, 0x20000)) | |
}, | |
sound1: { input: 'ddragon3_oki.bin', output: ['dd3.j7', 'dd3.j8'] } | |
}); | |
} | |
function ddragon3(srcdir) | |
{ | |
convert_roms('ddragon3', srcdir, { | |
maincpu: { | |
input: 'ddragon3_m68k.bin', | |
output: ['30a15-0.ic79', '30a14-0.ic78'], | |
transform: bin => { | |
const a = interleave(bin); | |
return [a[0].slice(0, 0x20000), a[1]]; | |
} | |
}, | |
audiocpu: { input: 'ddragon3_z80.bin', output: '30a13-0.ic43' }, | |
gfx1: { | |
input: { file: 'ddragon3_gfxdata1.bin', layout: WWF_TILE_LAYOUT }, | |
output: ['30j-6.ic5', '30j-4.ic7', '30j-7.ic4', '30j-5.ic6'], | |
transform: bin => interleave(bin).flatMap(b => split_at(b, 0x40000)) | |
}, | |
gfx2: { | |
input: { file: 'ddragon3_gfxdata2.bin', layout: WWF_SPRITE_LAYOUT}, | |
output: ['30j-3.ic9', '30a12-0.ic8', '30j-2.ic11', '30a11-0.ic10', | |
'30j-1.ic13', '30a10-0.ic12', '30j-0.ic15', '30a9-0.ic14'], | |
transform: bin => | |
split(bin, 0x90000).flatMap(b => split_at(b, 0x80000)) | |
}, | |
oki: { input: 'ddragon3_oki.bin', output: '30j-8.ic73' }, | |
// missing | |
proms: { input: Buffer.alloc(0x100), output: 'mb7114h.ic38' } | |
}); | |
} | |
function rtype(srcdir) | |
{ | |
convert_roms('rtype', srcdir, { | |
maincpu: { | |
input: 'RTYPE_CPU.BIN', | |
output: ['rt_r-l0-b.3b', 'rt_r-l1-b.3c', | |
'rt_r-h0-b.1b', 'rt_r-h1-b.1c'], | |
transform: bin => | |
interleave(bin).flatMap(b => split(b, 0x10000).slice(0, 2)) | |
}, | |
sprites: { | |
input: { file: 'RTYPE_GFXDATA1.BIN', layout: M72_SPRITE_LAYOUT }, | |
output: ['rt_r-00.1h', 'rt_r-01.1j', 'rt_r-10.1k', 'rt_r-11.1l', | |
'rt_r-20.3h', 'rt_r-21.3j', 'rt_r-30.3k', 'rt_r-31.3l'], | |
transform: bin => | |
split(bin, 0x10000).map((b, i) => | |
i % 2 == 0 ? b : b.slice(0, 0x08000)) | |
}, | |
gfx2: { | |
input: { file: 'RTYPE_GFXDATA2.BIN', layout: M72_TILE_LAYOUT }, | |
output: ['rt_b-a0.3c', 'rt_b-a1.3d', 'rt_b-a2.3a', 'rt_b-a3.3e'] | |
}, | |
gfx3: { | |
input: { file: 'RTYPE_GFXDATA3.BIN', layout: M72_TILE_LAYOUT }, | |
output: ['rt_b-b0.3j', 'rt_b-b1.3k', 'rt_b-b2.3h', 'rt_b-b3.3f'] | |
} | |
}); | |
} | |
function rtype2(srcdir) | |
{ | |
convert_roms('rtype2', srcdir, { | |
maincpu: { | |
input: 'RTYPE2_CPU1.BIN', | |
output: ['rt2-a-l0-d.60', 'rt2-a-l1-d.59', | |
'rt2-a-h0-d.54', 'rt2-a-h1-d.53'], | |
transform: bin => | |
interleave(bin).flatMap(b => split(b, 0x20000).slice(0, 2)) | |
}, | |
soundcpu: { input: 'RTYPE2_CPU2.BIN', output: 'ic17.4f' }, | |
sprites: { | |
input: 'RTYPE2_GFX1.BIN', | |
output: ['ic31.6l', 'ic21.4l', 'ic32.6m', 'ic22.4m'] | |
}, | |
gfx2: { | |
input: 'RTYPE2_GFX2.BIN', | |
output: ['ic50.7s', 'ic51.7u', 'ic56.8s', 'ic57.8u', | |
'ic65.9r', 'ic66.9u', 'ic63.9m', 'ic64.9p'] | |
}, | |
samples: { input: 'RTYPE2_SAMPLES.BIN', output: 'ic14.4c' } | |
}); | |
} | |
function airduelm72(srcdir) | |
{ | |
convert_roms('airduelm72', srcdir, { | |
maincpu: { | |
input: 'AIRDUEL_CPU.BIN', | |
output: ['ad-c-l0.bin', 'ad-c-l3.bin', | |
'ad-c-h0.bin', 'ad-c-h3.bin'], | |
transform: bin => | |
interleave(bin.slice(0, 0x80000)) | |
.flatMap(b => split(b, 0x20000)) | |
}, | |
sprites: { | |
input: 'AIRDUEL_GFX1.BIN', | |
output: ['ad-00.bin', 'ad-10.bin', 'ad-20.bin', 'ad-30.bin'] | |
}, | |
gfx2: { | |
input: 'AIRDUEL_GFX2.BIN', | |
output: ['ad-a0.bin', 'ad-a1.bin', 'ad-a2.bin', 'ad-a3.bin'] | |
}, | |
gfx3: { | |
input: 'AIRDUEL_GFX3.BIN', | |
output: ['ad-b0.bin', 'ad-b1.bin', 'ad-b2.bin', 'ad-b3.bin'] | |
}, | |
samples: { input: 'AIRDUEL_SAMPLES.BIN', output: 'ad-v0.bin' } | |
}); | |
} | |
function bchopper(srcdir) | |
{ | |
convert_roms('bchopper', srcdir, { | |
maincpu: { | |
input: 'BCHOPPER_CPU.BIN', | |
output: ['c-l0-b.rom', 'c-l1-b.rom', 'c-l3-b.rom', | |
'c-h0-b.rom', 'c-h1-b.rom', 'c-h3-b.rom'], | |
transform: bin => | |
interleave(bin).flatMap(b => { | |
var a = split(b, 0x10000); | |
return [a[0], a[1], a[3]]; | |
}) | |
}, | |
sprites: { | |
input: 'BCHOPPER_GFX1.BIN', | |
output: ['c-00-a.rom', 'c-01-b.rom', 'c-10-a.rom', 'c-11-b.rom', | |
'c-20-a.rom', 'c-21-b.rom', 'c-30-a.rom', 'c-31-b.rom'] | |
}, | |
gfx2: { | |
input: 'BCHOPPER_GFX2.BIN', | |
output: ['b-a0-b.rom', 'b-a1-b.rom', 'b-a2-b.rom', 'b-a3-b.rom'] | |
}, | |
gfx3: { | |
input: 'BCHOPPER_GFX3.BIN', | |
output: ['b-b0-.rom', 'b-b1-.rom', 'b-b2-.rom', 'b-b3-.rom'] | |
}, | |
samples: { input: 'BCHOPPER_SAMPLES.BIN', output: 'c-v0-b.rom' } | |
}); | |
} | |
function bmaster(srcdir) | |
{ | |
convert_roms('bmaster', srcdir, { | |
maincpu: { | |
input: 'BMASTER_CPU1.BIN', | |
output: ['bm_d-l0-b.5f', 'bm_d-l1-b.5j', | |
'bm_d-h0-b.5m', 'bm_d-h1-b.5l'], | |
transform: bin => | |
interleave(bin.slice(0, 0xa0000)).flatMap(b => { | |
return split_at(b, 0x40000); | |
}) | |
}, | |
soundcpu: { | |
input: 'BMASTER_CPU2.BIN', | |
output: ['bm_d-sl0.rom', 'bm_d-sh0.rom'], | |
transform: interleave | |
}, | |
gfx1: { | |
input: 'BMASTER_GFX1.BIN', | |
output: ['bm_c0.rom', 'bm_c1.rom', | |
'bm_c2.rom', 'bm_c3.rom'] | |
}, | |
gfx2: { | |
input: 'BMASTER_GFX2.BIN', | |
output: ['bm_000.rom', 'bm_010.rom', | |
'bm_020.rom', 'bm_030.rom'] | |
}, | |
irem: { input: 'BMASTER_SOUND.BIN', output: 'bm_da.rom' } | |
}); | |
} | |
function cosmccop(srcdir) | |
{ | |
convert_roms('cosmccop', srcdir, { | |
maincpu: { | |
input: 'COSMCCOP_CPU1.BIN', | |
output: ['cc-d-l0b.bin', 'cc-d-h0b.bin'], | |
transform: bin => interleave(bin.slice(0, 0x80000)) | |
}, | |
soundcpu: { input: 'COSMCCOP_CPU2.BIN', output: 'cc-d-sp.bin' }, | |
sprites: { | |
input: 'COSMCCOP_GFX1.BIN', | |
output: ['cc-c-00.bin', 'cc-c-10.bin', 'cc-c-20.bin', 'cc-c-30.bin'] | |
}, | |
gfx2: { | |
input: 'COSMCCOP_GFX2.BIN', | |
output: ['cc-d-g00.bin', 'cc-d-g10.bin', | |
'cc-d-g20.bin', 'cc-d-g30.bin'] | |
}, | |
samples: { input: 'COSMCCOP_SAMPLES.BIN', output: 'cc-c-v0.bin' } | |
}); | |
} | |
function dbreedm72(srcdir) | |
{ | |
convert_roms('dbreedm72', srcdir, { | |
maincpu: { | |
input: 'DBREED72_CPU.BIN', | |
output: ['db_c-l3.rom', 'db_c-l0.rom', | |
'db_c-h3.rom', 'db_c-h0.rom'], | |
transform: bin => | |
interleave(bin).flatMap(b => { | |
return [b.slice(0, 0x20000), b.slice(0x30000, 0x40000)] | |
}) | |
}, | |
sprites: { | |
input: 'DBREED72_GFX1.BIN', | |
output: ['db_k800m.00', 'db_k801m.10', 'db_k802m.20', 'db_k803m.30'] | |
}, | |
gfx2: { | |
input: 'DBREED72_GFX2.BIN', | |
output: ['db_k804m.a0', 'db_k805m.a1', 'db_k806m.a2', 'db_k807m.a3'] | |
}, | |
gfx3: { | |
input: 'DBREED72_GFX3.BIN', | |
output: ['db_k804m.b0', 'db_k805m.b1', 'db_k806m.b2', 'db_k807m.b3'] | |
}, | |
samples: { input: 'DBREED72_SAMPLES.BIN', output: 'db_c-v0.rom' } | |
}); | |
} | |
function gunforce(srcdir) | |
{ | |
convert_roms('gunforce', srcdir, { | |
maincpu: { | |
input: 'GUNFORCE_CPU1.BIN', | |
output: ['gf_l0-c.5f', 'gf_l1-c.5j', | |
'gf_h0-c.5m', 'gf_h1-c.5l'], | |
transform: bin => | |
interleave(bin.slice(0, 0x80000)).flatMap(b => { | |
return split_at(b, 0x20000); | |
}) | |
}, | |
soundcpu: { | |
input: 'GUNFORCE_CPU2.BIN', | |
output: ['gf_sl0.rom', 'gf_sh0.rom'], | |
transform: bin => interleave(bin.slice(0, 0x20000)) | |
}, | |
gfx1: { | |
input: 'GUNFORCE_GFX1.BIN', | |
output: ['gf_c0.rom', 'gf_c1.rom', | |
'gf_c2.rom', 'gf_c3.rom'] | |
}, | |
gfx2: { | |
input: 'GUNFORCE_GFX2.BIN', | |
output: ['gf_000.rom', 'gf_010.rom', | |
'gf_020.rom', 'gf_030.rom'] | |
}, | |
irem: { input: 'GUNFORCE_SOUND.BIN', output: 'gf-da.rom' } | |
}); | |
} | |
function gunforc2(srcdir) | |
{ | |
convert_roms('gunforc2', srcdir, { | |
maincpu: { | |
input: 'GUNFORC2_CPU1.BIN', | |
output: ['a2-l0-a.8h', 'a2-l1-a.8f', | |
'a2-h0-a.6h', 'a2-h1-a.6f'], | |
transform: bin => | |
interleave(bin).flatMap(b => { | |
return [b.slice(0, 0x40000), b.slice(0x80000, 0xc0000)]; | |
}) | |
}, | |
soundcpu: { | |
input: 'GUNFORC2_CPU2.BIN', | |
output: ['a2_sl0.5l', 'a2_sh0.3l'], | |
transform: bin => interleave(bin.slice(0, 0x20000)) | |
}, | |
gfx1: { | |
input: 'GUNFORC2_GFX1.BIN', | |
output: ['a2_c0.1a', 'a2_c1.1b', | |
'a2_c2.3a', 'a2_c3.3b'] | |
}, | |
gfx2: { | |
input: 'GUNFORC2_GFX2.BIN', | |
output: ['a2_000.8a', 'a2_010.8b', | |
'a2_020.8c', 'a2_030.8d'] | |
}, | |
irem: { input: 'GUNFORC2_SOUND.BIN', output: 'a2_da.1l' } | |
}); | |
} | |
function hharry(srcdir) | |
{ | |
convert_roms('hharry', srcdir, { | |
maincpu: { | |
input: 'HHARRY_CPU1.BIN', | |
output: ['a-l0-v.rom', 'a-l1-0.rom', 'a-h0-v.rom', 'a-h1-0.rom'], | |
transform: bin => | |
interleave(bin).flatMap(b => { | |
return [b.slice(0, 0x20000), b.slice(0x30000, 0x40000)] | |
}) | |
}, | |
soundcpu: { input: 'HHARRY_CPU2.BIN', output: 'a-sp-0.rom' }, | |
sprites: { | |
input: 'HHARRY_GFX1.BIN', | |
output: ['hh_00.rom', 'hh_10.rom', 'hh_20.rom', 'hh_30.rom'] | |
}, | |
gfx2: { | |
input: 'HHARRY_GFX2.BIN', | |
output: ['hh_a0.rom', 'hh_a1.rom', | |
'hh_a2.rom', 'hh_a3.rom'] | |
}, | |
samples: { input: 'HHARRY_SAMPLES.BIN', output: 'a-v0-0.rom' } | |
}); | |
} | |
function imgfight(srcdir) | |
{ | |
convert_roms('imgfight', srcdir, { | |
maincpu: { | |
input: 'IMGFIGHT_CPU.BIN', | |
output: ['if-c-l0-a.bin', 'if-c-l3.bin', | |
'if-c-h0-a.bin', 'if-c-h3.bin'], | |
transform: bin => | |
interleave(bin).flatMap(b => { | |
return [b.slice(0, 0x10000), b.slice(0x20000, 0x40000)] | |
}) | |
}, | |
sprites: { | |
input: 'IMGFIGHT_GFX1.BIN', | |
output: ['if-c-00.bin', 'if-c-10.bin', 'if-c-20.bin', 'if-c-30.bin'] | |
}, | |
gfx2: { | |
input: 'IMGFIGHT_GFX2.BIN', | |
output: ['if-a-a0.bin', 'if-a-a1.bin', 'if-a-a2.bin', 'if-a-a3.bin'] | |
}, | |
gfx3: { | |
input: 'IMGFIGHT_GFX3.BIN', | |
output: ['if-a-b0.bin', 'if-a-b1.bin', 'if-a-b2.bin', 'if-a-b3.bin'] | |
}, | |
samples: { | |
input: 'IMGFIGHT_SAMPLES.BIN', | |
output: ['if-c-v0.bin', 'if-c-v1.bin'] | |
} | |
}); | |
} | |
function inthunt(srcdir) | |
{ | |
convert_roms('inthunt', srcdir, { | |
maincpu: { | |
input: 'INTHUNT_CPU1.BIN', | |
output: ['ith-l0-d.bin', 'ith-l1-b.bin', | |
'ith-h0-d.bin', 'ith-h1-b.bin'], | |
transform: bin => | |
interleave(bin.slice(0, 0xc0000)).flatMap(b => { | |
return split_at(b, 0x40000); | |
}) | |
}, | |
soundcpu: { | |
input: 'INTHUNT_CPU2.BIN', | |
output: ['ith-sl0.rom', 'ith-sh0.rom'], | |
transform: interleave | |
}, | |
gfx1: { | |
input: 'INTHUNT_GFX1.BIN', | |
output: ['ith_ic26.rom', 'ith_ic25.rom', | |
'ith_ic24.rom', 'ith_ic23.rom'] | |
}, | |
gfx2: { | |
input: 'INTHUNT_GFX2.BIN', | |
output: ['ith_ic34.rom', 'ith_ic35.rom', | |
'ith_ic36.rom', 'ith_ic37.rom'] | |
}, | |
irem: { input: 'INTHUNT_SOUND.BIN', output: 'ith_ic9.rom' } | |
}); | |
} | |
function kungfum(srcdir) | |
{ | |
convert_roms('kungfum', srcdir, { | |
maincpu: { | |
input: 'KUNGFUM_Z80.BIN', | |
output: ['a-4e-c.bin', 'a-4d-c.bin'] | |
}, | |
irem_audio: { | |
input: 'KUNGFUM_M6803.BIN', | |
output: ['a-3e-.bin', 'a-3f-.bin', 'a-3h-.bin'] | |
}, | |
gfx1: { | |
input: 'KUNGFUM_GFX1.BIN', | |
output: ['g-4c-a.bin', 'g-4d-a.bin', 'g-4e-a.bin'] | |
}, | |
gfx2: { | |
input: 'KUNGFUM_GFX2.BIN', | |
output: ['b-4k-.bin', 'b-4f-.bin', 'b-4l-.bin', 'b-4h-.bin', | |
'b-3n-.bin', 'b-4n-.bin', 'b-4m-.bin', 'b-3m-.bin', | |
'b-4c-.bin', 'b-4e-.bin', 'b-4d-.bin', 'b-4a-.bin'] | |
}, | |
spr_height_prom: { input: 'KUNGFUM_SPRH.BIN', output: 'b-5f-.bin' }, | |
color_proms: { | |
input: 'KUNGFUM_PAL.BIN', | |
output: ['g-1j-.bin', 'b-1m-.bin', | |
'g-1f-.bin', 'b-1n-.bin', | |
'g-1h-.bin', 'b-1l-.bin'] | |
}, | |
// missing | |
timing: { input: Buffer.alloc(0x100), output: 'b-6f-.bin' } | |
}); | |
} | |
function loht(srcdir) | |
{ | |
convert_roms('loht', srcdir, { | |
maincpu: { | |
input: 'LOHT_CPU.BIN', | |
output: ['tom_c-l0.rom', 'tom_c-l3-', | |
'tom_c-h0.rom', 'tom_c-h3-'], | |
transform: bin => | |
interleave(bin.slice(0, 0x80000)).flatMap(b => { | |
return split_at(b, 0x20000); | |
}) | |
}, | |
sprites: { | |
input: 'LOHT_GFX1.BIN', | |
output: ['tom_m53.rom', 'tom_m51.rom', 'tom_m49.rom', 'tom_m47.rom'] | |
}, | |
gfx2: { | |
input: 'LOHT_GFX2.BIN', | |
output: ['tom_m21.rom', 'tom_m22.rom', 'tom_m20.rom', 'tom_m23.rom'] | |
}, | |
gfx3: { | |
input: 'LOHT_GFX3.BIN', | |
output: ['tom_m26.rom', 'tom_m27.rom', 'tom_m25.rom', 'tom_m24.rom'] | |
}, | |
samples: { input: 'LOHT_SAMPLES.BIN', output: 'tom_m44.rom' } | |
}); | |
} | |
function mysticri(srcdir) | |
{ | |
convert_roms('mysticri', srcdir, { | |
maincpu: { | |
input: 'MYSTICRI_CPU1.BIN', | |
output: ['mr-l0-b.bin', 'mr-l1-b.bin', | |
'mr-h0-b.bin', 'mr-h1-b.bin'], | |
transform: bin => | |
interleave(bin.slice(0, 0xa0000)).flatMap(b => { | |
return split_at(b, 0x40000); | |
}) | |
}, | |
soundcpu: { | |
input: 'MYSTICRI_CPU2.BIN', | |
output: ['mr-sl0.bin', 'mr-sh0.bin'], | |
transform: bin => interleave(bin.slice(0, 0x20000)) | |
}, | |
gfx1: { | |
input: 'MYSTICRI_GFX1.BIN', | |
output: ['mr-c0.bin', 'mr-c1.bin', | |
'mr-c2.bin', 'mr-c3.bin'] | |
}, | |
gfx2: { | |
input: 'MYSTICRI_GFX2.BIN', | |
output: ['mr-o00.bin', 'mr-o10.bin', | |
'mr-o20.bin', 'mr-o30.bin'], | |
transform: bin => { | |
var a = split(bin, 0x80000); | |
return [a[0], a[2], a[4], a[6]]; | |
} | |
}, | |
irem: { input: 'MYSTICRI_SOUND.BIN', output: 'mr-da.bin' } | |
}); | |
} | |
function nspirit_mame2010(srcdir) | |
{ | |
convert_roms('nspirit', srcdir, { | |
maincpu: { | |
input: 'NSPIRIT_CPU.BIN', | |
output: ['nin-c-l0.rom', 'nin-c-l1.rom', | |
'nin-c-l2.rom', 'nin-c-l3.rom', | |
'nin-c-h0.rom', 'nin-c-h1.rom', | |
'nin-c-h2.rom', 'nin-c-h3.rom'], | |
transform: bin => | |
interleave(bin.slice(0, 0x80000)).flatMap(b => { | |
return split(b, 0x10000); | |
}) | |
}, | |
gfx1: { | |
input: 'NSPIRIT_GFX1.BIN', | |
output: ['nin-r00.rom', 'nin-r10.rom', 'nin-r20.rom', 'nin-r30.rom'] | |
}, | |
gfx2: { | |
input: 'NSPIRIT_GFX2.BIN', | |
output: ['nin-b-a0.rom', 'nin-b-a1.rom', | |
'nin-b-a2.rom', 'nin-b-a3.rom'] | |
}, | |
gfx3: { | |
input: 'NSPIRIT_GFX3.BIN', | |
output: ['nin-b0.rom', 'nin-b1.rom', | |
'nin-b2.rom', 'nin-b3.rom'] | |
}, | |
samples: { input: 'NSPIRIT_SAMPLES.BIN', output: 'nin-v0.rom' } | |
}); | |
} | |
function nspirit(srcdir) | |
{ | |
convert_roms('nspirit', srcdir, { | |
maincpu: { | |
input: 'NSPIRIT_CPU.BIN', | |
output: ['nin_c-l0.6d', 'nin_c-l1.6c', | |
'nin_c-l2.6b', 'nin_c-l3.6a', | |
'nin_c-h0.6h', 'nin_c-h1.6j', | |
'nin_c-h2.6l', 'nin_c-h3.6m'], | |
transform: bin => | |
interleave(bin.slice(0, 0x80000)).flatMap(b => { | |
return split(b, 0x10000); | |
}) | |
}, | |
sprites: { | |
input: 'NSPIRIT_GFX1.BIN', | |
output: ['nin-r00.7m', 'nin-r10.7j', 'nin-r20.7f', 'nin-r30.7d'] | |
}, | |
gfx2: { | |
input: 'NSPIRIT_GFX2.BIN', | |
output: ['nin_b-a0.4c', 'nin_b-a1.4d', | |
'nin_b-a2.4b', 'nin_b-a3.4e'] | |
}, | |
gfx3: { | |
input: 'NSPIRIT_GFX3.BIN', | |
output: ['b0.4j', 'b1.4k', 'b2.4h', 'b3.4f'] | |
}, | |
samples: { input: 'NSPIRIT_SAMPLES.BIN', output: 'nin-v0.7a' }, | |
// missing | |
proms: { | |
input: Buffer.alloc(0x100 * 2), | |
output: [ 'm72_a-8l.8l', 'm72_a-9l.9l' ] | |
}, | |
plds: { | |
input: Buffer.alloc(0x100 * 3), | |
output: ['nin_c-3f.3f', 'm72_a-3d.3d', 'm72_a-4d.4d'] | |
} | |
}); | |
} | |
function rtypeleo(srcdir) | |
{ | |
convert_roms('rtypeleo', srcdir, { | |
maincpu: { | |
input: 'RTYPELEO_CPU1.BIN', | |
output: ['rtl-l0-c.bin', 'rtl-l1-d.bin', | |
'rtl-h0-c.bin', 'rtl-h1-d.bin'], | |
transform: bin => | |
interleave(bin.slice(0, 0xc0000)).flatMap(b => { | |
return split_at(b, 0x40000); | |
}) | |
}, | |
soundcpu: { | |
input: 'RTYPELEO_CPU2.BIN', | |
output: ['rtl-sl0a.bin', 'rtl-sh0a.bin'], | |
transform: interleave | |
}, | |
gfx1: { | |
input: 'RTYPELEO_GFX1.BIN', | |
output: ['rtl-c0.bin', 'rtl-c1.bin', | |
'rtl-c2.bin', 'rtl-c3.bin'] | |
}, | |
gfx2: { | |
input: 'RTYPELEO_GFX2.BIN', | |
output: ['rtl-000.bin', 'rtl-010.bin', | |
'rtl-020.bin', 'rtl-030.bin'] | |
}, | |
irem: { input: 'RTYPELEO_SOUND.BIN', output: 'rtl-da.bin' } | |
}); | |
} | |
function ssoldier(srcdir) | |
{ | |
convert_roms('ssoldier', srcdir, { | |
maincpu: { | |
input: 'SSOLDIER_CPU1.BIN', | |
output: ['f3-l0-h.bin', 'f3-l1-a.bin', | |
'f3-h0-h.bin', 'f3-h1-a.bin'], | |
transform: bin => | |
interleave(bin.slice(0, 0xc0000)).flatMap(b => { | |
return split_at(b, 0x40000); | |
}) | |
}, | |
soundcpu: { | |
input: 'SSOLDIER_CPU2.BIN', | |
output: ['f3_sl0.sl0', 'f3_sh0.sh0'], | |
transform: interleave | |
}, | |
gfx1: { | |
input: 'SSOLDIER_GFX1.BIN', | |
output: ['f3_w50.c0', 'f3_w51.c1', | |
'f3_w52.c2', 'f3_w53.c3'], | |
transform: bin => split(bin, 0x80000).map(b => b.slice(0, 0x40000)) | |
}, | |
gfx2: { | |
input: 'SSOLDIER_GFX2.BIN', | |
output: ['f3_w38.001', 'f3_w40.011', | |
'f3_w42.021', 'f3_w44.031', | |
'f3_w37.000', 'f3_w39.010', | |
'f3_w41.020', 'f3_w43.030'], | |
transform: bin => interleave(bin).flatMap(b => split(b, 0x100000)) | |
}, | |
irem: { input: 'SSOLDIER_SOUND.BIN', output: 'f3_w95.da' } | |
}); | |
} | |
function uccops(srcdir) | |
{ | |
convert_roms('uccops', srcdir, { | |
maincpu: { | |
input: 'UCCOPS_CPU1.BIN', | |
output: ['uc_l0.rom', 'uc_l1.rom', | |
'uc_h0.rom', 'uc_h1.rom'], | |
transform: bin => | |
interleave(bin.slice(0, 0xc0000)).flatMap(b => { | |
return split_at(b, 0x40000); | |
}) | |
}, | |
soundcpu: { | |
input: 'UCCOPS_CPU2.BIN', | |
output: ['uc_sl0.rom', 'uc_sh0.rom'], | |
transform: interleave | |
}, | |
gfx1: { | |
input: 'UCCOPS_GFX1.BIN', | |
output: ['uc_w38m.rom', 'uc_w39m.rom', | |
'uc_w40m.rom', 'uc_w41m.rom'] | |
}, | |
gfx2: { | |
input: 'UCCOPS_GFX2.BIN', | |
output: ['uc_k16m.rom', 'uc_k17m.rom', | |
'uc_k18m.rom', 'uc_k19m.rom'] | |
}, | |
irem: { input: 'UCCOPS_SOUND.BIN', output: 'uc_w42.rom' } | |
}); | |
} | |
function vigilant_mame2003(srcdir) | |
{ | |
convert_roms('vigilant', srcdir, { | |
cpu1: { | |
input: 'VIGILANT_CPU1.BIN', | |
output: ['g07_c03.bin', 'j07_c04.bin'], | |
transform: bin => | |
[bin.slice(0, 0x08000), bin.slice(0x10000, 0x20000)] | |
}, | |
cpu2: { input: 'VIGILANT_CPU2.BIN', output: 'g05_c02.bin' }, | |
gfx1: { | |
input: { file: 'VIGILANT_GFX1.BIN', layout: VIGILANT_TEXT_LAYOUT }, | |
output: ['f05_c08.bin', 'h05_c09.bin'] | |
}, | |
gfx2: { | |
input: { | |
file: 'VIGILANT_GFX2.BIN', layout: VIGILANT_SPRITE_LAYOUT | |
}, | |
output: ['n07_c12.bin', 'k07_c10.bin', | |
'o07_c13.bin', 'l07_c11.bin', | |
't07_c16.bin', 'p07_c14.bin', | |
'v07_c17.bin', 's07_c15.bin'] | |
}, | |
gfx3: { | |
input: 'VIGILANT_GFX_BG.BIN', | |
output: ['d01_c05.bin', 'e01_c06.bin', 'f01_c07.bin'], | |
transform: bin => | |
encode_gfx(vigilant_reorder(bin), VIGILANT_BACK_LAYOUT) | |
.slice(0, 0x30000) | |
}, | |
sound1: { input: 'VIGILANT_SAMPLES.BIN', output: 'd04_c01.bin' } | |
}); | |
} | |
function vigilantbl(srcdir) | |
{ | |
convert_roms('vigilantbl', srcdir, { | |
maincpu: { | |
input: 'VIGILANT_CPU1.BIN', | |
output: ['g07_c03.bin', 'j07_c04.bin'], | |
transform: bin => | |
[bin.slice(0, 0x08000), bin.slice(0x10000, 0x20000)] | |
}, | |
soundcpu: { input: 'VIGILANT_CPU2.BIN', output: 'g05_c02.bin' }, | |
gfx1: { | |
input: { file: 'VIGILANT_GFX1.BIN', layout: VIGILANT_TEXT_LAYOUT }, | |
output: ['f05_c08.bin', 'h05_c09.bin'] | |
}, | |
gfx2: { | |
input: { | |
file: 'VIGILANT_GFX2.BIN', layout: VIGILANT_SPRITE_LAYOUT | |
}, | |
output: ['n07_c12.bin', 'k07_c10.bin', | |
'o07_c13.bin', 'l07_c11.bin', | |
't07_c16.bin', 'p07_c14.bin', | |
'v07_c17.bin', 's07_c15.bin'] | |
}, | |
gfx3: { | |
input: 'VIGILANT_GFX_BG.BIN', | |
output: ['d01_c05.bin', 'e01_c06.bin', 'f01_c07.bin'], | |
transform: bin => | |
encode_gfx(vigilant_reorder(bin), VIGILANT_BACK_LAYOUT) | |
.slice(0, 0x30000) | |
}, | |
samples: { input: 'VIGILANT_SAMPLES.BIN', output: 'd04_c01.bin' }, | |
// missing | |
plds: { | |
input: Buffer.alloc(0x117 * 3), | |
output: ['VG_B-8R.ic90', 'VG_B-4M.ic38', 'VG_B-1B.ic1'] | |
} | |
}); | |
} | |
function raidenb(srcdir) | |
{ | |
convert_roms('raidenb', srcdir, { | |
maincpu: { | |
input: 'raiden_maincpu.bin', | |
output: ['1.u0253', '3__(raidenb).u022', | |
'2.u0252', '4__(raidenb).u023'], | |
transform: bin => interleave(bin).flatMap(b => split_at(b, 0x10000)) | |
}, | |
sub: { | |
input: 'raiden_subcpu.bin', | |
output: ['5__(raidenb).u042', '6__(raidenb).u043'], | |
transform: interleave | |
}, | |
audiocpu: { | |
input: 'raiden_audiocpu.bin', | |
output: 'rai6.u212', | |
transform: bin => { | |
const a = split(bin, 0x8000); | |
return Buffer.concat([a[0], a[2]]); | |
} | |
}, | |
gfx1: { | |
input: 'raiden_gfx1.bin', | |
output: ['9', '10'] | |
}, | |
gfx2: { | |
input: { | |
file: 'raiden_gfxdata2.bin', layout: RAIDEN_SPRITE_LAYOUT | |
}, | |
output: 'sei420' | |
}, | |
gfx3: { | |
input: { | |
file: 'raiden_gfxdata3.bin', layout: RAIDEN_SPRITE_LAYOUT | |
}, | |
output: 'sei430' | |
}, | |
gfx4: { | |
input: { | |
file: 'raiden_gfxdata4.bin', layout: RAIDEN_SPRITE_LAYOUT | |
}, | |
output: 'sei440' | |
}, | |
oki: { input: 'raiden_okim6295.bin', output: '7.u203' } | |
}); | |
} | |
function rdftj(srcdir) | |
{ | |
convert_roms('rdftj', srcdir, { | |
maincpu: { | |
input: 'rdft_i386.bin', | |
output: ['gd_1.211', 'gd_2.212', 'gd_3.210', 'gd_4.29'], | |
transform: bin => interleave(bin, [1,1,1,1]) | |
}, | |
gfx1: { // wrong checksums | |
input: { file: 'rdft_gfxdata1.bin', layout: SPI_CHAR_LAYOUT }, | |
output: ['gd_5.423', 'gd_6.424', 'gd_7.48'], | |
transform: bin => { | |
SPI.seibuspi_text_encrypt(bin); | |
return interleave(bin, [1,1,1]); | |
} | |
}, | |
gfx2: { | |
input: { file: 'rdft_gfxdata2.bin', layout: SPI_TILE_LAYOUT }, | |
output: ['gd_bg1-d.415', 'gd_bg2-d.416', | |
'gd_bg1-p.410', 'gd_bg2-p.49'], | |
transform: bin => { | |
SPI.seibuspi_bg_encrypt(bin); | |
return interleave(bin, [2,1]) | |
.flatMap(b => split_at(b, b.length/2)); | |
} | |
}, | |
gfx3: { | |
input: { file: 'rdft_gfxdata3.bin', layout: SPI_SPRITE_LAYOUT }, | |
output: ['gd_obj-1.322', 'gd_obj-2.324', 'gd_obj-3.323'], | |
transform: SPI.seibuspi_sprite_encrypt | |
}, | |
sound01: { | |
input: 'rdft_soundrom.bin', | |
output: ['gd_pcm.217', 'gd_8.216'], | |
transform: bin => split_at(bin, 0x200000) | |
}, | |
soundflash1: { | |
input: Buffer.alloc(0x100000, 0xff), | |
output: 'flash0_blank_region01.u1053', | |
transform: bin => { bin[0] = 0x01; return bin; } | |
} | |
}); | |
} | |
function rdft2(srcdir) | |
{ | |
convert_roms('rdft2', srcdir, { | |
maincpu: { | |
input: 'rdft2_i386.bin', | |
output: ['prg0.tun', 'prg1.bin', 'prg2.bin', 'prg3.bin'], | |
transform: bin => interleave(bin, [1,1,1,1]) | |
}, | |
gfx1: { // wrong checksums | |
input: { file: 'rdft2_gfxdata1.bin', layout: SPI_CHAR_LAYOUT }, | |
output: ['fix1.u0518', 'fix0.u0524', 'fixp.u0514'], | |
transform: bin => { | |
SPI.rdft2_text_encrypt(bin); | |
return interleave(bin, [1,1,1]); | |
} | |
}, | |
gfx2: { | |
input: { file: 'rdft2_gfxdata2.bin', layout: SPI_TILE_LAYOUT }, | |
output: ['bg-1d.u0535', 'bg-2d.u0536', | |
'bg-1p.u0537', 'bg-2p.u0538'], | |
transform: bin => { | |
SPI.rdft2_bg_encrypt(bin); | |
return interleave(bin, [2,1]) | |
.flatMap(b => split_at(b, b.length/2)); | |
} | |
}, | |
gfx3: { | |
input: { file: 'rdft2_gfxdata3.bin', layout: SPI_SPRITE_LAYOUT }, | |
output: ['obj3.u0434', 'obj3b.u0433', 'obj1.u0429', | |
'obj1b.u0430', 'obj2.u0431', 'obj2b.u0432'], | |
transform: bin => { | |
SPI.seibuspi_rise10_sprite_encrypt(bin); | |
return split(bin, 0x600000).flatMap(b => split_at(b, 0x400000)); | |
} | |
}, | |
sound01: { | |
input: 'rdft2_soundrom.bin', | |
output: ['pcm.u0217', 'sound1.u0222'], | |
transform: bin => split_at(bin, 0x200000) | |
}, | |
soundflash1: { | |
input: Buffer.alloc(0x100000, 0xff), | |
output: 'flash0_blank_region80.u1053', | |
transform: bin => { bin[0] = 0x80; return bin; } | |
} | |
}); | |
} | |
function rfjet(srcdir) | |
{ | |
convert_roms('rfjet', srcdir, { | |
maincpu: { | |
input: 'rfjet_i386.bin', | |
output: ['prg0.u0211', 'prg1.u0212', 'prg2.u0221', 'prg3.u0220'], | |
transform: bin => interleave(bin, [1,1,1,1]) | |
}, | |
gfx1: { // wrong checksums | |
input: { file: 'rfjet_gfxdata1.bin', layout: SPI_CHAR_LAYOUT }, | |
output: ['fix1.u0518', 'fix0.u0524', 'fixp.u0514'], | |
transform: bin => { | |
SPI.rfjet_text_encrypt(bin); | |
return interleave(bin, [1,1,1]); | |
} | |
}, | |
gfx2: { | |
input: { file: 'rfjet_gfxdata2.bin', layout: SPI_TILE_LAYOUT }, | |
output: ['bg-1d.u0543', 'bg-2d.u0545', | |
'bg-1p.u0544', 'bg-2p.u0546'], | |
transform: bin => { | |
SPI.rfjet_bg_encrypt(bin); | |
return interleave(bin, [2,1]) | |
.flatMap(b => split_at(b, b.length*2/3)); | |
} | |
}, | |
gfx3: { | |
input: { file: 'rfjet_gfxdata3.bin', layout: SPI_SPRITE_LAYOUT }, | |
output: ['obj-1.u0442', 'obj-2.u0443', 'obj-3.u0444'], | |
transform: bin => SPI.seibuspi_rise11_sprite_encrypt_rfjet(bin) | |
}, | |
sound01: { | |
input: 'rfjet_soundrom.bin', | |
output: ['pcm-d.u0227', 'sound1.u0222'], | |
transform: bin => split_at(bin, 0x200000) | |
}, | |
soundflash1: { | |
input: Buffer.alloc(0x100000, 0xff), | |
output: 'flash0_blank_region80.u1053', | |
transform: bin => { bin[0] = 0x80; return bin; } | |
} | |
}); | |
} | |
const NEOGEO_CONFS = { | |
bstars2: { | |
id: "041", | |
rom_size: [ 0x080000, 0x100000, 0x100000 ] | |
}, | |
blazstar: { | |
id: "239", | |
rom_size: [ 0x200000, 0x400000, 0x400000 ] | |
}, | |
kof97: { | |
id: "232", | |
rom_size: [ 0x400000, 0x400000, 0x800000 ] | |
}, | |
kof98: { | |
id: "242", | |
rom_size: [ 0x400000, 0x400000, 0x800000 ], | |
name: "kof98h", | |
maincpu: { output: ['242-pn1.p1', '242-p2.sp2'] }, | |
audiocpu: { output: '242-mg1.m1' } | |
}, | |
mslug: { | |
id: "201", | |
rom_size: [ 0x200000, 0x400000, 0x400000 ], | |
swap_68k: true | |
}, | |
mslug2: { | |
id: "241", | |
rom_size: [ 0x200000, 0x400000, 0x800000 ] | |
}, | |
mslugx: { // wrong checksums | |
id: "250", | |
rom_size: [ 0x400000, 0x400000, 0x800000 ], | |
maincpu: { output: ['250-p1.p1', '250-p2.ep1'] } | |
}, | |
mslug3: { | |
id: "256", | |
rom_size: [ 0x400000, 0x400000, 0x800000 ], | |
sma_encrypt: NeoGeo.mslug3_encrypt_68k, | |
cmc_encrypt_gfx: bin => | |
NeoGeo.cmc42_gfx_encrypt(bin, NeoGeo.MSLUG3_GFX_KEY), | |
maincpu: { output: ['neo-sma', '256-pg1.p1', '256-pg2.p2'] } | |
}, | |
samsho2: { | |
id: "063", | |
rom_size: [ 0x200000, 0x200000, 0x200000 ], | |
swap_68k: true | |
}, | |
shocktro: { | |
id: "238", | |
rom_size: [ 0x400000, 0x400000, 0x400000 ] | |
}, | |
twinspri: { | |
id: "224", | |
rom_size: [ 0x200000, 0x400000, 0x400000 ], | |
swap_68k: true | |
}, | |
fatfursp: { // not tested | |
id: "058", | |
rom_size: [ 0x080000, 0x200000, 0x200000 ] | |
}, | |
lastblad: { // not tested | |
id: "234", | |
rom_size: [ 0x400000, 0x400000, 0x800000 ] | |
}, | |
shocktr2: { // not tested | |
id: "246", | |
rom_size: [ 0x400000, 0x400000, 0x800000 ] | |
} | |
}; | |
function neogeo(srcdir, name) | |
{ | |
const conf = NEOGEO_CONFS[name]; | |
const maps_neogeo = { | |
zoomy: { input: `${name}_zoom_table`, output: '000-lo.lo' } | |
}; | |
const mainbios = fs.readFileSync(path.join(srcdir, `${name}_bios_m68k`)); | |
const fixed_bios = fs.readFileSync(path.join(srcdir, `${name}_bios_sfix`)); | |
let mainbios_name; | |
switch (sha1(mainbios)) { | |
case '5c6bba07d2ec8ac95776aa3511109f5e1e2e92eb': | |
mainbios_name = 'sp-u2.sp1'; | |
break; | |
case '1b3b22092f30c4d1b2c15f04d1670eb1e9fbea07': | |
mainbios_name = 'neo-epo.bin'; | |
break; | |
} | |
if (mainbios_name) | |
maps_neogeo.mainbios = { input: mainbios, output: mainbios_name }; | |
if (fs.existsSync(path.join(srcdir, `${name}_bios_m68k_jap`))) { | |
maps_neogeo.mainbios_jp = { | |
input: `${name}_bios_m68k_jap`, output: 'vs-bios.rom' | |
}; | |
} | |
if (sha1(fixed_bios) === '3d9c878d6d8e5d47fe58dfbdee31aed5c5b23360') { | |
maps_neogeo.fixed_bios = { | |
input: fixed_bios, output: 'sfix.sfix', | |
transform: NeoGeo.sfix_reorder | |
}; | |
} | |
const { id } = conf; | |
let maincpu = fs.readFileSync(path.join(srcdir, `${name}_game_m68k`)); | |
const ymsnd_size = fs.statSync(path.join(srcdir, `${name}_adpcm`)).size; | |
const sprites_size = fs.statSync(path.join(srcdir, `${name}_tiles`)).size; | |
const maincpu_files = [`${id}-p1.p1`]; | |
const ymsnd_files = []; | |
const sprites_files = []; | |
if (maincpu.length > conf.rom_size[0]) { | |
if (maincpu.slice(conf.rom_size[0]).every(b => b == 0)) | |
maincpu = maincpu.slice(0, conf.rom_size[0]); | |
else | |
maincpu_files.push(`${id}-p2.sp2`); | |
} | |
for (let i = 1; i <= Math.ceil(ymsnd_size/conf.rom_size[1]); i++) | |
ymsnd_files.push(`${id}-v${i}.v${i}`); | |
for (let i = 1; i <= Math.ceil(sprites_size/2/conf.rom_size[2])*2; i++) | |
sprites_files.push(`${id}-c${i}.c${i}`); | |
const maps_game = { | |
maincpu: { | |
input: maincpu, output: maincpu_files, | |
transform: bin => { | |
if (conf.swap_68k) { | |
const a = split_at(bin, bin.length/2); | |
bin = Buffer.concat([a[1], a[0]]); | |
} | |
if ('sma_encrypt' in conf) | |
conf.sma_encrypt(bin); | |
const rom_size = conf.rom_size[0]; | |
if (bin.length == rom_size) return bin; | |
const p1_size = bin.length >= 0x100000 + rom_size ? | |
0x100000 : bin.length - rom_size; | |
const a = split_at(bin, p1_size); | |
if ('sma_encrypt' in conf) | |
a[0] = a[0].slice(0x0c0000); | |
return [a[0], ...split(a[1], rom_size)]; | |
} | |
}, | |
sfix: { | |
input: `${name}_game_sfix`, output: `${id}-s1.s1`, | |
transform: NeoGeo.sfix_reorder | |
}, | |
audiocpu: { input: `${name}_game_z80`, output: `${id}-m1.m1` }, | |
ymsnd: { | |
input: `${name}_adpcm`, output: ymsnd_files, | |
transform: bin => split(bin, conf.rom_size[1]) | |
}, | |
sprites: { | |
input: `${name}_tiles`, output: sprites_files, | |
transform: bin => { | |
NeoGeo.deoptimize_sprites(bin); | |
if ('cmc_encrypt_gfx' in conf) | |
conf.cmc_encrypt_gfx(bin); | |
const a = interleave(bin).map(b => split(b, conf.rom_size[2])); | |
return a[0].flatMap((b, i) => [b, a[1][i]]); | |
} | |
} | |
}; | |
for (const region of ['maincpu', 'audiocpu']) | |
if (region in conf) | |
Object.assign(maps_game[region], conf[region]); | |
if ('cmc_encrypt_gfx' in conf) | |
delete maps_game.sfix; | |
convert_roms('neogeo', srcdir, maps_neogeo); | |
convert_roms(conf.name || name, srcdir, maps_game); | |
} | |
function find_neogeo_roms(dir) | |
{ | |
for (const f of fs.readdirSync(dir)) | |
if (f.endsWith('_game_m68k')) | |
return f.replace('_game_m68k', ''); | |
return null; | |
} | |
const srcdir = process.argv[2] || ''; | |
if (fs.existsSync(path.join(srcdir, 'ddragon_hd6309.bin'))) { | |
ddragon(srcdir); | |
ddragon2(srcdir); | |
ddragon3(srcdir); | |
} | |
else if (fs.existsSync(path.join(srcdir, 'RTYPE_CPU.BIN'))) | |
rtype(srcdir); | |
else if (fs.existsSync(path.join(srcdir, 'RTYPE2_CPU1.BIN'))) | |
rtype2(srcdir); | |
else if (fs.existsSync(path.join(srcdir, 'AIRDUEL_CPU.BIN'))) { | |
airduelm72(srcdir); | |
bchopper(srcdir); | |
bmaster(srcdir); | |
cosmccop(srcdir); | |
dbreedm72(srcdir); | |
gunforce(srcdir); | |
gunforc2(srcdir); | |
hharry(srcdir); | |
imgfight(srcdir); | |
inthunt(srcdir); | |
kungfum(srcdir); | |
loht(srcdir); | |
mysticri(srcdir); | |
nspirit(srcdir); | |
rtypeleo(srcdir); | |
ssoldier(srcdir); | |
uccops(srcdir); | |
vigilantbl(srcdir); | |
} | |
else if (fs.existsSync(path.join(srcdir, 'raiden_maincpu.bin'))) | |
raidenb(srcdir); | |
else if (fs.existsSync(path.join(srcdir, 'rdft_i386.bin'))) | |
rdftj(srcdir); | |
else if (fs.existsSync(path.join(srcdir, 'rdft2_i386.bin'))) | |
rdft2(srcdir); | |
else if (fs.existsSync(path.join(srcdir, 'rfjet_i386.bin'))) | |
rfjet(srcdir); | |
else if (find_neogeo_roms(srcdir)) | |
neogeo(srcdir, find_neogeo_roms(srcdir)); | |
else | |
console.log('Usage: node dotemu2mame.js [ROM directory]'); |
Never mind, I worked it out
shocktr2 romident:
246-v3.v3 NO MATCH
246-v4.v4 NO MATCH
Out of 14 files, 12 matched, 2 did not match.
dd if=shocktr2_adpcm of=246-v3.v3 bs=2097152 count=1 skip=4
zip -f shocktr2.zip 246-v3.v3
246-v3.v3 should be a 2MB ROM image. 246-v4.v4 was just created iteratively from the dotemu combined rom image.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Amazing resource. Thank you! I see Karateka (Google Play) isn't supported. It'd be awesome if it were (if it is possible).