"""Q1 scaffolding: locate the fcc_discardcoins query site and its containing
function(s), and print the raw instruction stream around the three bind sites.

HYPOTHESIS: the SQL at 0x1802231e4.. is built and bound inside one function whose
frame holds the item pointer; cardtype/level/rare come from three distinct item
struct offsets, and the result is stored at item+0x3c.

CONTROL: 0x18013fe00 (the shared ITEM deserializer, known function) and
0x1800d8330 (the known cardsubtypeid->cardtype mapper) must both resolve to real
functions with sane sizes. If they do not, the project copy is wrong and every
other answer here is void.

Absence discipline: nothing in this file claims absence. It only prints.
"""
import traceback

OUT = "/tmp/claude-1000/-home-alex-Documents-OpenFUT/8e521ca1-ca3e-4138-bb96-df1744dd1d30/scratchpad/cards/q1_out.txt"

try:
    lines = []
    def P(*a):
        s = " ".join(str(x) for x in a)
        lines.append(s)

    LITS = {
        0x1802231E4: "sql frag A",
        0x1802231F0: "sql frag B",
        0x1802231F4: "fcc_discardcoins",
        0x180223208: "sql frag C",
        0x180207848: "sql frag D",
        0x18022315C: "sql frag E",
    }
    P("=== LITERALS ===")
    for a, tag in sorted(LITS.items()):
        try:
            P("%#x %-18s %r" % (a, tag, rd_str(a, 120)))
        except Exception as e:
            P("%#x %-18s READ FAIL %s" % (a, tag, e))

    P("")
    P("=== XREFS TO LITERALS ===")
    for a, tag in sorted(LITS.items()):
        xs = xrefs_to(a)
        P("%#x %s -> %d refs" % (a, tag, len(xs)))
        for frm, typ, fn, ent in xs:
            P("    from %#x %-14s in %s @ %#x" % (frm, typ, fn, ent))

    P("")
    P("=== FUNCTION IDENTITY ===")
    for a in (0x18013FE00, 0x1800D8330, 0x180141025, 0x180141119, 0x180141140,
              0x180141660, 0x180141E8A, 0x180140F00):
        f = func(a)
        if f is None:
            P("%#x -> NO FUNCTION" % a)
            continue
        b = f.getBody()
        P("%#x -> %s entry=%#x body=[%#x..%#x] size=%d"
          % (a, f.getName(), int(f.getEntryPoint().getOffset()),
             int(b.getMinAddress().getOffset()), int(b.getMaxAddress().getOffset()),
             int(b.getNumAddresses())))

    P("")
    P("=== RAW INSTRUCTIONS 0x180140f80 .. 0x180141200 ===")
    p = 0x180140F80
    while p < 0x180141200:
        ins = listing.getInstructionAt(addr(p))
        if ins is None:
            P("%#x  <no instruction>" % p)
            p += 1
            continue
        P("%#x  %s" % (p, ins))
        p += ins.getLength()

    P("")
    P("=== RAW INSTRUCTIONS 0x180141e40 .. 0x180141f00 (level derivation) ===")
    p = 0x180141E40
    while p < 0x180141F00:
        ins = listing.getInstructionAt(addr(p))
        if ins is None:
            P("%#x  <no instruction>" % p)
            p += 1
            continue
        P("%#x  %s" % (p, ins))
        p += ins.getLength()

    src = dec(0x180141025)
    P("")
    P("=== FULL DECOMPILE of function containing 0x180141025, len=%d ===" % len(src))
    P(src)

    with open(OUT, "w") as fh:
        fh.write("\n".join(lines))
    print("wrote %s (%d lines)" % (OUT, len(lines)))
except Exception:
    traceback.print_exc()
