"""Q10: the fcc_ table vocabulary and the classifier's neighbourhood. Q8/Q9 changed the picture: inside the item deserializer, cardtype 9 items whose cardsubtypeid is in [0x91,0x95) take a custom-image path, and a SEPARATE deserializer FUN_180108c00 computes subtype = wireValue + 0x91 and then picks the loc format by range: 0x91 <= s < 0x95 -> "TOURNY_LOC_%d" 0x95 <= s < 0x97 -> "SEASON_LOC_%d" so 0x91..0x96 look like TROPHIES, not badges/kits/stadia/balls. Also, cardtype 7 (subtypes 9,10,11) has an arm that defaults a field to 0x23 = 35, and 35 is the kit cardassetid recorded in tools/fut_clubitems.py. This query gathers the vocabulary needed to test that: A. every "fcc_" table name literal in the binary, with the function that queries it -- the merge's per-family table map; B. every literal starting "cardsubtype" / "cardtype" (column names); C. the small helpers around the classifier: FUN_1800d84e0 (called right after it in the deser), FUN_1800d7b30/b50/af0/b10, FUN_1800d7170. CONTROL: "fcc_discardcoins" must appear in A, and its query site must be FUN_18013fe00 (line 784 of the Q8 decompile). If it does not, the literal scan is not seeing the same code the decompiler is. """ import traceback try: print("=== A: fcc_ table literals ===") seen = set() for h in find_all(b"fcc_"): s = rd_str(h, 64) if not s or s in seen: continue seen.add(s) xs = xrefs_to(h) who = ",".join(sorted({"%s(%#x)" % (fn, ent) for _f, _t, fn, ent in xs})) print(" %#x %-28r <- %s" % (h, s, who or "-")) print(" total distinct: %d" % len(seen)) print() print("=== B: cardtype / cardsubtype column literals ===") for pat in (b"cardtype", b"cardsubtype", b"carddbid", b"cardassetid"): for h in find_all(pat): s = rd_str(h, 64) xs = xrefs_to(h) who = ",".join(sorted({"%s(%#x)" % (fn, ent) for _f, _t, fn, ent in xs})) print(" %#x %-28r <- %s" % (h, s, who or "-")) print() print("=== C: helpers ===") for a in (0x1800D84E0, 0x1800D7B30, 0x1800D7B50, 0x1800D7AF0, 0x1800D7B10): src = dec(a) print("-" * 70) print("FUN_%x len=%d" % (a, len(src))) print(src if len(src) < 2500 else src[:2500] + "\n...[TRUNCATED, len above]") except Exception: traceback.print_exc()