diff options
Diffstat (limited to 'VP-roomwork.lua')
-rw-r--r-- | VP-roomwork.lua | 499 |
1 files changed, 499 insertions, 0 deletions
diff --git a/VP-roomwork.lua b/VP-roomwork.lua new file mode 100644 index 0000000..d1eabfe --- /dev/null +++ b/VP-roomwork.lua @@ -0,0 +1,499 @@ +function process_current_room_script() + local script, font, scriptfile, fontfile, nptrs + room_idx = current_file - 3610 + if not rooms_lookup[room_idx] then return nil, nil end + + script = Buffer(true) + scriptfile = Buffer(true) + fontfile = Buffer(true) + font = { idx = 1, ilookup = {}, clookup = {} } + for k, v in ipairs(script_types.room.translated) do + add_glyph(font, v) + end + for i = 1, script_types.room.size do + script:writeU8(script_types.room.header[i]) + end + scriptfile:writeU16(0) + scriptfile:writeU16(3) + nptrs = 0 + for pidx, pval in ipairs(rooms_lookup[room_idx]) do + nptrs = nptrs + 1 + local ptr = rooms_txts[pval] + scriptfile:writeU16(script:getsize()) + for k, v in ipairs(ptr) do + if type(v) == "string" then + local str = v + local char + local gidx + while str:len() ~= 0 do + char, str = get_next_utf8(str) + gidx = font.clookup[char] or add_glyph(font, char) + if gidx < 0x80 then + script:writeU8(gidx) + else + local high = shl(gidx, 7) + local low = andB(gidx, 127) + 0x80 + script:writeU8(low) + script:writeU8(high) + end + end + elseif type(v) == "table" then + local code = v[1] + local high = 0x80 + local low = 0x80 + code + script:writeU8(low) + script:writeU8(high) + if v[2] then script:writeU8(v[2]) end + if v[3] then script:writeU8(v[3]) end + if v[4] then error "Wrong script..." end + else + error("Wrong script...") + end + end + script:writeU8(0) + end + scriptfile:copyfrom(script) + script:destroy() + + local npadding = alignment(#font.ilookup, 4) + + fontfile:writeU32(#font.ilookup + npadding) + fontfile:writeU32(12) + + for _, glyph in ipairs(font.ilookup) do + if not glyphes[glyph] then error("No glyph in database for " .. glyph) end + fontfile:writeU8(glyphes[glyph].attr.Width) + end + for i = 1, npadding do + fontfile:writeU8(0) + end + + for _, glyph in ipairs(font.ilookup) do + Base64DecodeBin(glyphes[glyph].attr.Data, fontfile) + end + for i = 1, npadding do + for j = 1, 6 do fontfile:writeU32(0) end + end + + return scriptfile, fontfile, nptrs + 2 +end + +function insert_script(old, new, nptrs) + local size_1 = old:readU32() + local u1 = old:readU32() + local u2 = old:readU32() + local n_ptrs = old:readU32() + local u3 = old:readU32() + local u4 = old:readU32() + local u5 = old:readU32() + + local ret = Buffer(true) + + ret:writeU32(size_1) + ret:writeU32(u1) + ret:writeU32(u2) + if nptrs ~= n_ptrs then error("Script inconsistancy! Got " .. nptrs .. " instead of " .. n_ptrs) end + ret:writeU32(nptrs) + ret:writeU32(u3) + ret:writeU32(u4) + ret:writeU32(u5) + if got_us and current_file == (3610 + 125) and activate_debug_room then + ret:copyfrom(old, 0x1158 * 4) + ret:writeU32(0x9e000000) + old:readU32() + ret:copyfrom(old, size_1 - 0x1159 * 4) + else + ret:copyfrom(old, size_1) + end + ret:copyfrom(new) + + return ret +end + +function process_arcroom(fname, h, size, ext) + log("Processing " .. fname .. "." .. ext) + local o + + if dump_mode then + o = Output(fname .. "." .. ext) + o:copyfrom(h, size) + o:destroy() + h:seek(-size, SEEK_CUR) + end + log("Processing " .. fname .. " - format 'arcroom'") + dump_mkdir(fname) + + local nfiles = h:readU32() + local offset = h:readU32() + + if nfiles * 8 + 8 ~= offset then + error("Bad archive format.") + end + + local ret + + if not dump_mode then + ret = Buffer(true) + ret:writeU32(nfiles) + ret:writeU32(offset) + end + + index = {} + for i = 1, nfiles do + index[i] = {} + index[i].ftype = h:readU32() + index[i].size = h:readU32() + end + + local tell + local outfile = {} + local script = nil + local font = nil + local nptrs + if not dump_mode then + script, font, nptrs = process_current_room_script() + end + for i = 1, nfiles do + tell = h:tell() + local handler = nil + local counter = 1 + if dump_mode and index[i].ftype == 4 then + log("Preparing to dump script...") + script = Buffer(true) + font = Buffer(true) + handler = function(fname, h, size, ext) + if counter == 1 then + log("Taking script...") + script:copyfrom(h) + elseif counter == 2 then + log("Taking font...") + font:copyfrom(h) + else + error("Too many files.") + end + counter = counter + 1 + end + elseif index[i].ftype == 4 and script and font then + old_script = Buffer(true) + handler = function(fname, h, size, ext) + local ret + if counter == 1 then + log("Putting script...") + ret = insert_script(h, script, nptrs) + elseif counter == 2 then + log("Putting font...") + ret = Buffer(true) + ret:copyfrom(font) + else + error("Too many files.") + end + counter = counter + 1 + return ret + end + end + outfile[i] = process_single_file(fname .. string.format("/%04i-%08X", i, index[i].ftype), h, index[i].size, "room", handler) + if handler then + if counter ~= 3 then error("Didn't get enough files; got " .. (counter - 1) .. " instead of 2.") end + if dump_mode then + extract_room_script(fname .. string.format("/%04i", i), script, font) + end + script:destroy() + font:destroy() + end + h:seek(tell + index[i].size) + end + + if not dump_mode then + for i = 1, nfiles do + local alignment_bytes = alignment(outfile[i]:getsize(), 4) + for j = 1, alignment_bytes do + outfile[i]:writeU8(0) + end + ret:writeU32(index[i].ftype) + ret:writeU32(outfile[i]:getsize()) + end + for i = 1, nfiles do + ret:copyfrom(outfile[i]) + outfile[i]:destroy() + end + end + + return ret +end + +room_logic_check = { + [0x0090] = { 0x18000000, 0x00000008 }, [0x009B] = { 0x98100000, 0x17000000 }, + [0x033C] = { 0x18000000, 0x0000002C }, [0x03BC] = { 0x92100000, 0x150003E1 }, [0x03C7] = { 0x94100000, 0x150003E1 }, [0x03D3] = { 0x93100000, 0x150003E1 }, [0x03DF] = { 0x92100000, 0x150003E1 }, + [0x03E2] = { 0x18000000, 0x00000018 }, [0x03F0] = { 0x1400033C, 0x7E000000 }, + [0x03F5] = { 0x18000000, 0x00000018 }, [0x0403] = { 0x1400033C, 0x7E000000 }, + [0x0408] = { 0x18000000, 0x00000018 }, [0x0416] = { 0x1400033C, 0x7E000000 }, +-- [0x041B] = { 0x18000000, 0x00000020 }, [0x042B] = { 0x1400033C, 0x7E000000 }, +-- [0x0432] = { 0x18000000, 0x00000020 }, [0x0442] = { 0x1400033C, 0x7E000000 }, +-- [0x0449] = { 0x18000000, 0x00000020 }, [0x0459] = { 0x1400033C, 0x7E000000 }, +} + +function check_opcode(script, PC, supposed) + script:seek(PC * 4) + local r = script:readU32() + if r ~= supposed then error(string.format("Error for script: opcode %04X is %08X but was supposed to be %08X", PC, r, supposed)) end +end + +function check_room_logic(script) + for offset, v in pairs(room_logic_check) do + local PC = offset - 1 + for suboffset, supposed in ipairs(v) do + check_opcode(script, PC + suboffset, supposed) + end + end +end + +function extract_room_script(fname, script, font) + log("Processing script " .. fname) + dump_mkdir(fname) + dump_mkdir(fname .. "/EXTRA") + local font = extract_font(fname .. "/FONT", font) + local lookup = resolve_font(font) + local size_1 = script:readU32() + local logic_offset = script:readU32() + local u1 = script:readU32() + local n_ptrs = script:readU32() + local u3 = script:readU32() + local u4 = script:readU32() + local u5 = script:readU32() + + if logic_offset ~= 0 then error("Unhandled logic offset " .. logic_offset) end + + local o + o = Output(fname .. "/EXTRA/00-head1-" .. string.format("%08X", u1) .. ".bin") + o:writeU32(u1) + o:destroy() + o = Output(fname .. "/EXTRA/00-head2-" .. string.format("%08X-%08X-%08X", u3, u4, u5) .. ".bin") + o:writeU32(u3) + o:writeU32(u4) + o:writeU32(u5) + o:destroy() + o = Output(fname .. "/EXTRA/01-head1.bin") + o:writeU32(u1) + o:destroy() + o = Output(fname .. "/EXTRA/01-head2.bin") + o:writeU32(u3) + o:writeU32(u4) + o:writeU32(u5) + o:destroy() + o = Output(fname .. "/EXTRA/02-part1.bin") + o:copyfrom(script, size_1) + o:destroy() + script:seek(-size_1, SEEK_CUR) + local logic = Buffer(true) + logic:copyfrom(script, size_1) + + local ptrs = {} + local ptr_start = 1 + + for i = 1, n_ptrs do + ptrs[i] = script:readU16() + end + + local ptrs_contents, ptrs_raws = {}, {} + local tell = script:tell() + ptrs_contents[1] = "" + ptrs_contents[2] = "" + ptrs_raws[1] = "" + ptrs_raws[2] = "" + ptr_start = 3 + + local header = script_types.room.header + for i = 1, script_types.room.size do + if script:readU8() ~= header[i] then error("Script header file of type 'room' not according to its header") end + end + + for i = ptr_start, n_ptrs do + ptrs_contents[i] = "" + ptrs_raws[i] = "" + if tell + ptrs[i] ~= script:tell() then error("Script consistancy failure for pointer " .. i .. " - we're at " .. script:tell() .. " and " .. (tell + ptrs[i]) .. " was expected.") end + while true do + local r, rr = extract_char(script, lookup) + if not r then break end + ptrs_contents[i] = ptrs_contents[i] .. r + ptrs_raws[i] = ptrs_raws[i] .. rr + end + end + + o = Output(fname .. "/EXTRA/logic.txt") + check_room_logic(logic) + local textboxes = { } + local rd_opcode = function(PC) + logic:seek(PC * 4) + return logic:readU32() + end + local add_textbox = function(txtptr, txtbox) + if txtptr < 0 then return end + o:write("\n") + if ptrs_raws[txtptr + ptr_start] then + o:write(ptrs_raws[txtptr + ptr_start]) + if textboxes[txtptr + ptr_start] then + o:write("\n****SUSPECT****PTR ALREADY RECORDED****: " .. (txtptr + ptr_start)) + end + textboxes[txtptr + ptr_start] = txtbox + else + error("****SUSPECT****PTR TOO LARGE****: " .. (txtptr + ptr_start)) + end + end + local txt_process = function(PC) + local opcode = rd_opcode(PC) + local txtptr + local x, y, width, height + if andB(opcode, 0x00100000) ~= 0 then + local psh1 = rd_opcode(PC - 1) + local psh2 = rd_opcode(PC - 2) + local psh3 = rd_opcode(PC - 3) + local psh4 = rd_opcode(PC - 4) + local psh5 = rd_opcode(PC - 5) + local psh6 = rd_opcode(PC - 6) + + if andB(psh1, 0xff000000) ~= 0x12000000 then return end + if andB(psh2, 0xff000000) ~= 0x12000000 then return end + if andB(psh3, 0xff000000) ~= 0x12000000 then return end + if andB(psh4, 0xff000000) ~= 0x12000000 then return end + if andB(psh5, 0xff000000) ~= 0x12000000 then return end + if andB(psh6, 0xff000000) ~= 0x12000000 then return end + + local arg1 = andB(psh1, 0x7fffff) + local arg2 = andB(psh2, 0x7fffff) + local arg3 = andB(psh3, 0x7fffff) + local arg4 = andB(psh4, 0x7fffff) + local arg5 = andB(psh5, 0x7fffff) + local arg6 = andB(psh6, 0x7fffff) + + txtptr = arg6 + 1 - ptr_start + + x = arg5 + y = arg4 + width = arg3 + height = arg2 + else + txtptr = andB(opcode, 0xff) + 1 - ptr_start + local arg1 = rd_opcode(PC + 1) + local arg2 = rd_opcode(PC + 2) + x = andB(arg1, 0xffff) + y = shr(arg1, 16) + width = andB(arg2, 0xffff) + height = shr(arg2, 16) + end + add_textbox(txtptr, { + x = x, + y = y, + width = width, + height = height, + }) + end + local process_subtxt = function(PC) + local psh1 = rd_opcode(PC - 1) + local psh2 = rd_opcode(PC - 2) + local psh3 = rd_opcode(PC - 3) + local psh4 = rd_opcode(PC - 4) + local psh5 = rd_opcode(PC - 5) + local psh6 = rd_opcode(PC - 6) + + if andB(psh1, 0xff000000) ~= 0x12000000 and andB(psh1, 0xff000000) ~= 0x0B000000 then return end + if andB(psh2, 0xff000000) ~= 0x12000000 then return end + if andB(psh3, 0xff000000) ~= 0x12000000 and andB(psh3, 0xff000000) ~= 0x0B000000 then return end + if andB(psh4, 0xff000000) ~= 0x12000000 and andB(psh4, 0xff000000) ~= 0x0B000000 then return end + if andB(psh5, 0xff000000) ~= 0x12000000 and andB(psh5, 0xff000000) ~= 0x0B000000 then return end + if andB(psh6, 0xff000000) ~= 0x12000000 and andB(psh6, 0xff000000) ~= 0x0B000000 then return end + + local arg1 = andB(psh1, 0x7fffff) + local arg2 = andB(psh2, 0x7fffff) + local arg3 = andB(psh3, 0x7fffff) + local arg4 = andB(psh4, 0x7fffff) + local arg5 = andB(psh5, 0x7fffff) + local arg6 = andB(psh6, 0x7fffff) + + if andB(psh1, 0xff000000) == 0x0B000000 then arg1 = nil end + if andB(psh3, 0xff000000) == 0x0B000000 then arg3 = nil end + if andB(psh4, 0xff000000) == 0x0B000000 then arg4 = nil end + if andB(psh5, 0xff000000) == 0x0B000000 then arg5 = nil end + if andB(psh6, 0xff000000) == 0x0B000000 then arg6 = nil end + + local txtptr = arg2 + 1 - ptr_start + add_textbox(txtptr, { + x = arg6 or "var", + y = arg5 or "var", + width = arg4 or "var", + height = arg3 or "var", + }) + end + local process_subtxt2 = function(PC) + local psh1 = rd_opcode(PC - 1) + local psh2 = rd_opcode(PC - 2) + local psh3 = rd_opcode(PC - 3) + local psh4 = rd_opcode(PC - 4) + local psh5 = rd_opcode(PC - 5) + + if andB(psh1, 0xff000000) ~= 0x12000000 then return end + if andB(psh2, 0xff000000) ~= 0x0B000000 then return end + if andB(psh3, 0xff000000) ~= 0x22000000 then return end + if andB(psh4, 0xff000000) ~= 0x0B000000 then return end + if andB(psh5, 0xff000000) ~= 0xCB000000 then return end + + local txtptr = andB(psh5, 0xff) + 1 - ptr_start + add_textbox(txtptr, { + typ = "fixed", + }) + end + local call_process = function(PC) + local opcode = rd_opcode(PC) + if opcode == 0x1400033C or opcode == 0x140003E2 or opcode == 0x140003F5 or opcode == 0x14000408 then process_subtxt(PC) end + if opcode == 0x14000090 then process_subtxt2(PC) end + end + logic_disasm(logic, o, { + -- ret + [0x17] = function(PC) o:write("\n-----------------------------------------------------\n") end, + -- txtbox1 + [0x92] = txt_process, + -- txtbox2 + [0x93] = txt_process, + -- txtbox3 + [0x94] = txt_process, + -- txtbox4 + [0x98] = txt_process, + -- *sigh* + [0x14] = call_process, + } ) + + o:destroy() + logic:destroy() + + for i = ptr_start, n_ptrs do + if textboxes[i] then + local tb = textboxes[i] + if tb.typ == "fixed" then + ptrs_contents[i] = '<window type="fixed"/>\n' .. ptrs_contents[i] + elseif tb.typ == "auto" then + ptrs_contents[i] = '<window type="auto"/>\n' .. ptrs_contents[i] + else + ptrs_contents[i] = '<window x="' .. tb.x .. '" y="' .. tb.y .. '" width="' .. tb.width .. '" height="' .. tb.height .. '"/>\n' .. ptrs_contents[i] + end + else + ptrs_contents[i] = '<nowindowdetected/>\n' .. ptrs_contents[i] + end + end + + -- WARNING -- only for rooms + local ptrs_idx = process_ptrs(ptrs_contents, ptr_start, n_ptrs) + + local o = Output(fname .. "-script.txt") + o:write("template:room\n") + + for i = ptr_start, n_ptrs do + o:write(ptrs_idx[i] .. "\n") + end + + lookup_rooms:write(" [" .. current_file - 3610 .. "] = { ") + for i = ptr_start, n_ptrs do + lookup_rooms:write(ptrs_idx[i] .. ", ") + end + lookup_rooms:write "},\n" + + o:destroy() +end |