From 8375d6b6064a87985ff1d4b628b41b5a60961fe2 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Fri, 10 Oct 2025 13:56:39 -0400 Subject: [PATCH] rework partner variants, add tests --- .../src/mage/deck/AbstractCommander.java | 3 +- .../mage/cards/a/AbbyMercilessSoldier.java | 4 +- .../src/mage/cards/a/AtreusImpulsiveSon.java | 8 +- .../src/mage/cards/e/EllieBrickMaster.java | 3 +- .../src/mage/cards/e/EllieVengefulHunter.java | 8 +- .../mage/cards/j/JoelResoluteSurvivor.java | 4 +- .../deck/CommanderDeckValidationTest.java | 22 +++++ .../keyword/PartnerFatherAndSonAbility.java | 38 --------- .../keyword/PartnerSurvivorsAbility.java | 38 --------- .../mage/constants/PartnerVariantType.java | 80 +++++++++++++++++++ .../PartnerFatherAndSonValidator.java | 16 ---- .../validation/PartnerSurvivorsValidator.java | 16 ---- .../validation/PartnerVariantValidator.java | 16 ++++ 13 files changed, 128 insertions(+), 128 deletions(-) delete mode 100644 Mage/src/main/java/mage/abilities/keyword/PartnerFatherAndSonAbility.java delete mode 100644 Mage/src/main/java/mage/abilities/keyword/PartnerSurvivorsAbility.java create mode 100644 Mage/src/main/java/mage/constants/PartnerVariantType.java delete mode 100644 Mage/src/main/java/mage/util/validation/PartnerFatherAndSonValidator.java delete mode 100644 Mage/src/main/java/mage/util/validation/PartnerSurvivorsValidator.java create mode 100644 Mage/src/main/java/mage/util/validation/PartnerVariantValidator.java diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AbstractCommander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AbstractCommander.java index b90b5150ad1..e6b93fb521d 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AbstractCommander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AbstractCommander.java @@ -27,8 +27,7 @@ public abstract class AbstractCommander extends Constructed { private static List validators = Arrays.asList( PartnerValidator.instance, - PartnerSurvivorsValidator.instance, - PartnerFatherAndSonValidator.instance, + PartnerVariantValidator.instance, FriendsForeverValidator.instance, PartnerWithValidator.instance, ChooseABackgroundValidator.instance, diff --git a/Mage.Sets/src/mage/cards/a/AbbyMercilessSoldier.java b/Mage.Sets/src/mage/cards/a/AbbyMercilessSoldier.java index 768d6508925..8aac503b87c 100644 --- a/Mage.Sets/src/mage/cards/a/AbbyMercilessSoldier.java +++ b/Mage.Sets/src/mage/cards/a/AbbyMercilessSoldier.java @@ -6,10 +6,10 @@ import mage.abilities.dynamicvalue.common.ManaSpentToCastCount; import mage.abilities.effects.common.CastSourceTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.EntersBattlefieldUnderControlOfOpponentOfChoiceEffect; -import mage.abilities.keyword.PartnerSurvivorsAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.PartnerVariantType; import mage.constants.SubType; import mage.constants.SuperType; import mage.game.permanent.token.CordycepsInfectedToken; @@ -41,7 +41,7 @@ public final class AbbyMercilessSoldier extends CardImpl { this.addAbility(new EntersBattlefieldAbility(new EntersBattlefieldUnderControlOfOpponentOfChoiceEffect())); // Partner--Survivors - this.addAbility(PartnerSurvivorsAbility.getInstance()); + this.addAbility(PartnerVariantType.SURVIVORS.makeAbility()); } private AbbyMercilessSoldier(final AbbyMercilessSoldier card) { diff --git a/Mage.Sets/src/mage/cards/a/AtreusImpulsiveSon.java b/Mage.Sets/src/mage/cards/a/AtreusImpulsiveSon.java index 44e0980ea2d..6a9fea9455f 100644 --- a/Mage.Sets/src/mage/cards/a/AtreusImpulsiveSon.java +++ b/Mage.Sets/src/mage/cards/a/AtreusImpulsiveSon.java @@ -10,14 +10,10 @@ import mage.abilities.dynamicvalue.common.CountersControllerCount; import mage.abilities.effects.common.DamagePlayersEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.discard.DiscardControllerEffect; -import mage.abilities.keyword.PartnerFatherAndSonAbility; import mage.abilities.keyword.ReachAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.constants.TargetController; +import mage.constants.*; import mage.counters.CounterType; import java.util.UUID; @@ -50,7 +46,7 @@ public final class AtreusImpulsiveSon extends CardImpl { this.addAbility(ability); // Partner--Father & son - this.addAbility(PartnerFatherAndSonAbility.getInstance()); + this.addAbility(PartnerVariantType.FATHER_AND_SON.makeAbility()); } private AtreusImpulsiveSon(final AtreusImpulsiveSon card) { diff --git a/Mage.Sets/src/mage/cards/e/EllieBrickMaster.java b/Mage.Sets/src/mage/cards/e/EllieBrickMaster.java index e89acc2d5c8..53b6d244900 100644 --- a/Mage.Sets/src/mage/cards/e/EllieBrickMaster.java +++ b/Mage.Sets/src/mage/cards/e/EllieBrickMaster.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.OneShotEffect; -import mage.abilities.keyword.PartnerSurvivorsAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; @@ -34,7 +33,7 @@ public final class EllieBrickMaster extends CardImpl { this.addAbility(new EllieBrickMasterTriggeredAbility()); // Partner--Survivors - this.addAbility(PartnerSurvivorsAbility.getInstance()); + this.addAbility(PartnerVariantType.SURVIVORS.makeAbility()); } private EllieBrickMaster(final EllieBrickMaster card) { diff --git a/Mage.Sets/src/mage/cards/e/EllieVengefulHunter.java b/Mage.Sets/src/mage/cards/e/EllieVengefulHunter.java index dc328efafab..881c500b698 100644 --- a/Mage.Sets/src/mage/cards/e/EllieVengefulHunter.java +++ b/Mage.Sets/src/mage/cards/e/EllieVengefulHunter.java @@ -8,13 +8,9 @@ import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.IndestructibleAbility; -import mage.abilities.keyword.PartnerSurvivorsAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.SubType; -import mage.constants.SuperType; +import mage.constants.*; import mage.filter.StaticFilters; import mage.target.TargetPlayer; @@ -44,7 +40,7 @@ public final class EllieVengefulHunter extends CardImpl { this.addAbility(ability); // Partner--Survivors - this.addAbility(PartnerSurvivorsAbility.getInstance()); + this.addAbility(PartnerVariantType.SURVIVORS.makeAbility()); } private EllieVengefulHunter(final EllieVengefulHunter card) { diff --git a/Mage.Sets/src/mage/cards/j/JoelResoluteSurvivor.java b/Mage.Sets/src/mage/cards/j/JoelResoluteSurvivor.java index 213fa766283..786e680c57e 100644 --- a/Mage.Sets/src/mage/cards/j/JoelResoluteSurvivor.java +++ b/Mage.Sets/src/mage/cards/j/JoelResoluteSurvivor.java @@ -6,10 +6,10 @@ import mage.abilities.common.DiesCreatureTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.MenaceAbility; -import mage.abilities.keyword.PartnerSurvivorsAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.PartnerVariantType; import mage.constants.SubType; import mage.constants.SuperType; import mage.counters.CounterType; @@ -43,7 +43,7 @@ public final class JoelResoluteSurvivor extends CardImpl { this.addAbility(ability); // Partner--Survivors - this.addAbility(PartnerSurvivorsAbility.getInstance()); + this.addAbility(PartnerVariantType.SURVIVORS.makeAbility()); } private JoelResoluteSurvivor(final JoelResoluteSurvivor card) { diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/deck/CommanderDeckValidationTest.java b/Mage.Tests/src/test/java/org/mage/test/serverside/deck/CommanderDeckValidationTest.java index bc6b62530da..7c5eeb066f8 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/deck/CommanderDeckValidationTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/deck/CommanderDeckValidationTest.java @@ -143,6 +143,28 @@ public class CommanderDeckValidationTest extends MageTestPlayerBase { ); } + @Test + public void testPartnerVariants() { + DeckTester deckTester = new DeckTester(new Commander()); + deckTester.addMaindeck("Swamp", 98); + + deckTester.addSideboard("Ellie, Vengeful Hunter", 1); + deckTester.addSideboard("Joel, Resolute Survivor", 1); + + deckTester.validate("You can have two commanders if they both have the same Partner variant"); + } + + @Test(expected = AssertionError.class) + public void testPartnerVariants2() { + DeckTester deckTester = new DeckTester(new Commander()); + deckTester.addMaindeck("Mountain", 98); + + deckTester.addSideboard("Ellie, Vengeful Hunter", 1); + deckTester.addSideboard("Atreus, Impulsive Son", 1); + + deckTester.validate("You can't have two commanders if they don't have the same Partner variant"); + } + @Test() public void testVehicles1() { DeckTester deckTester = new DeckTester(new Commander()); diff --git a/Mage/src/main/java/mage/abilities/keyword/PartnerFatherAndSonAbility.java b/Mage/src/main/java/mage/abilities/keyword/PartnerFatherAndSonAbility.java deleted file mode 100644 index 222f6b65511..00000000000 --- a/Mage/src/main/java/mage/abilities/keyword/PartnerFatherAndSonAbility.java +++ /dev/null @@ -1,38 +0,0 @@ -package mage.abilities.keyword; - -import mage.abilities.MageSingleton; -import mage.abilities.StaticAbility; -import mage.constants.Zone; - -import java.io.ObjectStreamException; - -/** - * @author LevelX2 - */ -public class PartnerFatherAndSonAbility extends StaticAbility implements MageSingleton { - - private static final PartnerFatherAndSonAbility instance = new PartnerFatherAndSonAbility(); - - private Object readResolve() throws ObjectStreamException { - return instance; - } - - public static PartnerFatherAndSonAbility getInstance() { - return instance; - } - - private PartnerFatherAndSonAbility() { - super(Zone.BATTLEFIELD, null); - } - - @Override - public String getRule() { - return "Partner—Father & son (You can have two commanders if both have this ability.)"; - } - - @Override - public PartnerFatherAndSonAbility copy() { - return instance; - } - -} diff --git a/Mage/src/main/java/mage/abilities/keyword/PartnerSurvivorsAbility.java b/Mage/src/main/java/mage/abilities/keyword/PartnerSurvivorsAbility.java deleted file mode 100644 index 9693819ff8d..00000000000 --- a/Mage/src/main/java/mage/abilities/keyword/PartnerSurvivorsAbility.java +++ /dev/null @@ -1,38 +0,0 @@ -package mage.abilities.keyword; - -import mage.abilities.MageSingleton; -import mage.abilities.StaticAbility; -import mage.constants.Zone; - -import java.io.ObjectStreamException; - -/** - * @author LevelX2 - */ -public class PartnerSurvivorsAbility extends StaticAbility implements MageSingleton { - - private static final PartnerSurvivorsAbility instance = new PartnerSurvivorsAbility(); - - private Object readResolve() throws ObjectStreamException { - return instance; - } - - public static PartnerSurvivorsAbility getInstance() { - return instance; - } - - private PartnerSurvivorsAbility() { - super(Zone.BATTLEFIELD, null); - } - - @Override - public String getRule() { - return "Partner—Survivors (You can have two commanders if both have this ability.)"; - } - - @Override - public PartnerSurvivorsAbility copy() { - return instance; - } - -} diff --git a/Mage/src/main/java/mage/constants/PartnerVariantType.java b/Mage/src/main/java/mage/constants/PartnerVariantType.java new file mode 100644 index 00000000000..db3914a50b0 --- /dev/null +++ b/Mage/src/main/java/mage/constants/PartnerVariantType.java @@ -0,0 +1,80 @@ +package mage.constants; + +import mage.abilities.StaticAbility; +import mage.cards.Card; +import mage.util.CardUtil; + +import java.util.Set; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public enum PartnerVariantType { + FATHER_AND_SON("Father & son"), + SURVIVORS("Survivors"); + + private final String name; + + PartnerVariantType(String name) { + this.name = name; + } + + @Override + public String toString() { + return name; + } + + public PartnerVariantAbility makeAbility() { + return new PartnerVariantAbility(this); + } + + private static Set getTypes(Card card) { + return CardUtil + .castStream(card.getAbilities(), PartnerVariantAbility.class) + .map(PartnerVariantAbility::getType) + .collect(Collectors.toSet()); + } + + public static boolean checkCommanders(Card commander1, Card commander2) { + Set types1 = getTypes(commander1); + if (types1.isEmpty()) { + return false; + } + Set types2 = getTypes(commander2); + if (types2.isEmpty()) { + return false; + } + types1.retainAll(types2); + return !types1.isEmpty(); + } +} + +class PartnerVariantAbility extends StaticAbility { + + private final PartnerVariantType type; + + PartnerVariantAbility(PartnerVariantType type) { + super(Zone.BATTLEFIELD, null); + this.type = type; + } + + private PartnerVariantAbility(final PartnerVariantAbility ability) { + super(ability); + this.type = ability.type; + } + + @Override + public PartnerVariantAbility copy() { + return new PartnerVariantAbility(this); + } + + public PartnerVariantType getType() { + return type; + } + + @Override + public String getRule() { + return "Partner—" + type + " (You can have two commanders if both have this ability.)"; + } +} diff --git a/Mage/src/main/java/mage/util/validation/PartnerFatherAndSonValidator.java b/Mage/src/main/java/mage/util/validation/PartnerFatherAndSonValidator.java deleted file mode 100644 index 17b1d3b18fe..00000000000 --- a/Mage/src/main/java/mage/util/validation/PartnerFatherAndSonValidator.java +++ /dev/null @@ -1,16 +0,0 @@ -package mage.util.validation; - -import mage.abilities.keyword.PartnerFatherAndSonAbility; -import mage.cards.Card; - -/** - * @author TheElk801 - */ -public enum PartnerFatherAndSonValidator implements CommanderValidator { - instance; - - @Override - public boolean checkPartner(Card commander1, Card commander2) { - return commander1.getAbilities().containsClass(PartnerFatherAndSonAbility.class); - } -} diff --git a/Mage/src/main/java/mage/util/validation/PartnerSurvivorsValidator.java b/Mage/src/main/java/mage/util/validation/PartnerSurvivorsValidator.java deleted file mode 100644 index 46e086fae85..00000000000 --- a/Mage/src/main/java/mage/util/validation/PartnerSurvivorsValidator.java +++ /dev/null @@ -1,16 +0,0 @@ -package mage.util.validation; - -import mage.abilities.keyword.PartnerSurvivorsAbility; -import mage.cards.Card; - -/** - * @author TheElk801 - */ -public enum PartnerSurvivorsValidator implements CommanderValidator { - instance; - - @Override - public boolean checkPartner(Card commander1, Card commander2) { - return commander1.getAbilities().containsClass(PartnerSurvivorsAbility.class); - } -} diff --git a/Mage/src/main/java/mage/util/validation/PartnerVariantValidator.java b/Mage/src/main/java/mage/util/validation/PartnerVariantValidator.java new file mode 100644 index 00000000000..3084502ab91 --- /dev/null +++ b/Mage/src/main/java/mage/util/validation/PartnerVariantValidator.java @@ -0,0 +1,16 @@ +package mage.util.validation; + +import mage.cards.Card; +import mage.constants.PartnerVariantType; + +/** + * @author TheElk801 + */ +public enum PartnerVariantValidator implements CommanderValidator { + instance; + + @Override + public boolean checkPartner(Card commander1, Card commander2) { + return PartnerVariantType.checkCommanders(commander1, commander2); + } +}