# Pin the BASE template each suffix builder composes onto, by walking the vtable the
# builder sits in and reading the sibling slot that returns the base string.
BASES = ["ut/%s/sbs", "ut/%s/draft/mode", "ut/%s/club", "ut/%s/item", "ut/%s",
         "ut/%s/champion", "ut/%s/leaderboards", "ut/%s/season", "ut/%s/tournament",
         "ut/%s/auctionhouse", "ut/%s/trade", "ut/%s/tradePile", "ut/%s/marketdata",
         "ut/%s/purchased", "ut/%s/user", "ut/%s/squad", "ut/%s/squad/mode"]
for b in BASES:
    hits = find_all(b.encode() + b"\x00", blocks=(".rdata", ".data", ".text"))
    print("=== %-22s %s" % (b, [hex(h) for h in hits]))
    for h in hits:
        for (fr, ty, fn, en) in xrefs_to(h):
            print("      ref %#x  %-10s  %s @%#x" % (fr, ty, fn, en))

# Builders whose base we still need. Print the vtable that holds each.
BUILDERS = {"objective/reward FUN_180151610": 0x180151610,
            "objective/complete FUN_180147780": 0x180147780,
            "sets FUN_18017a980": 0x18017a980,
            "consumables FUN_1801308c0": 0x1801308c0,
            "clubstats FUN_18012f4f0": 0x18012f4f0}
for nm, a in BUILDERS.items():
    print("\n### vtable slots holding %s" % nm)
    for h in find_all(a.to_bytes(8, "little"), blocks=(".rdata", ".data")):
        print("   vt entry @%#x" % h)
        for k in range(-6, 7):
            try:
                q = qword(h + k * 8)
            except Exception:
                continue
            tag = ""
            if 0x180000000 <= q < 0x181000000:
                try:
                    s = rd_str(q, 60)
                    if s and all(32 <= ord(c) < 127 for c in s) and len(s) > 2:
                        tag = "  STR %r" % s
                except Exception:
                    pass
                f = fm.getFunctionAt(addr(q))
                if f is not None and not tag:
                    tag = "  FN %s" % f.getName()
            print("      [%+2d] %#018x%s" % (k, q, tag))
