summaryrefslogtreecommitdiff
path: root/VP-roomwork.lua
diff options
context:
space:
mode:
authorPixel <pixel@nobis-crew.org>2009-10-14 08:03:19 -0700
committerPixel <pixel@nobis-crew.org>2009-10-14 08:03:19 -0700
commite94c37a627ccd242f63bb08fdb99039c2af58289 (patch)
tree391a3efe42055ba95d324117a8827fd1ac5022a9 /VP-roomwork.lua
Initial import.
Diffstat (limited to 'VP-roomwork.lua')
-rw-r--r--VP-roomwork.lua499
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