"""Q5: resourceId decomposition, the value mappers, and who reads assetId (+0x20).

Established so far, and the reason for each question here:
  * FUN_180141660's TAIL, reached on EVERY family including the no-merge default,
    does record+0x54 = 3 if record+0xb4 >= 0x4b else 2 if >= 0x41 else 1. So +0x54
    is the bronze/silver/gold CARD LEVEL derived from rating, not itemType.
  * The players merge queries `players` by record+0x18 & 0xffffff and, on 0 rows,
    OVERWRITES rating=0x32, attrs=1, teamid=0x78d, nation=0xe, position=2, name=" ".
  * The item deser routes atom 0x1d1 nation to +0x148 for family 1 and +0xde for
    family 2 and NOWHERE otherwise, and atom 0x18a leagueId always to +0xe0.

Remaining:
 (a) FUN_180166ca0(resourceId, &out_byte, buf, &out_dword) -- the resourceId
     decomposition. out_dword lands at record+0x18 and out_byte at record+0x24,
     and +0x24 gates the "p%d.dds" FUTPlayerHeads photo registration. This decides
     Q3: what resourceId actually has to look like.
     CONTROL: DAT_7364642e642570 must read as "p%d.dds"; if it does not, my read of
     the photo path is wrong.
 (b) FUN_180136480 playStyle mapper, FUN_180166810 preferredPosition mapper,
     FUN_180166660 itemState mapper, FUN_1801666f0 injuryType mapper.
 (c) WHO READS record+0x20 (assetId)? Accessors FUN_1801a8020 and FUN_1801a8990
     read it. Enumerate their callers. HYPOTHESIS: only the staff/manager card
     art path, which the merge itself fills from the local DB, so a wire assetId
     is dead for every family.
     CONTROL: the same enumeration run on FUN_1801a87f0 (+0xb4 rating) must return
     the publishers we already found. An enumeration that returns nothing for
     rating is broken.
 (d) FUN_1800d84e0 -- the value written to record+0x30.
 (e) FUN_1801356c0 manager merge, for the family table.
"""
import traceback

try:
    print("=== CONTROL: the format string at 0x1801eaf90..0x1801eafa8 region ===")
    for a in (0x1801EAF98,):
        print("  %#x -> %r" % (a, rd_str(a, 32)))
    hits = find_all(b"p%d.dds")
    print("  'p%%d.dds' occurrences: %s" % " ".join("%#x" % h for h in hits))
    for h in find_all(b"FUTPlayerHeads"):
        print("  FUTPlayerHeads @%#x" % h)

    print()
    print("=== (a) FUN_180166ca0 resourceId decomposition ===")
    print(dec(0x180166CA0))

    print("=== (b) mappers ===")
    for lbl, a in (("playStyle FUN_180136480", 0x180136480),
                   ("preferredPosition FUN_180166810", 0x180166810),
                   ("itemState FUN_180166660", 0x180166660),
                   ("injuryType FUN_1801666f0", 0x1801666F0)):
        s = dec(a)
        print("--- %s len=%d" % (lbl, len(s)))
        print(s)

    print("=== (c) callers of the accessors ===")
    for lbl, a in (("+0x20 assetId FUN_1801a8020", 0x1801A8020),
                   ("+0x20/+0x4c FUN_1801a8990", 0x1801A8990),
                   ("+0x1c cardassetid FUN_1801a8010", 0x1801A8010),
                   ("+0x18 resourceId FUN_1801a80a0", 0x1801A80A0),
                   ("CONTROL +0xb4 rating FUN_1801a87f0", 0x1801A87F0),
                   ("+0x54 level FUN_1801a80c0", 0x1801A80C0),
                   ("+0x54 FUN_1801a8870", 0x1801A8870),
                   ("+0x54 FUN_1801a88f0", 0x1801A88F0)):
        print("--- %s" % lbl)
        for frm, typ, fn, ent in xrefs_to(a):
            print("      %#x %-10s %s(%#x)" % (frm, typ, fn, ent))

    print()
    print("=== (d) FUN_1800d84e0 (record+0x30) ===")
    print(dec(0x1800D84E0))

    print("=== (e) FUN_1801356c0 manager merge ===")
    s = dec(0x1801356C0)
    print("len=%d" % len(s))
    print(s)
except Exception:
    traceback.print_exc()
