enjine 0.1.0 → 0.2.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +30 -1
- data/SUPPORTED.md +12 -9
- data/docs/MECHANICS_COVERAGE.md +1 -1
- data/docs/guides/card-data-format.md +23 -4
- data/docs/plans/dsl-gaps.md +606 -0
- data/docs/plans/standard.md +3 -0
- data/docs/reference/abilities.md +33 -7
- data/docs/reference/costs.md +11 -1
- data/docs/reference/decisions.md +1 -1
- data/docs/reference/effects.md +30 -9
- data/docs/reference/triggers.md +3 -2
- data/lib/enjine/actions/special_action.rb +4 -2
- data/lib/enjine/engine/casting/alt_casting.rb +18 -2
- data/lib/enjine/engine/casting/casting.rb +3 -3
- data/lib/enjine/engine/casting/costs.rb +5 -1
- data/lib/enjine/engine/casting/permissions.rb +1 -1
- data/lib/enjine/engine/characteristics.rb +0 -13
- data/lib/enjine/engine/defined_power_toughness.rb +30 -0
- data/lib/enjine/engine/mana_sources.rb +8 -1
- data/lib/enjine/engine/resolution.rb +1 -0
- data/lib/enjine/engine/triggers.rb +1 -0
- data/lib/enjine/engine/turn_history.rb +25 -1
- data/lib/enjine/engine/zones.rb +16 -6
- data/lib/enjine/mechanics/abilities/additional_triggers.rb +23 -11
- data/lib/enjine/mechanics/abilities/cost_changes.rb +20 -7
- data/lib/enjine/mechanics/abilities/mana_ability.rb +21 -6
- data/lib/enjine/mechanics/abilities/stack_abilities.rb +13 -9
- data/lib/enjine/mechanics/abilities/static.rb +13 -7
- data/lib/enjine/mechanics/costs/sacrifice.rb +28 -2
- data/lib/enjine/mechanics/effects/become.rb +8 -4
- data/lib/enjine/mechanics/effects/choose_cards.rb +9 -7
- data/lib/enjine/mechanics/effects/delayed_triggers.rb +2 -1
- data/lib/enjine/mechanics/effects/search.rb +15 -8
- data/lib/enjine/mechanics/keywords/plot.rb +79 -0
- data/lib/enjine/mechanics/triggers/casting.rb +8 -6
- data/lib/enjine/mechanics/values.rb +82 -14
- data/lib/enjine/version.rb +1 -1
- metadata +4 -1
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Enjine
|
|
4
|
+
module Mechanics
|
|
5
|
+
module Abilities
|
|
6
|
+
# "Plot [cost]" (CR 702.170a-b, 116.2k): any time you have priority during your turn, if the stack is empty
|
|
7
|
+
# and it's your main phase, you may pay `cost` and exile this card from your hand (a special action,
|
|
8
|
+
# `{type: "special_action"}`). It becomes a plotted card (Effects::Plot.plot!): its owner may cast it
|
|
9
|
+
# without paying its mana cost during their main phase while the stack is empty, on a later turn
|
|
10
|
+
# (cast option `via: "plotted"`, Engine::AltCasting#plotted_methods).
|
|
11
|
+
class Plot < Primitive
|
|
12
|
+
primitive :ability, :plot,
|
|
13
|
+
description: "Plot `cost`: during your main phase, while the stack is empty, you may pay `cost` and " \
|
|
14
|
+
"exile this card from your hand (special action `{type: \"special_action\"}`). It becomes " \
|
|
15
|
+
"plotted: on a later turn you may cast it from exile without paying its mana cost, " \
|
|
16
|
+
"during your main phase while the stack is empty (cast option `via: \"plotted\"`).",
|
|
17
|
+
rules: %w[702.170a 702.170b 702.170d 116.2k],
|
|
18
|
+
params: { "cost" => "mana cost string" },
|
|
19
|
+
example: { "plot" => { "cost" => "{1}{R}" } }
|
|
20
|
+
|
|
21
|
+
attr_reader :special_cost
|
|
22
|
+
|
|
23
|
+
def self.build(params, errors, path, **)
|
|
24
|
+
Mechanics.check_keys(params, %w[cost], errors, path)
|
|
25
|
+
new(Costs::ManaPayment.build(Mechanics.fetch_param(params, :cost).to_s, errors, "#{path}.cost").mana_cost)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def initialize(cost)
|
|
29
|
+
super()
|
|
30
|
+
@special_cost = cost
|
|
31
|
+
freeze
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def kind = :plot
|
|
35
|
+
def mana_ability? = false
|
|
36
|
+
def allowed_types = nil
|
|
37
|
+
def try_effects = []
|
|
38
|
+
def to_s = "Plot #{special_cost}"
|
|
39
|
+
|
|
40
|
+
# CR 702.170a: during your turn, in your main phase, with an empty stack (as a sorcery, whatever its type).
|
|
41
|
+
def special_allowed?(engine, obj, index) = obj.zone == :hand && engine.sorcery_timing?(index)
|
|
42
|
+
|
|
43
|
+
def special!(engine, obj, _index) = Effects::Plot.plot!(engine, obj.id)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
module Effects
|
|
48
|
+
# "It becomes plotted" / "plot that card" (CR 702.170c-d): the card is exiled face up (or stays exiled) and
|
|
49
|
+
# becomes a plotted card, remembering the turn. Its owner may cast it without paying its mana cost on a later
|
|
50
|
+
# turn, during their main phase while the stack is empty.
|
|
51
|
+
class Plot < Effect
|
|
52
|
+
primitive :effect, :plot,
|
|
53
|
+
description: "Each referenced card or spell is exiled (if it isn't already) and becomes plotted: its " \
|
|
54
|
+
"owner may cast it from exile without paying its mana cost during their main phase while " \
|
|
55
|
+
"the stack is empty, on any later turn (cast option `via: \"plotted\"`).",
|
|
56
|
+
rules: %w[702.170c 702.170d 406.1],
|
|
57
|
+
params: { "to" => "selector (a spell, a card, or an exiled card such as {\"result\": 0})" },
|
|
58
|
+
example: { "plot" => { "to" => { "target" => 0 } } }
|
|
59
|
+
|
|
60
|
+
def self.keys = %w[to if]
|
|
61
|
+
|
|
62
|
+
def self.plot!(engine, id)
|
|
63
|
+
obj = engine.state.objects[id] or return
|
|
64
|
+
fresh = obj.zone == :exile ? obj : engine.move!(id, :exile, reason: "plot")
|
|
65
|
+
fresh.memory["plotted"] = engine.state.turn if fresh&.zone == :exile
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def apply(engine, ctx)
|
|
69
|
+
refs(engine, ctx).each do |id|
|
|
70
|
+
obj = engine.state.objects[id]
|
|
71
|
+
Plot.plot!(engine, id) if obj && !obj.ability? && obj.kind == "card"
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def to_s = "plot → #{to}"
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
@@ -173,14 +173,16 @@ module Enjine
|
|
|
173
173
|
"mana ability. `source`: optional filter on the source's card; `name: \"chosen\"`: only a " \
|
|
174
174
|
"source with the name chosen as this permanent entered. `exhaust: true`: only an exhaust " \
|
|
175
175
|
"ability (\"whenever you activate an exhaust ability\", CR 702.177). `boast: true`: only a " \
|
|
176
|
-
"boast ability (\"whenever a creature you control boasts\", CR 702.142b)."
|
|
177
|
-
|
|
176
|
+
"boast ability (\"whenever a creature you control boasts\", CR 702.142b). `loyalty: " \
|
|
177
|
+
"true`: only a loyalty ability (CR 606).",
|
|
178
|
+
rules: %w[602.2 605.1a 603.2 201.4 702.177a 702.142b 606.1],
|
|
178
179
|
params: { "controller" => PLAYERS.join(" | "), "source" => "card filter", "name" => "\"chosen\"",
|
|
179
|
-
"exhaust" => "true: only exhaust abilities", "boast" => "true: only boast abilities"
|
|
180
|
+
"exhaust" => "true: only exhaust abilities", "boast" => "true: only boast abilities",
|
|
181
|
+
"loyalty" => "true: only loyalty abilities" },
|
|
180
182
|
example: { "activates_ability" => { "controller" => "opponent" } }
|
|
181
183
|
|
|
182
|
-
def self.keys = %w[controller source name exhaust boast]
|
|
183
|
-
KINDS = { "exhaust" => :exhaust?, "boast" => :boast? }.freeze
|
|
184
|
+
def self.keys = %w[controller source name exhaust boast loyalty]
|
|
185
|
+
KINDS = { "exhaust" => :exhaust?, "boast" => :boast?, "loyalty" => :loyalty? }.freeze
|
|
184
186
|
def event_class = Events::AbilityActivated
|
|
185
187
|
|
|
186
188
|
def setup(params, errors, path)
|
|
@@ -202,7 +204,7 @@ module Enjine
|
|
|
202
204
|
|
|
203
205
|
def to_s
|
|
204
206
|
what = "#{@kinds.map { "#{it.to_s.delete("?")} " }.join}ability"
|
|
205
|
-
"Whenever #{who} activate#{"s" unless @controller == "you"} #{what.
|
|
207
|
+
"Whenever #{who} activate#{"s" unless @controller == "you"} #{what.match?(/\A[aeiou]/) ? "an" : "a"} #{what}#{chosen_words}"
|
|
206
208
|
end
|
|
207
209
|
|
|
208
210
|
private
|
|
@@ -9,10 +9,14 @@ module Enjine
|
|
|
9
9
|
# how many the first effect moved or created, e.g. cards drawn)
|
|
10
10
|
# {"power": selector} / {"toughness": ...} total power / toughness ("Picard's power": {"power": "self"})
|
|
11
11
|
# {"greatest_power" | "greatest_toughness": selector} the greatest power / toughness among them (0 for none)
|
|
12
|
-
# {"hand_size" | "life" | "graveyard_size": player selector}
|
|
12
|
+
# {"hand_size" | "life" | "graveyard_size" | "library_size": player selector}
|
|
13
13
|
# {"distinct_names": selector} how many different names they have (strange new worlds)
|
|
14
14
|
# {"mana_value": selector} their total mana value (a spell's X counts on the stack; a spell
|
|
15
15
|
# countered by the resolving one: as it last existed, CR 608.2h)
|
|
16
|
+
# {"greatest_mana_value": selector} the greatest mana value among them (0 for none, CR 202.3)
|
|
17
|
+
# {"sacrificed": "power" | "toughness" | "mana_value"} of the permanents sacrificed to pay the resolving
|
|
18
|
+
# spell's or ability's cost, as they last existed (CR 601.2h, 608.2h)
|
|
19
|
+
# {"card_types": selector} how many different card types among them (delirium, CR 205.2a)
|
|
16
20
|
# {"distinct_types": selector} how many different creature types they have (CR 205.3m)
|
|
17
21
|
# {"distinct_colors": selector} how many colors among them (CR 105.2, 202.2)
|
|
18
22
|
# {"distinct_land_types": selector} how many basic land types among them (domain, CR 305.6)
|
|
@@ -31,14 +35,16 @@ module Enjine
|
|
|
31
35
|
# {"mana_spent": {"of": ..., "color" | "colors": ...}} mana spent to cast a spell (CR 601.2h), see mana_spent.rb
|
|
32
36
|
# {"times": [a, b]} / {"plus": [a, b]} / {"divide": [a, b]} arithmetic on amounts; division rounds down
|
|
33
37
|
# (CR 107.1a). "-X" is {"times": ["x", -1]}.
|
|
34
|
-
# A source that has left the battlefield is used as it last existed (CR 608.2h)
|
|
38
|
+
# A source that has left the battlefield is used as it last existed (CR 608.2h), and so is any object the
|
|
39
|
+
# power, toughness or mana value of which is read after it left the battlefield during the resolving
|
|
40
|
+
# spell or ability (a destroyed target, or {"result": n} of a sacrifice).
|
|
35
41
|
class Amount
|
|
36
42
|
SELECTOR_KINDS = %w[count power toughness greatest_power hand_size life graveyard_size distinct_names distinct_types
|
|
37
43
|
distinct_colors distinct_land_types distinct_planeswalker_types
|
|
38
44
|
life_gained_this_turn life_lost_this_turn dilemmas_this_turn returned_this_turn
|
|
39
45
|
cards_drawn_this_turn cards_discarded_this_turn spells_cast_this_game speed
|
|
40
46
|
noncombat_damage_this_turn noncombat_damage_last_turn turns_taken greatest_toughness
|
|
41
|
-
mana_value].freeze
|
|
47
|
+
mana_value greatest_mana_value card_types library_size].freeze
|
|
42
48
|
ARITHMETIC = %w[times plus divide].freeze
|
|
43
49
|
BASIC_LAND_TYPES = %i[plains island swamp mountain forest].freeze # CR 305.6
|
|
44
50
|
# Object history lists: kind -> turn_log key (Engine::TurnHistory).
|
|
@@ -46,7 +52,7 @@ module Enjine
|
|
|
46
52
|
"sacrificed_this_turn" => "sacrificed", "attackers_this_turn" => "attackers",
|
|
47
53
|
"exiled_this_turn" => "exiled" }.freeze
|
|
48
54
|
KINDS = (SELECTOR_KINDS + ARITHMETIC + DEPARTED.keys + %w[counters spells_cast_this_turn lands_played_this_turn this_way
|
|
49
|
-
mana_spent]).freeze
|
|
55
|
+
mana_spent sacrificed]).freeze
|
|
50
56
|
# Player history counters: kind -> turn_log/game_log key.
|
|
51
57
|
HISTORY = { "life_gained_this_turn" => "life_gained", "life_lost_this_turn" => "life_lost",
|
|
52
58
|
"dilemmas_this_turn" => "dilemmas", "returned_this_turn" => "returned",
|
|
@@ -74,6 +80,7 @@ module Enjine
|
|
|
74
80
|
return Departed.build(kind, ref, errors, "#{path}.#{kind}") if DEPARTED.key?(kind)
|
|
75
81
|
return ThisWay.build(ref, errors, "#{path}.#{kind}", results_count) if kind == "this_way"
|
|
76
82
|
return ManaSpent.build(ref, errors, "#{path}.#{kind}", **context) if kind == "mana_spent" # mana_spent.rb
|
|
83
|
+
return Sacrificed.build(ref, errors, "#{path}.#{kind}") if kind == "sacrificed"
|
|
77
84
|
|
|
78
85
|
new(kind, Selector.build(ref, errors, "#{path}.#{kind}", **context))
|
|
79
86
|
end
|
|
@@ -96,15 +103,9 @@ module Enjine
|
|
|
96
103
|
when "count" then refs.size
|
|
97
104
|
when "power", "toughness" then refs.empty? ? Amount.last_known(engine, ctx, @selector, @kind) : stats(engine, refs).sum
|
|
98
105
|
when "greatest_power", "greatest_toughness" then stats(engine, refs).max.to_i
|
|
99
|
-
when "mana_value" then refs.sum
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
when "distinct_names" then live(engine, refs).map { engine.chars(it).name }.uniq.size
|
|
103
|
-
when "distinct_types" then live(engine, refs).flat_map { Amount.creature_types(engine.chars(it)) }.uniq.size
|
|
104
|
-
when "distinct_colors" then live(engine, refs).flat_map { engine.chars(it).colors }.uniq.size # CR 105.2
|
|
105
|
-
when "distinct_land_types" then (live(engine, refs).flat_map { engine.chars(it).subtypes } & BASIC_LAND_TYPES).size
|
|
106
|
-
when "distinct_planeswalker_types" # CR 205.3j: a planeswalker's subtypes are planeswalker types
|
|
107
|
-
live(engine, refs).flat_map { (c = engine.chars(it)).type?(:planeswalker) ? c.subtypes : [] }.uniq.size
|
|
106
|
+
when "mana_value" then mana_values(engine, refs).sum
|
|
107
|
+
when "greatest_mana_value" then mana_values(engine, refs).max.to_i
|
|
108
|
+
when *DISTINCT then distinct(live(engine, refs).map { engine.chars(it) })
|
|
108
109
|
else players(engine, refs).sum { player_value(engine, it) }
|
|
109
110
|
end
|
|
110
111
|
end
|
|
@@ -133,6 +134,17 @@ module Enjine
|
|
|
133
134
|
lki ? lki[key].to_i : 0
|
|
134
135
|
end
|
|
135
136
|
|
|
137
|
+
# How an object last existed on the battlefield if it left during the resolving spell or ability: by its
|
|
138
|
+
# old id (a destroyed target), or, for what an earlier effect moved (`moved`: a {"result": n} selector), as
|
|
139
|
+
# the new object it became (CR 400.7). A spell countered by the resolving one, as it last existed on the
|
|
140
|
+
# stack (Engine::TurnHistory#remember_spell!). Nil otherwise: a card in a graveyard looked at for itself is
|
|
141
|
+
# the card there.
|
|
142
|
+
def self.left_battlefield(engine, ref, moved: false)
|
|
143
|
+
return engine.departed_last_known(ref) if moved && engine.departed_last_known(ref)
|
|
144
|
+
|
|
145
|
+
engine.state.objects.key?(ref) ? nil : engine.resolving_last_known(ref)
|
|
146
|
+
end
|
|
147
|
+
|
|
136
148
|
# How a source that has left the battlefield last existed: remembered by the resolving ability, or,
|
|
137
149
|
# while its leaves-the-battlefield trigger is being checked (CR 603.4, 603.10a), the engine's.
|
|
138
150
|
def self.source_lki(engine, ctx)
|
|
@@ -141,10 +153,42 @@ module Enjine
|
|
|
141
153
|
|
|
142
154
|
private
|
|
143
155
|
|
|
156
|
+
DISTINCT = %w[card_types distinct_names distinct_types distinct_colors distinct_land_types
|
|
157
|
+
distinct_planeswalker_types].freeze
|
|
158
|
+
private_constant :DISTINCT
|
|
159
|
+
|
|
160
|
+
# How many different card types, names, creature types, colors, basic land types or planeswalker types
|
|
161
|
+
# the objects with these characteristics have between them.
|
|
162
|
+
def distinct(chars)
|
|
163
|
+
case @kind
|
|
164
|
+
when "card_types" then chars.flat_map(&:types).uniq.size # CR 205.2a
|
|
165
|
+
when "distinct_names" then chars.map(&:name).uniq.size
|
|
166
|
+
when "distinct_types" then chars.flat_map { Amount.creature_types(it) }.uniq.size
|
|
167
|
+
when "distinct_colors" then chars.flat_map(&:colors).uniq.size # CR 105.2
|
|
168
|
+
when "distinct_land_types" then (chars.flat_map(&:subtypes) & BASIC_LAND_TYPES).size
|
|
169
|
+
else chars.flat_map { it.type?(:planeswalker) ? it.subtypes : [] }.uniq.size # CR 205.3j
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
144
173
|
def live(engine, refs) = refs.select { engine.state.objects.key?(it) }
|
|
145
174
|
|
|
175
|
+
# Each one's mana value; one that has left as it last existed (CR 608.2h).
|
|
176
|
+
def mana_values(engine, refs)
|
|
177
|
+
refs.map do |ref|
|
|
178
|
+
lki = Amount.left_battlefield(engine, ref, moved: @selector.kind == :result)
|
|
179
|
+
lki ? lki["mana_value"].to_i : Amount.mana_value(engine, engine.state.objects[ref]) || 0
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# Each one's power or toughness; one that left the battlefield during the resolving spell or ability as it
|
|
184
|
+
# last existed (CR 608.2h), one that's simply gone not at all.
|
|
146
185
|
def stats(engine, refs)
|
|
147
|
-
|
|
186
|
+
key = @kind.end_with?("toughness") ? "toughness" : "power"
|
|
187
|
+
refs.filter_map do |ref|
|
|
188
|
+
if (lki = Amount.left_battlefield(engine, ref, moved: @selector.kind == :result)) then lki[key].to_i
|
|
189
|
+
elsif engine.state.objects.key?(ref) then engine.public_send(key, engine.object(ref))
|
|
190
|
+
end
|
|
191
|
+
end
|
|
148
192
|
end
|
|
149
193
|
|
|
150
194
|
def players(engine, refs) = refs.filter_map { Filters.player_index(engine, it) }
|
|
@@ -155,6 +199,7 @@ module Enjine
|
|
|
155
199
|
when "life" then engine.player(index).life
|
|
156
200
|
when "speed" then engine.speed(index) # CR 702.179f: 0 without speed
|
|
157
201
|
when "graveyard_size" then engine.player(index).graveyard.size
|
|
202
|
+
when "library_size" then engine.player(index).library.size # CR 401.1
|
|
158
203
|
when "spells_cast_this_game" then engine.game_log(index).fetch("spells", 0)
|
|
159
204
|
when "turns_taken" then engine.game_log(index).fetch("turns", 0) # this turn included, if it's theirs
|
|
160
205
|
when *LAST_TURN.keys then engine.last_turn_log(index).fetch(LAST_TURN.fetch(@kind), 0)
|
|
@@ -180,6 +225,29 @@ module Enjine
|
|
|
180
225
|
def to_s = "that many"
|
|
181
226
|
end
|
|
182
227
|
|
|
228
|
+
# {"sacrificed": "power" | "toughness" | "mana_value"}: "the sacrificed creature's power" — the total of the
|
|
229
|
+
# permanents sacrificed to pay the resolving spell's or ability's cost, as they last existed (CR 601.2h,
|
|
230
|
+
# 608.2h; recorded by Costs::SacrificePermanent). 0 when none was.
|
|
231
|
+
class Sacrificed
|
|
232
|
+
KEYS = %w[power toughness mana_value].freeze
|
|
233
|
+
|
|
234
|
+
def self.build(key, errors, path)
|
|
235
|
+
return new(key) if KEYS.include?(key)
|
|
236
|
+
|
|
237
|
+
errors << "#{path}: must be #{KEYS[0..-2].join(", ")} or #{KEYS.last}"
|
|
238
|
+
Fixed.new(0)
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
def initialize(key)
|
|
242
|
+
@key = key
|
|
243
|
+
freeze
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
def reads_power? = @key != "mana_value"
|
|
247
|
+
def value(engine, ctx) = (engine.state.objects[ctx.object]&.paid || []).sum { it[@key].to_i }
|
|
248
|
+
def to_s = "the sacrificed permanent's #{@key.tr("_", " ")}"
|
|
249
|
+
end
|
|
250
|
+
|
|
183
251
|
# A fixed number.
|
|
184
252
|
class Fixed
|
|
185
253
|
attr_reader :n
|
data/lib/enjine/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: enjine
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Mehmet Cetin
|
|
@@ -30,6 +30,7 @@ files:
|
|
|
30
30
|
- docs/guides/api.md
|
|
31
31
|
- docs/guides/card-data-format.md
|
|
32
32
|
- docs/guides/deck-builder.md
|
|
33
|
+
- docs/plans/dsl-gaps.md
|
|
33
34
|
- docs/plans/standard.md
|
|
34
35
|
- docs/reference/abilities.md
|
|
35
36
|
- docs/reference/costs.md
|
|
@@ -91,6 +92,7 @@ files:
|
|
|
91
92
|
- lib/enjine/engine/combat.rb
|
|
92
93
|
- lib/enjine/engine/copies.rb
|
|
93
94
|
- lib/enjine/engine/damage.rb
|
|
95
|
+
- lib/enjine/engine/defined_power_toughness.rb
|
|
94
96
|
- lib/enjine/engine/designations.rb
|
|
95
97
|
- lib/enjine/engine/emblems.rb
|
|
96
98
|
- lib/enjine/engine/entering.rb
|
|
@@ -231,6 +233,7 @@ files:
|
|
|
231
233
|
- lib/enjine/mechanics/keywords/kicker.rb
|
|
232
234
|
- lib/enjine/mechanics/keywords/mobilize_and_firebending.rb
|
|
233
235
|
- lib/enjine/mechanics/keywords/paradigm.rb
|
|
236
|
+
- lib/enjine/mechanics/keywords/plot.rb
|
|
234
237
|
- lib/enjine/mechanics/keywords/power_up.rb
|
|
235
238
|
- lib/enjine/mechanics/keywords/protection.rb
|
|
236
239
|
- lib/enjine/mechanics/keywords/prowess.rb
|