mirror of
https://github.com/magefree/mage.git
synced 2025-12-20 02:30:08 -08:00
[PIP] Implement Struggle for Project Purity (part of #11324)
This commit is contained in:
parent
e408836a19
commit
0612431ab2
3 changed files with 287 additions and 4 deletions
156
Mage.Sets/src/mage/cards/s/StruggleForProjectPurity.java
Normal file
156
Mage.Sets/src/mage/cards/s/StruggleForProjectPurity.java
Normal file
|
|
@ -0,0 +1,156 @@
|
||||||
|
package mage.cards.s;
|
||||||
|
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.TriggeredAbilityImpl;
|
||||||
|
import mage.abilities.common.EntersBattlefieldAbility;
|
||||||
|
import mage.abilities.condition.common.ModeChoiceSourceCondition;
|
||||||
|
import mage.abilities.decorator.ConditionalTriggeredAbility;
|
||||||
|
import mage.abilities.dynamicvalue.common.StaticValue;
|
||||||
|
import mage.abilities.effects.Effect;
|
||||||
|
import mage.abilities.effects.OneShotEffect;
|
||||||
|
import mage.abilities.effects.common.ChooseModeEffect;
|
||||||
|
import mage.abilities.effects.common.counter.AddCountersTargetEffect;
|
||||||
|
import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
|
||||||
|
import mage.cards.CardImpl;
|
||||||
|
import mage.cards.CardSetInfo;
|
||||||
|
import mage.constants.CardType;
|
||||||
|
import mage.constants.Outcome;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import mage.counters.CounterType;
|
||||||
|
import mage.filter.common.FilterCreaturePermanent;
|
||||||
|
import mage.filter.predicate.permanent.ControllerIdPredicate;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.game.events.GameEvent;
|
||||||
|
import mage.players.Player;
|
||||||
|
import mage.target.targetpointer.FixedTarget;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author JayDi85
|
||||||
|
*/
|
||||||
|
public final class StruggleForProjectPurity extends CardImpl {
|
||||||
|
|
||||||
|
private static final String ruleTrigger1 = "&bull Brotherhood — At the beginning of your upkeep, each opponent draws a card. You draw a card for each card drawn this way.";
|
||||||
|
private static final String ruleTrigger2 = "&bull Enclave — Whenever a player attacks you with one or more creatures, that player gets twice that many rad counters.";
|
||||||
|
|
||||||
|
public StruggleForProjectPurity(UUID ownerId, CardSetInfo setInfo) {
|
||||||
|
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{U}");
|
||||||
|
|
||||||
|
// As Struggle for Project Purity enters, choose Brotherhood or Enclave.
|
||||||
|
this.addAbility(new EntersBattlefieldAbility(new ChooseModeEffect("Brotherhood or Enclave?", "Brotherhood", "Enclave"), null,
|
||||||
|
"As {this} enters, choose Brotherhood or Enclave.", ""));
|
||||||
|
|
||||||
|
// * Brotherhood - At the beginning of your upkeep, each opponent draws a card. You draw a card for each card drawn this way.
|
||||||
|
Ability ability = new ConditionalTriggeredAbility(
|
||||||
|
new BeginningOfUpkeepTriggeredAbility(new StruggleForProjectDrawEffect()),
|
||||||
|
new ModeChoiceSourceCondition("Brotherhood"),
|
||||||
|
ruleTrigger1);
|
||||||
|
this.addAbility(ability);
|
||||||
|
|
||||||
|
// * Enclave - Whenever a player attacks you with one or more creatures, that player gets twice that many rad counters.
|
||||||
|
ability = new ConditionalTriggeredAbility(
|
||||||
|
new StruggleForProjectRadCountersTriggeredAbility(),
|
||||||
|
new ModeChoiceSourceCondition("Enclave"),
|
||||||
|
ruleTrigger2);
|
||||||
|
this.addAbility(ability);
|
||||||
|
}
|
||||||
|
|
||||||
|
private StruggleForProjectPurity(final StruggleForProjectPurity card) {
|
||||||
|
super(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StruggleForProjectPurity copy() {
|
||||||
|
return new StruggleForProjectPurity(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StruggleForProjectDrawEffect extends OneShotEffect {
|
||||||
|
|
||||||
|
StruggleForProjectDrawEffect() {
|
||||||
|
super(Outcome.DrawCard);
|
||||||
|
this.staticText = "Each opponent draws a card. You draw a card for each card drawn this way.";
|
||||||
|
}
|
||||||
|
|
||||||
|
private StruggleForProjectDrawEffect(final StruggleForProjectDrawEffect effect) {
|
||||||
|
super(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StruggleForProjectDrawEffect copy() {
|
||||||
|
return new StruggleForProjectDrawEffect(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
Player controller = game.getPlayer(source.getControllerId());
|
||||||
|
if (controller == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int count = game
|
||||||
|
.getOpponents(source.getControllerId(), true)
|
||||||
|
.stream()
|
||||||
|
.map(game::getPlayer)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.mapToInt(player -> player.drawCards(1, source, game))
|
||||||
|
.sum();
|
||||||
|
if (count > 0) {
|
||||||
|
controller.drawCards(count, source, game);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StruggleForProjectRadCountersTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
|
public StruggleForProjectRadCountersTriggeredAbility() {
|
||||||
|
super(Zone.BATTLEFIELD, null);
|
||||||
|
setTriggerPhrase("Whenever a player attacks you with one or more creatures, ");
|
||||||
|
}
|
||||||
|
|
||||||
|
private StruggleForProjectRadCountersTriggeredAbility(final StruggleForProjectRadCountersTriggeredAbility ability) {
|
||||||
|
super(ability);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StruggleForProjectRadCountersTriggeredAbility copy() {
|
||||||
|
return new StruggleForProjectRadCountersTriggeredAbility(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkEventType(GameEvent event, Game game) {
|
||||||
|
return event.getType() == GameEvent.EventType.DECLARED_ATTACKERS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkTrigger(GameEvent event, Game game) {
|
||||||
|
Player attackingPlayer = game.getPlayer(event.getPlayerId());
|
||||||
|
if (attackingPlayer == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<UUID> attackersOnYou = game.getCombat().getGroups().stream()
|
||||||
|
.filter(g -> Objects.equals(g.getDefenderId(), getControllerId()))
|
||||||
|
.flatMap(g -> g.getAttackers().stream())
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
if (attackersOnYou.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.getEffects().clear();
|
||||||
|
FilterCreaturePermanent filter = new FilterCreaturePermanent();
|
||||||
|
filter.add(new ControllerIdPredicate(event.getPlayerId()));
|
||||||
|
Effect effect = new AddCountersTargetEffect(
|
||||||
|
CounterType.RAD.createInstance(),
|
||||||
|
StaticValue.get(attackersOnYou.size() * 2)
|
||||||
|
);
|
||||||
|
effect.setTargetPointer(new FixedTarget(attackingPlayer.getId()));
|
||||||
|
this.getEffects().add(effect);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -839,10 +839,10 @@ public final class Fallout extends ExpansionSet {
|
||||||
//cards.add(new SetCardInfo("Strong, the Brutish Thespian", 612, Rarity.RARE, mage.cards.s.StrongTheBrutishThespian.class, NON_FULL_USE_VARIOUS));
|
//cards.add(new SetCardInfo("Strong, the Brutish Thespian", 612, Rarity.RARE, mage.cards.s.StrongTheBrutishThespian.class, NON_FULL_USE_VARIOUS));
|
||||||
//cards.add(new SetCardInfo("Strong, the Brutish Thespian", 84, Rarity.RARE, mage.cards.s.StrongTheBrutishThespian.class, NON_FULL_USE_VARIOUS));
|
//cards.add(new SetCardInfo("Strong, the Brutish Thespian", 84, Rarity.RARE, mage.cards.s.StrongTheBrutishThespian.class, NON_FULL_USE_VARIOUS));
|
||||||
//cards.add(new SetCardInfo("Strong, the Brutish Thespian", 931, Rarity.RARE, mage.cards.s.StrongTheBrutishThespian.class, NON_FULL_USE_VARIOUS));
|
//cards.add(new SetCardInfo("Strong, the Brutish Thespian", 931, Rarity.RARE, mage.cards.s.StrongTheBrutishThespian.class, NON_FULL_USE_VARIOUS));
|
||||||
//cards.add(new SetCardInfo("Struggle for Project Purity", 380, Rarity.RARE, mage.cards.s.StruggleForProjectPurity.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Struggle for Project Purity", 380, Rarity.RARE, mage.cards.s.StruggleForProjectPurity.class, NON_FULL_USE_VARIOUS));
|
||||||
//cards.add(new SetCardInfo("Struggle for Project Purity", 39, Rarity.RARE, mage.cards.s.StruggleForProjectPurity.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Struggle for Project Purity", 39, Rarity.RARE, mage.cards.s.StruggleForProjectPurity.class, NON_FULL_USE_VARIOUS));
|
||||||
//cards.add(new SetCardInfo("Struggle for Project Purity", 567, Rarity.RARE, mage.cards.s.StruggleForProjectPurity.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Struggle for Project Purity", 567, Rarity.RARE, mage.cards.s.StruggleForProjectPurity.class, NON_FULL_USE_VARIOUS));
|
||||||
//cards.add(new SetCardInfo("Struggle for Project Purity", 908, Rarity.RARE, mage.cards.s.StruggleForProjectPurity.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Struggle for Project Purity", 908, Rarity.RARE, mage.cards.s.StruggleForProjectPurity.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Sulfur Falls", 1040, Rarity.RARE, mage.cards.s.SulfurFalls.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Sulfur Falls", 1040, Rarity.RARE, mage.cards.s.SulfurFalls.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Sulfur Falls", 294, Rarity.RARE, mage.cards.s.SulfurFalls.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Sulfur Falls", 294, Rarity.RARE, mage.cards.s.SulfurFalls.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Sulfur Falls", 512, Rarity.RARE, mage.cards.s.SulfurFalls.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Sulfur Falls", 512, Rarity.RARE, mage.cards.s.SulfurFalls.class, NON_FULL_USE_VARIOUS));
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,127 @@
|
||||||
|
package org.mage.test.cards.single.pip;
|
||||||
|
|
||||||
|
import mage.constants.PhaseStep;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import mage.counters.CounterType;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mage.test.serverside.base.CardTestCommander4Players;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author JayDi85
|
||||||
|
*/
|
||||||
|
public class StruggleForProjectPurityTest extends CardTestCommander4Players {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link mage.cards.s.StruggleForProjectPurity Struggle for Project Purity}
|
||||||
|
* {3}{U}
|
||||||
|
* Enchantment
|
||||||
|
* As Struggle for Project Purity enters, choose Brotherhood or Enclave.
|
||||||
|
* • Brotherhood — At the beginning of your upkeep, each opponent draws a card. You draw a card for each card drawn this way.
|
||||||
|
* • Enclave — Whenever a player attacks you with one or more creatures, that player gets twice that many rad counters.
|
||||||
|
*/
|
||||||
|
private static final String struggle = "Struggle for Project Purity";
|
||||||
|
|
||||||
|
private void checkRadCounters(String info, int needA, int needB, int needC, int needD) {
|
||||||
|
Assert.assertEquals(info + ", rad counter on playerA", needA, playerA.getCountersCount(CounterType.RAD));
|
||||||
|
Assert.assertEquals(info + ", rad counter on playerB", needB, playerB.getCountersCount(CounterType.RAD));
|
||||||
|
Assert.assertEquals(info + ", rad counter on playerC", needC, playerC.getCountersCount(CounterType.RAD));
|
||||||
|
Assert.assertEquals(info + ", rad counter on playerD", needD, playerD.getCountersCount(CounterType.RAD));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_Brotherhood() {
|
||||||
|
// Player order: A -> D -> C -> B
|
||||||
|
|
||||||
|
// Brotherhood — At the beginning of your upkeep, each opponent draws a card. You draw a card for each card drawn this way.
|
||||||
|
addCard(Zone.HAND, playerA, struggle);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 4);
|
||||||
|
|
||||||
|
checkHandCount("before cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 2); // struggle + starting draw
|
||||||
|
|
||||||
|
// turn 1 - A - prepare brotherhood, no triggers
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, struggle);
|
||||||
|
setChoice(playerA, "Brotherhood");
|
||||||
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
|
||||||
|
// turn 2 - D - no triggers
|
||||||
|
checkHandCount("no draws on turn 2", 2, PhaseStep.PRECOMBAT_MAIN, playerA, 1);
|
||||||
|
|
||||||
|
// turn 3 - C - no triggers
|
||||||
|
checkHandCount("no draws on turn 3", 3, PhaseStep.PRECOMBAT_MAIN, playerA, 1);
|
||||||
|
|
||||||
|
// turn 4 - B - no triggers
|
||||||
|
checkHandCount("no draws on turn 4", 4, PhaseStep.PRECOMBAT_MAIN, playerA, 1);
|
||||||
|
|
||||||
|
// turn 5 - A - trigger
|
||||||
|
// opponent draw: +1
|
||||||
|
// you draw: +3
|
||||||
|
checkHandCount("draws trigger", 5, PhaseStep.PRECOMBAT_MAIN, playerA, 1 + 1 + 3); // draw 1 + draw 5 + draw trigger
|
||||||
|
checkHandCount("draws trigger", 5, PhaseStep.PRECOMBAT_MAIN, playerB, 2); // opponent turn + trigger
|
||||||
|
checkHandCount("draws trigger", 5, PhaseStep.PRECOMBAT_MAIN, playerC, 2); // opponent turn + trigger
|
||||||
|
checkHandCount("draws trigger", 5, PhaseStep.PRECOMBAT_MAIN, playerD, 2); // opponent turn + trigger
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(5, PhaseStep.BEGIN_COMBAT);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertPermanentCount(playerA, struggle, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_Enclave() {
|
||||||
|
// Player order: A -> D -> C -> B
|
||||||
|
|
||||||
|
// Enclave — Whenever a player attacks you with one or more creatures, that player gets twice that many rad counters.
|
||||||
|
addCard(Zone.HAND, playerA, struggle);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 4);
|
||||||
|
//
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears", 2);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Grizzly Bears", 2);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerC, "Grizzly Bears", 2);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerD, "Grizzly Bears", 2);
|
||||||
|
|
||||||
|
checkHandCount("before cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 2); // struggle + starting draw
|
||||||
|
runCode("rad count playerA turn 1", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> checkRadCounters(info, 0, 0, 0, 0));
|
||||||
|
|
||||||
|
// turn 1
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, struggle);
|
||||||
|
setChoice(playerA, "Enclave");
|
||||||
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
|
||||||
|
// turn 1
|
||||||
|
attack(1, playerA, "Grizzly Bears", playerD);
|
||||||
|
attack(1, playerA, "Grizzly Bears", playerD);
|
||||||
|
runCode("A attacked D on turn 1", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, (info, player, game) -> checkRadCounters(info, 0, 0, 0, 0));
|
||||||
|
|
||||||
|
// turn 2
|
||||||
|
attack(2, playerD, "Grizzly Bears", playerA); // <<< trigger for D
|
||||||
|
attack(2, playerD, "Grizzly Bears", playerA);
|
||||||
|
runCode("D attacked A on turn 2", 2, PhaseStep.POSTCOMBAT_MAIN, playerA, (info, player, game) -> checkRadCounters(info, 0, 0, 0, 2 * 2));
|
||||||
|
|
||||||
|
// turn 3
|
||||||
|
attack(3, playerC, "Grizzly Bears", playerB);
|
||||||
|
attack(3, playerC, "Grizzly Bears", playerB);
|
||||||
|
runCode("B attacked B on turn 3", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, (info, player, game) -> checkRadCounters(info, 0, 0, 0, 2 * 2));
|
||||||
|
|
||||||
|
// turn 4
|
||||||
|
attack(4, playerB, "Grizzly Bears", playerA); // <<< trigger for B
|
||||||
|
attack(4, playerB, "Grizzly Bears", playerA);
|
||||||
|
runCode("B attacked A on turn 4", 4, PhaseStep.POSTCOMBAT_MAIN, playerA, (info, player, game) -> checkRadCounters(info, 0, 2 * 2, 0, 2 * 2));
|
||||||
|
|
||||||
|
// turn 5
|
||||||
|
attack(5, playerA, "Grizzly Bears", playerD);
|
||||||
|
attack(5, playerA, "Grizzly Bears", playerD);
|
||||||
|
runCode("A attacked D on turn 5", 5, PhaseStep.POSTCOMBAT_MAIN, playerA, (info, player, game) -> checkRadCounters(info, 0, 2 * 2, 0, 2 * 2));
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(5, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertPermanentCount(playerA, struggle, 1);
|
||||||
|
assertLife(playerA, 20 - 2 * 2 - 2 * 2); // from D and B
|
||||||
|
assertLife(playerB, 20 - 2 * 2); // from C
|
||||||
|
assertLife(playerC, 20); // no attackers
|
||||||
|
assertLife(playerD, 20 - 2 * 2 - 2 * 2); // from A and A
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue