# Models Module Pydantic models for game state, card definitions, and player actions. --- ## Files | File | Description | |------|-------------| | `__init__.py` | Module exports | | `card.py` | Card-related models | | `game_state.py` | Game state and player state | | `actions.py` | Player action types | --- ## Card Models (`card.py`) ### CardDefinition Immutable template defining a card's properties. Stored in the card registry. ```python CardDefinition( id="pikachu-001", name="Pikachu", card_type=CardType.POKEMON, stage=PokemonStage.BASIC, hp=60, pokemon_type=EnergyType.LIGHTNING, attacks=[ Attack(name="Thunder Shock", damage=20, cost=[EnergyType.LIGHTNING]), ], weakness=WeaknessResistance(energy_type=EnergyType.FIGHTING, value=20), retreat_cost=1, ) ``` ### CardInstance A specific card in play, referencing a `CardDefinition`. Tracks runtime state. ```python CardInstance( instance_id="p1-pikachu-0", # Unique per-game definition_id="pikachu-001", # References CardDefinition damage=30, # Current damage attached_energy=[...], # Energy cards attached status_conditions=[StatusCondition.PARALYZED], ) ``` ### Attack A Pokemon's attack with cost, damage, and optional effect. ```python Attack( name="Crimson Storm", cost=[EnergyType.FIRE, EnergyType.FIRE, EnergyType.COLORLESS], damage=200, effect_id="discard_energy", effect_params={"count": 2}, effect_description="Discard 2 Energy from this Pokemon.", ) ``` ### Ability A Pokemon's special ability. ```python Ability( name="Psy Shadow", effect_id="energy_acceleration", effect_params={"energy_type": "psychic", "target": "active"}, effect_description="Attach Psychic Energy from Energy Zone to Active.", uses_per_turn=1, ) ``` ### WeaknessResistance Weakness or resistance to an energy type. ```python # Additive weakness (+20) WeaknessResistance(energy_type=EnergyType.FIRE, mode=ModifierMode.ADDITIVE, value=20) # Multiplicative weakness (x2) WeaknessResistance(energy_type=EnergyType.FIRE, mode=ModifierMode.MULTIPLICATIVE, value=2) # Resistance (-30) WeaknessResistance(energy_type=EnergyType.WATER, mode=ModifierMode.ADDITIVE, value=-30) ``` --- ## Game State Models (`game_state.py`) ### GameState Complete state of a game. Self-contained with embedded card registry. ```python GameState( game_id="match-123", rules=RulesConfig(), card_registry={...}, players={"p1": PlayerState(...), "p2": PlayerState(...)}, current_player_id="p1", turn_number=3, phase=TurnPhase.MAIN, ) ``` **Key Methods:** - `get_current_player()` - Current player's state - `get_opponent(player_id)` - Opponent's state - `get_card_definition(card_id)` - Lookup card definition - `advance_turn()` - Move to next player's turn ### PlayerState All zones and state for a single player. ```python player = game.players["p1"] # Zones (all are Zone objects) player.deck # Draw pile player.hand # Cards in hand player.active # Active Pokemon (0-1 cards) player.bench # Benched Pokemon player.discard # Discard pile player.prizes # Prize cards player.energy_deck # Energy deck (Pocket-style) player.energy_zone # Available energy this turn # State tracking player.score # Points scored player.energy_attachments_this_turn player.supporters_played_this_turn ``` **Key Methods:** - `get_active_pokemon()` - Returns active Pokemon or None - `get_all_pokemon_in_play()` - Active + bench - `can_attach_energy(rules)` - Check turn limits - `reset_turn_state()` - Clear per-turn counters ### Zone A collection of cards (deck, hand, bench, etc.). ```python zone = player.hand len(zone) # Card count "card-id" in zone # Check if card present zone.add(card) # Add to end zone.add_to_top(card) # Add to top (for deck) zone.remove("card-id") # Remove and return card zone.draw() # Remove and return from top zone.shuffle(rng) # Randomize order zone.get("card-id") # Get without removing zone.clear() # Remove all cards ``` ### ForcedAction Represents a required action (e.g., "select new active after KO"). ```python ForcedAction( player_id="p1", action_type="select_active", reason="Your active Pokemon was knocked out", params={"from_zones": ["bench"]}, ) ``` --- ## Action Models (`actions.py`) All actions implement a common interface with `type` discriminator field. ### Attack Actions ```python AttackAction(attack_index=0) # Use first attack ``` ### Energy Actions ```python AttachEnergyAction( energy_card_id="p1-lightning-0", target_pokemon_id="p1-pikachu-0", from_energy_zone=True, ) ``` ### Pokemon Actions ```python PlayPokemonAction(card_id="p1-bulbasaur-0", to_active=False) EvolvePokemonAction(card_id="p1-ivysaur-0", target_pokemon_id="p1-bulbasaur-0") ``` ### Trainer Actions ```python PlayTrainerAction(card_instance_id="p1-potion-0", targets=["p1-pikachu-0"]) ``` ### Ability Actions ```python UseAbilityAction(pokemon_id="p1-greninja-0", ability_index=0, targets=["p2-charmander-0"]) ``` ### Movement Actions ```python RetreatAction(new_active_id="p1-squirtle-0", energy_to_discard=["p1-water-0"]) SelectActiveAction(new_active_id="p1-squirtle-0") # After KO ``` ### Turn Control ```python PassAction() # End turn without attacking ResignAction() # Forfeit the game ``` ### Action Union Type ```python Action = ( AttackAction | AttachEnergyAction | PlayPokemonAction | EvolvePokemonAction | PlayTrainerAction | UseAbilityAction | RetreatAction | SelectActiveAction | PassAction | ResignAction | SelectPrizeAction ) ``` --- ## Model Relationships ``` GameState ├── card_registry: dict[str, CardDefinition] ├── players: dict[str, PlayerState] │ └── PlayerState │ ├── deck: Zone[CardInstance] │ ├── hand: Zone[CardInstance] │ ├── active: Zone[CardInstance] │ │ └── CardInstance │ │ ├── definition_id -> CardDefinition │ │ ├── attached_energy: list[CardInstance] │ │ └── evolution_stage: list[CardInstance] │ ├── bench: Zone[CardInstance] │ ├── discard: Zone[CardInstance] │ └── ... ├── stadium_in_play: CardInstance | None └── forced_actions: list[ForcedAction] ``` --- ## See Also - [../README.md](../README.md) - Core module overview - [/docs/ARCHITECTURE.md](/docs/ARCHITECTURE.md) - System architecture