feat(core): own the EA-authored non-player definition rating
CI / Build, lint & test (push) Successful in 3m23s
CI / Build, lint & test (push) Successful in 3m23s
Adds `CardDefinition.source_rating: Option<u8>` -- the authoritative rating a NON-PLAYER definition carries in EA's own tables (a staff card's `value` from managercards/*coachcards/physiocards, a consumable's rating). WHY NOT `overall`. `overall` feeds quick-sell pricing and squad projection, and it is deliberately 0 for every non-player. Reusing it would silently revalue staff, which is out of scope for the manager-contract milestone. `source_rating` is a separate number read only by tier rules, so both pricing paths stay byte-identical: Core's `quick_sell_coins(card.overall)` and the host's `legacy_discard_value(item.rating)` see exactly what they saw before, and `effective_overall` is unchanged. MUST stay Option: CardDefinition has no `#[serde(default)]`, so a required field would reject every already-shipped content pack, whereas a missing Option deserializes to None. A test pins that backwards compatibility, because it is the property that lets Core and the emitter be deployed independently. No migration: Core does not persist definitions at all -- they are JSON content packs parsed at startup into an immutable in-memory CardDb. `/collection` embeds the serialized definition wholesale, so `card.source_rating` reaches the host with no projection change.
This commit is contained in:
@@ -231,6 +231,20 @@ pub struct CardDefinition {
|
||||
pub physical: u8,
|
||||
pub rarity: Rarity,
|
||||
pub image_path: Option<String>,
|
||||
/// EA's authored definition rating for a NON-PLAYER: a staff card's `value`
|
||||
/// from its shipped family table, or a consumable's own rating.
|
||||
///
|
||||
/// This is deliberately NOT `overall`. `overall` feeds pricing and squad
|
||||
/// projection, so it stays 0 for every non-player; `source_rating` is the
|
||||
/// separate authoritative number the game's own tier rules read (bronze
|
||||
/// `<65`, silver `65..=74`, gold `>=75`). `None` for players, whose rating
|
||||
/// IS `overall`, and `None` whenever Core tracks no authored value — a
|
||||
/// caller MUST fail closed rather than substitute a tier.
|
||||
///
|
||||
/// MUST stay `Option`: `CardDefinition` has no `#[serde(default)]`, so a
|
||||
/// required field would reject every already-shipped content pack, whereas
|
||||
/// a missing `Option` deserializes to `None`.
|
||||
pub source_rating: Option<u8>,
|
||||
}
|
||||
|
||||
/// One owned content INSTANCE (stored in DB).
|
||||
|
||||
@@ -817,6 +817,8 @@ mod tests {
|
||||
physical: 60,
|
||||
rarity: Rarity::Bronze,
|
||||
image_path: None,
|
||||
// A player's rating IS `overall`; no separate authored value.
|
||||
source_rating: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user