fifa17-recon: club-item counts, and packs that contain more than footballers
Correcting an overstatement first: I said every card family works. Balls, stadia,
badges and kits do not, and this is the start of that, not the finish.
CLUB ITEMS (FUT_CLUBITEMS=1, default off). tools/fut_clubitems.py builds shelves from
the game's own tables: fcc_balls 42, fcc_stadium 78, fcc_badgecards 656,
fcc_kitcards 1482, fcc_leaguelogos 44, each with its real carddbid AND its real
cardassetid. Counts are wired into the club stat set, replacing the honest zeros
rather than appending a second row per id (the deserializer does
store[ctx][statId] = value, so two rows for one id is a coin toss).
Counts FIRST and on purpose. The consumables round proved the count gates the fetch:
the client does not ask for an item list until club/stats reports a non-zero count,
and the CLUB tab reads 0x1e balls, 0x28 kits, 0x14 stadia. Arming the counters is what
makes the client name the item route, which is the one thing static reading has never
produced for this family -- cardtype 9 has NO arm in the merge, so nothing about it is
discoverable from the card DB.
What is deliberately NOT guessed: which cardsubtypeid means ball versus stadium. The
eight values that reach cardtype 9 are {30,31,145..150} and the assignment appears in
none of the 149 dumped tables. probe_shelf() serves one item per candidate so the
screen can say which is which, rather than shipping a guess into someone's club.
PACKS (FUT_PACK_MIX=1, default on). A pack is no longer eleven footballers: roughly a
quarter of each pack is now consumables and occasionally staff, as a ratio so it
scales from a 5-card bronze to an 11-card premium. Club items are excluded until their
subtypes are verified -- a pack is the worst place to discover a wrong subtype,
because the card lands in the save and has to be cleaned out by hand.
Also fixes the art id AT THE SOURCE. fut_consumables now sets cardassetid from the
fcc_ tables, so a pack-granted consumable renders correctly too. The earlier fix only
corrected the copy served by the club route, which meant packs would have dealt cards
with the green NOT FOUND box again.
Pack tests run against a COPY of the profile, after an earlier test persisted 15 cards
into the live save and had to be undone by hand.
439 + 414 checks green.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VUT92pz6RWKih9dSr8ZpxW
This commit is contained in:
@@ -1193,6 +1193,19 @@ CONSUM_STATS = os.environ.get("FUT_CONSUM_STATS", "1") == "1"
|
||||
# Serve consumables as TRADEABLE by default; see _consumable_stacks for why.
|
||||
CONSUM_UNTRADEABLE = os.environ.get("FUT_CONSUM_UNTRADEABLE", "0") == "1"
|
||||
|
||||
# FUT_CLUBITEMS: balls, stadia, badges, kits and league logos.
|
||||
#
|
||||
# Counts FIRST, deliberately. The consumables round proved that the client does not
|
||||
# request an item list until club/stats reports a non-zero count for that family, and
|
||||
# the CLUB tab reads exactly these ids: 0x1e balls, 0x28 kits, 0x14 stadia. So arming
|
||||
# the counters is what makes the client name the item route it uses -- which is the
|
||||
# one thing no amount of static reading has produced for this family, because
|
||||
# cardtype 9 has no arm in the merge at all.
|
||||
#
|
||||
# Default OFF: nothing here has ever been requested by the client, so unlike the
|
||||
# consumables stat fix this is not correcting a demonstrably wrong answer.
|
||||
CLUBITEMS = os.environ.get("FUT_CLUBITEMS", "0") == "1"
|
||||
|
||||
|
||||
def _consumable_stat_rows():
|
||||
"""[(stat name, count)] for the consumables panel, counted from the shelf."""
|
||||
@@ -1261,6 +1274,18 @@ def _club_stat_set():
|
||||
("trophiesSeasonOffline", 0), # 0x37
|
||||
]
|
||||
counts += _consumable_stat_rows()
|
||||
if CLUBITEMS:
|
||||
import fut_clubitems
|
||||
ci = fut_clubitems.counts()
|
||||
# REPLACE the honest zeros above rather than appending a second row per name:
|
||||
# the deserializer writes store[contextValue][statId] = typeValue, so a later
|
||||
# row silently wins and two rows for one id is a coin toss.
|
||||
have = dict(ci)
|
||||
counts = [(t, have.get(t, v)) for t, v in counts]
|
||||
for t, v in ci:
|
||||
if t not in [c[0] for c in counts]:
|
||||
counts.append((t, v))
|
||||
log(" CLUBITEMS: %s" % ", ".join("%s=%d" % kv for kv in ci))
|
||||
# All four keys in every element -- see note 3 above.
|
||||
return [{"contextId": 1, "contextValue": 0, "type": t, "typeValue": int(v)}
|
||||
for t, v in counts]
|
||||
|
||||
Reference in New Issue
Block a user