Metadata-Version: 2.4
Name: ptg
Version: 0.1.19
Summary: A Python engine for MTG-like card games.
Author: Daniel Pérez Rodríguez
License-Expression: MIT
Project-URL: Repository, https://github.com/Dannyzimmer/PythonTheGathering
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Games/Entertainment :: Turn Based Strategy
Requires-Python: >=3.12
Description-Content-Type: text/markdown
License-File: LICENSE.txt
Requires-Dist: pyyaml
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Dynamic: license-file

# PTG — Python The Gathering

A library for building MTG-like card games.  Define your cards in YAML,
assemble decks, and drive the game through a small set of pure, testable
actions — no side-effects, no global state.

---

## Table of Contents

1. [Quick Start](#1-quick-start)
2. [Core Concepts](#2-core-concepts)
3. [Card Definition Reference](#3-card-definition-reference)
4. [Mana System](#4-mana-system)
5. [Abilities & Effects](#5-abilities--effects)
6. [Triggers](#6-triggers)
7. [Combat System](#7-combat-system)
8. [Loading Cards & Building Decks](#8-loading-cards--building-decks)
9. [Public API Reference](#9-public-api-reference)
10. [Appendix: Complete Card Examples](#10-appendix-complete-card-examples)

---

## 1. Quick Start

Minimum working example — two players, hard‑coded cards, one turn.

```python
from ptg.api import (
    Game, Player, CardDefinition,
    CardType, ManaType, ManaPool, ManaRequirement,
    PlayCardAction, DeclareAttackAction,
)
from ptg.engine.types import CardAbility, AlterationData
from ptg.effects.draw import DrawCardEffect

# ── Card definitions ──────────────────────────────────────────
goblin    = CardDefinition("gob_01", "Goblin Warrior", "Fast.",
                           CardType.CREATURE,
                           mana={ManaType.FIRE: 1},
                           attack=2, defense=2)

fire_mana = CardDefinition("fire_01", "Fire Mana", "Gives 1 fire.",
                           CardType.MANA,
                           mana={ManaType.FIRE: 1})

# ── Players ───────────────────────────────────────────────────
alice = Player("Alice", [fire_mana] * 3 + [goblin] * 3, hand_size=3)
bob   = Player("Bob",   [fire_mana] * 3 + [goblin] * 3, hand_size=3)

game = Game([alice, bob])
game.start()
game.advance_phase()                                      # DRAW → MAIN

# Play mana, then a creature
for _ in range(3):
    cid = next(id for id in game.state.hands[alice.uuid]
               if game.state.all_cards[id].name == "Fire Mana")
    game.apply_action(PlayCardAction(), player_id=alice.uuid, card_id=cid)

goblin_id = next(id for id in game.state.hands[alice.uuid]
                 if game.state.all_cards[id].name == "Goblin Warrior")
game.apply_action(PlayCardAction(), player_id=alice.uuid, card_id=goblin_id)

# Attack and end turn (advances through ATTACK, DEFENSE, COMBAT, POSTCOMBAT, END → DRAW)
attacker_id = next(id for id in game.state.battlefield[alice.uuid]
                   if game.state.all_cards[id].name == "Goblin Warrior")
game.apply_action(DeclareAttackAction(), player_id=alice.uuid,
                  attacker_id=attacker_id)
game.advance_phase()   # MAIN → ATTACK
game.advance_phase()   # ATTACK → DEFENSE
game.advance_phase()   # DEFENSE → COMBAT (auto-resolve)
game.advance_phase()   # COMBAT → MAIN_POSTCOMBAT
game.advance_phase()   # MAIN_POSTCOMBAT → END → next player DRAW

print(f"Bob HP: {game.state.players[bob.uuid].health}")   # 18
```

---

## 2. Core Concepts

```mermaid
flowchart LR
    subgraph Setup
        YAML[Card YAML files] -->|yaml_loader| Def[CardDefinition]
        Def -->|deck_builder| Deck[Deck list]
    end

    subgraph Runtime
        Deck -->|Player.initialize| GS[GameState]
        GS --> Actions[Play / Attack / Defend / Activate]
        Actions -->|returns new| GS2[GameState]
        GS2 -->|check_victory| Winner
    end
```

### Card

A card has two representations:

- **CardDefinition** — the blueprint. Immutable. Lives in YAML or Python.
  Contains `card_id`, `name`, `type`, `mana` cost, `health`, `attack`, `defense`,
  and optional `abilities`.
- **CardInstance** — one copy in play. Has a unique `uuid`, current `health`,
  `attack`, `defense`, and a reference back to its `CardDefinition`.

### Player

Each player owns four **zones**:

| Zone | Contents | Notes |
|------|----------|-------|
| `deck` | Cards not yet drawn | Shuffled at game start. |
| `hand` | Cards available to play | Hidden from opponent. |
| `battlefield` | Creatures in play | Public. |
| `graveyard` | Discarded / destroyed cards | Public. |

A player also has `health`, a `mana_pool`, and a maximum hand size.

### Game

The `Game` object owns the `GameState` and the `EventBus`.  It provides
methods to advance turns, apply actions, resolve combat, and check victory.

### GameState

The entire game at one point in time — cards, zones, players, pending combats.
Every action returns a **new** `GameState`; the old one is never modified.

---

## 3. Card Definition Reference

### Fields

| Field | Type | Required | Default | Notes |
|-------|------|----------|---------|-------|
| `card_id` | `str` | yes | — | Unique identifier. |
| `name` | `str` | yes | — | Display name. |
| `description` | `str` | no | `""` | Flavour or tooltip text. |
| `type` | `CardType` | yes | — | See table below. |
| `mana` | `dict[ManaType, int]` | no | `{}` | Cost to play OR mana provided (for mana cards). |
| `attack` | `int` | no | `0` | Damage dealt when attacking. |
| `defense` | `int` | no | `0` | Creature toughness — its current life. Regenerates each turn. |
| `abilities` | `list[CardAbility]` | no | `None` | See [Abilities & Effects](#5-abilities--effects). |

### CardType

| Value | Meaning |
|-------|---------|
| `creature` | Stays on the battlefield. Can attack and block. Its `defense` is its current life; it regenerates each turn. |
| `spell` | Resolves immediately, then goes to graveyard. |
| `mana` | Stays on the battlefield as a permanent.  Provides mana every turn.  Free to play. |

### Examples

```yaml
# A simple creature
card_id: goblin_01
name: Goblin Warrior
type: creature
mana:
  fire: 1
attack: 2
defense: 2
```

```yaml
# A mana card (always free to play)
card_id: fire_mana_01
name: Fire Mana
type: mana
mana:
  fire: 1
```

```yaml
# A spell that deals 3 damage
card_id: fireball_01
name: Fireball
type: spell
mana:
  fire: 2
abilities:
  - name: Explosion
    description: Deal 3 damage.
    ability_type: activated
    mana_requirement: {}
    alterations:
      - effect: damage_card
        start_trigger: null
        params:
          amount: 3
```

---

## 4. Mana System

### ManaType

| Type | Colour / flavour |
|------|-----------------|
| `fire` | Red |
| `earth` | Green |
| `water` | Blue |
| `air` | White |
| `any` | Generic — paid with leftover mana of any type |

### Playing mana

Mana cards are **free to play** and stay on the **battlefield** as permanents.
Playing a `Fire Mana` adds `1 fire` to your pool and to your `mana_sources`.
At the start of each of your turns, your pool is refilled from your sources.

You may only play **one mana card per turn**.  Effects that generate mana
(e.g. `gain_mana`) do not count toward this limit.

### Hand limit

Your maximum hand size is **7 cards**.  At the end of your turn, if you
have more than 7 cards, you discard down to 7 at random.

### First turn

The player who goes first skips their draw step on the first turn.

### The `ANY` type

When a requirement includes `any`, specific types are paid **first**, then
the `any` shortfall is covered from the remaining pool:

```
Pool:  {fire: 2, earth: 1}
Cost:  {fire: 1, any: 1}

1. Pay fire:  pool → {fire: 1, earth: 1}
2. Cover any: pool → {fire: 0, earth: 1}
```

### Cost fields in YAML

| Field | Where | Meaning |
|-------|-------|---------|
| `mana` | Top-level on a card | Cost to play the card (free for mana cards). |
| `mana_requirement` | Inside an `ability` | Cost to activate that ability. |

---

## 5. Abilities & Effects

An **ability** is a named power on a card.  An ability contains one or more
**alterations**; each alteration links an **effect** to a **target** with an
optional **trigger**.

### AbilityType

| Value | Behaviour |
|-------|----------|
| `triggered` | Fires automatically when its `start_trigger` event occurs.  No mana cost at trigger time. |
| `activated` | The player chooses when to use it and pays its `mana_requirement`. |

### Alteration structure

```yaml
alterations:
  - effect: <registered effect name>   # required
    target: <TargetSpec | null>        # default: null (see PendingTrigger below)
    start_trigger: <EventType | null>  # default: null
    end_trigger: <EventType | null>    # default: null
    trigger_self: <bool>               # default: true
    turn_duration: <int | null>        # default: null
    params:                            # depends on the effect
      ...
```

### TargetSpec

| Value | Resolves to |
|-------|------------|
| `self` | The card that owns the ability. |
| `owner` | The player who controls the card. |
| `opponent` | The other player. |
| `choose` | The player must choose a target manually (see PendingTrigger). |
| `null` | Same as `choose` — the player must choose. |

### trigger_self

Controls whether a triggered ability only fires for events originating from
the owning card itself:

| Value | Behaviour |
|-------|----------|
| `true` (default) | The ability fires only when the event's `source` matches the owning `card_id`.  Events with `source=None` (turn events) are never filtered. |
| `false` | The ability fires for **any** event of the matching type, regardless of source.  Useful for global-scope triggers like "whenever a creature dies". |

### end_trigger

When an alteration specifies both `start_trigger` and `end_trigger`, the engine
automatically registers a second listener that **reverses** the effect by
negating numeric params when the end event fires:

```yaml
# Temporary +1/+1 until end of turn:
alterations:
  - effect: buff_card
    start_trigger: on_turn_start
    end_trigger: on_turn_end
    target: self
    params:
      attack_increase: 1
      defense_increase: 1
```

At `on_turn_end`, the engine applies `buff_card(attack_increase=-1, defense_increase=-1)`.
This works for any effect with numeric params (`damage_card`, `heal_player`,
`draw_card`, etc.).

### Effect catalogue

| Effect name | Target type | Parameters | Description |
|------------|-------------|-----------|-------------|
| `damage_card` | Card | `amount: int` | Deals damage to a creature, reducing its defense. |
| `damage_player` | Player | `amount: int` | Deals damage to a player. |
| `heal_player` | Player | `amount: int` | Restores health to a player. |
| `buff_card` | Card | `attack_increase`, `defense_increase` (default 0) | Increases a creature's stats. |
| `buff_all` | Player | `attack_increase`, `defense_increase` (default 0) | Buffs every creature on that player's battlefield. |
| `draw_card` | Player | `count: int` (default 1) | Draws cards from the top of the deck. |
| `destroy_card` | Card | — | Sets a creature's health to 0. |
| `spend_mana` | Player | `mana_requirement: dict` | Deducts mana from the player's pool. |
| `gain_mana` | Player | `amounts: dict[ManaType, int]` | Adds temporary mana to a player's pool (does not increase mana_sources). |
| `spawn_creature` | Player | `template: CardDefinition` + `count: int` (default 1) | Creates copies of a creature on the battlefield. |
| `recruit` | Player | `card_definition_id: str`, `from_zone: ZoneType` | Moves a matching card from hand / deck / graveyard to the battlefield. |
| `return_to_hand` | Player | `card_uuid: str` | Removes a card from the battlefield and puts it back in the owner's hand. |
| `mill` | Player | `count: int` (default 1) | Moves cards from the top of the deck directly into the graveyard. |
| `random_discard` | Player | `count: int` (default 1) | Randomly discards cards from the player's hand into their graveyard. |
| `set_stats` | Card | `attack: int`, `defense: int` | Sets a creature's attack and/or defense to absolute values. |
| `recycle_graveyard` | Player | — | Shuffles all cards from the graveyard back into the deck. |
| `move_card` | Card | `from_zone: ZoneType`, `to_zone: ZoneType` | Moves a specific card from one zone to another within its owner. Example: `from_zone: hand, to_zone: graveyard`. |

### Example: triggered ability

```yaml
abilities:
  - name: Healing Aura
    description: When this enters, heal your hero for 3.
    ability_type: triggered
    mana_requirement: {}
    alterations:
      - effect: heal_player
        target: owner
        start_trigger: on_card_enter_battlefield
        params:
          amount: 3
```

### Example: activated ability

```yaml
abilities:
  - name: Fire Blast
    description: Pay 2 fire → deal 2 damage to opponent.
    ability_type: activated
    mana_requirement:
      fire: 2
    alterations:
      - effect: damage_player
        target: opponent
        params:
          amount: 2
```

### Dynamic parameter references

Params can reference the source card's current stats at runtime using:

| Syntax | Resolves to |
|--------|------------|
| `$attack` | The source card's current attack value. |
| `$defense` | The source card's current defense value. |

```yaml
abilities:
  - name: Life Drain
    description: When this enters, heal equal to its attack.
    ability_type: triggered
    mana_requirement: {}
    alterations:
      - effect: heal_player
        target: owner
        start_trigger: on_card_enter
        params:
          amount: $attack
```

### PendingTrigger — player-chosen targets

When a triggered ability has `target: null` or `target: choose`, the engine
cannot resolve the target automatically.  Instead of dropping the trigger, it
defers it by adding a `PendingTrigger` to `GameState.pending_triggers`.

The game server must:

1. After each action, check if `state.pending_triggers` is non-empty.
2. Prompt the player to select a target (creature or player).
3. Call `game.resolve_pending_trigger(trigger_index, chosen_target)` to apply
   the effect and register the `end_trigger` listener (if present).

The engine handles the full lifecycle — start, resolution, and end reversal —
automatically once the target is chosen.

```python
# Server-side flow
state = game.apply_action(PlayCardAction(), player_id=p1, card_id=card)

if state.pending_triggers:
    # Send trigger info to frontend for target selection
    trigger = state.pending_triggers[0]
    emit("choose_target", {
        "source_card_id": trigger.source_card_id,
        "trigger_index": 0,
    })

# After player picks target "g02":
state = game.resolve_pending_trigger(0, chosen_target=CardID("g02"))
# Engine applies effect and registers end_trigger listener automatically
```

### Example: spawn tokens

```yaml
# Using an inline template
- effect: spawn_creature
  target: owner
  start_trigger: on_card_enter_battlefield
  params:
    template:
      card_id: token_wasp
      name: Wasp
      type: creature
      defense: 1
      attack: 1
    count: 2

# Using a catalog reference (requires loading with a catalog)
- effect: spawn_creature
  target: owner
  start_trigger: on_card_death
  params:
    template_card_id: goblin_01
    count: 1
```

### Example: recruit from graveyard

```yaml
- effect: recruit
  target: owner
  start_trigger: on_card_enter_battlefield
  params:
    card_definition_id: goblin_01
    from_zone: graveyard
```

---

## 6. Triggers

Triggered abilities fire when a matching event is emitted.  The table below
lists every event in the engine.

| EventType (YAML value) | Emitted when … |
|------------------------|---------------|
| `on_card_enter_battlefield` | A creature is placed on the battlefield. |
| `on_card_death` | A creature's health drops to 0 (it is moved to the graveyard). |
| `on_card_receive_damage` | A creature takes damage. |
| `on_card_attack` | A creature is declared as an attacker. |
| `on_card_defense` | A creature is declared as a blocker. |
| `on_card_healed` | A creature is healed. |
| `on_card_draw` | A player draws one or more cards. |
| `on_card_enter_graveyard` | Any card enters the graveyard (creatures, spells). |
| `on_card_leave_battlefield` | A card is removed from the battlefield for any reason (death, bounce). |
| `on_card_leave_graveyard` | A card is removed from the graveyard (e.g., recruited to the battlefield). |
| `on_player_receive_damage` | A player takes damage. |
| `on_player_death` | A player's health drops to 0. |
| `on_player_mana_spent` | A player spends mana. |
| `on_player_mana_gained` | A player gains mana. |
| `on_player_healed` | A player is healed. |
| `on_turn_start` | A player's turn begins (after flags are reset). |
| `on_turn_end` | A player's turn ends. |
| `on_attack_declared` | An attack is declared (before blockers are chosen). |
| `on_defense_declared` | A blocker is assigned to an attacker. |
| `on_combat_resolved` | All pending combats are resolved for the turn. |
| `on_ability_activated` | A player activates an activated ability. |

### Event order during an attack

```mermaid
sequenceDiagram
    participant Attacker
    participant Blocker
    participant Engine

    Attacker->>Engine: DeclareAttackAction
    Engine-->>Engine: emit ON_ATTACK_DECLARED
    Blocker->>Engine: DeclareDefenseAction
    Engine-->>Engine: emit ON_DEFENSE_DECLARED
    Engine->>Engine: resolve_combat()
    Engine-->>Engine: emit ON_CARD_RECEIVE_DAMAGE
    Engine-->>Engine: emit ON_CARD_LEAVE_BATTLEFIELD (if any)
    Engine-->>Engine: emit ON_CARD_DEATH (if any)
    Engine-->>Engine: emit ON_PLAYER_RECEIVE_DAMAGE (spillover)
    Engine-->>Engine: emit ON_COMBAT_RESOLVED
```

---

## 7. Combat System

### Turn structure

```mermaid
flowchart TD
    Start([start]) --> DRAW[DRAW: auto-refresh mana, draw card]
    DRAW --> MAIN[MAIN: play cards, activate abilities]
    MAIN --> ATTACK[ATTACK: declare attackers]
    ATTACK --> DEFENSE[DEFENSE: declare blockers]
    DEFENSE --> COMBAT[COMBAT: auto-resolve damage]
    COMBAT --> MAIN2[MAIN_POSTCOMBAT: play cards]
    MAIN2 --> END[END: auto-switch player]
    END --> DRAW
```

### Direct attack (no blockers)

When no blockers are assigned, the attacker's full `attack` value hits the
defending player directly.

```python
game.apply_action(DeclareAttackAction(),
    player_id=alice.uuid, attacker_id=goblin_id)
game.resolve_combat()
# Bob loses attack value in health
```

### Blocked attack (damage exchange)

Both the attacker and the blocker deal damage to each other simultaneously.
Damage is applied directly to each card's `defense`.  A card dies when its
`defense` reaches 0.

```python
game.apply_action(DeclareDefenseAction(),
    player_id=bob.uuid, blocker_id=giant_id, combat_index=0)
game.resolve_combat()
```

### Multi-blocking

When multiple blockers are assigned to one attacker, the attacker distributes
its damage among them.  The engine assigns **minimum lethal damage** to each
blocker in declaration order until no attack remains.

### Spillover (trample)

If the attacker survives and all of its blockers die, any leftover damage
hits the defending player.

### Death & graveyard

Creatures that reach 0 health are moved from the battlefield to their owner's
graveyard, and an `on_card_death` event is emitted.

### Attack / block restriction

A creature that attacked during its controller's turn cannot block until the
beginning of that controller's **next** turn.  The `attacked_this_turn` flag
is set by `DeclareAttackAction` and reset by `_handle_draw` at turn start.
`DeclareDefenseAction` rejects any blocker with `attacked_this_turn=True`.

---

## 8. Loading Cards & Building Decks

### Card YAML files

Place one `.yaml` file per card in a directory:

```
cards/
  goblin.yaml
  fireball.yaml
  fire_mana.yaml
  ...
```

### Deck YAML files (optional)

```yaml
# decks/aggro.yaml
cards:
  goblin_01: 3
  fireball_01: 2
  fire_mana_01: 5
```

### Loading workflow

```python
from ptg.api import (
    load_cards_from_dir, build_catalog, load_deck, build_deck,
    Player, Game,
)

# 1. Load every card definition
all_cards = load_cards_from_dir("cards/")

# 2. Index by card_id for fast lookup
catalog = build_catalog(all_cards)

# 3. Build decks
alice_deck = load_deck(catalog, "decks/alice_aggro.yaml")
bob_deck   = build_deck(catalog, {"giant_01": 3, "fire_mana_01": 5, "heal_01": 2})

# 4. Create players
alice = Player("Alice", alice_deck, initial_health=20, hand_size=4)
bob   = Player("Bob",   bob_deck,   initial_health=20, hand_size=4)

game = Game([alice, bob])
game.start()
```

### Using a catalog for `template_card_id`

When a card references another card via `template_card_id`, pass the catalog
to the loader:

```python
# cards/hive_mind.yaml uses template_card_id: wasp_token_01
catalog = build_catalog(load_cards_from_dir("cards/"))
hive = load_card("cards/hive_mind.yaml", catalog=catalog)
```

---

## 9. Public API Reference

```python
from ptg.api import (
    # ── Core types ───────────────────────────────────────────
    CardType, ManaType, EventType, AbilityType, TargetSpec,
    ManaRequirement, ManaPool,
    # ── Engine ───────────────────────────────────────────────
    Game, GameState, Player,
    CardDefinition, CardAbility, AlterationData,
    PendingTrigger,
    # ── Actions ──────────────────────────────────────────────
    PlayCardAction, DeclareAttackAction,
    DeclareDefenseAction, ActivateAbilityAction,
    # ── I/O ──────────────────────────────────────────────────
    load_card, load_cards_from_dir,
    build_catalog, build_deck, load_deck,
)
```

### `Game` methods

The recommended way to control a turn is `advance_phase()`.  `begin_turn()`
and `end_turn()` are available for fine-grained manual control.

| Method | Returns | Description |
|--------|---------|-------------|
| `start()` | `GameState` | Initialises both players, draws starting hands, sets phase to `DRAW`. |
| `advance_phase()` | `GameState` | Moves to the next phase.  Executes automatic logic for `DRAW` / `COMBAT` / `END`. |
| `begin_turn()` | `GameState` | Manual jump to `DRAW` phase (legacy). |
| `end_turn()` | `GameState` | Manual jump to `END` phase (legacy). |
| `apply_action(action, **kwargs)` | `GameState` | Runs any action through the engine. |
| `resolve_combat()` | `GameState` | Processes all pending combats (called automatically in `COMBAT` phase). |
| `resolve_pending_trigger(index, chosen_target)` | `GameState` | Applies a deferred triggered ability to the player's chosen target and registers its `end_trigger` listener. |
| `check_victory()` | `Player \| None` | Returns the winner, or `None` if the game continues. |

| Property | Type | Description |
|----------|------|-------------|
| `current_phase` | `PhaseType \| None` | Current phase of the active player's turn. |
| `playable_phases` | `tuple[PhaseType, ...]` | Phases where the active player may play cards or activate abilities. |

### Action parameters

| Action | `kwargs` |
|--------|---------|
| `PlayCardAction` | `player_id`, `card_id` |
| `DeclareAttackAction` | `player_id`, `attacker_id` |
| `DeclareDefenseAction` | `player_id`, `blocker_id`, `combat_index` |
| `ActivateAbilityAction` | `player_id`, `card_id`, `ability_index`, `target_id` *(optional)* |

### I/O functions

| Function | Signature |
|----------|----------|
| `load_card` | `(path, catalog=None) → CardDefinition` |
| `load_cards_from_dir` | `(dir_path, catalog=None) → list[CardDefinition]` |
| `build_catalog` | `(cards) → dict[str, CardDefinition]` |
| `build_deck` | `(catalog, spec) → list[CardDefinition]` |
| `load_deck` | `(catalog, path) → list[CardDefinition]` |

---

## 10. Appendix: Complete Card Examples

### Creature with no abilities

```yaml
card_id: giant_01
name: Clumsy Giant
type: creature
mana:
  earth: 2
defense: 5
attack: 3
defense: 1
```

### Creature with a triggered ability

```yaml
card_id: priest_01
name: Healing Priest
description: When this enters, heal your hero for 3.
type: creature
mana:
  any: 2
defense: 3
attack: 1
defense: 1
abilities:
  - name: Healing Aura
    description: Heal your hero for 3.
    ability_type: triggered
    mana_requirement: {}
    alterations:
      - effect: heal_player
        target: owner
        start_trigger: on_card_enter_battlefield
        params:
          amount: 3
```

### Creature with an activated ability

```yaml
card_id: pyromancer_01
name: Pyromancer
type: creature
mana:
  fire: 2
defense: 3
attack: 2
defense: 0
abilities:
  - name: Fire Blast
    description: Pay 2 fire → deal 2 damage to opponent.
    ability_type: activated
    mana_requirement:
      fire: 2
    alterations:
      - effect: damage_player
        target: opponent
        params:
          amount: 2
```

### Creature that spawns tokens (inline template)

```yaml
card_id: hive_mind_01
name: Hive Mind
description: When this enters, create two 1/1 Wasps.
type: creature
mana:
  any: 3
defense: 2
attack: 1
defense: 0
abilities:
  - name: Swarm
    description: Spawn two Wasp tokens.
    ability_type: triggered
    mana_requirement: {}
    alterations:
      - effect: spawn_creature
        target: owner
        start_trigger: on_card_enter_battlefield
        params:
          template:
            card_id: token_wasp
            name: Wasp
            type: creature
            defense: 1
            attack: 1
          count: 2
```

### Creature that recruits from graveyard

```yaml
card_id: necromancer_01
name: Necromancer
description: When this enters, return a Goblin Warrior from your
             graveyard to the battlefield.
type: creature
mana:
  any: 4
defense: 3
attack: 2
defense: 1
abilities:
  - name: Dark Ritual
    description: Recruit a Goblin Warrior.
    ability_type: triggered
    mana_requirement: {}
    alterations:
      - effect: recruit
        target: owner
        start_trigger: on_card_enter_battlefield
        params:
          card_definition_id: goblin_01
          from_zone: graveyard
```

### Creature that mills the opponent

```yaml
card_id: mill_imp_01
name: Mill Imp
description: When this enters, mill 3 cards from your opponent's deck.
type: creature
mana:
  any: 2
defense: 2
attack: 1
defense: 0
abilities:
  - name: Mind Rot
    description: Mill 3 cards.
    ability_type: triggered
    mana_requirement: {}
    alterations:
      - effect: mill
        target: opponent
        start_trigger: on_card_enter_battlefield
        params:
          count: 3
```

### Creature that reacts to cards leaving the graveyard

```yaml
card_id: graveyard_watcher_01
name: Graveyard Watcher
description: Whenever a card leaves your graveyard, draw a card.
type: creature
mana:
  any: 3
defense: 3
attack: 2
defense: 1
abilities:
  - name: Soul Drain
    description: Draw a card.
    ability_type: triggered
    mana_requirement: {}
    alterations:
      - effect: draw_card
        target: owner
        start_trigger: on_card_leave_graveyard
        params:
          count: 1
```

### Spell

```yaml
card_id: fireball_01
name: Fireball
description: Deal 3 damage to any target.
type: spell
mana:
  fire: 2
abilities:
  - name: Explosion
    description: Deal 3 damage.
    ability_type: activated
    mana_requirement: {}
    alterations:
      - effect: damage_card
        params:
          amount: 3
```

### Creature that generates mana

```yaml
card_id: dark_ritualist_01
name: Dark Ritualist
description: When this enters, gain 2 fire mana until end of turn.
type: creature
mana:
  any: 2
defense: 2
attack: 1
defense: 0
abilities:
  - name: Dark Ritual
    description: Gain 2 fire mana this turn.
    ability_type: triggered
    mana_requirement: {}
    alterations:
      - effect: gain_mana
        target: owner
        start_trigger: on_card_enter
        params:
          amounts:
            fire: 2
```

### Creature that sets a creature's stats

```yaml
card_id: polymorphist_01
name: Polymorphist
description: When this enters, set another creature's stats to 1/1.
type: creature
mana:
  any: 3
defense: 2
attack: 2
defense: 1
abilities:
  - name: Polymorph
    description: Set target creature to 1/1.
    ability_type: triggered
    mana_requirement: {}
    alterations:
      - effect: set_stats
        target: null
        start_trigger: on_card_enter
        params:
          attack: 1
          defense: 0
```

### Creature that discards from opponent's hand

```yaml
card_id: mind_ripper_01
name: Mind Ripper
description: When this enters, your opponent discards a card at random.
type: creature
mana:
  any: 3
defense: 3
attack: 2
defense: 1
abilities:
  - name: Mind Rip
    description: Opponent discards a card at random.
    ability_type: triggered
    mana_requirement: {}
    alterations:
      - effect: random_discard
        target: opponent
        start_trigger: on_card_enter
        params:
          count: 1
```

### Spell that recycles the graveyard

```yaml
card_id: recycle_01
name: Recycle
description: Shuffle your graveyard into your deck.
type: spell
mana:
  any: 2
abilities:
  - name: Recycle
    description: Shuffle graveyard into deck.
    ability_type: activated
    mana_requirement: {}
    alterations:
      - effect: recycle_graveyard
        target: owner
```

### Mana card

```yaml
card_id: fire_mana_01
name: Fire Mana
description: Provides 1 fire mana.
type: mana
mana:
  fire: 1
```

### Deck YAML

```yaml
# decks/midrange.yaml
cards:
  goblin_01: 3
  giant_01: 2
  fireball_01: 2
  pyromancer_01: 2
  fire_mana_01: 5
  earth_mana_01: 6
```
