diff --git a/Mage.Server.Plugins/Mage.Game.OathbreakerFreeForAll/src/mage/game/OathbreakerFreeForAll.java b/Mage.Server.Plugins/Mage.Game.OathbreakerFreeForAll/src/mage/game/OathbreakerFreeForAll.java index 323fda1d684..55066b6f6f5 100644 --- a/Mage.Server.Plugins/Mage.Game.OathbreakerFreeForAll/src/mage/game/OathbreakerFreeForAll.java +++ b/Mage.Server.Plugins/Mage.Game.OathbreakerFreeForAll/src/mage/game/OathbreakerFreeForAll.java @@ -8,6 +8,7 @@ import mage.abilities.condition.common.OathbreakerOnBattlefieldCondition; import mage.abilities.effects.common.InfoEffect; import mage.abilities.hint.ConditionHint; import mage.cards.Card; +import mage.constants.CommanderCardType; import mage.constants.MultiplayerAttackOption; import mage.constants.RangeOfInfluence; import mage.game.match.MatchType; @@ -138,4 +139,33 @@ public class OathbreakerFreeForAll extends GameCommanderImpl { public OathbreakerFreeForAll copy() { return new OathbreakerFreeForAll(this); } + + @Override + public Set getCommandersIds(Player player, CommanderCardType commanderCardType) { + Set res = new HashSet<>(); + if (player != null) { + List commanders = this.playerCommanders.getOrDefault(player.getId(), new ArrayList<>()); + UUID spell = this.playerSignatureSpell.getOrDefault(player.getId(), null); + for (UUID id : player.getCommandersIds()) { + switch (commanderCardType) { + case ANY: + res.add(id); + break; + case COMMANDER_OR_OATHBREAKER: + if (commanders.contains(id)) { + res.add(id); + } + break; + case SIGNATURE_SPELL: + if (id.equals(spell)) { + res.add(id); + } + break; + default: + throw new IllegalStateException("Unknown commander type " + commanderCardType); + } + } + } + return res; + } } diff --git a/Mage.Sets/src/mage/cards/a/ArcaneAdaptation.java b/Mage.Sets/src/mage/cards/a/ArcaneAdaptation.java index 56674534e04..fb1a7691d33 100644 --- a/Mage.Sets/src/mage/cards/a/ArcaneAdaptation.java +++ b/Mage.Sets/src/mage/cards/a/ArcaneAdaptation.java @@ -93,7 +93,7 @@ class ConspyEffect extends ContinuousEffectImpl { } } // commander in command zone - for (UUID commanderId : controller.getCommandersIds()) { + for (UUID commanderId : game.getCommandersIds(controller)) { if (game.getState().getZone(commanderId) == Zone.COMMAND) { Card card = game.getCard(commanderId); if (card != null && card.isCreature() && !card.hasSubtype(subType, game)) { diff --git a/Mage.Sets/src/mage/cards/c/CommandBeacon.java b/Mage.Sets/src/mage/cards/c/CommandBeacon.java index 22413ce686e..cedd962fac9 100644 --- a/Mage.Sets/src/mage/cards/c/CommandBeacon.java +++ b/Mage.Sets/src/mage/cards/c/CommandBeacon.java @@ -1,9 +1,5 @@ - package mage.cards.c; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeSourceCost; @@ -14,19 +10,23 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.CommanderCardType; import mage.constants.Outcome; import mage.constants.Zone; import mage.game.Game; import mage.players.Player; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + /** - * * @author emerald000 */ public final class CommandBeacon extends CardImpl { public CommandBeacon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.LAND},""); + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); // {T}: Add {C}. this.addAbility(new ColorlessManaAbility()); @@ -67,7 +67,7 @@ class CommandBeaconEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { List commandersInCommandZone = new ArrayList<>(1); - for (UUID commanderId : controller.getCommandersIds()) { + for (UUID commanderId : game.getCommandersIds(controller, CommanderCardType.COMMANDER_OR_OATHBREAKER)) { Card commander = game.getCard(commanderId); if (commander != null && game.getState().getZone(commander.getId()) == Zone.COMMAND) { commandersInCommandZone.add(commander); @@ -75,14 +75,12 @@ class CommandBeaconEffect extends OneShotEffect { } if (commandersInCommandZone.size() == 1) { controller.moveCards(commandersInCommandZone.get(0), Zone.HAND, source, game); - } - else if (commandersInCommandZone.size() == 2) { + } else if (commandersInCommandZone.size() == 2) { Card firstCommander = commandersInCommandZone.get(0); Card secondCommander = commandersInCommandZone.get(1); if (controller.chooseUse(Outcome.ReturnToHand, "Return which commander to hand?", null, firstCommander.getName(), secondCommander.getName(), source, game)) { controller.moveCards(firstCommander, Zone.HAND, source, game); - } - else { + } else { controller.moveCards(secondCommander, Zone.HAND, source, game); } } diff --git a/Mage.Sets/src/mage/cards/c/Conspiracy.java b/Mage.Sets/src/mage/cards/c/Conspiracy.java index 934ebd7db95..2fb5ee65265 100644 --- a/Mage.Sets/src/mage/cards/c/Conspiracy.java +++ b/Mage.Sets/src/mage/cards/c/Conspiracy.java @@ -95,7 +95,7 @@ class ConspiracyEffect extends ContinuousEffectImpl { } } // commander in command zone - for (UUID commanderId : controller.getCommandersIds()) { + for (UUID commanderId : game.getCommandersIds(controller)) { if (game.getState().getZone(commanderId) == Zone.COMMAND) { Card card = game.getCard(commanderId); if (card != null && card.isCreature()) { diff --git a/Mage.Sets/src/mage/cards/k/KarnLiberated.java b/Mage.Sets/src/mage/cards/k/KarnLiberated.java index 1c3779d9e49..ecc83a1a607 100644 --- a/Mage.Sets/src/mage/cards/k/KarnLiberated.java +++ b/Mage.Sets/src/mage/cards/k/KarnLiberated.java @@ -109,8 +109,9 @@ class KarnLiberatedEffect extends OneShotEffect { if (card.isOwnedBy(player.getId()) && !card.isCopy() // no copies && !player.getSideboard().contains(card.getId()) && !cards.contains(card)) { // not the exiled cards - if (player.getCommandersIds().contains(card.getId())) { - game.addCommander(new Commander(card)); + if (game.getCommandersIds(player).contains(card.getId())) { + game.addCommander(new Commander(card)); // TODO: check restart and init + // no needs in initCommander call -- it's uses on game startup (init) game.setZone(card.getId(), Zone.COMMAND); } else { player.getLibrary().putOnTop(card, game); diff --git a/Mage.Sets/src/mage/cards/m/MythUnbound.java b/Mage.Sets/src/mage/cards/m/MythUnbound.java index 6e23fdbbc8c..cf9ce5e0134 100644 --- a/Mage.Sets/src/mage/cards/m/MythUnbound.java +++ b/Mage.Sets/src/mage/cards/m/MythUnbound.java @@ -95,7 +95,7 @@ class MythUnboundCostReductionEffect extends CostModificationEffectImpl { if (abilityToModify instanceof SpellAbility || abilityToModify instanceof PlayLandAbility) { if (abilityToModify.isControlledBy(source.getControllerId())) { - return player.getCommandersIds().contains(abilityToModify.getSourceId()); + return game.getCommandersIds(player).contains(abilityToModify.getSourceId()); } } return false; diff --git a/Mage.Sets/src/mage/cards/o/OpalPalace.java b/Mage.Sets/src/mage/cards/o/OpalPalace.java index 92fa165d6a4..1ab89afe676 100644 --- a/Mage.Sets/src/mage/cards/o/OpalPalace.java +++ b/Mage.Sets/src/mage/cards/o/OpalPalace.java @@ -93,7 +93,7 @@ class OpalPalaceWatcher extends Watcher { for (UUID playerId : game.getPlayerList()) { Player player = game.getPlayer(playerId); if (player != null) { - if (player.getCommandersIds().contains(card.getId())) { + if (game.getCommandersIds(player).contains(card.getId())) { commanderId.add(card.getId()); break; } diff --git a/Mage.Sets/src/mage/cards/p/PathOfAncestry.java b/Mage.Sets/src/mage/cards/p/PathOfAncestry.java index 9e490d07baf..82a171c7a79 100644 --- a/Mage.Sets/src/mage/cards/p/PathOfAncestry.java +++ b/Mage.Sets/src/mage/cards/p/PathOfAncestry.java @@ -1,7 +1,5 @@ package mage.cards.p; -import java.util.Iterator; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; @@ -22,8 +20,11 @@ import mage.game.permanent.Permanent; import mage.game.stack.Spell; import mage.players.Player; +import java.util.Iterator; +import java.util.Set; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class PathOfAncestry extends CardImpl { @@ -88,9 +89,10 @@ class PathOfAncestryTriggeredAbility extends TriggeredAbilityImpl { Spell spell = game.getStack().getSpell(event.getTargetId()); if (spell != null && spell.isCreature()) { Player controller = game.getPlayer(getControllerId()); - if (controller != null && controller.getCommandersIds() != null && !controller.getCommandersIds().isEmpty()) { + Set commanders = game.getCommandersIds(controller); + if (controller != null && commanders != null && !commanders.isEmpty()) { if (spell.getAbilities().contains(ChangelingAbility.getInstance())) { - for (UUID cmdr : controller.getCommandersIds()) { + for (UUID cmdr : commanders) { MageObject commander = game.getObject(cmdr); if (commander != null) { if (commander.getAbilities().contains(ChangelingAbility.getInstance())) { @@ -110,7 +112,7 @@ class PathOfAncestryTriggeredAbility extends TriggeredAbilityImpl { while (spellSubs.hasNext()) { SubType sType = spellSubs.next(); if (sType.getSubTypeSet() == SubTypeSet.CreatureType) { - for (UUID cmdr : controller.getCommandersIds()) { + for (UUID cmdr : commanders) { MageObject commander = game.getObject(cmdr); if (commander != null && (commander.hasSubtype(sType, game) || commander.getAbilities().contains(ChangelingAbility.getInstance()))) { return true; diff --git a/Mage.Sets/src/mage/cards/t/TeferiMageOfZhalfir.java b/Mage.Sets/src/mage/cards/t/TeferiMageOfZhalfir.java index cdc5ecb0c9a..e1efa6ce2df 100644 --- a/Mage.Sets/src/mage/cards/t/TeferiMageOfZhalfir.java +++ b/Mage.Sets/src/mage/cards/t/TeferiMageOfZhalfir.java @@ -99,7 +99,7 @@ class TeferiMageOfZhalfirAddFlashEffect extends ContinuousEffectImpl { } } // commander in command zone - for (UUID commanderId : controller.getCommandersIds()) { + for (UUID commanderId : game.getCommandersIds(controller)) { if (game.getState().getZone(commanderId) == Zone.COMMAND) { Card card = game.getCard(commanderId); if (card != null && card.isCreature()) { diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java index e0e3b0006b3..2f11fbd5307 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java @@ -750,7 +750,7 @@ public class TestPlayer implements Player { // show command if (params[0].equals(SHOW_COMMAND_COMMAND) && params.length == 1) { printStart(action.getActionName()); - CardsImpl cards = new CardsImpl(computerPlayer.getCommandersIds()); + CardsImpl cards = new CardsImpl(game.getCommandersIds(computerPlayer)); printCards(cards.getCards(game)); printEnd(); actions.remove(action); diff --git a/Mage/src/main/java/mage/abilities/condition/common/CommanderInPlayCondition.java b/Mage/src/main/java/mage/abilities/condition/common/CommanderInPlayCondition.java index ac0d85ce0e3..28e8f13ca8f 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/CommanderInPlayCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/CommanderInPlayCondition.java @@ -1,8 +1,8 @@ - package mage.abilities.condition.common; import mage.abilities.Ability; import mage.abilities.condition.Condition; +import mage.constants.CommanderCardType; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -22,7 +22,7 @@ public enum CommanderInPlayCondition implements Condition { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - for (UUID commanderId : controller.getCommandersIds()) { + for (UUID commanderId : game.getCommandersIds(controller, CommanderCardType.COMMANDER_OR_OATHBREAKER)) { Permanent commander = game.getPermanent(commanderId); if (commander != null && commander.isControlledBy(source.getControllerId())) { return true; diff --git a/Mage/src/main/java/mage/abilities/keyword/CommanderStormAbility.java b/Mage/src/main/java/mage/abilities/keyword/CommanderStormAbility.java index fb0d3beb18b..7a7e10b7406 100644 --- a/Mage/src/main/java/mage/abilities/keyword/CommanderStormAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/CommanderStormAbility.java @@ -5,6 +5,7 @@ import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; +import mage.constants.CommanderCardType; import mage.constants.Outcome; import mage.constants.Zone; import mage.game.Game; @@ -83,7 +84,7 @@ class CommanderStormEffect extends OneShotEffect { if (player == null) { return false; } - stormCount = player.getCommandersIds().stream() + stormCount = game.getCommandersIds(player, CommanderCardType.COMMANDER_OR_OATHBREAKER).stream() .map((commanderId) -> game.getState().getWatcher(CommanderPlaysCountWatcher.class).getPlaysCount(commanderId)) .reduce(stormCount, Integer::sum); if (stormCount == 0) { diff --git a/Mage/src/main/java/mage/abilities/keyword/NinjutsuAbility.java b/Mage/src/main/java/mage/abilities/keyword/NinjutsuAbility.java index e63ae4d5a2d..157a173354b 100644 --- a/Mage/src/main/java/mage/abilities/keyword/NinjutsuAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/NinjutsuAbility.java @@ -1,6 +1,5 @@ package mage.abilities.keyword; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.ActivatedAbilityImpl; import mage.abilities.costs.Cost; @@ -21,24 +20,25 @@ import mage.players.Player; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetControlledPermanent; +import java.util.UUID; + /** * 702.47. Ninjutsu - * + *

* 702.47a Ninjutsu is an activated ability that functions only while the card * with ninjutsu is in a player's hand. "Ninjutsu [cost]" means "[Cost], Reveal * this card from your hand, Return an unblocked attacking creature you control * to its owner's hand: Put this card onto the battlefield from your hand tapped * and attacking." - * + *

* 702.47b The card with ninjutsu remains revealed from the time the ability is * announced until the ability leaves the stack. - * + *

* 702.47c A ninjutsu ability may be activated only while a creature on the * battlefield is unblocked (see rule 509.1h). The creature with ninjutsu is put * onto the battlefield unblocked. It will be attacking the same player or * planeswalker as the creature that was returned to its owner's hand. * - * * @author LevelX2 */ public class NinjutsuAbility extends ActivatedAbilityImpl { @@ -51,7 +51,6 @@ public class NinjutsuAbility extends ActivatedAbilityImpl { } /** - * * @param manaCost ninjutsu mana cost */ public NinjutsuAbility(ManaCost manaCost) { @@ -195,7 +194,7 @@ class RevealNinjutsuCardCost extends CostImpl { Card card = player.getHand().get(ability.getSourceId(), game); if (card == null && commander - && player.getCommandersIds().contains(ability.getSourceId())) { + && game.getCommandersIds(player).contains(ability.getSourceId())) { for (CommandObject coj : game.getState().getCommand()) { if (coj != null && coj.getId().equals(ability.getSourceId())) { card = game.getCard(ability.getSourceId()); diff --git a/Mage/src/main/java/mage/abilities/mana/CommanderColorIdentityManaAbility.java b/Mage/src/main/java/mage/abilities/mana/CommanderColorIdentityManaAbility.java index 44ad62ff232..47f7d1dea56 100644 --- a/Mage/src/main/java/mage/abilities/mana/CommanderColorIdentityManaAbility.java +++ b/Mage/src/main/java/mage/abilities/mana/CommanderColorIdentityManaAbility.java @@ -1,8 +1,5 @@ package mage.abilities.mana; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; import mage.Mana; import mage.abilities.Ability; import mage.abilities.costs.Cost; @@ -17,8 +14,11 @@ import mage.filter.FilterMana; import mage.game.Game; import mage.players.Player; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + /** - * * @author LevelX2 */ public class CommanderColorIdentityManaAbility extends ActivatedManaAbilityImpl { @@ -46,7 +46,7 @@ public class CommanderColorIdentityManaAbility extends ActivatedManaAbilityImpl if (netMana.isEmpty() && game != null) { Player controller = game.getPlayer(getControllerId()); if (controller != null) { - for (UUID commanderId : controller.getCommandersIds()) { + for (UUID commanderId : game.getCommandersIds(controller)) { Card commander = game.getCard(commanderId); if (commander != null) { FilterMana commanderMana = commander.getColorIdentity(); @@ -114,7 +114,7 @@ class CommanderIdentityManaEffect extends ManaEffect { if (controller != null) { Choice choice = new ChoiceImpl(); choice.setMessage("Pick a mana color"); - for (UUID commanderId : controller.getCommandersIds()) { + for (UUID commanderId : game.getCommandersIds(controller)) { Card commander = game.getCard(commanderId); if (commander != null) { FilterMana commanderMana = commander.getColorIdentity(); diff --git a/Mage/src/main/java/mage/constants/CommanderCardType.java b/Mage/src/main/java/mage/constants/CommanderCardType.java new file mode 100644 index 00000000000..a4c3e007d26 --- /dev/null +++ b/Mage/src/main/java/mage/constants/CommanderCardType.java @@ -0,0 +1,10 @@ +package mage.constants; + +/** + * @author JayDi85 + */ +public enum CommanderCardType { + ANY, + COMMANDER_OR_OATHBREAKER, + SIGNATURE_SPELL +} diff --git a/Mage/src/main/java/mage/filter/predicate/permanent/CommanderPredicate.java b/Mage/src/main/java/mage/filter/predicate/permanent/CommanderPredicate.java index 58bc4269b22..ada3bcbaeaa 100644 --- a/Mage/src/main/java/mage/filter/predicate/permanent/CommanderPredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/permanent/CommanderPredicate.java @@ -20,7 +20,7 @@ public enum CommanderPredicate implements Predicate { public boolean apply(Permanent input, Game game) { Player owner = game.getPlayer(input.getOwnerId()); return owner != null - && owner.getCommandersIds().contains(input.getId()); + && game.getCommandersIds(owner).contains(input.getId()); } @Override diff --git a/Mage/src/main/java/mage/game/Game.java b/Mage/src/main/java/mage/game/Game.java index 30638c63a1c..af5ce5a1ead 100644 --- a/Mage/src/main/java/mage/game/Game.java +++ b/Mage/src/main/java/mage/game/Game.java @@ -476,4 +476,9 @@ public interface Game extends MageItem, Serializable { Mulligan getMulligan(); + Set getCommandersIds(Player player, CommanderCardType commanderCardType); + + default Set getCommandersIds(Player player) { + return getCommandersIds(player, CommanderCardType.ANY); + } } diff --git a/Mage/src/main/java/mage/game/GameCommanderImpl.java b/Mage/src/main/java/mage/game/GameCommanderImpl.java index c36b09fff95..1430103aca7 100644 --- a/Mage/src/main/java/mage/game/GameCommanderImpl.java +++ b/Mage/src/main/java/mage/game/GameCommanderImpl.java @@ -59,7 +59,7 @@ public abstract class GameCommanderImpl extends GameImpl { } // init commanders - for (UUID commanderId : player.getCommandersIds()) { + for (UUID commanderId : this.getCommandersIds(player)) { Card commander = this.getCard(commanderId); if (commander != null) { initCommander(commander, player); @@ -183,7 +183,7 @@ public abstract class GameCommanderImpl extends GameImpl { @Override protected boolean checkStateBasedActions() { for (Player player : getPlayers().values()) { - for (UUID commanderId : player.getCommandersIds()) { + for (UUID commanderId : this.getCommandersIds(player)) { CommanderInfoWatcher damageWatcher = getState().getWatcher(CommanderInfoWatcher.class, commanderId); if (damageWatcher == null) { continue; diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index 5994ff0ca26..f3f48ac1436 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -3193,4 +3193,9 @@ public abstract class GameImpl implements Game, Serializable { return mulligan; } + @Override + public Set getCommandersIds(Player player, CommanderCardType commanderCardType) { + return player.getCommandersIds(); + } + } diff --git a/Mage/src/main/java/mage/players/Player.java b/Mage/src/main/java/mage/players/Player.java index 6dc09c8f9dd..bef24d471ef 100644 --- a/Mage/src/main/java/mage/players/Player.java +++ b/Mage/src/main/java/mage/players/Player.java @@ -696,9 +696,11 @@ public interface Player extends MageItem, Copyable { /** * Get the commanderIds of the player + * Deprecated, use game.getCommandersIds(xxx) instead * * @return */ + @Deprecated Set getCommandersIds(); /** diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index c39eff82b06..569f68e1811 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -302,7 +302,7 @@ public abstract class PlayerImpl implements Player, Serializable { this.sideboard = player.getSideboard().copy(); this.hand = player.getHand().copy(); this.graveyard = player.getGraveyard().copy(); - this.commandersIds = player.getCommandersIds(); + this.commandersIds = new HashSet<>(player.getCommandersIds()); this.abilities = player.getAbilities().copy(); this.counters = player.getCounters().copy(); diff --git a/Mage/src/main/java/mage/watchers/common/CommanderPlaysCountWatcher.java b/Mage/src/main/java/mage/watchers/common/CommanderPlaysCountWatcher.java index 789cb2d2c84..43c7a19b8d8 100644 --- a/Mage/src/main/java/mage/watchers/common/CommanderPlaysCountWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/CommanderPlaysCountWatcher.java @@ -43,7 +43,7 @@ public class CommanderPlaysCountWatcher extends Watcher { UUID possibleCommanderId = event.getSourceId(); boolean isCommanderObject = false; for (Player player : game.getPlayers().values()) { - if (player.getCommandersIds().contains(possibleCommanderId)) { + if (game.getCommandersIds(player).contains(possibleCommanderId)) { isCommanderObject = true; break; }