b2697b13dc
Single source of truth for FIFA 17 FUT card families, reconciled against the authoritative shipped fcc_*.json + staff tables (verified byte-identical between .105 and this repo, 36/36 sha256). - docs/CARD_TAXONOMY.md: family -> table/rowcount/subtype/carddbid/cardassetid, with OBSERVED/INFERRED/HYPOTHESIS/UNKNOWN labels. Corrects four superseded claims (chem styles are 250-273 not 91-136; 6300/6400xxx are kits not badges; 5004xxx misc and 8010xxx league logos exist). Manager-league precision kept distinct: shipped table 300-340 (41 rows) vs client enum 300-341 (341 defined, unshipped). Club-item wire subtype->family mapping preserved as UNKNOWN. - docs/evidence/fifa17-recon/table-hashes.sha256: 36-file provenance manifest (31 fcc_*.json + 5 staff tables), combined hash 10f239ad... Describes the FIFA 17 data/client model only; not OpenFUT Core assumptions.
143 lines
8.2 KiB
Markdown
143 lines
8.2 KiB
Markdown
# FIFA 17 FUT — Card Taxonomy (single source of truth)
|
||
|
||
Status: verified 2026-08-12. This document supersedes every earlier scattered
|
||
taxonomy claim in the repo (see "Superseded taxonomy" at the bottom).
|
||
|
||
Evidence labels: **OBSERVED** = read directly from a shipped table or decompiled
|
||
function; **INFERRED** = derived from OBSERVED facts; **HYPOTHESIS** = plausible,
|
||
not yet proven. `UNKNOWN` is a valid answer and is stated as such.
|
||
|
||
## Provenance
|
||
|
||
- Authoritative tables: `10.10.0.105:/home/alex/Documents/OpenFUT/fifa17-recon/data/tables/`,
|
||
copied byte-identical into this repo at `fifa17-recon/data/tables/`.
|
||
SHA-256 manifest + verification: `docs/evidence/fifa17-recon/table-hashes.sha256`
|
||
(36 files: 31 `fcc_*.json` + 5 staff tables; combined hash-of-hashes
|
||
`10f239add919089354d8dbff873fc9737b0a0f80f6ac41b1aa2a096c0ec8d331`).
|
||
- Each table file is a DECODED dump `{table, source, rowcount, schema[], rows[]}`;
|
||
card instances are in `rows[]`, one object per card. Row counts and id ranges
|
||
below were re-extracted from the in-repo `.120` copies.
|
||
- Semantic (subtype→kind) labels are decompiler-derived, carried in
|
||
`fifa17-recon/tools/fut_consumables.py` (`BY_SUBTYPE`, `_DOC`), generated by
|
||
`tools/build_consumables.py` from `FUN_1800d8330`, `FUN_18013f4d0`,
|
||
`FUN_1801bfac0`, `FUN_1801aa230`, `FUN_180048780` + the fcc tables.
|
||
- Staff family selection: `fifa17-recon/docs/CARD_SYSTEM.md` (2026-08-04/05 blocks)
|
||
and `fifa17-recon/tools/fut_staff.py` / `fut_coaches.py`.
|
||
|
||
## Family selector (OBSERVED, binary)
|
||
|
||
Before registering an item, `FUN_180141660` merges the client's local DB. It
|
||
switches on record `+0x4c` (`cardtype`), which `FUN_1800d8330` derives from JSON
|
||
atom `0x6c cardsubtypeid` alone:
|
||
|
||
```
|
||
cardsubtypeid 0..3 -> cardtype 1 players
|
||
4 -> cardtype 2 managercards
|
||
5 -> cardtype 3 headcoachcards
|
||
6 -> cardtype 10 gkcoachcards
|
||
7 -> cardtype 5 physiocards
|
||
8 -> cardtype 4 fitnesscoachcards
|
||
0x1e,0x1f,0x91..0x96,0xe7..0xe9,0xec -> cardtype 9 club items + misc
|
||
absent (default 342) -> cardtype 0 no merge
|
||
```
|
||
|
||
Key: `carddbid == resourceId` for non-player families (queried RAW, no mask);
|
||
players are queried by `playerid = resourceId & 0xffffff` (atom `0x287`), and
|
||
`assetId` (atom `0x23`) is never read by the merge.
|
||
|
||
## Consumable & staff families — evidence table (OBSERVED, `.120` tables)
|
||
|
||
| Family | Table | Rows | carddbid range | cardsubtype set | cardassetid (ART) |
|
||
|---|---|---|---|---|---|
|
||
| Contracts | `fcc_contractcards.json` | 13 | 5001001–5001013 | {201, 202} | {7, 8} |
|
||
| Fitness + Healing | `fcc_healingcards.json` | 27 | 5002001–5002030 | {211,212,213,215,216,217,218,219,220} | {9, 10} |
|
||
| Training (6 sub-families) | `fcc_trainingcards.json` | 143 | 5003001–5003159 | 51-57, 61-67, 91-110, 121-136, 250-273, 300-340 | {1,3,32,34,35,50,51} |
|
||
| Misc | `fcc_misccards.json` | 42 | 5004001–5004042 | {231, 232, 233, 236} | {43, 44, 45, 46} |
|
||
| Badges | `fcc_badgecards.json` | 656 | 6000000–6000656 | (none in row) | {39} |
|
||
| Stadiums | `fcc_stadium.json` | 78 | 6200000–6200077 | (none in row) | {36} |
|
||
| Kits | `fcc_kitcards.json` | 1482 | 6300000–6400654 | (none in row) | {35} |
|
||
| League logos | `fcc_leaguelogos.json` | 44 | 8010000–8010044 | (none in row) | {40} |
|
||
| League logo stickers | `fcc_leaguelogostickers.json` | 39 | 8010000–8010039 | (none in row) | {40} |
|
||
| Balls | `fcc_balls.json` | 42 | 8120194–8120236 | (none in row) | {37} |
|
||
| Managers | `managercards.json` | 417 | 1000001–1001552 | (staff; by cardsubtypeid 4) | (assetid col) |
|
||
| Head coaches | `headcoachcards.json` | 124 | 2000004–2000328 | (staff; subtype 5) | — |
|
||
| GK coaches | `gkcoachcards.json` | 121 | 9000001–9000324 | (staff; subtype 6) | — |
|
||
| Physios | `physiocards.json` | 51 | 4000002–4000259 | (staff; subtype 7) | — |
|
||
| Fitness coaches | `fitnesscoachcards.json` | 115 | 3000019–3000328 | (staff; subtype 8) | — |
|
||
|
||
Notes:
|
||
- **Contracts (5001xxx)** — 201 = player_contract, 202 = manager_contract
|
||
(OBSERVED, `BY_SUBTYPE`).
|
||
- **Fitness + Healing (5002xxx)** — subtype **214 is a valid enum value but ships
|
||
ZERO rows** (OBSERVED: 214 absent from `rows[]`). Enum split (OBSERVED,
|
||
`BY_SUBTYPE`): healing = 211-218, player_fitness = 219, squad_fitness = 220.
|
||
The `+0x58 rareflag == 1` trap flips subtype 219 to squad-fitness.
|
||
- **Training (5003xxx)** — SIX sub-families, all OBSERVED in `rows[]` and labelled
|
||
in `BY_SUBTYPE`:
|
||
- `gk_training` 51-57 (7)
|
||
- `player_training` 61-67 (7)
|
||
- `position_mod` 91-110 (20)
|
||
- `formation_mod` 121-136 (16)
|
||
- chem/play styles 250-273 (24): `player_playstyle` 250-268 (19) +
|
||
`gk_playstyle` 269-273 (5)
|
||
- `manager_league` 300-**341** in the client enum (42), but the shipped table
|
||
contains only 300-340 (41 rows) — 341 is defined, not shipped.
|
||
- Client enum also defines vestigial/unshipped ranges NOT in the table:
|
||
`manager_formation_mod` 71-86, and `DEAD_ZONE`
|
||
58-60,68-70,87-90,111-120,203-210 (28). These have no rows.
|
||
- **Misc (5004xxx)** — subtypes {231,232,233,236}; cardassetid ART 43-46.
|
||
cardsubtype 231 = 0xe7 anchors the 0xe7..0xe9 block to misc via `FUN_1800d8330`.
|
||
- **Club items (badges/stadiums/kits/logos/balls)** carry no `cardsubtype` in the
|
||
row; they are keyed by `carddbid` range and distinguished on the wire by ART
|
||
`cardassetid` (badges 39, stadium 36, kits 35, logos 40, balls 37). **Kits live
|
||
at 6300000–6400654 and are NOT badges** (badges are 6000xxx). The client-side
|
||
subtype→family map (which of 0x1e,0x1f,0x91..0x96 is ball vs stadium vs badge vs
|
||
kit) is **UNKNOWN** — it is in none of the dumped tables and cardtype 9 has no
|
||
miss-fill arm (see `CARD_SYSTEM.md`, "Club items", 2026-08-05).
|
||
|
||
## Staff — subtype/cardtype selectors (OBSERVED, binary)
|
||
|
||
| cardsubtypeid | cardtype | Family | Table | Rows | carddbid range |
|
||
|---|---|---|---|---|---|
|
||
| 4 | 2 | Manager | `managercards.json` | 417 | 1000001–1001552 |
|
||
| 5 | 3 | Head coach | `headcoachcards.json` | 124 | 2000004–2000328 |
|
||
| 6 | 10 | GK coach | `gkcoachcards.json` | 121 | 9000001–9000324 |
|
||
| 7 | 5 | Physio | `physiocards.json` | 51 | 4000002–4000259 |
|
||
| 8 | 4 | Fitness coach | `fitnesscoachcards.json` | 115 | 3000019–3000328 |
|
||
|
||
`cardsubtypeid -> rec+0x50` is the only family selector; `FUN_1800d8330` maps it to
|
||
`rec+0x4c cardtype`. Manager merge = `FUN_1801356c0` (queries `managercards` by
|
||
`carddbid` raw); coach merges live in the respective tables (`fut_coaches.py`).
|
||
All five render live with real photos/bonuses, zero "DB Error" (CARD_SYSTEM.md,
|
||
2026-08-05).
|
||
|
||
## Players (context, out of taxonomy scope here)
|
||
|
||
Players use cardsubtypeid 0..3 -> cardtype 1; merged by `playerid = resourceId &
|
||
0xffffff` against the local `players` table. Identity/name/nation/team come from
|
||
the client DB; rating/position/attributes come from our item JSON. See
|
||
`CARD_SYSTEM.md` and the migration work in `openfut-adapter-fifa17`.
|
||
|
||
## Superseded taxonomy (report only — no other files edited)
|
||
|
||
The earlier working taxonomy (in prior agent-session notes / long-term memory, and
|
||
partially in the original `TablesTaxonomy` scout output) got four things wrong.
|
||
Corrected here:
|
||
|
||
1. **Chemistry / play styles are 250-273, NOT 91-136.** 91-110 = `position_mod`,
|
||
121-136 = `formation_mod`. (OBSERVED in `fcc_trainingcards` + `BY_SUBTYPE`.)
|
||
2. **6300xxx/6400xxx are KITS, not badges.** Badges are 6000xxx. (OBSERVED.)
|
||
3. **5004xxx misc cards exist** (subtypes 231/232/233/236, ART 43-46). Previously
|
||
omitted. (OBSERVED, `fcc_misccards`.)
|
||
4. **8010xxx league logos exist** (+ stickers), ART 40. Previously omitted.
|
||
(OBSERVED, `fcc_leaguelogos`.)
|
||
|
||
**Repo blast-radius of the superseded values: NONE.** A repo-wide grep
|
||
(`docs/`, `openfut-adapter-fifa17/`, `openfut-core/`, `fifa17-recon/`) for the wrong
|
||
claims (`91-136` chem styles; `6300/6400xxx` as badges) returns zero hits.
|
||
`fifa17-recon/docs/CARD_SYSTEM.md` and `plan-2026-08-06-card-subsystem.md` already
|
||
use the correct `250..273` for chem styles and the correct staff subtypes 4-8;
|
||
`CARD_SYSTEM.md` is a mechanism log, not a taxonomy, and asserts none of the wrong
|
||
ranges. The superseded values therefore live only in non-repo agent memory, which
|
||
should be corrected to point at this document.
|