Created
August 26, 2022 13:17
-
-
Save AltimorTASDK/0b5aabfc0666ef33bf13e49ccd85e00e 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
import io | |
import os | |
import os.path | |
import struct | |
import sys | |
class NcdFile(): | |
def __init__(self, name, compressed, offset, size): | |
self.name = name | |
self.compressed = compressed | |
self.offset = offset | |
self.size = size | |
FILES = [ | |
NcdFile("LOGO.BMP", compressed=True, offset=0x01333C32, size=0x000946), | |
NcdFile("PSEL.BMP", compressed=True, offset=0x01334578, size=0x0079E2), | |
NcdFile("TITLE.BMP", compressed=True, offset=0x0133BF5A, size=0x0026B6), | |
NcdFile("TOKYO.BMP", compressed=True, offset=0x0133E610, size=0x00CEF0), | |
NcdFile("SE.NCD", compressed=True, offset=0x0134B500, size=0x023752), | |
NcdFile("MANUALBG.BMP", compressed=True, offset=0x0136EC52, size=0x00B336), | |
NcdFile("SIGN.BMP", compressed=True, offset=0x01379F88, size=0x004A7A), | |
NcdFile("GRAD.BMP", compressed=True, offset=0x0137EA02, size=0x003034), | |
NcdFile("AE.FRM", compressed=True, offset=0x026B5648, size=0x002234), | |
NcdFile("AE.SP", compressed=True, offset=0x026B787C, size=0x012479), | |
NcdFile("AE.PAL", compressed=True, offset=0x026C9CF5, size=0x00011B), | |
NcdFile("AE.VSE", compressed=True, offset=0x026C9E10, size=0x0032C4), | |
NcdFile("AE.NCD", compressed=True, offset=0x026CD0D4, size=0x00D4C5), | |
NcdFile("AS.FRM", compressed=True, offset=0x03A0E1AB, size=0x003F99), | |
NcdFile("AS.SP", compressed=True, offset=0x03A12144, size=0x012BE2), | |
NcdFile("AS.PAL", compressed=True, offset=0x03A24D26, size=0x000128), | |
NcdFile("AS.VSE", compressed=True, offset=0x03A24E4E, size=0x0033E6), | |
NcdFile("AS.NCD", compressed=True, offset=0x03A28234, size=0x0175D8), | |
NcdFile("CH.FRM", compressed=True, offset=0x04D7341E, size=0x003DA1), | |
NcdFile("CH.SP", compressed=True, offset=0x04D771BF, size=0x0138FD), | |
NcdFile("CH.PAL", compressed=True, offset=0x04D8AABC, size=0x000129), | |
NcdFile("CH.VSE", compressed=True, offset=0x04D8ABE5, size=0x0036B2), | |
NcdFile("CH.NCD", compressed=True, offset=0x04D8E297, size=0x017C70), | |
NcdFile("FU.FRM", compressed=True, offset=0x060D9B19, size=0x003CF0), | |
NcdFile("FU.SP", compressed=True, offset=0x060DD809, size=0x00FD54), | |
NcdFile("FU.PAL", compressed=True, offset=0x060ED55D, size=0x000103), | |
NcdFile("FU.VSE", compressed=True, offset=0x060ED660, size=0x0035DA), | |
NcdFile("FU.NCD", compressed=True, offset=0x060F0C3A, size=0x013172), | |
NcdFile("HA.FRM", compressed=True, offset=0x074379BE, size=0x002B45), | |
NcdFile("HA.SP", compressed=True, offset=0x0743A503, size=0x0122A2), | |
NcdFile("HA.PAL", compressed=True, offset=0x0744C7A5, size=0x0000FE), | |
NcdFile("HA.VSE", compressed=True, offset=0x0744C8A3, size=0x002F58), | |
NcdFile("HA.NCD", compressed=True, offset=0x0744F7FB, size=0x0188C3), | |
NcdFile("HI.FRM", compressed=True, offset=0x0879BCD0, size=0x004677), | |
NcdFile("HI.SP", compressed=True, offset=0x087A0347, size=0x014895), | |
NcdFile("HI.PAL", compressed=True, offset=0x087B4BDC, size=0x0000EB), | |
NcdFile("HI.VSE", compressed=True, offset=0x087B4CC7, size=0x0033AC), | |
NcdFile("HI.NCD", compressed=True, offset=0x087B8073, size=0x00AAB7), | |
NcdFile("HO.FRM", compressed=True, offset=0x09AF673C, size=0x004321), | |
NcdFile("HO.SP", compressed=True, offset=0x09AFAA5D, size=0x0126FB), | |
NcdFile("HO.PAL", compressed=True, offset=0x09B0D158, size=0x0000E8), | |
NcdFile("HO.VSE", compressed=True, offset=0x09B0D240, size=0x003895), | |
NcdFile("HO.NCD", compressed=True, offset=0x09B10AD5, size=0x011CF4), | |
NcdFile("KA.FRM", compressed=True, offset=0x0AE563DB, size=0x001E7D), | |
NcdFile("KA.SP", compressed=True, offset=0x0AE58258, size=0x00AF8D), | |
NcdFile("KA.PAL", compressed=True, offset=0x0AE631E5, size=0x000118), | |
NcdFile("KA.VSE", compressed=True, offset=0x0AE632FD, size=0x002A70), | |
NcdFile("KA.NCD", compressed=True, offset=0x0AE65D6D, size=0x013D79), | |
NcdFile("RE.FRM", compressed=True, offset=0x0C1AD6F8, size=0x00432C), | |
NcdFile("RE.SP", compressed=True, offset=0x0C1B1A24, size=0x0117DC), | |
NcdFile("RE.PAL", compressed=True, offset=0x0C1C3200, size=0x000144), | |
NcdFile("RE.VSE", compressed=True, offset=0x0C1C3344, size=0x0039A9), | |
NcdFile("RE.NCD", compressed=True, offset=0x0C1C6CED, size=0x00E806), | |
NcdFile("RR.FRM", compressed=True, offset=0x0D509105, size=0x003FF4), | |
NcdFile("RR.SP", compressed=True, offset=0x0D50D0F9, size=0x012848), | |
NcdFile("RR.PAL", compressed=True, offset=0x0D51F941, size=0x00011C), | |
NcdFile("RR.VSE", compressed=True, offset=0x0D51FA5D, size=0x0030A6), | |
NcdFile("RR.NCD", compressed=True, offset=0x0D522B03, size=0x0182EC), | |
NcdFile("RY.FRM", compressed=True, offset=0x0E86EA01, size=0x002F88), | |
NcdFile("RY.SP", compressed=True, offset=0x0E871989, size=0x012A82), | |
NcdFile("RY.PAL", compressed=True, offset=0x0E88440B, size=0x0000AF), | |
NcdFile("RY.VSE", compressed=True, offset=0x0E8844BA, size=0x002E6D), | |
NcdFile("RY.NCD", compressed=True, offset=0x0E887327, size=0x019A27), | |
NcdFile("UM.FRM", compressed=True, offset=0x0FBD4960, size=0x003470), | |
NcdFile("UM.SP", compressed=True, offset=0x0FBD7DD0, size=0x010061), | |
NcdFile("UM.PAL", compressed=True, offset=0x0FBE7E31, size=0x0000F1), | |
NcdFile("UM.VSE", compressed=True, offset=0x0FBE7F22, size=0x002DB8), | |
NcdFile("UM.NCD", compressed=True, offset=0x0FBEACDA, size=0x00AE7F), | |
NcdFile("US.FRM", compressed=True, offset=0x10F2976B, size=0x00386F), | |
NcdFile("US.SP", compressed=True, offset=0x10F2CFDA, size=0x012573), | |
NcdFile("US.PAL", compressed=True, offset=0x10F3F54D, size=0x0000F8), | |
NcdFile("US.VSE", compressed=True, offset=0x10F3F645, size=0x0031A8), | |
NcdFile("US.NCD", compressed=True, offset=0x10F427ED, size=0x014906), | |
NcdFile("MA.FRM", compressed=True, offset=0x1228AD05, size=0x005027), | |
NcdFile("MA.SP", compressed=True, offset=0x1228FD2C, size=0x01ACD2), | |
NcdFile("MA.PAL", compressed=True, offset=0x122AA9FE, size=0x0000E7), | |
NcdFile("MA.VSE", compressed=True, offset=0x122AAAE5, size=0x00412F), | |
NcdFile("MA.NCD", compressed=False, offset=0x122AEC14, size=0x017CC8) | |
] | |
def decompress(data: io.BufferedIOBase, out: io.BufferedIOBase): | |
def read(): | |
result = data.read(1) | |
if len(result) == 0: | |
raise EOFError | |
return result[0] | |
def write(value): | |
out.write(bytes([value])) | |
nonlocal history_index | |
history[history_index] = value | |
history_index = (history_index + 1) % HISTORY_SIZE | |
HISTORY_SIZE = 0x1000 | |
history = [0] * HISTORY_SIZE | |
history_index = 0xFEE | |
try: | |
while True: | |
mask = read() | |
for bit in range(8): | |
if mask & (1 << bit) != 0: | |
write(read()) | |
else: | |
b1, b2 = (read(), read()) | |
copy_size = (b2 & 0xF) + 3 | |
copy_start = b1 | ((b2 & 0xF0) << 4) | |
for offset in range(0, copy_size): | |
write(history[(copy_start + offset) % HISTORY_SIZE]) | |
except EOFError: | |
return | |
def extract_sound_ncd(ncd: io.BufferedIOBase, out_directory): | |
_, _, flags, count = struct.unpack("IIII", ncd.read(0x10)) | |
if (flags & 1) == 0: | |
raise Exception("Sound NCD must have flag bit 0") | |
os.makedirs(out_directory, exist_ok=True) | |
for index in range(count): | |
ncd.seek(0x20 + index * 0x10) | |
offset, _, _, size = struct.unpack("IIII", ncd.read(0x10)) | |
ncd.seek(offset) | |
data = ncd.read(size) | |
with open(os.path.join(out_directory, f"{index}.wav"), "wb") as out: | |
out.write(data) | |
def main(): | |
if len(sys.argv) < 3: | |
print("Usage: extract_ncd.py <LIGHTS2.NCD> <out directory>", | |
file=sys.stderr) | |
sys.exit(1) | |
ncd_path, out_directory = sys.argv[1:3] | |
with open(ncd_path, "rb") as ncd: | |
os.makedirs(out_directory, exist_ok=True) | |
for file in FILES: | |
ncd.seek(file.offset) | |
data = ncd.read(file.size) | |
if file.compressed: | |
buffer = io.BytesIO() | |
decompress(io.BytesIO(data), buffer) | |
decompressed = buffer.getvalue() | |
else: | |
decompressed = data | |
out_path = os.path.join(out_directory, file.name) | |
with open(out_path, "wb") as out: | |
out.write(decompressed) | |
if file.name.endswith(".NCD"): | |
extract_sound_ncd(io.BytesIO(decompressed), out_path[:-4]) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment