mantimon-tcg/backend/app/core/models/README.md
Cal Corum 3ed67ea16b Add Active Effects system design and module README files
Design Documentation:
- docs/ACTIVE_EFFECTS_DESIGN.md: Comprehensive design for persistent effect system
  - Data model (ActiveEffect, EffectTrigger, EffectScope, StackingMode)
  - Core operations (register, remove, query effects)
  - Integration points (damage calc, energy counting, retreat, lifecycle)
  - Effect categories from Pokemon Pocket card research (~372 cards)
  - Example implementations (Serperior, Greninja, Mr. Mime, Victreebel)
  - Post-launch TODO for generic modifier system

Module README Files:
- backend/app/core/README.md: Core engine overview and key classes
- backend/app/core/effects/README.md: Effects module index and quick reference
- backend/app/core/models/README.md: Models module with relationship diagram

Minor cleanup:
- Revert Bulbasaur weakness to Fire (was test change for Lightning)
- Clean up debug output in game walkthrough
2026-01-26 22:39:02 -06:00

6.6 KiB

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.

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.

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.

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.

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.

# 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.

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.

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.).

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").

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

AttackAction(attack_index=0)  # Use first attack

Energy Actions

AttachEnergyAction(
    energy_card_id="p1-lightning-0",
    target_pokemon_id="p1-pikachu-0",
    from_energy_zone=True,
)

Pokemon Actions

PlayPokemonAction(card_id="p1-bulbasaur-0", to_active=False)
EvolvePokemonAction(card_id="p1-ivysaur-0", target_pokemon_id="p1-bulbasaur-0")

Trainer Actions

PlayTrainerAction(card_instance_id="p1-potion-0", targets=["p1-pikachu-0"])

Ability Actions

UseAbilityAction(pokemon_id="p1-greninja-0", ability_index=0, targets=["p2-charmander-0"])

Movement Actions

RetreatAction(new_active_id="p1-squirtle-0", energy_to_discard=["p1-water-0"])
SelectActiveAction(new_active_id="p1-squirtle-0")  # After KO

Turn Control

PassAction()    # End turn without attacking
ResignAction()  # Forfeit the game

Action Union Type

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