Files

743 lines
64 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
MTG Rules Engine - Keyword Database Module
Contains hardcoded keyword definitions mapped to the official Magic: The Gathering rules.
Based on MTG Rules 2024-06-19 (version 5.3.0+20260722) with custom keywords from Keywords.json.
Data sources:
- /home/user/wall-o/mtg-rules/Keywords.json (keyword names)
- /home/user/wall-o/mtg-rules/rules/GLOSSARY.md (keyword definitions)
- /home/user/wall-o/mtg-rules/rules/rules/7-additional-rules/701-keyword-actions.md
- /home/user/wall-o/mtg-rules/rules/rules/7-additional-rules/702-keyword-abilities.md
"""
# =============================================================================
# KEYWORD ACTIONS (Rule 701)
# =============================================================================
KEYWORD_ACTIONS = {
"activate": {
"rule": "701.2",
"definition": "To activate an activated ability is to put it onto the stack and pay its costs, so that it will eventually resolve and have its effect.",
"type": "action"
},
"attach": {
"rule": "701.3",
"definition": "To attach an Aura, Equipment, or Fortification to an object or player means to take it from where it currently is and put it onto that object or player.",
"type": "action"
},
"behold": {
"rule": "701.4",
"definition": "Reveal a [quality] card from your hand or choose a [quality] permanent you control on the battlefield.",
"type": "action"
},
"cast": {
"rule": "701.5",
"definition": "To cast a spell is to take it from the zone it's in (usually the hand), put it on the stack, and pay its costs, so that it will eventually resolve and have its effect.",
"type": "action"
},
"counter": {
"rule": "701.6",
"definition": "To counter a spell or ability means to cancel it, removing it from the stack. It doesn't resolve and none of its effects occur.",
"type": "action"
},
"create": {
"rule": "701.7",
"definition": "To create one or more tokens with certain characteristics, put the specified number of tokens with the specified characteristics onto the battlefield.",
"type": "action"
},
"destroy": {
"rule": "701.8",
"definition": "To destroy a permanent, move it from the battlefield to its owner's graveyard.",
"type": "action"
},
"discard": {
"rule": "701.9",
"definition": "To discard a card, move it from its owner's hand to that player's graveyard.",
"type": "action"
},
"double": {
"rule": "701.10",
"definition": "Doubling a creature's power and/or toughness creates a continuous effect. This effect modifies that creature's power and/or toughness but doesn't set those characteristics to a specific value.",
"type": "action"
},
"exchange": {
"rule": "701.12",
"definition": "A spell or ability may instruct players to exchange something (for example, life totals or control of two permanents) as part of its resolution.",
"type": "action"
},
"exile": {
"rule": "701.13",
"definition": "To exile an object, move it to the exile zone from wherever it is.",
"type": "action"
},
"fight": {
"rule": "701.14",
"definition": "To have a creature fight another creature means each of those creatures deals damage equal to its power to the other creature.",
"type": "action"
},
"goad": {
"rule": "701.15",
"definition": "A permanent is goaded until the next turn of the controller of the permanent, spell, or ability that caused it to be goaded. A goaded creature attacks each combat if able.",
"type": "action"
},
"investigate": {
"rule": "701.16",
"definition": "To create a Clue artifact token.",
"type": "action"
},
"mill": {
"rule": "701.17",
"definition": "To mill a number of cards, put that many cards from the top of your library into your graveyard.",
"type": "action"
},
"play": {
"rule": "701.18",
"definition": "To play a land means to put it onto the battlefield from the zone it's in. To play a card means to play it as a land or to cast it as a spell.",
"type": "action"
},
"regenerate": {
"rule": "701.19",
"definition": "Regenerate creates a replacement effect that protects a permanent the next time it would be destroyed this turn: remove all damage marked on it and its controller taps it.",
"type": "action"
},
"reveal": {
"rule": "701.20",
"definition": "To reveal a card, show that card to all players for a brief time.",
"type": "action"
},
"sacrifice": {
"rule": "701.21",
"definition": "To sacrifice a permanent, its controller moves it from the battlefield directly to its owner's graveyard.",
"type": "action"
},
"scry": {
"rule": "701.22",
"definition": "To scry N means to look at the top N cards of your library, then put any number of them on the bottom of your library in any order and the rest on top in any order.",
"type": "action"
},
"search": {
"rule": "701.23",
"definition": "To search for a card in a zone, look at all cards in that zone and find a card that matches the given description.",
"type": "action"
},
"shuffle": {
"rule": "701.24",
"definition": "To shuffle a library or a face-down pile of cards, randomize the cards within it so that no player knows their order.",
"type": "action"
},
"surveil": {
"rule": "701.25",
"definition": "To surveil N means to look at the top N cards of your library, then put any number of them into your graveyard and the rest on top of your library in any order.",
"type": "action"
},
"tap": {
"rule": "701.26",
"definition": "To tap a permanent, turn it sideways from an upright position. To untap a permanent, rotate it back to the upright position.",
"type": "action"
},
"transform": {
"rule": "701.27",
"definition": "To transform a permanent, turn it over so its other face is up.",
"type": "action"
},
"convert": {
"rule": "701.28",
"definition": "To convert a permanent, turn it so its other face is up. This follows rules 701.27af.",
"type": "action"
},
"fateseal": {
"rule": "701.29",
"definition": "To fateseal N means to look at the top N cards of an opponent's library, then put any number of them on the bottom of that library in any order and the rest on top in any order.",
"type": "action"
},
"clash": {
"rule": "701.30",
"definition": "To clash, reveal the top card of your library. That player may put that card on the bottom of their library.",
"type": "action"
},
"planeswalk": {
"rule": "701.31",
"definition": "To planeswalk is to put each face-up plane card and phenomenon card on the bottom of its owner's planar deck face down, then move the top card of your planar deck face up.",
"type": "action"
},
"set_in_motion": {
"rule": "701.32",
"definition": "To set a scheme in motion, move it off the top of your scheme deck if it's on top of your scheme deck and turn it face up if it isn't face up.",
"type": "action"
},
"abandon": {
"rule": "701.33",
"definition": "To abandon a scheme, turn it face down and put it on the bottom of its owner's scheme deck.",
"type": "action"
},
"proliferate": {
"rule": "701.34",
"definition": "To proliferate means to choose any number of permanents and/or players that have a counter, then give each one additional counter of each kind that permanent or player already has.",
"type": "action"
},
"detain": {
"rule": "701.35",
"definition": "A permanent is detained until the next turn of the controller of the spell or ability. A detained permanent can't attack or block and its activated abilities can't be activated.",
"type": "action"
},
"populate": {
"rule": "701.36",
"definition": "To populate means to choose a creature token you control and create a token that's a copy of that creature token.",
"type": "action"
},
"monstrosity": {
"rule": "701.37",
"definition": "If this permanent isn't monstrous, put N +1/+1 counters on it. If it becomes monstrous, it stays monstrous until it leaves the battlefield.",
"type": "action"
},
"vote": {
"rule": "701.38",
"definition": "Players vote for one choice from a list of options to determine some aspect of the effect of that spell or ability.",
"type": "action"
},
"bolster": {
"rule": "701.39",
"definition": "Choose a creature you control with the least toughness or tied for least toughness among creatures you control. Put N +1/+1 counters on that creature.",
"type": "action"
},
"manifest": {
"rule": "701.40",
"definition": "To manifest a card, turn it face down. It becomes a 2/2 face-down creature card with ward {2}, no name, no subtypes, and no mana cost. Put that card onto the battlefield face down.",
"type": "action"
},
"support": {
"rule": "701.41",
"definition": "Put a +1/+1 counter on each of up to N other target creatures.",
"type": "action"
},
"meld": {
"rule": "701.42",
"definition": "Meld is a keyword action that appears in an ability on one card in a meld pair. To meld the two cards, put them onto the battlefield with their back faces up and combined.",
"type": "action"
},
"exert": {
"rule": "701.43",
"definition": "To exert a permanent, you choose to have it not untap during your next untap step.",
"type": "action"
},
"explore": {
"rule": "701.44",
"definition": "Reveal the top card of your library. If a land card is revealed, put it into your hand. Otherwise, put a +1/+1 counter on the exploring permanent and may put the revealed card into your graveyard.",
"type": "action"
},
"assemble": {
"rule": "701.45",
"definition": "Unstable set mechanic. Puts Contraptions onto the battlefield.",
"type": "action"
},
"adapt": {
"rule": "701.46",
"definition": "If this permanent has no +1/+1 counters on it, put N +1/+1 counters on it.",
"type": "action"
},
"amass": {
"rule": "701.47",
"definition": "If you don't control an Army creature, create a 0/0 black Army creature token. Choose an Army creature you control. Put N +1/+1 counters on that creature.",
"type": "action"
},
"learn": {
"rule": "701.48",
"definition": "You may discard a card. If you do, draw a card. If you didn't discard a card, you may reveal a Lesson card you own from outside the game and put it into your hand.",
"type": "action"
},
"venture_into_the_dungeon": {
"rule": "701.49",
"definition": "Choose a dungeon card you own from outside the game and put it into the command zone. Put your venture marker on the topmost room.",
"type": "action"
},
"connive": {
"rule": "701.50",
"definition": "Draw a card, then discard a card. If a nonland card is discarded, put a +1/+1 counter on the conniving permanent.",
"type": "action"
},
"open_an_attraction": {
"rule": "701.51",
"definition": "Move the top card of your Attraction deck off the Attraction deck, turn it face up, and put it onto the battlefield under your control.",
"type": "action"
},
"roll_to_visit_your_attractions": {
"rule": "701.52",
"definition": "Roll a six-sided die. If you control one or more Attractions with a number lit up that is equal to that result, each of those Attractions has been 'visited' and its visit ability triggers.",
"type": "action"
},
"incubate": {
"rule": "701.53",
"definition": "Create an Incubator token that enters the battlefield with N +1/+1 counters on it.",
"type": "action"
},
"the_ring_tempts_you": {
"rule": "701.54",
"definition": "Choose a creature you control. That creature becomes your Ring-bearer until another creature becomes your Ring-bearer or another player gains control of it.",
"type": "action"
},
"face_a_villainous_choice": {
"rule": "701.55",
"definition": "Choose [option A] or [option B]. Then all actions in the chosen option are performed.",
"type": "action"
},
"time_travel": {
"rule": "701.56",
"definition": "Choose any number of permanents you control with one or more time counters and/or suspended cards you own in exile with one or more time counters, and, for each of those objects, put a time counter on it or remove a time counter from it.",
"type": "action"
},
"discover": {
"rule": "701.57",
"definition": "Exile cards from the top of your library until you exile a nonland card with mana value N or less. You may cast that card without paying its mana cost if the resulting spell's mana value is less than or equal to N. If you don't cast it, put that card into your hand.",
"type": "action"
},
"cloak": {
"rule": "701.58",
"definition": "To cloak a card, turn it face down. It becomes a 2/2 face-down creature card with ward {2}, no name, no subtypes, and no mana cost. Put that card onto the battlefield face down.",
"type": "action"
},
"collect_evidence": {
"rule": "701.59",
"definition": "Exile any number of cards from your graveyard with total mana value N or greater.",
"type": "action"
},
"suspect": {
"rule": "701.60",
"definition": "A creature becomes suspected. A suspected permanent has menace and can't block. A suspected permanent can't become suspected again.",
"type": "action"
},
"forage": {
"rule": "701.61",
"definition": "Exile three cards from your graveyard or sacrifice a Food.",
"type": "action"
},
"manifest_dread": {
"rule": "701.62",
"definition": "Look at the top two cards of your library. Manifest one of them, then put the cards you looked at that were not manifested into your graveyard.",
"type": "action"
},
"endure": {
"rule": "701.63",
"definition": "Create an N/N white Spirit creature token unless you put N +1/+1 counters on that permanent.",
"type": "action"
},
"harness": {
"rule": "701.64",
"definition": "If this permanent isn't harnessed, it becomes harnessed. Harnessed is a designation permanents can have.",
"type": "action"
},
"airbend": {
"rule": "701.65",
"definition": "Exile one or more permanents and/or spells. For each card exiled this way, for as long as it remains exiled, its owner may cast it by paying {2} rather than paying its mana cost.",
"type": "action"
},
"earthbend": {
"rule": "701.66",
"definition": "Target land you control becomes a 0/0 land creature with haste in addition to its other types. Put N +1/+1 counters on it. When that land dies or is put into exile, return it to the battlefield tapped under your control.",
"type": "action"
},
"waterbend": {
"rule": "701.67",
"definition": "Pay [cost]. For each generic mana in that cost, you may tap an untapped artifact or creature you control rather than pay that mana.",
"type": "action"
},
"blight": {
"rule": "701.68",
"definition": "Put N -1/-1 counters on a creature you control.",
"type": "action"
},
"heal": {
"rule": "701.69",
"definition": "To heal damage already dealt to a permanent, remove that marked damage from that permanent.",
"type": "action"
},
}
# =============================================================================
# KEYWORD ABILITIES (Rule 702)
# =============================================================================
KEYWORD_ABILITIES = {
# Static abilities
"deathtouch": {"rule": "702.2", "type": "static", "definition": "A creature with toughness greater than 0 that's been dealt damage by a source with deathtouch since the last time state-based actions were checked is destroyed as a state-based action."},
"defender": {"rule": "702.3", "type": "static", "definition": "A creature with defender can't attack."},
"double_strike": {"rule": "702.4", "type": "static", "definition": "If at least one attacking or blocking creature has first strike or double strike as the combat damage step begins, the only creatures that assign combat damage in that step are those with first strike or double strike."},
"enchant": {"rule": "702.5", "type": "static", "definition": "Enchant is a static ability, written 'Enchant [object or player].' The enchant ability restricts what an Aura spell can target and what an Aura can enchant."},
"equip": {"rule": "702.6", "type": "activated", "definition": "Equip is an activated ability of Equipment cards. 'Equip [cost]' means '[Cost]: Attach this permanent to target creature you control. Activate only as a sorcery.'"},
"first_strike": {"rule": "702.7", "type": "static", "definition": "First strike is a static ability that modifies the rules for the combat damage step. Creatures with first strike or double strike deal damage in the first combat damage step."},
"flash": {"rule": "702.8", "type": "static", "definition": "Flash is a static ability that functions in any zone from which you could play the card it's on. 'Flash' means 'You may play this card any time you could cast an instant.'"},
"flying": {"rule": "702.9", "type": "evasion", "definition": "Flying is an evasion ability. A creature with flying can't be blocked except by creatures with flying and/or reach."},
"haste": {"rule": "702.10", "type": "static", "definition": "Haste is a static ability. If a creature has haste, it can attack even if it hasn't been controlled by its controller continuously since their most recent turn began."},
"hexproof": {"rule": "702.11", "type": "static", "definition": "Hexproof is a static ability. 'Hexproof' on a permanent means 'This permanent can't be the target of spells or abilities your opponents control.'"},
"indestructible": {"rule": "702.12", "type": "static", "definition": "Indestructible is a static ability. A permanent with indestructible can't be destroyed. Such permanents aren't destroyed by lethal damage, and they ignore the state-based action that checks for lethal damage."},
"intimidate": {"rule": "702.13", "type": "evasion", "definition": "Intimidate is an evasion ability. A creature with intimidate can't be blocked except by artifact creatures and/or creatures that share a color with it."},
"landwalk": {"rule": "702.14", "type": "evasion", "definition": "Landwalk is a generic term for a group of keyword abilities that restrict whether a creature may be blocked. A creature with landwalk can't be blocked as long as the defending player controls at least one land with the specified land type."},
"lifelink": {"rule": "702.15", "type": "static", "definition": "Damage dealt by a source with lifelink causes that source's controller, or its owner if it has no controller, to gain that much life (in addition to any other results that damage causes)."},
"protection": {"rule": "702.16", "type": "static", "definition": "Protection is a static ability, written 'Protection from [quality].' A permanent or player with protection can't be targeted by spells with the stated quality and can't be targeted by abilities from a source with the stated quality."},
"reach": {"rule": "702.17", "type": "evasion", "definition": "Reach is a static ability. A creature with flying can't be blocked except by creatures with flying and/or reach."},
"shroud": {"rule": "702.18", "type": "static", "definition": "Shroud is a static ability. 'Shroud' means 'This permanent or player can't be the target of spells or abilities.'"},
"trample": {"rule": "702.19", "type": "static", "definition": "Trample is a static ability that modifies the rules for assigning an attacking creature's combat damage. The controller of an attacking creature with trample first assigns damage to the creature(s) blocking it. Once all those blocking creatures are assigned lethal damage, any excess damage is assigned as its controller chooses among those blocking creatures and the player, planeswalker, or battle the creature is attacking."},
"vigilance": {"rule": "702.20", "type": "static", "definition": "Vigilance is a static ability that modifies the rules for the declare attackers step. Attacking doesn't cause creatures with vigilance to tap."},
"ward": {"rule": "702.21", "type": "triggered", "definition": "Ward [cost] means 'Whenever this permanent becomes the target of a spell or ability an opponent controls, counter that spell or ability unless that player pays [cost].'"},
"banding": {"rule": "702.22", "type": "static", "definition": "Banding is a static ability that modifies the rules for combat. Creatures with banding can form attacking bands."},
"rampage": {"rule": "702.23", "type": "triggered", "definition": "Rampage N means 'Whenever this creature becomes blocked, it gets +N/+N until end of turn for each creature blocking it beyond the first.'"},
"cumulative_upkeep": {"rule": "702.24", "type": "triggered", "definition": "Cumulative upkeep [cost] means 'At the beginning of your upkeep, if this permanent is on the battlefield, put an age counter on this permanent. Then you may pay [cost] for each age counter on it. If you don't, sacrifice it.'"},
"flanking": {"rule": "702.25", "type": "triggered", "definition": "Flanking means 'Whenever this creature becomes blocked by a creature without flanking, the blocking creature gets -1/-1 until end of turn.'"},
"phasing": {"rule": "702.26", "type": "static", "definition": "Phasing is a static ability that modifies the rules of the untap step. During each player's untap step, before the active player untaps permanents, all phased-in permanents with phasing that player controls 'phase out.' Simultaneously, all phased-out permanents that had phased out under that player's control 'phase in.'"},
"buyback": {"rule": "702.27", "type": "static", "definition": "Buyback [cost] means 'You may pay an additional [cost] as you cast this spell' and 'If the buyback cost was paid, put this spell into its owner's hand instead of into that player's graveyard as it resolves.'"},
"shadow": {"rule": "702.28", "type": "evasion", "definition": "Shadow is an evasion ability. A creature with shadow can't be blocked by creatures without shadow, and a creature without shadow can't be blocked by creatures with shadow."},
"cycling": {"rule": "702.29", "type": "activated", "definition": "Cycling is an activated ability that functions only while the card with cycling is in a player's hand. 'Cycling [cost]' means '[Cost], Discard this card: Draw a card.'"},
"echo": {"rule": "702.30", "type": "triggered", "definition": "Echo [cost] means 'At the beginning of your upkeep, if this permanent came under your control since the beginning of your last upkeep, sacrifice it unless you pay [cost].'"},
"horsemanship": {"rule": "702.31", "type": "evasion", "definition": "Horsemanship is an evasion ability. A creature with horsemanship can't be blocked by creatures without horsemanship. A creature with horsemanship can block a creature with or without horsemanship."},
"fading": {"rule": "702.32", "type": "static", "definition": "Fading N means 'This permanent enters with N fade counters on it' and 'At the beginning of your upkeep, remove a fade counter from this permanent. If you can't, sacrifice the permanent.'"},
"kicker": {"rule": "702.33", "type": "static", "definition": "Kicker [cost] means 'You may pay an additional [cost] as you cast this spell.' A spell has been 'kicked' if its controller declared the intention to pay any of that spell's kicker costs."},
"flashback": {"rule": "702.34", "type": "static", "definition": "Flashback [cost] means 'You may cast this card from your graveyard if the resulting spell is an instant or sorcery spell by paying [cost] rather than paying its mana cost' and 'If the flashback cost was paid, exile this card instead of putting it anywhere else any time it would leave the stack.'"},
"madness": {"rule": "702.35", "type": "static", "definition": "Madness [cost] means 'If a player would discard this card, that player discards it, but exiles it instead of putting it into their graveyard' and 'When this card is exiled this way, its owner may cast it by paying [cost] rather than paying its mana cost.'"},
"fear": {"rule": "702.36", "type": "evasion", "definition": "Fear is an evasion ability. A creature with fear can't be blocked except by artifact creatures and/or black creatures."},
"morph": {"rule": "702.37", "type": "static", "definition": "Morph [cost] means 'You may cast this card as a 2/2 face-down creature with no text, no name, no subtypes, and no mana cost by paying {3} rather than paying its mana cost.'"},
"amplify": {"rule": "702.38", "type": "static", "definition": "As this object enters, reveal any number of cards from your hand that share a creature type with it. This permanent enters with N +1/+1 counters on it for each card revealed this way."},
"provoke": {"rule": "702.39", "type": "triggered", "definition": "Whenever this creature attacks, you may choose to have target creature defending player controls block this creature this combat if able. If you do, untap that creature."},
"storm": {"rule": "702.40", "type": "triggered", "definition": "When you cast this spell, copy it for each other spell that was cast before it this turn. If the spell has any targets, you may choose new targets for the copies."},
"affinity": {"rule": "702.41", "type": "static", "definition": "Affinity for [text] means 'This spell costs {1} less to cast for each [text] you control.'"},
"entwine": {"rule": "702.42", "type": "static", "definition": "Entwine [cost] means 'You may choose all modes of this spell instead of just the number specified. If you do, you pay an additional [cost].'"},
"modular": {"rule": "702.43", "type": "static", "definition": "Modular N means 'This permanent enters with N +1/+1 counters on it' and 'When this permanent is put into a graveyard from the battlefield, you may put a +1/+1 counter on target artifact creature for each +1/+1 counter on this permanent.'"},
"sunburst": {"rule": "702.44", "type": "static", "definition": "As this object enters, ignoring any type-changing effects that would affect it, it enters with a +1/+1 counter on it for each color of mana spent to cast it. Otherwise, it enters with a charge counter on it for each color of mana spent to cast it."},
"bushido": {"rule": "702.45", "type": "triggered", "definition": "Whenever this creature blocks or becomes blocked, it gets +N/+N until end of turn."},
"soulshift": {"rule": "702.46", "type": "triggered", "definition": "When this permanent is put into a graveyard from the battlefield, you may return target Spirit card with mana value N or less from your graveyard to your hand."},
"splice": {"rule": "702.47", "type": "static", "definition": "Splice onto [quality] [cost] means 'You may reveal this card from your hand as you cast a [quality] spell. If you do, that spell gains the text of this card's rules text and you pay [cost] as an additional cost to cast that spell.'"},
"offering": {"rule": "702.48", "type": "static", "definition": "As an additional cost to cast this spell, you may sacrifice a [quality] permanent. If you chose to pay the additional cost, this spell's total cost is reduced by the sacrificed permanent's mana cost, and you may cast this spell any time you could cast an instant."},
"ninjutsu": {"rule": "702.49", "type": "activated", "definition": "Ninjutsu [cost] means '[Cost], Reveal this card from your hand, Return an unblocked attacking creature you control to its owner's hand: Put this card onto the battlefield from your hand tapped and attacking.'"},
"epic": {"rule": "702.50", "type": "static", "definition": "Epic means 'For the rest of the game, you can't cast spells,' and 'At the beginning of each of your upkeeps for the rest of the game, copy this spell except for its epic ability. If the spell has any targets, you may choose new targets for the copy.'"},
"convoke": {"rule": "702.51", "type": "static", "definition": "Convoke means 'For each colored mana in this spell's total cost, you may tap an untapped creature of that color you control rather than pay that mana. For each generic mana in this spell's total cost, you may tap an untapped creature you control rather than pay that mana.'"},
"dredge": {"rule": "702.52", "type": "static", "definition": "As long as you have at least N cards in your library, if you would draw a card, you may instead mill N cards and return this card from your graveyard to your hand."},
"transmute": {"rule": "702.53", "type": "activated", "definition": "Transmute [cost] means '[Cost], Discard this card: Search your library for a card with the same mana value as the discarded card, reveal that card, and put it into your hand. Then shuffle your library. Activate only as a sorcery.'"},
"bloodthirst": {"rule": "702.54", "type": "static", "definition": "Bloodthirst N means 'If an opponent was dealt damage this turn, this permanent enters with N +1/+1 counters on it.'"},
"haunt": {"rule": "702.55", "type": "triggered", "definition": "When this permanent is put into a graveyard from the battlefield, exile it haunting target creature."},
"replicate": {"rule": "702.56", "type": "static", "definition": "As an additional cost to cast this spell, you may pay [cost] any number of times. When you cast this spell, if a replicate cost was paid for it, copy it for each time its replicate cost was paid."},
"forecast": {"rule": "702.57", "type": "activated", "definition": "Forecast — [Activated ability]. The controller of the forecast ability reveals the card with that ability from their hand as the ability is activated. That player plays with that card revealed in their hand until it leaves the player's hand or until a step or phase that isn't an upkeep step begins."},
"graft": {"rule": "702.58", "type": "static", "definition": "This permanent enters with N +1/+1 counters on it and 'Whenever another creature enters, if this permanent has a +1/+1 counter on it, you may move a +1/+1 counter from this permanent onto that creature.'"},
"recover": {"rule": "702.59", "type": "activated", "definition": "When a creature is put into your graveyard from the battlefield, you may pay [cost]. If you do, return this card from your graveyard to your hand. Otherwise, exile this card."},
"ripple": {"rule": "702.60", "type": "triggered", "definition": "When you cast this spell, you may reveal the top N cards of your library, or, if there are fewer than N cards in your library, you may reveal all the cards in your library. If you reveal cards from your library this way, you may cast any of those cards with the same name as this spell without paying their mana costs."},
"split_second": {"rule": "702.61", "type": "static", "definition": "As long as this spell is on the stack, players can't cast other spells or activate abilities that aren't mana abilities."},
"suspend": {"rule": "702.62", "type": "static", "definition": "If you could begin to cast this card by putting it onto the stack from your hand, you may pay [cost] and exile it with N time counters on it. This action doesn't use the stack. At the beginning of your upkeep, if this card is suspended, remove a time counter from it. When the last time counter is removed from this card, if it's exiled, you may play it without paying its mana cost if able."},
"vanishing": {"rule": "702.63", "type": "static", "definition": "This permanent enters with N time counters on it, 'At the beginning of your upkeep, if this permanent has a time counter on it, remove a time counter from it,' and 'When the last time counter is removed from this permanent, sacrifice it.'"},
"absorb": {"rule": "702.64", "type": "static", "definition": "If a source would deal damage to this creature, prevent N of that damage."},
"aura_swap": {"rule": "702.65", "type": "activated", "definition": "You may exchange this permanent with an Aura card in your hand."},
"delve": {"rule": "702.66", "type": "static", "definition": "For each generic mana in this spell's total cost, you may exile a card from your graveyard rather than pay that mana."},
"fortify": {"rule": "702.67", "type": "activated", "definition": "Fortify [cost] means '[Cost]: Attach this Fortification to target land you control. Activate only as a sorcery.'"},
"frenzy": {"rule": "702.68", "type": "triggered", "definition": "Whenever this creature attacks and isn't blocked, it gets +N/+0 until end of turn."},
"gravestorm": {"rule": "702.69", "type": "triggered", "definition": "When you cast this spell, copy it for each permanent that was put into a graveyard from the battlefield this turn. If the spell has any targets, you may choose new targets for the copies."},
"poisonous": {"rule": "702.70", "type": "triggered", "definition": "Whenever this creature deals combat damage to a player, that player gets N poison counters."},
"transfigure": {"rule": "702.71", "type": "activated", "definition": "Transfigure [cost] means '[Cost], Sacrifice this permanent: Search your library for a creature card with the same mana value as this permanent and put it onto the battlefield. Then shuffle your library. Activate only as a sorcery.'"},
"champion": {"rule": "702.72", "type": "triggered", "definition": "When this permanent enters, sacrifice it unless you exile another [object] you control. When this permanent leaves the battlefield, return the exiled card to the battlefield under its owner's control."},
"changeling": {"rule": "702.73", "type": "static", "definition": "Changeling is a characteristic-defining ability. 'Changeling' means 'This object is every creature type.'"},
"evoke": {"rule": "702.74", "type": "static", "definition": "You may cast this card by paying [cost] rather than paying its mana cost. When this permanent enters, if its evoke cost was paid, its controller sacrifices it."},
"hideaway": {"rule": "702.75", "type": "triggered", "definition": "When this permanent enters, look at the top N cards of your library. Exile one of them face down and put the rest on the bottom of your library in a random order. The exiled card gains 'The player who controls the permanent that exiled this card may look at this card in the exile zone.'"},
"prowl": {"rule": "702.76", "type": "static", "definition": "You may pay [cost] rather than pay this spell's mana cost if a player was dealt combat damage this turn by a source that, at the time it dealt that damage, was under your control and had any of this spell's creature types."},
"reinforce": {"rule": "702.77", "type": "activated", "definition": "Reinforce N—[cost] means '[Cost], Discard this card: Put N +1/+1 counters on target creature.'"},
"conspire": {"rule": "702.78", "type": "static", "definition": "As an additional cost to cast this spell, you may tap two untapped creatures you control that each share a color with it. When you cast this spell, if its conspire cost was paid, copy it. If the spell has any targets, you may choose new targets for the copy."},
"persist": {"rule": "702.79", "type": "triggered", "definition": "When this permanent is put into a graveyard from the battlefield, if it had no -1/-1 counters on it, return it to the battlefield under its owner's control with a -1/-1 counter on it."},
"wither": {"rule": "702.80", "type": "static", "definition": "Damage dealt to a creature by a source with wither isn't marked on that creature. Rather, it causes that source's controller to put that many -1/-1 counters on that creature."},
"retrace": {"rule": "702.81", "type": "activated", "definition": "Retrace means 'You may cast this card from your graveyard by discarding a land card as an additional cost to cast it.'"},
"devour": {"rule": "702.82", "type": "static", "definition": "As this object enters, you may sacrifice any number of creatures. This permanent enters with N +1/+1 counters on it for each creature sacrificed this way."},
"exalted": {"rule": "702.83", "type": "triggered", "definition": "Whenever a creature you control attacks alone, that creature gets +1/+1 until end of turn."},
"unearth": {"rule": "702.84", "type": "activated", "definition": "Unearth [cost] means '[Cost]: Return this card from your graveyard to the battlefield. It gains haste. Exile it at the beginning of the next end step. If it would leave the battlefield, exile it instead of putting it anywhere else. Activate only as a sorcery.'"},
"cascade": {"rule": "702.85", "type": "triggered", "definition": "When you cast this spell, exile cards from the top of your library until you exile a nonland card with mana value less than this spell's mana value. You may cast that card without paying its mana cost if the resulting spell's mana value is less than this spell's mana value. Then put all cards exiled this way that weren't cast on the bottom of your library in a random order."},
"annihilator": {"rule": "702.86", "type": "triggered", "definition": "Whenever this creature attacks, defending player sacrifices N permanents."},
"level_up": {"rule": "702.87", "type": "activated", "definition": "Level up [cost] means '[Cost]: Put a level counter on this permanent. Activate only as a sorcery.'"},
"rebound": {"rule": "702.88", "type": "static", "definition": "If this spell was cast from your hand, instead of putting it into your graveyard as it resolves, exile it and, at the beginning of your next upkeep, you may cast this card from exile without paying its mana cost."},
"umbra_armor": {"rule": "702.89", "type": "static", "definition": "If enchanted permanent would be destroyed, instead remove all damage marked on it and destroy this Aura."},
"infect": {"rule": "702.90", "type": "static", "definition": "Damage dealt to a player by a source with infect doesn't cause that player to lose life. Rather, it causes that source's controller to give the player that many poison counters. Damage dealt to a creature by a source with infect isn't marked on that creature. Rather, it causes that source's controller to put that many -1/-1 counters on that creature."},
"battle_cry": {"rule": "702.91", "type": "triggered", "definition": "Whenever this creature attacks, each other attacking creature gets +1/+0 until end of turn."},
"living_weapon": {"rule": "702.92", "type": "triggered", "definition": "When this Equipment enters, create a 0/0 black Phyrexian Germ creature token, then attach this Equipment to it."},
"undying": {"rule": "702.93", "type": "triggered", "definition": "When this permanent is put into a graveyard from the battlefield, if it had no +1/+1 counters on it, return it to the battlefield under its owner's control with a +1/+1 counter on it."},
"miracle": {"rule": "702.94", "type": "static", "definition": "If a player would discard this card, that player discards it, but exiles it instead of putting it into their graveyard. When this card is exiled this way, its owner may cast it by paying [cost] rather than paying its mana cost."},
"soulbond": {"rule": "702.95", "type": "triggered", "definition": "When this creature enters, if you control both this creature and another creature and both are unpaired, you may pair this creature with another unpaired creature you control for as long as both remain creatures on the battlefield under your control."},
"overload": {"rule": "702.96", "type": "static", "definition": "You may choose to pay [cost] rather than pay this spell's mana cost. If you chose to pay this spell's overload cost, change its text by replacing all instances of the word 'target' with the word 'each.'"},
"scavenge": {"rule": "702.97", "type": "activated", "definition": "Scavenge [cost] means '[Cost], Exile this card from your graveyard: Put a number of +1/+1 counters equal to the power of the card you exiled on target creature. Activate only as a sorcery.'"},
"unleash": {"rule": "702.98", "type": "static", "definition": "You may have this permanent enter with an additional +1/+1 counter on it. This permanent can't block as long as it has a +1/+1 counter on it."},
"cipher": {"rule": "702.99", "type": "static", "definition": "If this spell is represented by a card, you may exile this card encoded on a creature you control. For as long as this card is encoded on that creature, that creature has 'Whenever this creature deals combat damage to a player, you may copy the encoded card and you may cast the copy without paying its mana cost.'"},
"evolve": {"rule": "702.100", "type": "triggered", "definition": "Whenever a creature you control enters, if that creature's power is greater than this creature's power and/or that creature's toughness is greater than this creature's toughness, put a +1/+1 counter on this creature."},
"extort": {"rule": "702.101", "type": "triggered", "definition": "Whenever you cast a spell, you may pay {W/B}. If you do, each opponent loses 1 life and you gain life equal to the total life lost this way."},
"fuse": {"rule": "702.102", "type": "static", "definition": "You may choose to cast both halves of a split card rather than choose one half. The resulting spell is a fused split spell."},
"bestow": {"rule": "702.103", "type": "static", "definition": "As you cast this spell, you may choose to cast it bestowed. If you do, you pay [cost] rather than its mana cost. As a spell cast bestowed is put onto the stack, it becomes an Aura enchantment and gains enchant creature."},
"dethrone": {"rule": "702.105", "type": "triggered", "definition": "Whenever this creature attacks the player with the most life or tied for most life, put a +1/+1 counter on this creature."},
"hidden_agenda": {"rule": "702.106", "type": "static", "definition": "As you put this conspiracy card into the command zone, turn it face down and secretly choose a card name."},
"double_agenda": {"rule": "702.106", "type": "static", "definition": "As you put a conspiracy card with double agenda into the command zone, you secretly name two different cards rather than one."},
"outlast": {"rule": "702.107", "type": "activated", "definition": "Outlast [cost] means '[Cost], {T}: Put a +1/+1 counter on this creature. Activate only as a sorcery.'"},
"prowess": {"rule": "702.108", "type": "triggered", "definition": "Whenever you cast a noncreature spell, this creature gets +1/+1 until end of turn."},
"dash": {"rule": "702.109", "type": "static", "definition": "You may cast this card by paying [cost] rather than paying its mana cost. If this spell's dash cost was paid, return the permanent this spell becomes to its owner's hand at the beginning of the next end step. As long as this permanent's dash cost was paid, it has haste."},
"exploit": {"rule": "702.110", "type": "triggered", "definition": "When this creature enters, you may sacrifice a creature."},
"menace": {"rule": "702.111", "type": "evasion", "definition": "A creature with menace can't be blocked except by two or more creatures."},
"renown": {"rule": "702.112", "type": "triggered", "definition": "Whenever this creature deals combat damage to a player, if it isn't renowned, put N +1/+1 counters on it and it becomes renowned."},
"awaken": {"rule": "702.113", "type": "static", "definition": "You may pay [cost] rather than pay this spell's mana cost. If this spell's awaken cost was paid, put N +1/+1 counters on target land you control. That land becomes a 0/0 Elemental creature with haste. It's still a land."},
"devoid": {"rule": "702.114", "type": "static", "definition": "Devoid is a characteristic-defining ability. 'Devoid' means 'This object is colorless.'"},
"ingest": {"rule": "702.115", "type": "triggered", "definition": "Whenever this creature deals combat damage to a player, that player exiles the top card of their library."},
"myriad": {"rule": "702.116", "type": "triggered", "definition": "Whenever this creature attacks, for each opponent other than defending player, you may create a token that's a copy of this creature that's tapped and attacking that player or a planeswalker they control. If one or more tokens are created this way, exile the tokens at end of combat."},
"surge": {"rule": "702.117", "type": "static", "definition": "You may pay [cost] rather than pay this spell's mana cost if you or one of your teammates has cast another spell this turn."},
"skulk": {"rule": "702.118", "type": "evasion", "definition": "A creature with skulk can't be blocked by creatures with greater power."},
"emerge": {"rule": "702.119", "type": "static", "definition": "You may cast this spell by paying [cost] and sacrificing a creature rather than paying its mana cost. If you chose to pay this spell's emerge cost, its total cost is reduced by an amount of generic mana equal to the sacrificed creature's mana value."},
"escalate": {"rule": "702.120", "type": "static", "definition": "Choose one or more modes. As an additional cost to cast this spell, pay the costs associated with those modes."},
"train": {"rule": "702.149", "type": "triggered", "definition": "Whenever this creature and at least one other creature with power greater than this creature's power attack, put a +1/+1 counter on this creature."},
"completed": {"rule": "702.150", "type": "static", "definition": "If this permanent would enter with one or more loyalty counters on it and the player who cast it chose to pay life for any part of its cost represented by Phyrexian mana symbols, it instead enters the battlefield with that many loyalty counters minus two for each of those mana symbols."},
"reconfigure": {"rule": "702.151", "type": "activated", "definition": "Reconfigure [cost] means '[Cost]: Attach this permanent to another target creature you control. Activate only as a sorcery.'"},
"blitz": {"rule": "702.152", "type": "static", "definition": "You may cast this card by paying [cost] rather than paying its mana cost. If this spell's blitz cost was paid, sacrifice the permanent this spell becomes at the beginning of the next end step. As long as this permanent's blitz cost was paid, it has haste and 'When this permanent is put into a graveyard from the battlefield, draw a card.'"},
"casualty": {"rule": "702.153", "type": "static", "definition": "As an additional cost to cast this spell, you may sacrifice a creature with power N or greater. When you cast this spell, if a casualty cost was paid for it, copy it. If the spell has any targets, you may choose new targets for the copy."},
"enlist": {"rule": "702.154", "type": "static", "definition": "As this creature attacks, you may tap up to one untapped creature you control that you didn't choose to attack with and that either has haste or has been under your control continuously since this turn began. When you do, this creature gets +X/+0 until end of turn, where X is the tapped creature's power."},
"foretell": {"rule": "702.143", "type": "static", "definition": "Any time a player has priority during their turn, that player may pay {2} and exile a card with foretell from their hand face down. That player may look at that card as long as it remains in exile and it may be cast for any foretell cost it has after the turn it became a foretold card has ended."},
"demonstrate": {"rule": "702.144", "type": "triggered", "definition": "When you cast this spell, you may copy it and you may choose an opponent. That player copies the spell and may choose new targets for that copy."},
"daybound": {"rule": "702.145", "type": "static", "definition": "If it is night and this permanent is represented by a double-faced card, it enters transformed. As it becomes night, if this permanent is front face up, transform it. This permanent can't transform except due to its daybound ability."},
"nightbound": {"rule": "702.145", "type": "static", "definition": "As it becomes day, if this permanent is back face up, transform it. This permanent can't transform except due to its nightbound ability."},
"disturb": {"rule": "702.146", "type": "static", "definition": "Disturb [cost] means 'You may cast this card transformed from your graveyard by paying [cost] rather than its mana cost.'"},
"decayed": {"rule": "702.147", "type": "static", "definition": "This creature can't block and 'When this creature attacks, sacrifice it at end of combat.'"},
"cleave": {"rule": "702.148", "type": "static", "definition": "You may cast this spell by paying [cost] rather than paying its mana cost. If this spell's cleave cost was paid, change its text by removing all text found within square brackets in the spell's rules text."},
"firebending": {"rule": "702.189", "type": "triggered", "definition": "Whenever this creature attacks, add N {R}. Until end of combat, you don't lose this mana as steps and phases end."},
"sneak": {"rule": "702.190", "type": "static", "definition": "Any time you could cast an instant during your declare blockers step, you may cast this spell by paying [cost] and returning an unblocked creature you control to its owner's hand rather than paying this spell's mana cost."},
"increment": {"rule": "702.191", "type": "triggered", "definition": "Whenever you cast a spell, if this permanent is a creature and the amount of mana spent to cast that spell is greater than this creature's power or this creature's toughness, put a +1/+1 counter on this creature."},
"paradigm": {"rule": "702.192", "type": "static", "definition": "If this is the first time a spell you control with this spell's name has resolved this game, at the beginning of each of your precombat main phases for the rest of the game, create a copy of this object in exile. You may cast the copy without paying its mana cost."},
"power_up": {"rule": "702.193", "type": "activated", "definition": "Power-up — [Cost]: [Effect]. If this permanent entered this turn, this ability's cost is reduced by this permanent's mana cost. Activate this ability only once."},
"teamwork": {"rule": "702.194", "type": "static", "definition": "As an additional cost to cast this spell, you may tap any number of creatures you control with total power N or more."},
"web_slinging": {"rule": "702.188", "type": "static", "definition": "You may cast this spell by paying [cost] and returning a tapped creature you control to its owner's hand rather than paying its mana cost."},
"firebending": {"rule": "702.189", "type": "triggered", "definition": "Whenever this creature attacks, add N {R}. Until end of combat, you don't lose this mana as steps and phases end."},
"start_your_engines": {"rule": "702.179", "type": "static", "definition": "If a player controls a permanent with start your engines! and that player has no speed, their speed becomes 1. This is a state-based action."},
"max_speed": {"rule": "702.178", "type": "static", "definition": "As long as your speed is 4, this object has '[Ability].'"},
"harmonize": {"rule": "702.180", "type": "static", "definition": "You may cast this card from your graveyard by paying [cost] and tapping up to one untapped creature you control rather than paying this spell's mana cost. If you cast this spell using its harmonize ability, its total cost is reduced by an amount of generic mana equal to the tapped creature's power."},
"mobilize": {"rule": "702.181", "type": "triggered", "definition": "Whenever this creature attacks, create N 1/1 red Warrior creature tokens. Those tokens enter tapped and attacking. Sacrifice them at the beginning of the next end step."},
"job_select": {"rule": "702.182", "type": "triggered", "definition": "When this Equipment enters, create a 1/1 colorless Hero creature token, then attach this Equipment to it."},
"tiered": {"rule": "702.183", "type": "static", "definition": "Choose one. As an additional cost to cast this spell, pay the cost associated with that mode."},
"station": {"rule": "702.184", "type": "activated", "definition": "Station means 'Tap another untapped creature you control: Put a number of charge counters on this permanent equal to the tapped creature's power. Activate only as a sorcery.'"},
"infinity": {"rule": "702.186", "type": "static", "definition": "As long as this permanent is harnessed, it has [ability]."},
"mayhem": {"rule": "702.187", "type": "static", "definition": "As long as you discarded this card this turn, you may cast it from your graveyard by paying [cost] rather than paying its mana cost."},
"training": {"rule": "702.149", "type": "triggered", "definition": "Whenever this creature and at least one other creature with power greater than this creature's power attack, put a +1/+1 counter on this creature."},
}
# =============================================================================
# ABILITY WORDS (No rules meaning - flavor words)
# =============================================================================
ABILITY_WORDS = [
"adamant", "addendum", "alliance", "battalion", "bloodrush", "celebration",
"channel", "chroma", "cohort", "constellation", "converge", "corrupted",
"council's dilemma", "coven", "covercast", "delirium", "descend", "disappear",
"domain", "eerie", "eminence", "enrage", "fateful hour", "fathomless descent",
"ferocious", "flurry", "formidable", "grandeur", "hellbent", "hero's reward",
"heroic", "imprint", "infusion", "inspired", "join forces", "kinfall", "kinship",
"landfall", "landship", "legacy", "lieutenant", "magecraft", "metalcraft",
"morbid", "opus", "pack tactics", "paradox", "parley", "radiance", "raid",
"rally", "renew", "repartee", "revolt", "secret council", "spell mastery",
"start your engines!", "strive", "survival", "sweep", "tempting offer",
"threshold", "underdog", "undergrowth", "valiant", "vivid", "void",
"will of the planeswalkers", "will of the council"
]
# =============================================================================
# KEYWORD VARIANTS (Special forms of keywords)
# =============================================================================
KEYWORD_VARIANTS = {
"megamorph": {"base": "morph", "description": "A variant of the morph ability that puts a +1/+1 counter on the creature as it turns face up."},
"basic_landcycling": {"base": "cycling", "description": "Typecycling where you search for a basic land card."},
"forestcycling": {"base": "cycling", "description": "Typecycling where you search for a forest card."},
"mountaincycling": {"base": "cycling", "description": "Typecycling where you search for a mountain card."},
"islandcycling": {"base": "cycling", "description": "Typecycling where you search for an island card."},
"swampcycling": {"base": "cycling", "description": "Typecycling where you search for a swamp card."},
"plainscycling": {"base": "cycling", "description": "Typecycling where you search for a plains card."},
"slivercycling": {"base": "cycling", "description": "Typecycling where you search for a sliver creature card."},
"typecycling": {"base": "cycling", "description": "A variant of the cycling ability where you search for a card of a specified type."},
"hexproof_from": {"base": "hexproof", "description": "Hexproof that only applies to a specific quality (e.g., 'hexproof from black')."},
"protection_from": {"base": "protection", "description": "Protection that only applies to a specific quality (e.g., 'protection from black')."},
"partner_with": {"base": "partner", "description": "Partner variant that works even outside of the Commander variant to help two cards reach the battlefield together."},
"choose_a_background": {"base": "partner", "description": "Partner variant that lets two legendary permanent cards be your commander if one has choose a Background and the other is a Background enchantment."},
"doctor's_companion": {"base": "partner", "description": "Partner variant that lets two legendary creature cards be your commander if one has Doctor's companion and the other is a Time Lord Doctor."},
"basic_landcycling": {"base": "cycling", "description": "Typecycling where you search for a basic land card."},
"forestcycling": {"base": "cycling", "description": "Typecycling where you search for a forest card."},
"mountaincycling": {"base": "cycling", "description": "Typecycling where you search for a mountain card."},
"islandcycling": {"base": "cycling", "description": "Typecycling where you search for an island card."},
"swampcycling": {"base": "cycling", "description": "Typecycling where you search for a swamp card."},
"plainscycling": {"base": "cycling", "description": "Typecycling where you search for a plains card."},
"slivercycling": {"base": "cycling", "description": "Typecycling where you search for a sliver creature card."},
"forestwalk": {"base": "landwalk", "description": "Landwalk variant for forest."},
"islandwalk": {"base": "landwalk", "description": "Landwalk variant for island."},
"mountainwalk": {"base": "landwalk", "description": "Landwalk variant for mountain."},
"swampwalk": {"base": "landwalk", "description": "Landwalk variant for swamp."},
"plainswalk": {"base": "landwalk", "description": "Landwalk variant for plains."},
"nonbasic_landwalk": {"base": "landwalk", "description": "Landwalk variant for nonbasic lands."},
"snow_swampwalk": {"base": "landwalk", "description": "Landwalk variant for snow swamp."},
"artifact_landwalk": {"base": "landwalk", "description": "Landwalk variant for artifact lands."},
"snow_forestwalk": {"base": "landwalk", "description": "Landwalk variant for snow forest."},
"snow_islandwalk": {"base": "landwalk", "description": "Landwalk variant for snow island."},
"snow_mountainwalk": {"base": "landwalk", "description": "Landwalk variant for snow mountain."},
"snow_plainswalk": {"base": "landwalk", "description": "Landwalk variant for snow plains."},
"snow_swampwalk": {"base": "landwalk", "description": "Landwalk variant for snow swamp."},
}
# =============================================================================
# KEYWORD TYPES
# =============================================================================
KEYWORD_TYPES = {
"static": {
"description": "A permanent effect that is always active. The object with a static ability has the effect all the time.",
"examples": ["flying", "haste", "deathtouch", "indestructible"]
},
"triggered": {
"description": "An effect that triggers in response to a game event. The effect is put on the stack and resolves like any other spell or ability.",
"examples": ["rampage", "squad", "storm", "cascade"]
},
"activated": {
"description": "An effect that a player can choose to activate. Activated abilities have an activation cost and are activated like spells.",
"examples": ["cycling", "sacrifice", "evolve", "spend"]
},
"evasion": {
"description": "A keyword ability that restricts how a creature may be blocked or which creatures it may block.",
"examples": ["flying", "fear", "hexproof", "shroud", "trample"]
}
}
# =============================================================================
# RULES REFERENCE INDEX
# =============================================================================
RULES_INDEX = {
"1-game-concepts": "General rules about playing Magic",
"2-parts-of-a-card": "Card structure: name, mana cost, types, text box, etc.",
"3-card-types": "Card types: creature, spell, land, enchantment, etc.",
"4-zones": "Game zones: battlefield, stack, hand, library, graveyard, exile.",
"5-turn-structure": "Turn phases: untap, draw, main, combat, end.",
"6-spells-abilities-and-effects": "How spells and abilities work: casting, resolving, targeting.",
"7-additional-rules": "Additional rules: keyword actions (701), keyword abilities (702).",
"8-multiplayer-rules": "Multiplayer game rules.",
"9-casual-variants": "Casual variants: Commander, Vanguard, etc."
}
# =============================================================================
# UTILITY FUNCTIONS
# =============================================================================
def get_keyword_definition(keyword: str) -> dict | None:
"""
Get the definition and metadata for a keyword.
Args:
keyword: The keyword name (case-insensitive).
Returns:
Dictionary with keyword information or None if not found.
"""
keyword = keyword.lower().replace(" ", "_")
# Check ability words first
if keyword in [w.lower() for w in ABILITY_WORDS]:
return {
"keyword": keyword,
"type": "ability_word",
"definition": "An italicized word with no rules meaning that ties together abilities on different cards that have similar functionality. See rule 207.2c.",
"rule": "207.2c",
"has_definition": False,
}
# Check keyword abilities
if keyword in KEYWORD_ABILITIES:
ability = KEYWORD_ABILITIES[keyword]
return {
"keyword": keyword,
"type": "keyword_ability",
"definition": ability["definition"],
"rule": ability["rule"],
"ability_type": ability["type"],
"has_definition": True,
}
# Check keyword actions
if keyword in KEYWORD_ACTIONS:
action = KEYWORD_ACTIONS[keyword]
return {
"keyword": keyword,
"type": "keyword_action",
"definition": action["definition"],
"rule": action["rule"],
"has_definition": True,
}
return None
def get_all_keywords() -> list[str]:
"""Get a complete list of all keywords (actions, abilities, and ability words)."""
keywords = set()
keywords.update(KEYWORD_ACTIONS.keys())
keywords.update(KEYWORD_ABILITIES.keys())
keywords.update(ABILITY_WORDS)
return sorted(keywords)
def get_keyword_by_rule(rule: str) -> list[str]:
"""
Get all keywords defined in a specific rule section.
Args:
rule: Rule section (e.g., "701.2" or "702.9").
Returns:
List of keyword names.
"""
keywords = []
# Check keyword actions
for kw, data in KEYWORD_ACTIONS.items():
if data["rule"] == rule:
keywords.append(kw)
# Check keyword abilities
for kw, data in KEYWORD_ABILITIES.items():
if data["rule"] == rule:
keywords.append(kw)
return keywords
def search_keywords(query: str) -> list[dict]:
"""
Search for keywords matching a query string.
Args:
query: Search query (case-insensitive).
Returns:
List of matching keyword dictionaries.
"""
query = query.lower()
results = []
for kw, data in KEYWORD_ABILITIES.items():
if query in kw.lower() or query in data["definition"].lower():
results.append({**data, "keyword": kw})
for kw, data in KEYWORD_ACTIONS.items():
if query in kw.lower() or query in data["definition"].lower():
results.append({**data, "keyword": kw})
for kw in ABILITY_WORDS:
if query in kw.lower():
results.append({
"keyword": kw,
"type": "ability_word",
"definition": "An italicized word with no rules meaning that ties together abilities on different cards that have similar functionality.",
"rule": "207.2c",
"has_definition": False,
})
return results
if __name__ == "__main__":
# Quick test
print("Total keywords:", len(get_all_keywords()))
print("\nSample keywords:")
for kw in ["flying", "haste", "deathtouch", "destroy", "exile"]:
result = get_keyword_definition(kw)
if result:
print(f" {kw}: {result['type']} (Rule {result['rule']})")
else:
print(f" {kw}: NOT FOUND")