Player and Battle Deck - UQcsse3200/2026-studio-3 GitHub Wiki
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.
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
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:
- Team 3 confirms a card play attempt and sends the selected
instanceId/ target information to Team 5. - Team 5 reads the card config from Team 6's card library.
- Team 5 calls Team 7's energy function, such as
spendEnergy(card.cost), to check whether the card can actually be played. - If the player does not have enough energy, Team 5 returns a failed
CardPlayResultto Team 3. No card effects are resolved, no effects are applied, and the card remains in hand. - If the player has enough energy, Team 5 resolves the card effects and packages them into a successful
CardPlayResult. - Team 5 returns the
CardPlayResultto Team 3 / battle flow. - Team 3 / battle flow then passes
enemyEffects()to Team 1 andplayerEffects()to Team 7.
PlayerDeck stores the player's owned cards outside a single combat encounter.
- Stores
CardInstancevalues 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 sharedcardId. - Provides immutable snapshots of both the
CardInstancecollection and the card-ID view. - Can create an independent copy of the deck.
- Keeps persistent player-owned cards separate from combat-only state.
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.
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.
BattleDeck stores temporary card state for one combat encounter.
- 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.
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
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.
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
BattleDeckhand/discard state. - Team 7 energy checks and energy spending.
- Team 5 card effect resolution.
- Immutable post-play
DeckSnapshotdata 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.
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.
| 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 |
- Card Effect Resolution - Team 5 effect resolver and resolved card effects
- Card Library API - Team 6 card lookup API
- Initial Cards - Team 6's initial Sprint 1 cards