Skip to content

Commit

Permalink
Add Battle for Bretagard (first saga card)
Browse files Browse the repository at this point in the history
  • Loading branch information
radar committed Nov 11, 2024
1 parent 00b2d25 commit 39454d7
Show file tree
Hide file tree
Showing 10 changed files with 223 additions and 18 deletions.
59 changes: 59 additions & 0 deletions lib/magic/cards/battle_for_bretagard.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
module Magic
module Cards
class BattleForBretagard < Saga
card_name "Battle for Bretagard"
cost generic: 1, green: 1, white: 1

HumanWarriorToken = Token.create "Human Warrior" do
creature_type "Human Warrior"
power 1
toughness 1
colors :white
end

ElfWarriorToken = Token.create "Elf Warrior" do
creature_type "Elf Warrior"
power 1
toughness 1
colors :green
end

class Chapter1 < Chapter
def start
actor.trigger_effect(:create_token, token_class: HumanWarriorToken)
end
end

class Chapter2 < Chapter
def start
actor.trigger_effect(:create_token, token_class: ElfWarriorToken)
end
end

class Chapter3 < Chapter
def start
actor.game.add_choice(BattleForBretagard::Choice.new(actor: actor))
end
end

class Choice < Magic::Choice
def choices
you_control = battlefield.controlled_by(controller)

Magic::Targets::Choices.new(
choices: you_control.artifact.tokens + you_control.creature.tokens,
amount: 0..
)
end

def resolve!(targets:)
targets.each(&:copy!)
end
end

def chapters
[Chapter1, Chapter2, Chapter3]
end
end
end
end
58 changes: 58 additions & 0 deletions lib/magic/cards/saga.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
module Magic
module Cards
class Saga < Card
class Chapter
attr_reader :actor

def initialize(actor:)
@actor = actor
end
end

type T::Enchantment, "Saga"

enters_the_battlefield do
actor.trigger_effect(:add_counter, counter_type: Counters::Lore, target: actor)
end

class CounterAddedTrigger < TriggeredAbility
def should_perform?
this? && event.counter_type == Counters::Lore
end

def call
lore_counters = actor.counters.of_type(Counters::Lore)
chapter_class = card.chapter(lore_counters)
chapter_class.new(actor: actor).start

actor.sacrifice! if card.chapters.count == lore_counters.count
end
end

class FirstMainPhaseTrigger < TriggeredAbility
def should_perform?
you?
end

def call
actor.trigger_effect(:add_counter, counter_type: Counters::Lore, target: actor)
end
end

def chapter(counters)
chapters[counters.count - 1]
end

def chapters
raise NotImplementedError
end

def event_handlers
{
Events::CounterAddedToPermanent => CounterAddedTrigger,
Events::FirstMainPhaseStarted => FirstMainPhaseTrigger,
}
end
end
end
end
4 changes: 2 additions & 2 deletions lib/magic/cards/sanctum_of_calm_waters.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ module Cards

def event_handlers
{
Events::FirstMainPhase => -> (receiver, event) do
return unless event.active_player == receiver.controller
Events::FirstMainPhaseStarted => -> (receiver, event) do
return unless event.player == receiver.controller

game.choices.add(SanctumOfCalmWaters::Choice.new(actor: receiver))
end
Expand Down
6 changes: 6 additions & 0 deletions lib/magic/counters/lore.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module Magic
module Counters
class Lore
end
end
end
15 changes: 0 additions & 15 deletions lib/magic/events/first_main_phase.rb

This file was deleted.

15 changes: 15 additions & 0 deletions lib/magic/events/first_main_phase_started.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module Magic
module Events
class FirstMainPhaseStarted
attr_reader :player

def initialize(player:)
@player = player
end

def inspect
"#<Events::FirstMainPhase>"
end
end
end
end
2 changes: 1 addition & 1 deletion lib/magic/game/turn.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class Turn

after_transition to: :first_main do |turn|
turn.notify!(
Events::FirstMainPhase.new(active_player: turn.active_player)
Events::FirstMainPhaseStarted.new(player: turn.active_player)
)
end

Expand Down
11 changes: 11 additions & 0 deletions lib/magic/permanent.rb
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,17 @@ def copy?
@copy
end

def copy!
self.class.resolve(
game: game,
owner: owner,
card: card,
token: token?,
cast: false,
copy: true,
)
end

def cast?
@cast
end
Expand Down
4 changes: 4 additions & 0 deletions lib/magic/triggered_ability.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ def type?(type)
event.permanent.types.include?(type)
end

def card
actor.card
end

def perform!
return unless should_perform?
call
Expand Down
67 changes: 67 additions & 0 deletions spec/game/integration/saga_lore_counters_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
require "spec_helper"

RSpec.describe "Saga Lore Counters" do
include_context "two player game"

let(:p1_library) do
10.times.map { Card("Island", owner: p1) }
end

let(:p2_library) do
10.times.map { Card("Mountain", owner: p2) }
end

context "as a card" do
let(:card) { Card("Battle For Bretagard") }

it "adds a lore counter when it enters" do
p1.add_mana(white: 2, green: 1)
p1.cast(card: card) do
_1.auto_pay_mana
end

game.stack.resolve!

permanent = game.battlefield.by_name("Battle for Bretagard").first

expect(permanent.counters.of_type(Magic::Counters::Lore).count).to eq(1)
human_warrior = game.battlefield.by_name("Human Warrior")
expect(human_warrior.count).to eq(1)

game.next_turn
game.next_turn

turn_3 = game.current_turn

turn_3.untap!
turn_3.upkeep!
turn_3.draw!
turn_3.first_main!

expect(permanent.counters.of_type(Magic::Counters::Lore).count).to eq(2)

elf_warrior = game.battlefield.by_name("Elf Warrior")
expect(elf_warrior.count).to eq(1)

game.next_turn
game.next_turn

turn_5 = game.current_turn
turn_5.untap!
turn_5.upkeep!
turn_5.draw!
turn_5.first_main!

expect(game.battlefield.by_name("Battle for Bretagard")).to be_empty
expect(card.zone).to be_graveyard

human_warrior = game.battlefield.by_name("Human Warrior").first
elf_warrior = game.battlefield.by_name("Elf Warrior").first

game.resolve_choice!(targets: [human_warrior, elf_warrior])

expect(game.battlefield.by_name("Human Warrior").count).to eq(2)
expect(game.battlefield.by_name("Elf Warrior").count).to eq(2)
end
end
end

0 comments on commit 39454d7

Please sign in to comment.