Player and Battle Deck - UQcsse3200/2026-studio-3 GitHub Wiki

Player and Battle Deck

This page describes Team 5's deck-side card systems. PlayerDeck owns the cards collected by the player across a run, while BattleDeck owns the temporary draw, hand and discard state for one combat encounter. These systems do not define card data, calculate gameplay effects or render the battle UI.

Team 6 owns the static card definitions such as CardConfig, card IDs, costs, targets and effects. Team 5 stores each owned copy as a CardInstance(instanceId, cardId, upgradeLevel): the cardId resolves the Team 6 definition, while instanceId identifies one exact physical copy. This prevents duplicate copies or independently upgraded copies from being confused.


Cross-Team Integration

CardPlayService is the bridge between deck state and the wider combat flow in main.

flowchart LR
    T6[Team 6 Card Library<br/>CardConfig / EffectConfig / CardService]
    T5Deck[Team 5 Decks<br/>PlayerDeck / BattleDeck]
    T3[Team 3 Battle Flow and UI<br/>turn phase, selected card, selected target,<br/>result dispatch]
    T5Play[Team 5 CardPlayService<br/>validate play request]
    T7Energy[Team 7 EnergyComponent<br/>canAfford / spendEnergy]
    T5Effects[Team 5 CardEffectResolutionService<br/>resolve card effects]
    Result[CardPlayResult<br/>resolved effects + DeckSnapshot]
    T1[Team 1 Enemy System<br/>consume enemyEffects]
    T7Stats[Team 7 Combat Stats<br/>consume playerEffects]

    T6 --> T5Deck
    T5Deck --> T5Play
    T3 --> T5Play
    T6 --> T5Play
    T7Energy --> T5Play
    T5Play --> T5Effects
    T5Effects --> Result
    Result --> T3
    T3 --> T1
    T3 --> T7Stats
Loading

Team 3 provides the combat timing, selected card instance and selected target. Team 5 validates that request, spends energy through Team 7, resolves the card effects, updates the battle deck, and returns a structured CardPlayResult to Team 3. Team 3 / battle flow then distributes enemyEffects() to Team 1 and playerEffects() to Team 7.

The intended communication flow is:

  1. Team 3 confirms a card play attempt and sends the selected instanceId / target information to Team 5.
  2. Team 5 reads the card config from Team 6's card library.
  3. Team 5 calls Team 7's energy function, such as spendEnergy(card.cost), to check whether the card can actually be played.
  4. If the player does not have enough energy, Team 5 returns a failed CardPlayResult to Team 3. No card effects are resolved, no effects are applied, and the card remains in hand.
  5. If the player has enough energy, Team 5 resolves the card effects and packages them into a successful CardPlayResult.
  6. Team 5 returns the CardPlayResult to Team 3 / battle flow.
  7. Team 3 / battle flow then passes enemyEffects() to Team 1 and playerEffects() to Team 7.

Player Deck

PlayerDeck stores the player's owned cards outside a single combat encounter.

What it does

  • Stores CardInstance values in deck order.
  • Adds a card definition as a fresh instance, or restores an existing instance without changing its identity or upgrade level.
  • Removes or upgrades one exact owned copy by instanceId, while still allowing counts by shared cardId.
  • Provides immutable snapshots of both the CardInstance collection and the card-ID view.
  • Can create an independent copy of the deck.
  • Keeps persistent player-owned cards separate from combat-only state.

Starter deck

PlayerDeckFactory creates the starter player deck using Team 6's initial card IDs:

Card ID Copies Purpose
strike 4 Basic attack
defend 2 Basic defence
poison_dagger 1 Attack plus poison
expose 1 Enemy vulnerable effect
inner_focus 1 Strength buff
bandage 2 Healing card

The starter deck currently has 11 individually identified cards. New-run setup creates the deck through PlayerDeckFactory; RunState.getOrCreatePlayerDeck() preserves it through screen transitions, and Save/Load preserves every instance ID and upgrade level.

Important boundary

The Player Deck only stores card ownership and deck order. It does not shuffle cards, draw cards, discard cards, spend energy, resolve effects, or apply damage. Combat systems should copy the Player Deck into a Battle Deck when combat begins.


Battle Deck

BattleDeck stores temporary card state for one combat encounter.

What it does

  • Creates combat deck state from a PlayerDeck.
  • Maintains a draw pile.
  • Maintains the player's current hand.
  • Maintains a discard pile.
  • Shuffles the draw pile.
  • Draws one card from the draw pile into the hand.
  • Draws multiple cards in order.
  • Moves a played card from the hand into the discard pile.
  • Discards a selected card from the hand.
  • Discards the whole hand.
  • Reshuffles the discard pile into the draw pile when the draw pile is empty.
  • Provides immutable snapshots of the draw pile, hand, and discard pile.
  • Provides size helpers for each pile.

Combat flow

The intended flow is:

flowchart TD
    A[PlayerDeck: owned CardInstances] --> B[Create BattleDeck at battle start]
    B --> C[Copy cards into draw pile]
    C --> D[Shuffle draw pile]
    D --> E[Draw cards]
    E --> F[Hand]
    F --> G{Card played?}
    G -- Yes --> H[Validate card, target and energy]
    H --> I[Resolve card effects]
    I --> J[Move played card to discard pile]
    G -- No, turn ends --> K[Discard hand]
    K --> L[Discard pile]
    J --> L
    L --> M{Draw pile empty?}
    M -- Yes --> N[Reshuffle discard pile into draw pile]
    N --> C
    M -- No --> E
Loading

BattleDeck.playCard(instanceId) moves one exact card from hand to discard. Card validation, target selection, energy spending and effect resolution happen around this call in the wider combat flow.

Card play service

CardPlayService is the higher-level entry point for playing a card from the current hand. It coordinates:

  • Team 6 card lookup and card validation.
  • Team 5 BattleDeck hand/discard state.
  • Team 7 energy checks and energy spending.
  • Team 5 card effect resolution.
  • Immutable post-play DeckSnapshot data for Team 3/UI.

CardPlayRequest contains the played card's instanceId and a CardPlayTarget such as SELF, SINGLE_ENEMY, or ALL_ENEMIES. A successful play returns CardPlayResult.success(...) with resolved effects and updated draw/hand/discard snapshots. A failed play returns a CardPlayFailureReason and does not spend energy or move the card.


Runtime and Save/Load Integration

RunState owns the durable PlayerDeck; gameplay screens use that shared deck instead of creating a fresh starter deck whenever a screen changes. BattleDeck is a separate per-combat copy, so shuffling, drawing, discarding and playing a card do not mutate long-term ownership.

The save format writes each owned card as CardInstanceSaveData(instanceId, cardId, upgradeLevel). Restore validates the card definition and upgrade compatibility before rebuilding the deck, so duplicate cards and independently upgraded copies retain their identity across a full save/reload.


Current Limitations

Item Current state
Real card data lookup Decks store instances that reference Team 6 card IDs; full static data is still resolved through the Card Library
Drag-and-drop Out of scope for Team 5 deck logic; expected to integrate with Team 3
Effect resolution Handled by Team 5's Card Effect Resolution system, not by PlayerDeck or BattleDeck
Damage/status application Out of scope for deck logic; resolved effects are returned to Team 3, then Team 3 distributes them to the relevant gameplay systems
UI integration Battle presentation and drag-and-drop input remain Team 3's responsibility; deck APIs expose immutable instance-aware snapshots for them
Full combat integration Cross-team battle flow owns when to submit a CardPlayRequest; Team 5 owns validation, deck movement and effect-resolution results

Related Pages

⚠️ **GitHub.com Fallback** ⚠️