[NCC] Implement Smuggler's Share (#9295)

This commit is contained in:
Spencer Lanman 2022-07-23 08:07:07 -07:00 committed by GitHub
parent 97b34e3129
commit 40fbb9af9b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 444 additions and 2 deletions

View file

@ -15,6 +15,7 @@ import mage.filter.StaticFilters;
import mage.filter.common.FilterCreaturePermanent;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetLandPermanent;
import mage.watchers.common.PermanentsEnteredBattlefieldWatcher;
@ -57,9 +58,10 @@ enum LavaballTrapCondition implements Condition {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
PermanentsEnteredBattlefieldWatcher watcher = game.getState().getWatcher(PermanentsEnteredBattlefieldWatcher.class);
if (watcher != null) {
for (UUID opponentId : game.getOpponents(source.getControllerId())) {
if (watcher != null && controller != null) {
for (UUID opponentId : game.getOpponents(controller.getId())) {
List<Permanent> permanents = watcher.getThisTurnEnteringPermanents(opponentId);
if (permanents != null) {
int count = 0;

View file

@ -0,0 +1,137 @@
package mage.cards.s;
import java.util.List;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.BeginningOfEndStepTriggeredAbility;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.TargetController;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.game.permanent.token.TreasureToken;
import mage.players.Player;
import mage.watchers.common.CardsAmountDrawnThisTurnWatcher;
import mage.watchers.common.PermanentsEnteredBattlefieldWatcher;
/**
* One way or another, everyone gets paid what they're owed.
* Based on Gadrak, the Crown Scourge, Hoard Hauler, Lavaball Trap, Walker Of The Grove, Widespread Thieving, and Wound Reflection
*
* @author Slanman3755
*/
public final class SmugglersShare extends CardImpl {
public SmugglersShare(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}");
// At the beginning of each end step, draw a card for each opponent who drew two or more cards this turn, then
// create a Treasure token for each opponent who had two or more lands enter the battlefield under their control
// this turn.
Ability ability = new BeginningOfEndStepTriggeredAbility(new DrawCardSourceControllerEffect(SmugglersShareDrawValue.instance), TargetController.EACH_PLAYER, false);
ability.addEffect((new CreateTokenEffect(new TreasureToken(), SmugglersShareTreasureValue.instance)).concatBy(", then"));
ability.addWatcher(new CardsAmountDrawnThisTurnWatcher());
ability.addWatcher(new PermanentsEnteredBattlefieldWatcher());
this.addAbility(ability);
}
private SmugglersShare(final SmugglersShare card) {
super(card);
}
@Override
public SmugglersShare copy() {
return new SmugglersShare(this);
}
}
enum SmugglersShareDrawValue implements DynamicValue {
instance;
@Override
public int calculate(Game game, Ability source, Effect effect) {
Player controller = game.getPlayer(source.getControllerId());
CardsAmountDrawnThisTurnWatcher watcher = game.getState().getWatcher(CardsAmountDrawnThisTurnWatcher.class);
if (watcher == null || controller == null) {
return 0;
}
int drawCount = 0;
for (UUID opponentId : game.getOpponents(controller.getId())) {
Player opponent = game.getPlayer(opponentId);
if (opponent != null && watcher.getAmountCardsDrawn(opponentId) >= 2) {
drawCount++;
}
}
return drawCount;
}
@Override
public SmugglersShareDrawValue copy() {
return instance;
}
@Override
public String getMessage() {
return "opponent who drew two or more cards this turn";
}
@Override
public String toString() {
return "1";
}
}
enum SmugglersShareTreasureValue implements DynamicValue {
instance;
@Override
public int calculate(Game game, Ability source, Effect effect) {
Player controller = game.getPlayer(source.getControllerId());
PermanentsEnteredBattlefieldWatcher watcher = game.getState().getWatcher(PermanentsEnteredBattlefieldWatcher.class);
if (watcher == null || controller == null) {
return 0;
}
int treasureCount = 0;
for (UUID opponentId : game.getOpponents(controller.getId())) {
Player opponent = game.getPlayer(opponentId);
if (opponent == null) {
continue;
}
List<Permanent> enteredPermanents = watcher.getThisTurnEnteringPermanents(opponentId);
if (enteredPermanents == null) {
continue;
}
int enteredLandCount = 0;
for (Permanent permanent : enteredPermanents) {
if (permanent.isLand(game)) enteredLandCount++;
}
if (enteredLandCount >= 2) {
treasureCount++;
}
}
return treasureCount;
}
@Override
public SmugglersShareTreasureValue copy() {
return instance;
}
@Override
public String getMessage() {
return "opponent who had two or more lands enter the battlefield under their control this turn";
}
@Override
public String toString() {
return "1";
}
}

View file

@ -268,6 +268,7 @@ public final class NewCapennaCommander extends ExpansionSet {
cards.add(new SetCardInfo("Skyship Plunderer", 232, Rarity.UNCOMMON, mage.cards.s.SkyshipPlunderer.class));
cards.add(new SetCardInfo("Slippery Bogbonder", 312, Rarity.RARE, mage.cards.s.SlipperyBogbonder.class));
cards.add(new SetCardInfo("Smoldering Marsh", 428, Rarity.RARE, mage.cards.s.SmolderingMarsh.class));
cards.add(new SetCardInfo("Smuggler's Share", 21, Rarity.RARE, mage.cards.s.SmugglersShare.class));
cards.add(new SetCardInfo("Sol Ring", 379, Rarity.UNCOMMON, mage.cards.s.SolRing.class));
cards.add(new SetCardInfo("Solemn Simulacrum", 380, Rarity.RARE, mage.cards.s.SolemnSimulacrum.class));
cards.add(new SetCardInfo("Spellbinding Soprano", 53, Rarity.RARE, mage.cards.s.SpellbindingSoprano.class));

View file

@ -0,0 +1,302 @@
package org.mage.test.cards.single.ncc;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestCommander4Players;
/**
*
* @author Slanman3755
*/
public class SmugglersShareTest extends CardTestCommander4Players {
/*
Smuggler's Share {2}{W}
Enchantment
At the beginning of each end step, draw a card for each opponent who drew two or more cards this turn, then
create a Treasure token for each opponent who had two or more lands enter the battlefield under their control
this turn.
*/
String smugglersShare = "Smuggler's Share";
/*
Cultivate {2}{G}
Sorcery
Search your library for up to two basic land cards, reveal those cards, put one onto the battlefield tapped and
the other into your hand, then shuffle.
*/
String cultivate = "Cultivate";
/*
Forest
Basic Land - Forest
({T}: Add {G}.)
*/
String forest = "Forest";
/*
Harmonize {2}{G}{G}
Sorcery
Draw three cards.
*/
String harmonize = "Harmonize";
/*
Harrow {2}{G}
Instant
As an additional cost to cast this spell, sacrifice a land.
Search your library for up to two basic land cards, put them onto the battlefield, then shuffle.
*/
String harrow = "Harrow";
/*
Chemister's Insight {3}{U}
Instant
Draw two cards.
Jump-start
*/
String chemistersInsight = "Chemister's Insight";
/*
Island
Basic Land - Island
({T}: Add {U}.)
*/
String island = "Island";
/*
Plains
Basic Land - Plains
({T}: Add {W}.)
*/
String plains = "Plains";
/*
Treasure
Token Artifact - Treasure
{T}, Sacrifice this artifact: Add one mana of any color.
*/
String treasureToken = "Treasure Token";
/**
* Test with two players:
* A with Cultivate
* B with Smuggler's Share
*
* A plays Cultivate, B gets 1 Treasure token
*/
@Test
public void testTreasure() {
removeAllCardsFromLibrary(playerA);
addCard(Zone.BATTLEFIELD, playerB, smugglersShare, 1);
addCard(Zone.BATTLEFIELD, playerA, forest, 3);
addCard(Zone.LIBRARY, playerA, forest, 3);
addCard(Zone.HAND, playerA, cultivate, 1);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, cultivate);
addTarget(playerA, forest + "^" + forest);
setChoice(playerA, forest);
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, forest);
setStopAt(1, PhaseStep.CLEANUP);
execute();
assertAllCommandsUsed();
// 2 lands entered the battlefield under opponent's control, create Treasure token.
assertPermanentCount(playerB, treasureToken, 1);
}
/**
* Test with two players:
* A with Harmonize
* B with Smuggler's Share
*
* A plays Harmonize, B draws 1 card
*/
@Test
public void testDraw() {
assertHandCount(playerB, 0);
removeAllCardsFromLibrary(playerA);
addCard(Zone.BATTLEFIELD, playerB, smugglersShare, 1);
addCard(Zone.BATTLEFIELD, playerA, forest, 4);
addCard(Zone.LIBRARY, playerA, forest, 4);
addCard(Zone.HAND, playerA, harmonize, 1);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, harmonize);
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, forest);
setStopAt(1, PhaseStep.CLEANUP);
execute();
assertAllCommandsUsed();
// More than 2 cards were drawn by an opponent, draw a card.
assertHandCount(playerB, 1);
}
/**
* Test with two players:
* A with Harmonize and Cultivate
* B with Smuggler's Share
*
* A plays Harmonize, B draws 1 card
*/
@Test
public void testDrawAndTreasure() {
assertHandCount(playerB, 0);
removeAllCardsFromLibrary(playerA);
addCard(Zone.BATTLEFIELD, playerA, forest, 6);
addCard(Zone.BATTLEFIELD, playerB, smugglersShare, 1);
addCard(Zone.LIBRARY, playerA, forest, 6);
addCard(Zone.HAND, playerA, cultivate, 1);
addCard(Zone.HAND, playerA, harmonize, 1);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, cultivate);
addTarget(playerA, forest + "^" + forest);
setChoice(playerA, forest);
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, forest);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, harmonize);
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
setStopAt(1, PhaseStep.CLEANUP);
execute();
assertAllCommandsUsed();
// 2 lands entered the battlefield under opponent's control, create Treasure token.
assertPermanentCount(playerB, treasureToken, 1);
// More than 2 cards were drawn by an opponent, draw a card.
assertHandCount(playerB, 1);
}
/**
* Test with four players:
* A with Harmonize and Cultivate
* B with Chemister's Insight
* C with Harrow
* D with Smuggler's Share
*
* A plays Harmonize, B draws 1 card
*/
@Test
public void testMultipleOpponents() {
assertHandCount(playerB, 0);
removeAllCardsFromLibrary(playerA);
addCard(Zone.LIBRARY, playerA, forest, 6);
removeAllCardsFromLibrary(playerB);
addCard(Zone.LIBRARY, playerB, island, 2);
removeAllCardsFromLibrary(playerC);
addCard(Zone.LIBRARY, playerC, forest, 2);
addCard(Zone.BATTLEFIELD, playerA, forest, 6);
addCard(Zone.BATTLEFIELD, playerB, island, 4);
addCard(Zone.BATTLEFIELD, playerC, forest, 4);
addCard(Zone.BATTLEFIELD, playerD, smugglersShare, 1);
addCard(Zone.HAND, playerA, cultivate, 1);
addCard(Zone.HAND, playerA, harmonize, 1);
addCard(Zone.HAND, playerB, chemistersInsight, 1);
addCard(Zone.HAND, playerC, harrow, 1);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, cultivate);
addTarget(playerA, forest + "^" + forest);
setChoice(playerA, forest);
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, forest);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, harmonize);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, chemistersInsight);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerC, harrow);
setChoice(playerC, forest);
addTarget(playerC, forest + "^" + forest);
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
setStopAt(1, PhaseStep.CLEANUP);
execute();
assertAllCommandsUsed();
// 2 lands entered the battlefield for 2 different opponents, create 2 Treasure tokens.
assertPermanentCount(playerD, treasureToken, 2);
// More than 2 cards were drawn by 2 opponents, draw 2 cards.
assertHandCount(playerD, 2);
}
/**
* Test with two players:
* A with Smuggler's Share
* B with Harrow and Chemister's Insight
*
* B plays Harrow and Chemister's Insight, A plays Smuggler's Share, A draws 1 card and creates 1 Treasure token
*/
@Test
public void testDrawAndTreasureEarly() {
assertHandCount(playerA, 0);
addCard(Zone.BATTLEFIELD, playerB, forest, 4);
addCard(Zone.BATTLEFIELD, playerB, island, 4);
addCard(Zone.BATTLEFIELD, playerA, plains, 3);
removeAllCardsFromLibrary(playerB);
addCard(Zone.LIBRARY, playerB, forest, 5);
addCard(Zone.HAND, playerB, harrow, 1);
addCard(Zone.HAND, playerB, chemistersInsight, 1);
addCard(Zone.HAND, playerA, smugglersShare, 1);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, harrow);
setChoice(playerB, forest);
addTarget(playerB, forest + "^" + forest);
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, chemistersInsight);
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, smugglersShare);
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
setStopAt(1, PhaseStep.PRECOMBAT_MAIN);
execute();
assertAllCommandsUsed();
// 1 card drawn for turn
assertHandCount(playerA, 1);
// No treasure tokens created yet
assertPermanentCount(playerA, treasureToken, 0);
setStopAt(1, PhaseStep.CLEANUP);
execute();
assertAllCommandsUsed();
// 2 lands entered the battlefield under opponent's control, create Treasure token.
assertPermanentCount(playerA, treasureToken, 1);
// More than 2 cards were drawn by an opponent, draw a card.
assertHandCount(playerA, 2);
}
}