# 9. System Integrations

[< Back to Index](README.md) | [Next: Economy >](10-economy.md)

---

## 9.1 Crafting System (#49) — Future Integration

The crafting system (Gitea #49) is out of scope for this PRD and has not been fully designed.
When crafting ships, the evolution system will need to define interaction rules (e.g., what
happens to evolution state when a card is used as a crafting ingredient, whether evolution tier
affects crafting output). Those rules will be specified in the crafting PRD.

---

## 9.2 Campaign Mode

Evolution milestones of the `complete_campaign_stage` type are met when the team completes a
campaign stage. The bot already records campaign stage completions; the evolution subsystem hooks
into the post-game callback.

Evolved cards used in campaign games contribute normally to game mechanics. No special
campaign-mode rules for evolved cards.

## 9.3 Gauntlet Mode

Gauntlet is the highest-stakes game mode. Two milestone types reference it directly:
`complete_gauntlet` (finish any gauntlet) and `win_gauntlet` (place first). These are evaluated
via the `gauntletreward` table's post-event callback, which triggers milestone evaluation for all
active teams.

Fully evolved cards used in gauntlet display their evolved name in the gauntlet bracket display,
providing social prestige incentive for completing evolutions before entering gauntlet events.

## 9.4 Unlimited / Ranked PvP

Evolved cards are legal in all game modes. Their higher ratings reflect the investment of gameplay
time, not additional spending. This positions evolved cards as earned rather than bought power,
which is important for PvP mode balance.

There is no separate evolved card bracket or ladder. Evolved cards compete in the same pool.

## 9.5 Scouting System

The scouting reports (`pd-cards scouting all`) aggregate stats at the `player_id` level across
all cardsets. Evolution creates `variant`-specific rating rows, which the scouting report
generator should ignore (it reads `variant = 0` base rows). No changes needed to scouting scripts.

A future enhancement could flag evolved cards in scouting output with a visual marker.

## 9.6 Trading (Not Yet Implemented — Roadmap)

Trading is not yet implemented but is on the roadmap. When it ships, the following rules apply:

**Evolution resets on trade.** The traded card's `card.variant` is set to `0`, and it is
disassociated from the selling team's `evolution_card_state` record. If the new team already has
an `evolution_card_state` for this `player_id`, the traded card inherits that state (and its
variant). If the new team has no prior state for this player, a fresh `evolution_card_state` is
created with `current_tier = 0` and `progress_since` set to the trade date. The new team starts
fresh — only stats accumulated in games played by the *new* team count toward milestones.

**The selling team's state is unaffected.** If Oakland still has other copies of the same
player_id, their `evolution_card_state` remains intact. The trade only affects the specific
card instance being transferred.

Example: If Mark McGwire evolves to T2 on the Oakland Athletics and that card gets traded to the
St. Louis Cardinals, the Cardinals' McGwire card starts at T0 (assuming they had no prior McGwire
cards). Only stats from Cardinals games count toward the new evolution progress.

**The card's variant resets.** `card.variant` is set to `0` on the traded card instance, meaning
it falls back to `player.image` and base ratings. The old variant's
`battingcard`/`pitchingcard` rows and S3 images are NOT deleted — they may still be shared by
other cards with the same hash.

**The evolved card name resets.** Since the card is at T0 on the new team, no evolved name is
displayed.

**Purchased cosmetics do not transfer.** Cosmetics are attached to the selling team's
`evolution_card_state`. The new team does not inherit the previous owner's premium visuals.

**Design rationale:** This creates a loyalty incentive — the longer you keep a card, the more
evolved it becomes. Trading away a fully evolved card is a real sacrifice, creating meaningful
tension when trading eventually ships.

## 9.7 Pack Opening and paperdex

When cards are acquired (pack opening, reward, etc.), the system resolves evolution state using
a **batched eager** approach so that card flair is visible immediately during the opening:

1. Collect all `player_id` values from the pack's cards
2. Single batch query: `SELECT player_id, current_tier, variant FROM evolution_card_state WHERE team_id = ? AND player_id IN (?...)`
3. For cards with an existing state: set `card.variant` to match (inherits tier, cosmetics, flair)
4. For cards without a state: batch `INSERT` new `evolution_card_state` rows at `current_tier = 0`, `progress_since = card.created_at`
5. Batch `UPDATE` card variants for all cards that inherited existing state

This reduces evolution resolution to ~3 queries total regardless of pack size, avoiding per-card
round trips. The eager approach ensures evolved card visuals (and any future random cosmetic
effects like holo pulls) display immediately during the pack opening experience rather than
loading lazily on first view.

paperdex tracks ownership booleans at the team+player level and does not need modification for
evolution.
