Spaces:
Running
Running
| from dataclasses import dataclass | |
| from typing import Literal | |
| PrimitiveId = Literal[ | |
| "deal", | |
| "burn", | |
| "bomb", | |
| "block", | |
| "ward", | |
| "weak", | |
| "draw", | |
| "energy", | |
| "initiative", | |
| "multi_hit", | |
| "vulnerable", | |
| "conditional", | |
| "scaling", | |
| ] | |
| School = Literal["fire", "ice", "earth"] | |
| class PrimitiveSpec: | |
| id: PrimitiveId | |
| name: str | |
| category: str | |
| schools: frozenset[School] | |
| class Effect: | |
| primitive_id: PrimitiveId | |
| amount: int = 0 | |
| duration: int = 0 | |
| delay: int = 0 | |
| hits: int = 1 | |
| condition: str = "" | |
| PRIMITIVES: dict[PrimitiveId, PrimitiveSpec] = { | |
| "deal": PrimitiveSpec("deal", "Deal", "damage", frozenset(("fire",))), | |
| "burn": PrimitiveSpec("burn", "Burn", "damage", frozenset(("fire",))), | |
| "bomb": PrimitiveSpec("bomb", "Bomb", "damage", frozenset(("fire",))), | |
| "block": PrimitiveSpec("block", "Block", "defense", frozenset(("earth",))), | |
| "ward": PrimitiveSpec("ward", "Ward", "defense", frozenset(("earth",))), | |
| "weak": PrimitiveSpec("weak", "Weak", "defense", frozenset()), | |
| "draw": PrimitiveSpec("draw", "Draw", "tempo", frozenset()), | |
| "energy": PrimitiveSpec("energy", "Energy", "tempo", frozenset()), | |
| "initiative": PrimitiveSpec("initiative", "Initiative", "tempo", frozenset(("ice",))), | |
| "multi_hit": PrimitiveSpec("multi_hit", "Multi-hit", "combo", frozenset(("ice",))), | |
| "vulnerable": PrimitiveSpec("vulnerable", "Vulnerable", "combo", frozenset(("ice",))), | |
| "conditional": PrimitiveSpec("conditional", "Conditional", "combo", frozenset(("ice", "earth"))), | |
| "scaling": PrimitiveSpec("scaling", "Scaling", "combo", frozenset(("fire", "earth"))), | |
| } | |
| SCHOOL_PRIMITIVES: dict[School, tuple[PrimitiveId, ...]] = { | |
| "fire": ("deal", "burn", "bomb", "scaling", "draw", "energy", "block", "conditional"), | |
| "ice": ("deal", "initiative", "vulnerable", "multi_hit", "conditional", "draw", "energy", "block"), | |
| "earth": ("deal", "ward", "block", "weak", "scaling", "conditional", "draw", "energy"), | |
| } | |
| SCHOOL_BIAS: dict[School, str] = { | |
| "fire": "Prefer immediate Deal first, then Burn/Scaling, then occasional Bomb, Draw, Energy, or Block.", | |
| "ice": "Prefer tempo pressure through Deal, Initiative, Vulnerable, Multi-hit, and Conditional, with occasional Draw or Block.", | |
| "earth": "Prefer Block and Ward to bank shield charge, then Scaling to release that charge as burst damage. Add some Deal, Weak, and Draw.", | |
| } | |
| # Return all primitive identifiers in canonical order. | |
| def primitive_ids() -> tuple[PrimitiveId, ...]: | |
| return tuple(PRIMITIVES) | |
| # Return a primitive spec by id. | |
| def get_primitive(primitive_id: PrimitiveId) -> PrimitiveSpec: | |
| return PRIMITIVES[primitive_id] | |
| # Return the primitive ids available to a school. | |
| def school_primitives(school: School) -> tuple[PrimitiveId, ...]: | |
| return SCHOOL_PRIMITIVES[school] | |
| # Return whether a primitive belongs in a school's draft pool. | |
| def primitive_allowed_for_school(primitive_id: PrimitiveId, school: School) -> bool: | |
| return primitive_id in SCHOOL_PRIMITIVES[school] | |
| # Return a school's generation bias. | |
| def school_bias(school: School) -> str: | |
| return SCHOOL_BIAS[school] | |
| # Render a costed effect into fixed card text. | |
| def render_effect(effect: Effect) -> str: | |
| match effect.primitive_id: | |
| case "deal": | |
| return f"Deal {effect.amount} damage." | |
| case "burn": | |
| return f"Burn {effect.amount} damage for {effect.duration} turns." | |
| case "bomb": | |
| return f"Bomb: deal {effect.amount} damage in {effect.delay} turns." | |
| case "block": | |
| return f"Gain {effect.amount} block until your next turn." | |
| case "ward": | |
| return f"Gain {effect.amount} ward." | |
| case "weak": | |
| return f"Opponent deals {effect.amount} less damage until your next turn." | |
| case "draw": | |
| return f"Draw {effect.amount} card{'s' if effect.amount != 1 else ''}." | |
| case "energy": | |
| return f"Gain {effect.amount} energy this turn." | |
| case "initiative": | |
| return "Opponent acts second next round." | |
| case "multi_hit": | |
| return f"Deal {effect.amount} damage {effect.hits} times." | |
| case "vulnerable": | |
| return f"Opponent takes {effect.amount} more damage for {effect.duration} turns." | |
| case "conditional": | |
| return f"Deal up to {effect.amount} damage based on opponent's missing HP." | |
| case "scaling": | |
| if effect.condition == "shield_charge": | |
| return f"Deal {effect.amount} damage plus your banked shield charge, then empty it." | |
| return f"Deal {effect.amount} damage plus cards played this turn." | |