[PIP] Implement Struggle for Project Purity (part of #11324)

This commit is contained in:
Oleg Agafonov 2025-02-08 02:00:43 +04:00
parent e408836a19
commit 0612431ab2
3 changed files with 287 additions and 4 deletions

View 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;
}
}

View file

@ -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));

View file

@ -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
}
}