summaryrefslogtreecommitdiff
path: root/VP-roomwork.lua
blob: d07cdf45e69c922d441667c1a2e51945187f1412 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
function patch_logic(logic, windows, activate_debug)
    local ptr_start = 3
    local rd_opcode = function(PC)
        logic:seek(PC * 4)
        return logic:readU32()
    end
    local patch_opcode = function(PC, newcode)
        logic:wseek(PC * 4)
        logic:writeU32(newcode)
    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
            
            if txtptr < 0 then return end
            
            local window = windows[txtptr + ptr_start]
            
            if not window then return end
            
            if window.x and window.x ~= "var" then psh5 = orB(andB(psh5, 0xff800000), window.x) end
            if window.y and window.y ~= "var" then psh4 = orB(andB(psh4, 0xff800000), window.y) end
            if window.width and window.width ~= "var" then psh3 = orB(andB(psh3, 0xff800000), window.width) end
            if window.height and window.height ~= "var" then psh2 = orB(andB(psh2, 0xff800000), window.height) end
            
            patch_opcode(PC - 2, psh2)
            patch_opcode(PC - 3, psh3)
            patch_opcode(PC - 4, psh4)
            patch_opcode(PC - 5, psh5)
        else
            txtptr = andB(opcode, 0xff) + 1 - ptr_start
            if txtptr < 0 then return end
            local window = windows[txtptr + ptr_start]
            if not window then return end
            if window.wtype == "fixed" then return end
            if window.x == "var" or window.y == "var" or window.width == "var" or window.height == "var" then return end
            local arg1 = orB(window.x, shl(window.y, 16))
            local arg2 = orB(window.width, shl(window.height, 16))
            patch_opcode(PC + 1, arg1)
            patch_opcode(PC + 2, arg2)
        end
    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 arg2 = andB(psh2, 0x7fffff)
        
        local txtptr = arg2 + 1 - ptr_start
        if txtptr < 0 then return end
        
        local window = windows[txtptr + ptr_start]
        if not window then return end

        if andB(psh3, 0xff000000) ~= 0x0B000000 and window.height and window.height ~= "var" then psh3 = orB(andB(psh3, 0xff800000), window.height) end
        if andB(psh4, 0xff000000) ~= 0x0B000000 and window.width and window.width ~= "var" then psh4 = orB(andB(psh4, 0xff800000), window.width) end
        if andB(psh5, 0xff000000) ~= 0x0B000000 and window.y and window.y ~= "var" then psh5 = orB(andB(psh5, 0xff800000), window.y) end
        if andB(psh6, 0xff000000) ~= 0x0B000000 and window.x and window.x ~= "var" then psh6 = orB(andB(psh6, 0xff800000), window.x) end
        
        patch_opcode(PC - 3, psh3)
        patch_opcode(PC - 4, psh4)
        patch_opcode(PC - 5, psh5)
        patch_opcode(PC - 6, psh6)
    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
    end
    check_room_logic(logic)
    if activate_debug then patch_opcode(0x1158, 0x9e000000) end
    logic_disasm(logic, nil, {
        -- txtbox1
        [0x92] = txt_process,
        -- txtbox2
        [0x93] = txt_process,
        -- txtbox3
        [0x94] = txt_process,
        -- txtbox4
        [0x98] = txt_process,
        -- *sigh*
        [0x14] = call_process,
    } )
end

function process_current_room_script()
    local script, font, scriptfile, fontfile, nptrs, windows
    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
    windows = {}
    for pidx, pval in ipairs(rooms_lookup[room_idx]) do
        nptrs = nptrs + 1
        local ptr = rooms_txts[pval]
        windows[nptrs] = windows_data[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, windows
end

function insert_script(old, new, nptrs, windows)
    local size_logic = 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_logic)
    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)
    local logic = Buffer(true)
    logic:copyfrom(old, size_logic)
    patch_logic(logic, windows, got_us and current_file == (3610 + 125) and activate_debug_room)
    logic:seek(0)
    ret:copyfrom(logic)
    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' - " .. ext)
    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
    local windows = {}
    if not dump_mode then
        script, font, nptrs, windows = process_current_room_script()
    end
    for i = 1, nfiles do
        tell = h:tell()
        local handler = nil
        local counter = 1
        if dump_mode and ext == "arm" and index[i].ftype == 4 then
            log("Preparing to dump script...")
            handler = function(fname, h, size, ext)
                if counter == 1 then
                    log("Taking script...")
                    script = Buffer(true)
                    script:copyfrom(h)
                elseif counter == 2 then
                    log("Taking font...")
                    font = Buffer(true)
                    font:copyfrom(h)
                else
                    error("Too many files.")
                end
                counter = counter + 1
            end
        elseif not dump_mode and ext == "arm" and 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, windows)
                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
        elseif dump_mode and ext == "sarc" and index[i].ftype == 4 then
            handler = function(fname, h, size, ext)
                if counter == 1 then
                    if script then error "Can't have two scripts in these..." end
                    log("Taking text...")
                    script = Buffer(true)
                    script:copyfrom(h)
                elseif counter == 2 then
                    if font then error "Can't have two fonts in these..." end
                    log("Taking font...")
                    font = Buffer(true)
                    font:copyfrom(h)
                else
                    error("Too many files")
                end
                counter = counter + 1
            end
        elseif dump_mode and ext == "sarc" and index[i].ftype == 7 then
            if font then error "Can't have two fonts in these..." end
            handler = function(fname, h, size, ext)
                if counter == 1 then
                    log("Taking font...")
                    font = Buffer(true)
                    font:copyfrom(h)
                else
                    error("Too many files")
                end
                counter = counter + 1
            end
        elseif not dump_mode and ext == "sarc" and index[i].ftype == 4 then
--            error "Not written yet"
            handler = nil
        elseif not dump_mode and ext == "sarc" and index[i].ftype == 7 then
--            error "Not written yet"
            handler = nil
        end
        outfile[i] = process_single_file(fname .. string.format("/%04i-%08X", i, index[i].ftype), h, index[i].size, "room", handler)
        if handler and script and font then
            if dump_mode and ext == "arm" then
                extract_room_script(fname .. string.format("/%04i", i), script, font)
            elseif dump_mode then
                extract_simple_script(fname .. string.format("/%04i", i), script, font)
            end
            script:destroy()
            font:destroy()
            script = nil
            font = nil
        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

function extract_simple_script(fname, script, font)
    log("Processing script " .. fname)
    dump_mkdir(fname)
    local font = extract_font(fname .. "/FONT", font)
    local lookup = resolve_font(font)
    local n_ptrs = 1
    local script_begin = script:readU32()
    
    local ptrs = {}
    local unks = {}
    local ptr_start = 1
    local tell = script:tell()
    
    while tell < script_begin do
        unks[n_ptrs] = script:readU32()
        ptrs[n_ptrs] = script:readU32()
        tell = script:tell()
        n_ptrs = n_ptrs + 1
    end
    ptrs[n_ptrs] = script:getsize() - script_begin
    n_ptrs = n_ptrs - 1
    
    local ptrs_contents, ptrs_raws = {}, {}
    ptr_start = 1
    for i = ptr_start, n_ptrs do
        ptrs_contents[i] = ""
        ptrs_raws[i] = ""

--        if tell + ptrs[i] ~= script:tell() then print("Script consistancy failure for pointer " .. i .. " - we're at " .. script:tell() .. " and " .. (tell + ptrs[i]) .. " was expected.") end

        script:seek(script_begin + ptrs[i])
        while script:tell() ~= (script_begin + ptrs[i + 1]) do
            local r, rr = extract_char(script, lookup)
            if r then
                ptrs_contents[i] = ptrs_contents[i] .. r
                ptrs_raws[i] = ptrs_raws[i] .. rr
            elseif script:tell() ~= (script_begin + ptrs[i + 1]) then
                ptrs_contents[i] = ptrs_contents[i] .. "<ZERO>"
            end
        end
    end
    
    local o = Output(fname .. "-script.txt")
    for i = ptr_start, n_ptrs do
        o:write("<ptr " .. i .. " - " .. unks[i] .. ">\n")
        o:write(ptrs_contents[i])
        o:write("\n")
    end
    
    o:destroy()
end