Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions crates/sage-engine/data/catalog/dismissive_pyromancer.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,20 @@
"Human",
"Wizard"
],
"mana_cost": "{2}{R}",
"mana_cost": "{1}{R}",
"colors": [
"red"
],
"power": 2,
"toughness": 1,
"toughness": 2,
"abilities": [
{
"type": "activated",
"cost": [
{
"kind": "mana",
"mana": "{R}"
},
{
"kind": "tap"
},
Expand All @@ -41,6 +45,9 @@
"kind": "mana",
"mana": "{2}{R}"
},
{
"kind": "tap"
},
{
"kind": "sacrifice_this"
}
Expand Down
2 changes: 1 addition & 1 deletion crates/sage-engine/data/catalog/enigma_drake.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"subtypes": [
"Drake"
],
"mana_cost": "{2}{U}{R}",
"mana_cost": "{1}{U}{R}",
"colors": [
"blue",
"red"
Expand Down
2 changes: 1 addition & 1 deletion crates/sage-engine/data/catalog/gargoyle_sentinel.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"mana_cost": "{3}",
"colors": [],
"power": 3,
"toughness": 4,
"toughness": 3,
"keywords": [
"defender"
],
Expand Down
6 changes: 3 additions & 3 deletions crates/sage-engine/data/catalog/ghastbark_twins.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@
"subtypes": [
"Treefolk"
],
"mana_cost": "{4}{G}",
"mana_cost": "{5}{G}{G}",
"colors": [
"green"
],
"power": 5,
"toughness": 5,
"power": 7,
"toughness": 7,
"keywords": [
"trample"
],
Expand Down
2 changes: 1 addition & 1 deletion crates/sage-engine/data/catalog/gift_of_paradise.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
{
"kind": "gain_life",
"player_ref": "controller",
"amount": 2
"amount": 3
}
]
}
Expand Down
7 changes: 2 additions & 5 deletions crates/sage-engine/data/catalog/goblin_trashmaster.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
"creature"
],
"subtypes": [
"Goblin"
"Goblin",
"Warrior"
],
"mana_cost": "{2}{R}{R}",
"colors": [
Expand All @@ -31,10 +32,6 @@
{
"type": "activated",
"cost": [
{
"kind": "mana",
"mana": "{1}{R}"
},
{
"kind": "sacrifice",
"subtype": "Goblin"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
"subtypes": [
"Bear"
],
"mana_cost": "{4}{G}",
"mana_cost": "{3}{G}",
"colors": [
"green"
],
"power": 4,
"toughness": 4,
"toughness": 3,
"abilities": [
{
"type": "cost_modifier",
Expand Down
2 changes: 1 addition & 1 deletion crates/sage-engine/data/catalog/hired_blade.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"colors": [
"black"
],
"power": 2,
"power": 3,
"toughness": 2,
"keywords": [
"flash"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"types": [
"artifact"
],
"mana_cost": "{4}",
"mana_cost": "{3}",
"colors": [],
"abilities": [
{
Expand Down
4 changes: 2 additions & 2 deletions crates/sage-engine/data/catalog/marauder_s_axe.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
"subtypes": [
"Equipment"
],
"mana_cost": "{3}",
"mana_cost": "{2}",
"colors": [],
"attachment": {
"kind": "equipment",
"attach_to": "any_creature_you_control",
"equip": "{2}",
"power": 2,
"toughness": 1
"toughness": 0
}
}
10 changes: 4 additions & 6 deletions crates/sage-engine/data/catalog/mistcaller.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,15 @@
"creature"
],
"subtypes": [
"Spirit"
"Merfolk",
"Wizard"
],
"mana_cost": "{1}{U}",
"mana_cost": "{U}",
"colors": [
"blue"
],
"power": 2,
"power": 1,
"toughness": 1,
"keywords": [
"flash"
],
"abilities": [
{
"type": "activated",
Expand Down
7 changes: 1 addition & 6 deletions crates/sage-engine/data/catalog/ravenous_harpy.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"cost": [
{
"kind": "mana",
"mana": "{B}"
"mana": "{1}"
},
{
"kind": "sacrifice",
Expand All @@ -36,11 +36,6 @@
"kind": "put_counters_on_self",
"counter": "plus_one_plus_one",
"count": 1
},
{
"kind": "gain_life",
"player_ref": "controller",
"amount": 1
}
]
}
Expand Down
11 changes: 6 additions & 5 deletions crates/sage-engine/data/catalog/regal_bloodlord.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@
],
"subtypes": [
"Vampire",
"Noble"
"Soldier"
],
"mana_cost": "{3}{B}{B}",
"mana_cost": "{3}{W}{B}",
"colors": [
"white",
"black"
],
"power": 2,
Expand All @@ -24,7 +25,7 @@
"event": {
"beginning_of_step": {
"step": "end_step",
"whose_turn": "yours"
"whose_turn": "each"
}
},
"effects": [
Expand All @@ -48,8 +49,8 @@
"colors": [
"black"
],
"power": 2,
"toughness": 2,
"power": 1,
"toughness": 1,
"keywords": [
"flying"
]
Expand Down
4 changes: 2 additions & 2 deletions crates/sage-engine/data/catalog/runic_armasaur.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
"subtypes": [
"Dinosaur"
],
"mana_cost": "{2}{G}",
"mana_cost": "{1}{G}{G}",
"colors": [
"green"
],
"power": 1,
"power": 2,
"toughness": 5,
"abilities": [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
{
"kind": "create_token",
"count": 1,
"tapped": true,
"attacking": true,
"token": {
"name": "Knight",
Expand Down
2 changes: 1 addition & 1 deletion crates/sage-engine/src/card/attachment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ mod tests {
attach_to: TargetSpec::AnyCreatureYouControl,
equip: Some("{2}".to_string()),
power: 2,
toughness: 1,
toughness: 0,
count_of: None,
keywords: vec![],
restrictions: vec![],
Expand Down
53 changes: 30 additions & 23 deletions crates/sage-engine/tests/blocking_an_additional_creature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,11 +307,11 @@ fn ghastbark_twins_records_its_blocks_in_the_order_it_declared_them() {

#[test]
fn a_blocker_spreads_one_pool_of_power_across_the_attackers_it_blocks() {
// CR 510.1c/e from the blocker's side: the Twins' 5 power is *one* pool, assigned
// CR 510.1c/e from the blocker's side: the Twins' 7 power is *one* pool, assigned
// just-lethal to the first attacker in its order and the remainder to the last —
// not 5 to each, which is what an attacker-driven loop would deal.
// not 7 to each, which is what an attacker-driven loop would deal.
//
// A 3/3 first and a 6/6 second: 3 is lethal to the courser, and the 2 left over
// A 3/3 first and a 6/6 second: 3 is lethal to the courser, and the 4 left over
// reaches the dreadmaw and stays marked on it.
let db = db();
let mut state = main_phase();
Expand Down Expand Up @@ -345,21 +345,22 @@ fn a_blocker_spreads_one_pool_of_power_across_the_attackers_it_blocks() {
);
assert_eq!(
damage(&after, dreadmaw),
Some(2),
"and the remaining 2 reached the second, which survived it"
Some(4),
"and the remaining 4 reached the second, which survived it"
);
assert_eq!(
damage(&after, twins),
None,
"both attackers struck the one blocker back, which is 9 on a 5/5"
"both attackers struck the one blocker back, which is 9 on a 7/7"
);
}

#[test]
fn the_blockers_order_decides_which_attacker_the_damage_reaches() {
// The mirror of the test above with the declaration order reversed. The 6/6 is now
// first and soaks all 5 — nothing is left for the 3/3, which walks away untouched.
// Nothing but the order changed, which is what makes the order load-bearing.
// first, so 6 of the Twins' 7 is lethal to *it* and the single point left over is all
// the 3/3 behind it takes. Nothing but the order changed, and it moved the death from
// one attacker to the other, which is what makes the order load-bearing.
let db = db();
let mut state = main_phase();
let courser = place(&mut state, &db, "centaur_courser", PlayerId(0));
Expand Down Expand Up @@ -387,13 +388,13 @@ fn the_blockers_order_decides_which_attacker_the_damage_reaches() {

assert_eq!(
damage(&after, dreadmaw),
Some(5),
"the first in the order takes everything it can absorb"
None,
"the first in the order took lethal damage and died (CR 704.5g)"
);
assert_eq!(
damage(&after, courser),
Some(0),
"and the second, behind a creature that never took lethal, takes nothing"
Some(1),
"and the second took only what the first could not absorb"
);
}

Expand All @@ -404,26 +405,28 @@ fn one_blocked_attacker_still_takes_the_whole_of_its_blockers_power() {
// there is something to spread across.
let db = db();
let mut state = main_phase();
let dreadmaw = place(&mut state, &db, "colossal_dreadmaw", PlayerId(0));
// An 8/8 rather than the 6/6 the spread tests use: the whole pool is only *visible*
// on an attacker that survives it, and 7 kills a 6/6.
let mammoth = place(&mut state, &db, "aggressive_mammoth", PlayerId(0));
let twins = place(&mut state, &db, "ghastbark_twins", PlayerId(1));

let state = attack_with(&state, &db, &[dreadmaw]);
let state = attack_with(&state, &db, &[mammoth]);
let state = apply_action(
&state,
&Action::DeclareBlockers {
blocks: vec![Block {
blocker: twins,
attacker: dreadmaw,
attacker: mammoth,
}],
},
&db,
);
let after = settle_until(&state, &db, |s| s.step == Step::EndCombat);

assert_eq!(
damage(&after, dreadmaw),
Some(5),
"all 5 power on the one attacker it blocked"
damage(&after, mammoth),
Some(7),
"all 7 power on the one attacker it blocked"
);
}

Expand All @@ -435,11 +438,13 @@ fn blocking_two_attackers_leaves_neither_of_them_unblocked() {
let db = db();
let mut state = main_phase();
let courser = place(&mut state, &db, "centaur_courser", PlayerId(0));
let dreadmaw = place(&mut state, &db, "colossal_dreadmaw", PlayerId(0));
// An 8/8 trampler, because 7 of anything less is swallowed whole by a 7/7 blocker and
// there would be no overflow left to be the point of this test.
let mammoth = place(&mut state, &db, "aggressive_mammoth", PlayerId(0));
let twins = place(&mut state, &db, "ghastbark_twins", PlayerId(1));
let before = state.players[1].life;

let state = attack_with(&state, &db, &[courser, dreadmaw]);
let state = attack_with(&state, &db, &[courser, mammoth]);
let state = apply_action(
&state,
&Action::DeclareBlockers {
Expand All @@ -450,15 +455,17 @@ fn blocking_two_attackers_leaves_neither_of_them_unblocked() {
},
Block {
blocker: twins,
attacker: dreadmaw,
attacker: mammoth,
},
],
},
&db,
);
let after = settle_until(&state, &db, |s| s.step == Step::EndCombat);

// The courser is blocked and has no trample, so it reaches nobody; the dreadmaw
// assigns 5 to the 5/5 blocker and tramples the 1 that is left (CR 702.19e).
// The courser has 3 power against a 7-toughness blocker, so it reaches nobody — the
// trample the Mammoth grants it changes nothing, because there is no lethal-and-then-
// some to spill. The Mammoth itself assigns 7 to the blocker and tramples the 1 that
// is left (CR 702.19e), and that single point is the whole of the life lost.
assert_eq!(after.players[1].life, before - 1);
}
Loading
Loading