"""Q1 cont: the UI-facing readers. GetMaxPileSize -> FUN_18003ff60, GetAuctionTunables -> FUN_18003fa40, and model vt+0x130 (the object whose +0x30 holds NUM_MAX_AUCTIONS). HYPOTHESIS: GetMaxPileSize is what the transfer-list UI actually calls, and it resolves to the same model+0x1fd1c that TRADE_PILE_SIZE publishes -- OR to the separate (vt+0x130)+0x30 auction cap. These are two different numbers and the brief conflates them. CONTROL: FUN_18000d550 (already decompiled) is the known-good reader of model+0x1fd1c via vt+0xa58. If FUN_18003ff60 reaches vt+0xa58 too, they agree. Also: form-independent disp32 writer scan for the auction-cap field. I search .text for the raw little-endian 4-byte displacement, which catches mov/movzx/cmp/ lea in EVERY encoding -- the search form that caught the +0x1fd2e writer. For a small offset like 0x30 a disp32 scan is useless (it would be disp8), so instead I enumerate every writer of the object returned by vt+0x130 by decompiling its allocator/deserialiser. """ import struct, traceback try: for a, tag in [ (0x18003ff60, "GetMaxPileSize script binding"), (0x18003fa40, "GetAuctionTunables script binding"), ]: src = dec(a) print("\n\n########## %#x %s (len=%d) ##########" % (a, tag, len(src))) print(src) except Exception: traceback.print_exc() try: VT = 0x18021c2a0 print("\n\n########## model vtable slots of interest ##########") for slot in (0x08, 0x130, 0x270, 0xa58, 0xa60, 0x988, 0x998, 0xb00): t = qword(VT + slot) f = fm.getFunctionAt(addr(t)) if 0x180001000 <= t < 0x1801e5000 else None stub = read_bytes(t, 16) if f or (0x180001000 <= t < 0x1801e5000) else b"" print(" vt+%#05x -> %#x %s stub=%s" % (slot, t, f.getName() if f else "?", stub.hex())) if 0x180001000 <= t < 0x1801e5000: s = dec(t) print(" ---- decompile (len=%d) ----" % len(s)) print(" " + s.replace("\n", "\n ")) except Exception: traceback.print_exc()