Architectural refactor to eliminate circular imports and establish clean module boundaries: - Move enums from app/core/models/enums.py to app/core/enums.py (foundational module with zero dependencies) - Update all imports across 30 files to use new enum location - Set up clean export structure: - app.core.enums: canonical source for all enums - app.core: convenience exports for full public API - app.core.models: exports models only (not enums) - Add module exports to app/core/__init__.py and app/core/effects/__init__.py - Remove circular import workarounds from game_state.py This enables app.core.models to export GameState without circular import issues, since enums no longer depend on the models package. All 826 tests passing.
219 lines
6.5 KiB
Python
219 lines
6.5 KiB
Python
"""Enumeration types for the Mantimon TCG game engine.
|
|
|
|
This module defines all enum types used throughout the game engine. We use StrEnum
|
|
for JSON serialization compatibility - enum values serialize as strings directly.
|
|
|
|
This is the foundational module with zero internal dependencies, allowing other
|
|
core modules to import from it without circular import concerns.
|
|
|
|
Note on extensibility: While these enums define the standard types, the game engine
|
|
is designed to be configurable. Custom energy types or card types could be added
|
|
via configuration for free play mode.
|
|
"""
|
|
|
|
from enum import StrEnum
|
|
|
|
|
|
class CardType(StrEnum):
|
|
"""The primary type of a card.
|
|
|
|
Every card in the game belongs to exactly one of these types, which determines
|
|
how it can be played and what rules apply to it.
|
|
"""
|
|
|
|
POKEMON = "pokemon"
|
|
TRAINER = "trainer"
|
|
ENERGY = "energy"
|
|
|
|
|
|
class PokemonStage(StrEnum):
|
|
"""The evolution stage of a Pokemon card.
|
|
|
|
Determines how the Pokemon can be played:
|
|
- BASIC: Can be played directly from hand to bench
|
|
- STAGE_1: Must evolve from a Basic Pokemon
|
|
- STAGE_2: Must evolve from a Stage 1 Pokemon
|
|
|
|
Note: This is separate from PokemonVariant (EX, V, GX, etc.) which affects
|
|
knockout points but not evolution mechanics.
|
|
"""
|
|
|
|
BASIC = "basic"
|
|
STAGE_1 = "stage_1"
|
|
STAGE_2 = "stage_2"
|
|
|
|
|
|
class PokemonVariant(StrEnum):
|
|
"""Special variant classification for Pokemon cards.
|
|
|
|
Variants affect knockout points and may have special rules, but are
|
|
orthogonal to evolution stage. A card can be a "Basic EX" or "Stage 2 GX".
|
|
|
|
- NORMAL: Standard Pokemon, worth 1 knockout point
|
|
- EX: Worth 2 knockout points
|
|
- GX: Worth 2 knockout points, has GX attack (once per game)
|
|
- V: Worth 2 knockout points
|
|
- VMAX: Evolves from V variant, worth 3 knockout points
|
|
- VSTAR: Evolves from V variant, worth 3 knockout points, has VSTAR power
|
|
"""
|
|
|
|
NORMAL = "normal"
|
|
EX = "ex"
|
|
GX = "gx"
|
|
V = "v"
|
|
VMAX = "vmax"
|
|
VSTAR = "vstar"
|
|
|
|
|
|
class EnergyType(StrEnum):
|
|
"""Energy types available in the game.
|
|
|
|
Based on modern Pokemon TCG with 10 types. Colorless is special - any energy
|
|
can satisfy colorless requirements.
|
|
|
|
Note: The engine supports all types, but specific games can restrict which
|
|
types are enabled via RulesConfig.
|
|
"""
|
|
|
|
COLORLESS = "colorless"
|
|
DARKNESS = "darkness"
|
|
DRAGON = "dragon"
|
|
FIGHTING = "fighting"
|
|
FIRE = "fire"
|
|
GRASS = "grass"
|
|
LIGHTNING = "lightning"
|
|
METAL = "metal"
|
|
PSYCHIC = "psychic"
|
|
WATER = "water"
|
|
|
|
|
|
class TrainerType(StrEnum):
|
|
"""Subtypes of Trainer cards.
|
|
|
|
Each subtype has different rules for how many can be played per turn:
|
|
- ITEM: Unlimited per turn
|
|
- SUPPORTER: One per turn
|
|
- STADIUM: One per turn, stays in play
|
|
- TOOL: Attached to Pokemon, unlimited per turn
|
|
"""
|
|
|
|
ITEM = "item"
|
|
SUPPORTER = "supporter"
|
|
STADIUM = "stadium"
|
|
TOOL = "tool"
|
|
|
|
|
|
class TurnPhase(StrEnum):
|
|
"""Phases within a player's turn.
|
|
|
|
Turn structure:
|
|
1. SETUP: Initial game setup (draw starting hand, place basics, set prizes)
|
|
2. DRAW: Draw a card from deck
|
|
3. MAIN: Play cards, attach energy, evolve, use abilities, retreat
|
|
4. ATTACK: Declare and resolve an attack (optional)
|
|
5. END: Apply end-of-turn effects, check knockouts, score points
|
|
|
|
Valid transitions:
|
|
- SETUP -> DRAW (game start, first player's turn)
|
|
- DRAW -> MAIN
|
|
- MAIN -> ATTACK or END (can skip attack)
|
|
- ATTACK -> END
|
|
- END -> DRAW (next player's turn)
|
|
"""
|
|
|
|
SETUP = "setup"
|
|
DRAW = "draw"
|
|
MAIN = "main"
|
|
ATTACK = "attack"
|
|
END = "end"
|
|
|
|
|
|
class StatusCondition(StrEnum):
|
|
"""Status conditions that can affect Pokemon in play.
|
|
|
|
Status conditions have specific effects and removal conditions:
|
|
- POISONED: 10 damage between turns; removed by evolution, retreat, or card effect
|
|
- BURNED: 20 damage between turns + flip to remove; removed on heads
|
|
- ASLEEP: Cannot attack or retreat; removed on heads flip; overrides PARALYZED/CONFUSED
|
|
- PARALYZED: Cannot attack or retreat for 1 turn; removed at end of next turn;
|
|
overrides ASLEEP/CONFUSED
|
|
- CONFUSED: Flip to attack, 30 self-damage on tails; removed by evolution/retreat;
|
|
overrides ASLEEP/PARALYZED
|
|
|
|
Note: POISONED and BURNED stack with other conditions. ASLEEP, PARALYZED, and
|
|
CONFUSED override each other (only one can be active at a time).
|
|
"""
|
|
|
|
POISONED = "poisoned"
|
|
BURNED = "burned"
|
|
ASLEEP = "asleep"
|
|
PARALYZED = "paralyzed"
|
|
CONFUSED = "confused"
|
|
|
|
|
|
class ActionType(StrEnum):
|
|
"""Types of actions a player can take during their turn.
|
|
|
|
Each action type has specific validation rules and can only be performed
|
|
during certain phases. See rules_validator.py for details.
|
|
"""
|
|
|
|
PLAY_POKEMON = "play_pokemon"
|
|
EVOLVE = "evolve"
|
|
ATTACH_ENERGY = "attach_energy"
|
|
PLAY_TRAINER = "play_trainer"
|
|
USE_ABILITY = "use_ability"
|
|
ATTACK = "attack"
|
|
RETREAT = "retreat"
|
|
PASS = "pass"
|
|
|
|
|
|
class GameEndReason(StrEnum):
|
|
"""Reasons why a game ended.
|
|
|
|
Used in GameState.end_reason to indicate how the game concluded:
|
|
- PRIZES_TAKEN: A player took all required prize points
|
|
- NO_POKEMON: A player has no Pokemon in play (active or bench)
|
|
- DECK_EMPTY: A player cannot draw a card at the start of their turn
|
|
- RESIGNATION: A player resigned from the match
|
|
- TIMEOUT: A player ran out of time (multiplayer only)
|
|
- TURN_LIMIT: The turn limit was reached (winner determined by score)
|
|
- DRAW: The game ended in a draw (tie on points at timer expiration)
|
|
"""
|
|
|
|
PRIZES_TAKEN = "prizes_taken"
|
|
NO_POKEMON = "no_pokemon"
|
|
DECK_EMPTY = "deck_empty"
|
|
RESIGNATION = "resignation"
|
|
TIMEOUT = "timeout"
|
|
TURN_LIMIT = "turn_limit"
|
|
DRAW = "draw"
|
|
|
|
|
|
class ModifierMode(StrEnum):
|
|
"""How damage modifiers (weakness/resistance) are calculated.
|
|
|
|
- MULTIPLICATIVE: Multiply damage by modifier (e.g., x2 for weakness)
|
|
- ADDITIVE: Add modifier to damage (e.g., +20 for weakness, -30 for resistance)
|
|
|
|
Standard Pokemon TCG uses multiplicative weakness (x2) and additive resistance (-30).
|
|
Some game variants or house rules may prefer different calculations.
|
|
"""
|
|
|
|
MULTIPLICATIVE = "multiplicative"
|
|
ADDITIVE = "additive"
|
|
|
|
|
|
__all__ = [
|
|
"ActionType",
|
|
"CardType",
|
|
"EnergyType",
|
|
"GameEndReason",
|
|
"ModifierMode",
|
|
"PokemonStage",
|
|
"PokemonVariant",
|
|
"StatusCondition",
|
|
"TrainerType",
|
|
"TurnPhase",
|
|
]
|