enjine 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (269) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +28 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +201 -0
  5. data/SUPPORTED.md +387 -0
  6. data/docs/ARCHITECTURE.md +141 -0
  7. data/docs/DESIGN.md +139 -0
  8. data/docs/MECHANICS_COVERAGE.md +670 -0
  9. data/docs/guides/adding-a-mechanic.md +60 -0
  10. data/docs/guides/api.md +614 -0
  11. data/docs/guides/card-data-format.md +1472 -0
  12. data/docs/guides/deck-builder.md +157 -0
  13. data/docs/plans/standard.md +371 -0
  14. data/docs/reference/abilities.md +1680 -0
  15. data/docs/reference/costs.md +339 -0
  16. data/docs/reference/counters.md +121 -0
  17. data/docs/reference/decisions.md +102 -0
  18. data/docs/reference/effects.md +2340 -0
  19. data/docs/reference/filters.md +172 -0
  20. data/docs/reference/keywords.md +647 -0
  21. data/docs/reference/subtypes.md +169 -0
  22. data/docs/reference/supertypes.md +31 -0
  23. data/docs/reference/triggers.md +797 -0
  24. data/docs/reference/types.md +216 -0
  25. data/exe/enjine +7 -0
  26. data/lib/enjine/actions/activate_mana_ability.rb +24 -0
  27. data/lib/enjine/actions/cast.rb +57 -0
  28. data/lib/enjine/actions/pass.rb +18 -0
  29. data/lib/enjine/actions/play_land.rb +52 -0
  30. data/lib/enjine/actions/special_action.rb +37 -0
  31. data/lib/enjine/actions.rb +20 -0
  32. data/lib/enjine/agents/busy.rb +27 -0
  33. data/lib/enjine/agents/random.rb +28 -0
  34. data/lib/enjine/card_definition.rb +433 -0
  35. data/lib/enjine/card_faces.rb +116 -0
  36. data/lib/enjine/catalog.rb +56 -0
  37. data/lib/enjine/characteristics.rb +39 -0
  38. data/lib/enjine/cli/text.rb +295 -0
  39. data/lib/enjine/cli.rb +312 -0
  40. data/lib/enjine/decisions/bottom.rb +29 -0
  41. data/lib/enjine/decisions/casting.rb +188 -0
  42. data/lib/enjine/decisions/combat.rb +75 -0
  43. data/lib/enjine/decisions/discard.rb +29 -0
  44. data/lib/enjine/decisions/effect_choice.rb +21 -0
  45. data/lib/enjine/decisions/enter_choice.rb +26 -0
  46. data/lib/enjine/decisions/legend_rule.rb +21 -0
  47. data/lib/enjine/decisions/mulligan.rb +26 -0
  48. data/lib/enjine/decisions/order_triggers.rb +21 -0
  49. data/lib/enjine/decisions/play_or_draw.rb +19 -0
  50. data/lib/enjine/decisions/priority.rb +22 -0
  51. data/lib/enjine/decisions/untap_choice.rb +35 -0
  52. data/lib/enjine/decisions.rb +22 -0
  53. data/lib/enjine/deck.rb +151 -0
  54. data/lib/enjine/deck_builder.rb +454 -0
  55. data/lib/enjine/docs.rb +90 -0
  56. data/lib/enjine/engine/ability_layers.rb +118 -0
  57. data/lib/enjine/engine/attachments.rb +86 -0
  58. data/lib/enjine/engine/casting/alt_casting.rb +254 -0
  59. data/lib/enjine/engine/casting/cast_choices.rb +292 -0
  60. data/lib/enjine/engine/casting/casting.rb +326 -0
  61. data/lib/enjine/engine/casting/cost_options.rb +99 -0
  62. data/lib/enjine/engine/casting/costs.rb +117 -0
  63. data/lib/enjine/engine/casting/payment.rb +353 -0
  64. data/lib/enjine/engine/casting/permissions.rb +412 -0
  65. data/lib/enjine/engine/casting/target_counts.rb +113 -0
  66. data/lib/enjine/engine/casting/waterbend.rb +90 -0
  67. data/lib/enjine/engine/characteristics.rb +379 -0
  68. data/lib/enjine/engine/class_levels.rb +25 -0
  69. data/lib/enjine/engine/combat.rb +315 -0
  70. data/lib/enjine/engine/copies.rb +208 -0
  71. data/lib/enjine/engine/damage.rb +196 -0
  72. data/lib/enjine/engine/designations.rb +46 -0
  73. data/lib/enjine/engine/emblems.rb +37 -0
  74. data/lib/enjine/engine/entering.rb +156 -0
  75. data/lib/enjine/engine/face_down.rb +30 -0
  76. data/lib/enjine/engine/faces.rb +222 -0
  77. data/lib/enjine/engine/follow_ups.rb +27 -0
  78. data/lib/enjine/engine/mana_sources.rb +230 -0
  79. data/lib/enjine/engine/phasing.rb +74 -0
  80. data/lib/enjine/engine/pregame.rb +95 -0
  81. data/lib/enjine/engine/priority.rb +47 -0
  82. data/lib/enjine/engine/resolution.rb +168 -0
  83. data/lib/enjine/engine/rules.rb +287 -0
  84. data/lib/enjine/engine/sagas.rb +41 -0
  85. data/lib/enjine/engine/speed.rb +104 -0
  86. data/lib/enjine/engine/spell_grants.rb +46 -0
  87. data/lib/enjine/engine/state_based_actions.rb +157 -0
  88. data/lib/enjine/engine/triggers.rb +364 -0
  89. data/lib/enjine/engine/turn_history.rb +240 -0
  90. data/lib/enjine/engine/turn_structure.rb +224 -0
  91. data/lib/enjine/engine/zones.rb +278 -0
  92. data/lib/enjine/engine.rb +55 -0
  93. data/lib/enjine/errors.rb +62 -0
  94. data/lib/enjine/events.rb +161 -0
  95. data/lib/enjine/frames.rb +84 -0
  96. data/lib/enjine/fuzz.rb +112 -0
  97. data/lib/enjine/game.rb +204 -0
  98. data/lib/enjine/history.rb +26 -0
  99. data/lib/enjine/mana.rb +142 -0
  100. data/lib/enjine/mechanics/abilities/additional_triggers.rb +86 -0
  101. data/lib/enjine/mechanics/abilities/chosen_values.rb +213 -0
  102. data/lib/enjine/mechanics/abilities/cost_changes.rb +154 -0
  103. data/lib/enjine/mechanics/abilities/damage_replacements.rb +569 -0
  104. data/lib/enjine/mechanics/abilities/double_counters.rb +71 -0
  105. data/lib/enjine/mechanics/abilities/entering_choices.rb +91 -0
  106. data/lib/enjine/mechanics/abilities/entering_copy.rb +69 -0
  107. data/lib/enjine/mechanics/abilities/enters_tapped.rb +159 -0
  108. data/lib/enjine/mechanics/abilities/enters_with_counters.rb +116 -0
  109. data/lib/enjine/mechanics/abilities/mana_ability.rb +209 -0
  110. data/lib/enjine/mechanics/abilities/play_permissions.rb +527 -0
  111. data/lib/enjine/mechanics/abilities/player_rules.rb +169 -0
  112. data/lib/enjine/mechanics/abilities/replacement_effects.rb +368 -0
  113. data/lib/enjine/mechanics/abilities/restrictions.rb +144 -0
  114. data/lib/enjine/mechanics/abilities/spell_keywords.rb +55 -0
  115. data/lib/enjine/mechanics/abilities/stack_abilities.rb +542 -0
  116. data/lib/enjine/mechanics/abilities/static.rb +365 -0
  117. data/lib/enjine/mechanics/abilities/tapping_power.rb +71 -0
  118. data/lib/enjine/mechanics/abilities/turn_rules.rb +49 -0
  119. data/lib/enjine/mechanics/card_spec.rb +177 -0
  120. data/lib/enjine/mechanics/copy_except.rb +73 -0
  121. data/lib/enjine/mechanics/costs/base.rb +115 -0
  122. data/lib/enjine/mechanics/costs/behold.rb +76 -0
  123. data/lib/enjine/mechanics/costs/discard.rb +65 -0
  124. data/lib/enjine/mechanics/costs/exert.rb +29 -0
  125. data/lib/enjine/mechanics/costs/exile_cards.rb +39 -0
  126. data/lib/enjine/mechanics/costs/from_graveyard.rb +45 -0
  127. data/lib/enjine/mechanics/costs/get_counters.rb +39 -0
  128. data/lib/enjine/mechanics/costs/mana.rb +37 -0
  129. data/lib/enjine/mechanics/costs/one_of.rb +49 -0
  130. data/lib/enjine/mechanics/costs/pay_life.rb +50 -0
  131. data/lib/enjine/mechanics/costs/remove_counters.rb +51 -0
  132. data/lib/enjine/mechanics/costs/sacrifice.rb +59 -0
  133. data/lib/enjine/mechanics/costs/tap.rb +56 -0
  134. data/lib/enjine/mechanics/costs/waterbend.rb +29 -0
  135. data/lib/enjine/mechanics/counters/kinds.rb +190 -0
  136. data/lib/enjine/mechanics/effects/add_subtypes.rb +30 -0
  137. data/lib/enjine/mechanics/effects/airbend.rb +41 -0
  138. data/lib/enjine/mechanics/effects/amass.rb +124 -0
  139. data/lib/enjine/mechanics/effects/assimilate.rb +72 -0
  140. data/lib/enjine/mechanics/effects/base.rb +148 -0
  141. data/lib/enjine/mechanics/effects/become.rb +182 -0
  142. data/lib/enjine/mechanics/effects/behold.rb +48 -0
  143. data/lib/enjine/mechanics/effects/blight.rb +94 -0
  144. data/lib/enjine/mechanics/effects/choose_cards.rb +168 -0
  145. data/lib/enjine/mechanics/effects/copy.rb +370 -0
  146. data/lib/enjine/mechanics/effects/counter_spell.rb +21 -0
  147. data/lib/enjine/mechanics/effects/counters.rb +161 -0
  148. data/lib/enjine/mechanics/effects/damage.rb +72 -0
  149. data/lib/enjine/mechanics/effects/delayed_triggers.rb +112 -0
  150. data/lib/enjine/mechanics/effects/destroy.rb +22 -0
  151. data/lib/enjine/mechanics/effects/discard.rb +86 -0
  152. data/lib/enjine/mechanics/effects/draw.rb +16 -0
  153. data/lib/enjine/mechanics/effects/earthbend.rb +70 -0
  154. data/lib/enjine/mechanics/effects/emblem.rb +52 -0
  155. data/lib/enjine/mechanics/effects/endure.rb +63 -0
  156. data/lib/enjine/mechanics/effects/exile.rb +49 -0
  157. data/lib/enjine/mechanics/effects/extra_turn.rb +122 -0
  158. data/lib/enjine/mechanics/effects/faces.rb +115 -0
  159. data/lib/enjine/mechanics/effects/fight.rb +76 -0
  160. data/lib/enjine/mechanics/effects/flip_coins.rb +97 -0
  161. data/lib/enjine/mechanics/effects/gain_control.rb +94 -0
  162. data/lib/enjine/mechanics/effects/game_end.rb +42 -0
  163. data/lib/enjine/mechanics/effects/library.rb +327 -0
  164. data/lib/enjine/mechanics/effects/life.rb +83 -0
  165. data/lib/enjine/mechanics/effects/look_at_hand.rb +17 -0
  166. data/lib/enjine/mechanics/effects/loot.rb +118 -0
  167. data/lib/enjine/mechanics/effects/mana.rb +96 -0
  168. data/lib/enjine/mechanics/effects/may.rb +82 -0
  169. data/lib/enjine/mechanics/effects/meld.rb +77 -0
  170. data/lib/enjine/mechanics/effects/mill.rb +22 -0
  171. data/lib/enjine/mechanics/effects/pay.rb +231 -0
  172. data/lib/enjine/mechanics/effects/phasing.rb +51 -0
  173. data/lib/enjine/mechanics/effects/proliferate.rb +72 -0
  174. data/lib/enjine/mechanics/effects/pump.rb +60 -0
  175. data/lib/enjine/mechanics/effects/put_in_library.rb +98 -0
  176. data/lib/enjine/mechanics/effects/return_choice.rb +29 -0
  177. data/lib/enjine/mechanics/effects/return_to_battlefield.rb +80 -0
  178. data/lib/enjine/mechanics/effects/return_to_hand.rb +20 -0
  179. data/lib/enjine/mechanics/effects/roll_dice.rb +45 -0
  180. data/lib/enjine/mechanics/effects/sacrifice.rb +118 -0
  181. data/lib/enjine/mechanics/effects/scry_and_surveil.rb +74 -0
  182. data/lib/enjine/mechanics/effects/search.rb +156 -0
  183. data/lib/enjine/mechanics/effects/tap_untap.rb +23 -0
  184. data/lib/enjine/mechanics/effects/tokens.rb +76 -0
  185. data/lib/enjine/mechanics/filters/any_target.rb +15 -0
  186. data/lib/enjine/mechanics/filters/base.rb +386 -0
  187. data/lib/enjine/mechanics/filters/graveyard.rb +23 -0
  188. data/lib/enjine/mechanics/filters/one_of.rb +55 -0
  189. data/lib/enjine/mechanics/filters/permanents.rb +52 -0
  190. data/lib/enjine/mechanics/filters/players.rb +20 -0
  191. data/lib/enjine/mechanics/filters/stack.rb +97 -0
  192. data/lib/enjine/mechanics/follow_up.rb +46 -0
  193. data/lib/enjine/mechanics/keywords/alternative_costs.rb +361 -0
  194. data/lib/enjine/mechanics/keywords/beam_me_up.rb +78 -0
  195. data/lib/enjine/mechanics/keywords/changeling.rb +58 -0
  196. data/lib/enjine/mechanics/keywords/convoke.rb +77 -0
  197. data/lib/enjine/mechanics/keywords/crew.rb +155 -0
  198. data/lib/enjine/mechanics/keywords/cycling.rb +58 -0
  199. data/lib/enjine/mechanics/keywords/decayed.rb +25 -0
  200. data/lib/enjine/mechanics/keywords/devour.rb +61 -0
  201. data/lib/enjine/mechanics/keywords/evergreen.rb +54 -0
  202. data/lib/enjine/mechanics/keywords/extort.rb +26 -0
  203. data/lib/enjine/mechanics/keywords/flags.rb +46 -0
  204. data/lib/enjine/mechanics/keywords/foretell.rb +45 -0
  205. data/lib/enjine/mechanics/keywords/gift.rb +50 -0
  206. data/lib/enjine/mechanics/keywords/hideaway.rb +28 -0
  207. data/lib/enjine/mechanics/keywords/increment.rb +31 -0
  208. data/lib/enjine/mechanics/keywords/job_select.rb +29 -0
  209. data/lib/enjine/mechanics/keywords/kicker.rb +92 -0
  210. data/lib/enjine/mechanics/keywords/mobilize_and_firebending.rb +84 -0
  211. data/lib/enjine/mechanics/keywords/paradigm.rb +91 -0
  212. data/lib/enjine/mechanics/keywords/power_up.rb +48 -0
  213. data/lib/enjine/mechanics/keywords/protection.rb +111 -0
  214. data/lib/enjine/mechanics/keywords/prowess.rb +30 -0
  215. data/lib/enjine/mechanics/keywords/riot.rb +35 -0
  216. data/lib/enjine/mechanics/keywords/saddle.rb +115 -0
  217. data/lib/enjine/mechanics/keywords/speed.rb +89 -0
  218. data/lib/enjine/mechanics/keywords/station.rb +163 -0
  219. data/lib/enjine/mechanics/keywords/storied.rb +41 -0
  220. data/lib/enjine/mechanics/keywords/storm_and_cascade.rb +86 -0
  221. data/lib/enjine/mechanics/keywords/sunburst.rb +29 -0
  222. data/lib/enjine/mechanics/keywords/suspend.rb +191 -0
  223. data/lib/enjine/mechanics/keywords/teamwork.rb +45 -0
  224. data/lib/enjine/mechanics/keywords/ward.rb +67 -0
  225. data/lib/enjine/mechanics/linked.rb +67 -0
  226. data/lib/enjine/mechanics/mana_spent.rb +99 -0
  227. data/lib/enjine/mechanics/selector.rb +207 -0
  228. data/lib/enjine/mechanics/subtypes/auras_and_equipment.rb +176 -0
  229. data/lib/enjine/mechanics/subtypes/basic_land_types.rb +36 -0
  230. data/lib/enjine/mechanics/subtypes/class_levels.rb +102 -0
  231. data/lib/enjine/mechanics/subtypes/saga.rb +89 -0
  232. data/lib/enjine/mechanics/supertypes/basic.rb +17 -0
  233. data/lib/enjine/mechanics/supertypes/legendary.rb +18 -0
  234. data/lib/enjine/mechanics/triggers/ability_triggers.rb +51 -0
  235. data/lib/enjine/mechanics/triggers/any_of.rb +43 -0
  236. data/lib/enjine/mechanics/triggers/base.rb +228 -0
  237. data/lib/enjine/mechanics/triggers/casting.rb +219 -0
  238. data/lib/enjine/mechanics/triggers/combat.rb +123 -0
  239. data/lib/enjine/mechanics/triggers/damage.rb +130 -0
  240. data/lib/enjine/mechanics/triggers/dilemma.rb +37 -0
  241. data/lib/enjine/mechanics/triggers/draw_and_discard.rb +85 -0
  242. data/lib/enjine/mechanics/triggers/keyword_actions.rb +55 -0
  243. data/lib/enjine/mechanics/triggers/life.rb +35 -0
  244. data/lib/enjine/mechanics/triggers/steps.rb +39 -0
  245. data/lib/enjine/mechanics/triggers/tap_and_counters.rb +111 -0
  246. data/lib/enjine/mechanics/triggers/zone_changes.rb +249 -0
  247. data/lib/enjine/mechanics/types/kindred.rb +30 -0
  248. data/lib/enjine/mechanics/types/land.rb +24 -0
  249. data/lib/enjine/mechanics/types/permanent_types.rb +67 -0
  250. data/lib/enjine/mechanics/types/spell_types.rb +38 -0
  251. data/lib/enjine/mechanics/values.rb +675 -0
  252. data/lib/enjine/mechanics.rb +74 -0
  253. data/lib/enjine/player.rb +30 -0
  254. data/lib/enjine/primitive.rb +61 -0
  255. data/lib/enjine/replacements.rb +191 -0
  256. data/lib/enjine/rng.rb +57 -0
  257. data/lib/enjine/rules_monitor.rb +404 -0
  258. data/lib/enjine/setup.rb +45 -0
  259. data/lib/enjine/snapshot/player_checks.rb +86 -0
  260. data/lib/enjine/snapshot/turn_checks.rb +91 -0
  261. data/lib/enjine/snapshot.rb +307 -0
  262. data/lib/enjine/state.rb +173 -0
  263. data/lib/enjine/steps.rb +117 -0
  264. data/lib/enjine/tokens.rb +25 -0
  265. data/lib/enjine/verify.rb +233 -0
  266. data/lib/enjine/version.rb +7 -0
  267. data/lib/enjine/view.rb +162 -0
  268. data/lib/enjine.rb +46 -0
  269. metadata +315 -0
@@ -0,0 +1,797 @@
1
+ # Trigger conditions
2
+
3
+ <!-- Generated by `rake docs` from the primitive registry. Do not edit. -->
4
+
5
+ ## ability_triggers
6
+
7
+ A triggered ability of the subject triggers. `cause: "attacks"` (required): its trigger event was the subject attacking. {"triggering": "ability"} is that triggered ability while it's on the stack.
8
+
9
+ Rules: CR 603.2, CR 603.3b, CR 508.1, CR 707.10
10
+
11
+ | Parameter | Description |
12
+ | --- | --- |
13
+ | `subject` | "self" (default) or {"each": filter, "controller": ..., "other": true} |
14
+ | `cause` | attacks |
15
+
16
+ ```json
17
+ {
18
+ "ability_triggers": {
19
+ "subject": {
20
+ "each": "creature",
21
+ "controller": "you"
22
+ },
23
+ "cause": "attacks"
24
+ }
25
+ }
26
+ ```
27
+
28
+ ## activates_ability
29
+
30
+ A player (`controller`: you (default) | opponent | any) activates an ability that isn't a mana ability. `source`: optional filter on the source's card; `name: "chosen"`: only a source with the name chosen as this permanent entered. `exhaust: true`: only an exhaust ability ("whenever you activate an exhaust ability", CR 702.177). `boast: true`: only a boast ability ("whenever a creature you control boasts", CR 702.142b).
31
+
32
+ Rules: CR 602.2, CR 605.1a, CR 603.2, CR 201.4, CR 702.177a, CR 702.142b
33
+
34
+ | Parameter | Description |
35
+ | --- | --- |
36
+ | `controller` | you | opponent | any |
37
+ | `source` | card filter |
38
+ | `name` | "chosen" |
39
+ | `exhaust` | true: only exhaust abilities |
40
+ | `boast` | true: only boast abilities |
41
+
42
+ ```json
43
+ {
44
+ "activates_ability": {
45
+ "controller": "opponent"
46
+ }
47
+ }
48
+ ```
49
+
50
+ ## airbends
51
+
52
+ A player (`controller`: you (default) | opponent | any) airbends.
53
+
54
+ Rules: CR 701.65b
55
+
56
+ | Parameter | Description |
57
+ | --- | --- |
58
+ | `controller` | you | opponent | any |
59
+
60
+ ```json
61
+ {
62
+ "airbends": {}
63
+ }
64
+ ```
65
+
66
+ ## any_of
67
+
68
+ Triggers when any of the listed trigger conditions is met.
69
+
70
+ Rules: CR 603.2, CR 603.2c
71
+
72
+ | Parameter | Description |
73
+ | --- | --- |
74
+ | `(list)` | two or more trigger conditions |
75
+
76
+ ```json
77
+ {
78
+ "any_of": [
79
+ {
80
+ "enters": {}
81
+ },
82
+ {
83
+ "attacks": {}
84
+ }
85
+ ]
86
+ }
87
+ ```
88
+
89
+ ## attacks
90
+
91
+ The subject is declared as an attacker. `first_time_this_turn: true`: only the first time that creature attacks this turn (later combats of the turn don't trigger it).
92
+
93
+ Rules: CR 508.3a, CR 603.2
94
+
95
+ | Parameter | Description |
96
+ | --- | --- |
97
+ | `subject` | "self" (default) or {"each": filter, ...} |
98
+ | `first_time_this_turn` | boolean |
99
+
100
+ ```json
101
+ {
102
+ "attacks": {
103
+ "subject": "self",
104
+ "first_time_this_turn": true
105
+ }
106
+ }
107
+ ```
108
+
109
+ ## becomes_blocked
110
+
111
+ The subject becomes blocked: once per combat when blockers are declared, even if several creatures block it.
112
+
113
+ Rules: CR 509.3c, CR 509.1h, CR 603.2e
114
+
115
+ | Parameter | Description |
116
+ | --- | --- |
117
+ | `subject` | "self" (default) or {"each": filter, ...} |
118
+
119
+ ```json
120
+ {
121
+ "becomes_blocked": {
122
+ "subject": "self"
123
+ }
124
+ }
125
+ ```
126
+
127
+ ## becomes_crewed
128
+
129
+ A crew ability of the subject resolves (it becomes crewed).
130
+
131
+ Rules: CR 702.122e, CR 603.2
132
+
133
+ | Parameter | Description |
134
+ | --- | --- |
135
+ | `subject` | "self" (default) or {"each": filter, ...} |
136
+
137
+ ```json
138
+ {
139
+ "becomes_crewed": {}
140
+ }
141
+ ```
142
+
143
+ ## becomes_level
144
+
145
+ This permanent's level becomes `level` (a class level bar's ability resolves).
146
+
147
+ Rules: CR 717.2a, CR 603.2
148
+
149
+ | Parameter | Description |
150
+ | --- | --- |
151
+ | `level` | integer >= 2 |
152
+
153
+ ```json
154
+ {
155
+ "becomes_level": {
156
+ "level": 3
157
+ }
158
+ }
159
+ ```
160
+
161
+ ## becomes_saddled
162
+
163
+ The subject becomes saddled (its saddle ability resolved, or an effect saddled it).
164
+
165
+ Rules: CR 702.171b, CR 603.2
166
+
167
+ | Parameter | Description |
168
+ | --- | --- |
169
+ | `subject` | "self" (default) or {"each": filter, ...} |
170
+
171
+ ```json
172
+ {
173
+ "becomes_saddled": {}
174
+ }
175
+ ```
176
+
177
+ ## becomes_tapped
178
+
179
+ The subject becomes tapped (for any reason: a cost, attacking, an effect). A permanent that enters tapped doesn't become tapped. `for: "teamwork"`: only when it's tapped to pay a teamwork cost (it triggers once the spell is cast).
180
+
181
+ Rules: CR 603.2e, CR 701.26a, CR 702.194a
182
+
183
+ | Parameter | Description |
184
+ | --- | --- |
185
+ | `subject` | "self" (default) or {"each": filter, ...} |
186
+ | `for` | teamwork |
187
+
188
+ ```json
189
+ {
190
+ "becomes_tapped": {
191
+ "subject": "self"
192
+ }
193
+ }
194
+ ```
195
+
196
+ ## becomes_target
197
+
198
+ The subject becomes the target of a spell or ability (controlled by `by`: opponent | you | any (default), relative to the source's controller). One trigger per matching object targeted.
199
+
200
+ Rules: CR 115.1, CR 601.2c, CR 603.2, CR 603.2c
201
+
202
+ | Parameter | Description |
203
+ | --- | --- |
204
+ | `subject` | "self" (default) or {"each": filter, ...} |
205
+ | `by` | opponent | you | any |
206
+
207
+ ```json
208
+ {
209
+ "becomes_target": {
210
+ "subject": {
211
+ "each": "creature",
212
+ "controller": "you"
213
+ },
214
+ "by": "opponent"
215
+ }
216
+ }
217
+ ```
218
+
219
+ ## becomes_untapped
220
+
221
+ The subject becomes untapped (in the untap step or by an effect). A permanent that enters untapped doesn't become untapped.
222
+
223
+ Rules: CR 603.2e, CR 701.26b
224
+
225
+ | Parameter | Description |
226
+ | --- | --- |
227
+ | `subject` | "self" (default), "attached" or {"each": filter, ...} |
228
+
229
+ ```json
230
+ {
231
+ "becomes_untapped": {
232
+ "subject": "attached"
233
+ }
234
+ }
235
+ ```
236
+
237
+ ## blocks
238
+
239
+ The subject is declared as a blocker. With `blocking`, only when the attacking creature it blocks matches that filter ("blocks a creature with flying"). {"triggering": "object"} is the blocking creature.
240
+
241
+ Rules: CR 509.3a, CR 509.3b, CR 509.3f, CR 603.2
242
+
243
+ | Parameter | Description |
244
+ | --- | --- |
245
+ | `subject` | "self" (default) or {"each": filter, ...} |
246
+ | `blocking` | filter |
247
+
248
+ ```json
249
+ {
250
+ "blocks": {
251
+ "blocking": {
252
+ "creature": {
253
+ "keywords": [
254
+ "flying"
255
+ ]
256
+ }
257
+ }
258
+ }
259
+ }
260
+ ```
261
+
262
+ ## cast
263
+
264
+ A player casts a spell. `controller`: you (default) | opponent | any; `spell`: creature | noncreature | instant_or_sorcery, or any spell filter, e.g. {"spell": {"subtypes": ["saga"]}} or {"one_of": [...]} for "creature or Spacecraft spell"; `name` / `mana_value`: "chosen" (the source's as-it-entered choice); `self: true`: "when you cast this spell" (it functions on the stack). `targets`: only a spell that targets something matching this filter ("self": this permanent), e.g. {"creature": {"controller": "you"}}. `from` / `not_from`: only a spell cast from (not from) that zone: hand | graveyard | exile | library | outside. `single_target: true`: only a spell with exactly one target.
265
+
266
+ Rules: CR 603.2, CR 601.2i, CR 113.6, CR 202.3e, CR 201.4, CR 607.2, CR 115.1, CR 601.2a, CR 601.2c
267
+
268
+ | Parameter | Description |
269
+ | --- | --- |
270
+ | `controller` | you | opponent | any |
271
+ | `spell` | creature | noncreature | instant_or_sorcery | filter |
272
+ | `name` | "chosen" |
273
+ | `mana_value` | "chosen" |
274
+ | `self` | true |
275
+ | `targets` | "self" or a target filter |
276
+ | `from` | zone |
277
+ | `not_from` | zone |
278
+ | `single_target` | true |
279
+
280
+ ```json
281
+ {
282
+ "cast": {
283
+ "controller": "you",
284
+ "spell": "noncreature"
285
+ }
286
+ }
287
+ ```
288
+
289
+ ## counters_placed
290
+
291
+ One or more counters (only `counter`, if given) are put on the subject, including the counters it enters the battlefield with. Triggers once per event, however many counters.
292
+
293
+ Rules: CR 122.6, CR 603.2, CR 603.2c
294
+
295
+ | Parameter | Description |
296
+ | --- | --- |
297
+ | `subject` | "self" (default) or {"each": filter, ...} |
298
+ | `counter` | counter name |
299
+ | `first_time_this_turn` | true: only the first time each turn such counters are put on that permanent (an earlier placement counts even if nothing could trigger then) |
300
+
301
+ ```json
302
+ {
303
+ "counters_placed": {
304
+ "counter": "+1/+1"
305
+ }
306
+ }
307
+ ```
308
+
309
+ ## crews_vehicle
310
+
311
+ The subject (a creature) crews a Vehicle: it's tapped to pay that Vehicle's crew cost. {"triggering": "object"} is the Vehicle.
312
+
313
+ Rules: CR 702.122b, CR 603.2
314
+
315
+ | Parameter | Description |
316
+ | --- | --- |
317
+ | `subject` | "self" (default) or {"each": filter, ...} |
318
+
319
+ ```json
320
+ {
321
+ "crews_vehicle": {
322
+ "subject": "self"
323
+ }
324
+ }
325
+ ```
326
+
327
+ ## cycles
328
+
329
+ A player (`controller`: you (default) | opponent | any) cycles a card (activates its cycling or typecycling ability; optional `card` filter).
330
+
331
+ Rules: CR 702.29a, CR 702.29e
332
+
333
+ | Parameter | Description |
334
+ | --- | --- |
335
+ | `controller` | you | opponent | any |
336
+ | `card` | card filter |
337
+
338
+ ```json
339
+ {
340
+ "cycles": {
341
+ "controller": "you"
342
+ }
343
+ }
344
+ ```
345
+
346
+ ## deals_damage
347
+
348
+ The subject deals damage. `combat: true` only counts combat damage, `noncombat: true` only noncombat damage; `to`: player | opponent (of the source's controller) | creature | any (default). Triggers once per damage event (each combat damage step is one, so double strike can trigger twice).
349
+
350
+ Rules: CR 510.2, CR 603.2, CR 603.2c, CR 120.2a, CR 120.2b, CR 120.3
351
+
352
+ | Parameter | Description |
353
+ | --- | --- |
354
+ | `subject` | "self" (default) or {"each": filter, ...} |
355
+ | `combat` | true | false |
356
+ | `noncombat` | true | false |
357
+ | `to` | player | opponent | creature | any |
358
+
359
+ ```json
360
+ {
361
+ "deals_damage": {
362
+ "combat": true,
363
+ "to": "player"
364
+ }
365
+ }
366
+ ```
367
+
368
+ ## dealt_damage
369
+
370
+ Damage is dealt to the `subject` (a permanent: "self" by default, "attached" or {"each": filter, ...}) or, with `player` (you | opponent | any), to a player. `combat` / `noncombat`: only that damage. {"triggering": "object"} is the permanent dealt damage, {"triggering": "player"} the player, {"triggering": "amount"} how much. `batched: true`: "one or more ..." (once per damage event, CR 603.2c).
371
+
372
+ Rules: CR 120.3, CR 603.2, CR 603.2c, CR 120.2a, CR 120.2b
373
+
374
+ | Parameter | Description |
375
+ | --- | --- |
376
+ | `subject` | "self" (default), "attached" or {"each": filter, ...} |
377
+ | `player` | you | opponent | any |
378
+ | `combat` | true | false |
379
+ | `noncombat` | true | false |
380
+ | `batched` | true | false |
381
+
382
+ ```json
383
+ {
384
+ "dealt_damage": {
385
+ "subject": "self"
386
+ }
387
+ }
388
+ ```
389
+
390
+ ## dies
391
+
392
+ The subject is put into a graveyard from the battlefield. Looks back in time (CR 603.10a).
393
+
394
+ Rules: CR 603.6c, CR 603.10a, CR 700.4
395
+
396
+ | Parameter | Description |
397
+ | --- | --- |
398
+ | `subject` | "self" (default) or {"each": filter, ...} |
399
+
400
+ ```json
401
+ {
402
+ "dies": {
403
+ "subject": "self"
404
+ }
405
+ }
406
+ ```
407
+
408
+ ## discards
409
+
410
+ A player (`controller`: you (default) | opponent | any) discards a card (optional `card` filter). `batched: true`: "one or more cards", once per event batch; then "that many" is how many were discarded.
411
+
412
+ Rules: CR 701.9a, CR 603.2c, CR 702.29d
413
+
414
+ | Parameter | Description |
415
+ | --- | --- |
416
+ | `controller` | you | opponent | any |
417
+ | `card` | card filter |
418
+ | `batched` | true | false |
419
+
420
+ ```json
421
+ {
422
+ "discards": {
423
+ "controller": "you",
424
+ "batched": true
425
+ }
426
+ }
427
+ ```
428
+
429
+ ## draws
430
+
431
+ A player draws a card; triggers once per card (draws happen one at a time). `controller`: you (default) | opponent | any.
432
+
433
+ Rules: CR 121.1, CR 121.2
434
+
435
+ | Parameter | Description |
436
+ | --- | --- |
437
+ | `controller` | you | opponent | any |
438
+
439
+ ```json
440
+ {
441
+ "draws": {
442
+ "controller": "you"
443
+ }
444
+ }
445
+ ```
446
+
447
+ ## earthbends
448
+
449
+ A player (`controller`: you (default) | opponent | any) earthbends.
450
+
451
+ Rules: CR 701.66b
452
+
453
+ | Parameter | Description |
454
+ | --- | --- |
455
+ | `controller` | you | opponent | any |
456
+
457
+ ```json
458
+ {
459
+ "earthbends": {}
460
+ }
461
+ ```
462
+
463
+ ## enters
464
+
465
+ The subject enters the battlefield. `untapped: true`: only if it entered untapped. `from`: only if it entered from that zone ("enters from exile").
466
+
467
+ Rules: CR 603.6a, CR 603.2, CR 614.12
468
+
469
+ | Parameter | Description |
470
+ | --- | --- |
471
+ | `subject` | "self" (default) or {"each": filter, "controller": you|opponent|any, "other": true} |
472
+ | `untapped` | true | false |
473
+ | `from` | hand | graveyard | exile | library | stack | outside |
474
+
475
+ ```json
476
+ {
477
+ "enters": {
478
+ "subject": {
479
+ "each": "land",
480
+ "controller": "you"
481
+ }
482
+ }
483
+ }
484
+ ```
485
+
486
+ ## faces_dilemma
487
+
488
+ A player faces a dilemma: they chose one or more modes for a spell or ability (cast, activated, or a triggered ability put on the stack). `controller`: you (default) | opponent | any. CR 700.17.
489
+
490
+ Rules: CR 700.17, CR 700.2, CR 601.2b, CR 603.3c
491
+
492
+ | Parameter | Description |
493
+ | --- | --- |
494
+ | `controller` | you | opponent | any |
495
+
496
+ ```json
497
+ {
498
+ "faces_dilemma": {}
499
+ }
500
+ ```
501
+
502
+ ## firebends
503
+
504
+ A player (`controller`: you (default) | opponent | any) firebends.
505
+
506
+ Rules: CR 702.189b
507
+
508
+ | Parameter | Description |
509
+ | --- | --- |
510
+ | `controller` | you | opponent | any |
511
+
512
+ ```json
513
+ {
514
+ "firebends": {}
515
+ }
516
+ ```
517
+
518
+ ## gains_life
519
+
520
+ A player gains life (once per life gain event; lifelink combat damage is one event per source). `controller`: you (default) | opponent | any.
521
+
522
+ Rules: CR 119.9, CR 120.3f
523
+
524
+ | Parameter | Description |
525
+ | --- | --- |
526
+ | `controller` | you | opponent | any |
527
+
528
+ ```json
529
+ {
530
+ "gains_life": {
531
+ "controller": "you"
532
+ }
533
+ }
534
+ ```
535
+
536
+ ## leaves_battlefield
537
+
538
+ The subject leaves the battlefield (for any zone, or only `to` that zone). Looks back in time: the permanent is matched as it last existed (types, controller, counters).
539
+
540
+ Rules: CR 603.6c, CR 603.10a, CR 400.7
541
+
542
+ | Parameter | Description |
543
+ | --- | --- |
544
+ | `subject` | "self" (default) or {"each": filter, "controller": ..., "other": true} |
545
+ | `to` | graveyard | exile | hand | library |
546
+
547
+ ```json
548
+ {
549
+ "leaves_battlefield": {
550
+ "subject": {
551
+ "each": "creature",
552
+ "controller": "you",
553
+ "other": true
554
+ }
555
+ }
556
+ }
557
+ ```
558
+
559
+ ## leaves_graveyard
560
+
561
+ A card leaves a graveyard (whose: `controller` you (default) | opponent | any). Optional `card` filter on its card types. `batched: true` is "one or more cards leave": once per event that moves cards (one effect, cost or action), however many cards.
562
+
563
+ Rules: CR 603.10a, CR 603.2c, CR 404.1
564
+
565
+ | Parameter | Description |
566
+ | --- | --- |
567
+ | `controller` | you | opponent | any |
568
+ | `card` | card type filter, e.g. "creature" |
569
+ | `batched` | true | false |
570
+
571
+ ```json
572
+ {
573
+ "leaves_graveyard": {
574
+ "controller": "you",
575
+ "batched": true
576
+ }
577
+ }
578
+ ```
579
+
580
+ ## loses_life
581
+
582
+ A player loses life (damage to a player is life loss, CR 120.3a). `controller`: you (default) | opponent | any.
583
+
584
+ Rules: CR 119.3, CR 120.3a
585
+
586
+ | Parameter | Description |
587
+ | --- | --- |
588
+ | `controller` | you | opponent | any |
589
+
590
+ ```json
591
+ {
592
+ "loses_life": {
593
+ "controller": "opponent"
594
+ }
595
+ }
596
+ ```
597
+
598
+ ## player_attacks
599
+
600
+ A player declares one or more attackers (once per combat, not per creature). `controller`: you (default) | opponent | any. `attacking_power` ({"at_least": n}): only when the attacking creatures' total power is at least n as they're declared; with `first_time_this_turn: true`, only the first combat this turn in which it was.
601
+
602
+ Rules: CR 508.3d, CR 508.1, CR 603.2
603
+
604
+ | Parameter | Description |
605
+ | --- | --- |
606
+ | `controller` | you | opponent | any |
607
+ | `attacking_power` | {"at_least": n} |
608
+ | `first_time_this_turn` | boolean |
609
+
610
+ ```json
611
+ {
612
+ "player_attacks": {
613
+ "controller": "you",
614
+ "attacking_power": {
615
+ "at_least": 12
616
+ },
617
+ "first_time_this_turn": true
618
+ }
619
+ }
620
+ ```
621
+
622
+ ## plays_land
623
+
624
+ A player (`controller`: you (default) | opponent | any) plays a land. `from` / `not_from`: only a land played from (not from) that zone: hand | graveyard | exile | library | outside. Lands put onto the battlefield by effects aren't played.
625
+
626
+ Rules: CR 305.1, CR 603.2, CR 601.2a
627
+
628
+ | Parameter | Description |
629
+ | --- | --- |
630
+ | `controller` | you | opponent | any |
631
+ | `from` | zone |
632
+ | `not_from` | zone |
633
+
634
+ ```json
635
+ {
636
+ "plays_land": {
637
+ "not_from": "hand"
638
+ }
639
+ }
640
+ ```
641
+
642
+ ## put_into
643
+
644
+ A card is put into `zone` (graveyard | exile) from anywhere, or only `from` the listed zones. `controller`: the card's owner (you (default) | opponent | any); optional `card` filter on the card. `batched: true`: "one or more cards", once per event batch. With "battlefield" among `from` it looks back in time like leaves_battlefield.
645
+
646
+ Rules: CR 603.6c, CR 603.2c, CR 400.3
647
+
648
+ | Parameter | Description |
649
+ | --- | --- |
650
+ | `zone` | graveyard | exile |
651
+ | `from` | list of battlefield, graveyard, hand, library, stack, exile (default: anywhere) |
652
+ | `controller` | you | opponent | any |
653
+ | `card` | card filter |
654
+ | `batched` | true | false |
655
+
656
+ ```json
657
+ {
658
+ "put_into": {
659
+ "zone": "graveyard",
660
+ "card": "creature",
661
+ "batched": true
662
+ }
663
+ }
664
+ ```
665
+
666
+ ## sacrifices
667
+
668
+ The subject is sacrificed (`controller` of the subject: who sacrificed it). Looks back in time, like leaves_battlefield. `batched: true`: "one or more", once per event batch.
669
+
670
+ Rules: CR 701.21a, CR 603.10a, CR 603.2c
671
+
672
+ | Parameter | Description |
673
+ | --- | --- |
674
+ | `subject` | "self" (default) or {"each": filter, "controller": you, "other": true} |
675
+ | `batched` | true | false |
676
+
677
+ ```json
678
+ {
679
+ "sacrifices": {
680
+ "subject": {
681
+ "each": "artifact",
682
+ "controller": "you"
683
+ }
684
+ }
685
+ }
686
+ ```
687
+
688
+ ## saddles_mount
689
+
690
+ The subject (a creature) saddles a Mount: it's tapped to pay that Mount's saddle cost. {"triggering": "object"} is the Mount.
691
+
692
+ Rules: CR 702.171c, CR 603.2
693
+
694
+ | Parameter | Description |
695
+ | --- | --- |
696
+ | `subject` | "self" (default) or {"each": filter, ...} |
697
+
698
+ ```json
699
+ {
700
+ "saddles_mount": {
701
+ "subject": "self"
702
+ }
703
+ }
704
+ ```
705
+
706
+ ## scries
707
+
708
+ A player (`controller`: you (default) | opponent | any) scries (not scry 0). Triggers after the scry is complete.
709
+
710
+ Rules: CR 701.22a, CR 701.22b
711
+
712
+ | Parameter | Description |
713
+ | --- | --- |
714
+ | `controller` | you | opponent | any |
715
+
716
+ ```json
717
+ {
718
+ "any_of": [
719
+ {
720
+ "scries": {}
721
+ },
722
+ {
723
+ "surveils": {}
724
+ }
725
+ ]
726
+ }
727
+ ```
728
+
729
+ ## step_begins
730
+
731
+ A step begins. `whose`: "your" (default), "each" or "opponent".
732
+
733
+ Rules: CR 603.6b, CR 503.1a, CR 513.1a
734
+
735
+ | Parameter | Description |
736
+ | --- | --- |
737
+ | `step` | upkeep | draw | precombat_main | end | ... |
738
+ | `whose` | your | each | opponent |
739
+
740
+ ```json
741
+ {
742
+ "step_begins": {
743
+ "step": "upkeep",
744
+ "whose": "your"
745
+ }
746
+ }
747
+ ```
748
+
749
+ ## surveils
750
+
751
+ A player (`controller`: you (default) | opponent | any) surveils (not surveil 0). Triggers after the surveil is complete.
752
+
753
+ Rules: CR 701.25a, CR 701.25c, CR 701.25d
754
+
755
+ | Parameter | Description |
756
+ | --- | --- |
757
+ | `controller` | you | opponent | any |
758
+
759
+ ```json
760
+ {
761
+ "surveils": {
762
+ "controller": "you"
763
+ }
764
+ }
765
+ ```
766
+
767
+ ## transforms
768
+
769
+ The subject transforms. For the default subject (this permanent), the ability is on the face that's up afterward, so it means "whenever this transforms into [this face]".
770
+
771
+ Rules: CR 701.27f, CR 603.2
772
+
773
+ | Parameter | Description |
774
+ | --- | --- |
775
+ | `subject` | "self" (default) or {"each": filter, ...} |
776
+
777
+ ```json
778
+ {
779
+ "transforms": {}
780
+ }
781
+ ```
782
+
783
+ ## waterbends
784
+
785
+ A player (`controller`: you (default) | opponent | any) waterbends.
786
+
787
+ Rules: CR 701.67c
788
+
789
+ | Parameter | Description |
790
+ | --- | --- |
791
+ | `controller` | you | opponent | any |
792
+
793
+ ```json
794
+ {
795
+ "waterbends": {}
796
+ }
797
+ ```