Skip to content

Commit

Permalink
Add Opt
Browse files Browse the repository at this point in the history
Fixes #69
  • Loading branch information
radar committed Jul 10, 2023
1 parent 947189c commit bf32c88
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 3 deletions.
19 changes: 19 additions & 0 deletions lib/magic/cards/opt.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
module Magic
module Cards
Opt = Instant("Opt") do
cost blue: 1
end

class Opt < Instant
def resolve!(_controller)
game.add_effect(
Effects::Scry.new(source: self, amount: 1, then_do: -> do
game.add_effect(Effects::DrawCards.new(source: self, player: controller))
end)
)

super
end
end
end
end
13 changes: 11 additions & 2 deletions lib/magic/effect.rb
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
module Magic
class Effect
attr_reader :source, :targets, :choices
attr_reader :source, :targets, :choices, :then_do

class InvalidTarget < StandardError; end;

def initialize(source:, targets: [], choices: [])
def initialize(source:, targets: [], choices: [], then_do: nil)
@source = source
@targets = targets
@choices = choices.select { |choice| choice.can_be_targeted_by?(source) }
@resolved = false
@then_do = then_do
end

def multiple_targets?
targets > 1
end

def single_choice?
requires_choices? && choices.count == 1
end

def requires_choices?
false
end
Expand All @@ -29,6 +34,10 @@ def multiple_targets?

def resolve(*)
@resolved = true

if then_do
then_do.call
end
end

def skip!
Expand Down
25 changes: 25 additions & 0 deletions lib/magic/effects/scry.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
module Magic
module Effects
class Scry < Effect
attr_reader :player, :amount

def initialize(source:, amount:, then_do:)
@source = source
@amount = amount
super(source: source, then_do: then_do)

end

def requires_choices?
true
end

def resolve(top: [], bottom: [])
source.controller.scry(amount:, top:, bottom:)

super

end
end
end
end
17 changes: 17 additions & 0 deletions lib/magic/events/scry.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module Magic
module Events
class Scry
attr_reader :player, :top, :bottom

def initialize(player:, top:, bottom:)
@player = player
@top = top
@bottom = bottom
end

def inspect
"#<Events::Scry player: #{player}, top: #{top}, bottom: #{bottom}>"
end
end
end
end
13 changes: 13 additions & 0 deletions lib/magic/player.rb
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,19 @@ def mill(amount)
end
end

def scry(amount:, top:, bottom:)
cards = library.shift(amount)
library.unshift(*top)
library.push(*bottom)
game.notify!(
Events::Scry.new(
player: self,
top: top.count,
bottom: bottom.count,
)
)
end

def tap!(card)
card.tap!
end
Expand Down
2 changes: 1 addition & 1 deletion lib/magic/zone.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ class Zone
extend Forwardable
include Enumerable

def_delegators :@cards, :each, :<<, :by_name, :creatures, :by_any_type, :basic_lands, :controlled_by, :cmc_lte, :by_card
def_delegators :@cards, :each, :last, :shift, :unshift, :push, :<<, :by_name, :creatures, :by_any_type, :basic_lands, :controlled_by, :cmc_lte, :by_card

attr_reader :owner, :cards

Expand Down
55 changes: 55 additions & 0 deletions spec/cards/opt_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
require 'spec_helper'

RSpec.describe Magic::Cards::Opt do
include_context "two player game"

let(:opt) { described_class.new(game: game) }

def p1_library
[
Card("Forest"),
Card("Forest"),
Card("Forest"),
Card("Forest"),
Card("Forest"),
Card("Forest"),
Card("Forest"),
# End initial card draw
Card("Sol Ring"),
Card("Forest"),
]
end

it "scries to the top" do
top_card = p1.library.first
p1.add_mana(blue: 1)
action = cast_action(player: p1, card: opt)
action.pay_mana(blue: 1)
game.take_action(action)
game.tick!
effect = game.effects.first
expect(effect).to be_a(Magic::Effects::Scry)
game.resolve_pending_effect(top: [top_card])

expect(opt.zone).to be_graveyard
expect(p1.library.first.name).to eq("Forest")
expect(p1.hand.map(&:name)).to include("Sol Ring")
end

it "scries to the bottom" do
top_card = p1.library.first
p1.add_mana(blue: 1)
action = cast_action(player: p1, card: opt)
action.pay_mana(blue: 1)
game.take_action(action)
game.tick!
effect = game.effects.first
expect(effect).to be_a(Magic::Effects::Scry)
game.resolve_pending_effect(bottom: [top_card])

expect(opt.zone).to be_graveyard
expect(p1.library.last).to eq(top_card)

expect(p1.hand.map(&:name)).not_to include("Sol Ring")
end
end

0 comments on commit bf32c88

Please sign in to comment.