Cards compatibility with oathbreaker format;

This commit is contained in:
Oleg Agafonov 2019-05-27 17:21:17 +04:00
parent e1259d0dd6
commit 913ee65f36
22 changed files with 99 additions and 46 deletions

View file

@ -8,6 +8,7 @@ import mage.abilities.condition.common.OathbreakerOnBattlefieldCondition;
import mage.abilities.effects.common.InfoEffect; import mage.abilities.effects.common.InfoEffect;
import mage.abilities.hint.ConditionHint; import mage.abilities.hint.ConditionHint;
import mage.cards.Card; import mage.cards.Card;
import mage.constants.CommanderCardType;
import mage.constants.MultiplayerAttackOption; import mage.constants.MultiplayerAttackOption;
import mage.constants.RangeOfInfluence; import mage.constants.RangeOfInfluence;
import mage.game.match.MatchType; import mage.game.match.MatchType;
@ -138,4 +139,33 @@ public class OathbreakerFreeForAll extends GameCommanderImpl {
public OathbreakerFreeForAll copy() { public OathbreakerFreeForAll copy() {
return new OathbreakerFreeForAll(this); return new OathbreakerFreeForAll(this);
} }
@Override
public Set<UUID> getCommandersIds(Player player, CommanderCardType commanderCardType) {
Set<UUID> res = new HashSet<>();
if (player != null) {
List<UUID> 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;
}
} }

View file

@ -93,7 +93,7 @@ class ConspyEffect extends ContinuousEffectImpl {
} }
} }
// commander in command zone // commander in command zone
for (UUID commanderId : controller.getCommandersIds()) { for (UUID commanderId : game.getCommandersIds(controller)) {
if (game.getState().getZone(commanderId) == Zone.COMMAND) { if (game.getState().getZone(commanderId) == Zone.COMMAND) {
Card card = game.getCard(commanderId); Card card = game.getCard(commanderId);
if (card != null && card.isCreature() && !card.hasSubtype(subType, game)) { if (card != null && card.isCreature() && !card.hasSubtype(subType, game)) {

View file

@ -1,9 +1,5 @@
package mage.cards.c; package mage.cards.c;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.SacrificeSourceCost;
@ -14,13 +10,17 @@ import mage.cards.Card;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.CommanderCardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.Zone; import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.players.Player;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/** /**
*
* @author emerald000 * @author emerald000
*/ */
public final class CommandBeacon extends CardImpl { public final class CommandBeacon extends CardImpl {
@ -67,7 +67,7 @@ class CommandBeaconEffect extends OneShotEffect {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
if (controller != null) { if (controller != null) {
List<Card> commandersInCommandZone = new ArrayList<>(1); List<Card> commandersInCommandZone = new ArrayList<>(1);
for (UUID commanderId : controller.getCommandersIds()) { for (UUID commanderId : game.getCommandersIds(controller, CommanderCardType.COMMANDER_OR_OATHBREAKER)) {
Card commander = game.getCard(commanderId); Card commander = game.getCard(commanderId);
if (commander != null && game.getState().getZone(commander.getId()) == Zone.COMMAND) { if (commander != null && game.getState().getZone(commander.getId()) == Zone.COMMAND) {
commandersInCommandZone.add(commander); commandersInCommandZone.add(commander);
@ -75,14 +75,12 @@ class CommandBeaconEffect extends OneShotEffect {
} }
if (commandersInCommandZone.size() == 1) { if (commandersInCommandZone.size() == 1) {
controller.moveCards(commandersInCommandZone.get(0), Zone.HAND, source, game); 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 firstCommander = commandersInCommandZone.get(0);
Card secondCommander = commandersInCommandZone.get(1); Card secondCommander = commandersInCommandZone.get(1);
if (controller.chooseUse(Outcome.ReturnToHand, "Return which commander to hand?", null, firstCommander.getName(), secondCommander.getName(), source, game)) { if (controller.chooseUse(Outcome.ReturnToHand, "Return which commander to hand?", null, firstCommander.getName(), secondCommander.getName(), source, game)) {
controller.moveCards(firstCommander, Zone.HAND, source, game); controller.moveCards(firstCommander, Zone.HAND, source, game);
} } else {
else {
controller.moveCards(secondCommander, Zone.HAND, source, game); controller.moveCards(secondCommander, Zone.HAND, source, game);
} }
} }

View file

@ -95,7 +95,7 @@ class ConspiracyEffect extends ContinuousEffectImpl {
} }
} }
// commander in command zone // commander in command zone
for (UUID commanderId : controller.getCommandersIds()) { for (UUID commanderId : game.getCommandersIds(controller)) {
if (game.getState().getZone(commanderId) == Zone.COMMAND) { if (game.getState().getZone(commanderId) == Zone.COMMAND) {
Card card = game.getCard(commanderId); Card card = game.getCard(commanderId);
if (card != null && card.isCreature()) { if (card != null && card.isCreature()) {

View file

@ -109,8 +109,9 @@ class KarnLiberatedEffect extends OneShotEffect {
if (card.isOwnedBy(player.getId()) && !card.isCopy() // no copies if (card.isOwnedBy(player.getId()) && !card.isCopy() // no copies
&& !player.getSideboard().contains(card.getId()) && !player.getSideboard().contains(card.getId())
&& !cards.contains(card)) { // not the exiled cards && !cards.contains(card)) { // not the exiled cards
if (player.getCommandersIds().contains(card.getId())) { if (game.getCommandersIds(player).contains(card.getId())) {
game.addCommander(new Commander(card)); 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); game.setZone(card.getId(), Zone.COMMAND);
} else { } else {
player.getLibrary().putOnTop(card, game); player.getLibrary().putOnTop(card, game);

View file

@ -95,7 +95,7 @@ class MythUnboundCostReductionEffect extends CostModificationEffectImpl {
if (abilityToModify instanceof SpellAbility || abilityToModify instanceof PlayLandAbility) { if (abilityToModify instanceof SpellAbility || abilityToModify instanceof PlayLandAbility) {
if (abilityToModify.isControlledBy(source.getControllerId())) { if (abilityToModify.isControlledBy(source.getControllerId())) {
return player.getCommandersIds().contains(abilityToModify.getSourceId()); return game.getCommandersIds(player).contains(abilityToModify.getSourceId());
} }
} }
return false; return false;

View file

@ -93,7 +93,7 @@ class OpalPalaceWatcher extends Watcher {
for (UUID playerId : game.getPlayerList()) { for (UUID playerId : game.getPlayerList()) {
Player player = game.getPlayer(playerId); Player player = game.getPlayer(playerId);
if (player != null) { if (player != null) {
if (player.getCommandersIds().contains(card.getId())) { if (game.getCommandersIds(player).contains(card.getId())) {
commanderId.add(card.getId()); commanderId.add(card.getId());
break; break;
} }

View file

@ -1,7 +1,5 @@
package mage.cards.p; package mage.cards.p;
import java.util.Iterator;
import java.util.UUID;
import mage.MageObject; import mage.MageObject;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl; import mage.abilities.TriggeredAbilityImpl;
@ -22,8 +20,11 @@ import mage.game.permanent.Permanent;
import mage.game.stack.Spell; import mage.game.stack.Spell;
import mage.players.Player; import mage.players.Player;
import java.util.Iterator;
import java.util.Set;
import java.util.UUID;
/** /**
*
* @author TheElk801 * @author TheElk801
*/ */
public final class PathOfAncestry extends CardImpl { public final class PathOfAncestry extends CardImpl {
@ -88,9 +89,10 @@ class PathOfAncestryTriggeredAbility extends TriggeredAbilityImpl {
Spell spell = game.getStack().getSpell(event.getTargetId()); Spell spell = game.getStack().getSpell(event.getTargetId());
if (spell != null && spell.isCreature()) { if (spell != null && spell.isCreature()) {
Player controller = game.getPlayer(getControllerId()); Player controller = game.getPlayer(getControllerId());
if (controller != null && controller.getCommandersIds() != null && !controller.getCommandersIds().isEmpty()) { Set<UUID> commanders = game.getCommandersIds(controller);
if (controller != null && commanders != null && !commanders.isEmpty()) {
if (spell.getAbilities().contains(ChangelingAbility.getInstance())) { if (spell.getAbilities().contains(ChangelingAbility.getInstance())) {
for (UUID cmdr : controller.getCommandersIds()) { for (UUID cmdr : commanders) {
MageObject commander = game.getObject(cmdr); MageObject commander = game.getObject(cmdr);
if (commander != null) { if (commander != null) {
if (commander.getAbilities().contains(ChangelingAbility.getInstance())) { if (commander.getAbilities().contains(ChangelingAbility.getInstance())) {
@ -110,7 +112,7 @@ class PathOfAncestryTriggeredAbility extends TriggeredAbilityImpl {
while (spellSubs.hasNext()) { while (spellSubs.hasNext()) {
SubType sType = spellSubs.next(); SubType sType = spellSubs.next();
if (sType.getSubTypeSet() == SubTypeSet.CreatureType) { if (sType.getSubTypeSet() == SubTypeSet.CreatureType) {
for (UUID cmdr : controller.getCommandersIds()) { for (UUID cmdr : commanders) {
MageObject commander = game.getObject(cmdr); MageObject commander = game.getObject(cmdr);
if (commander != null && (commander.hasSubtype(sType, game) || commander.getAbilities().contains(ChangelingAbility.getInstance()))) { if (commander != null && (commander.hasSubtype(sType, game) || commander.getAbilities().contains(ChangelingAbility.getInstance()))) {
return true; return true;

View file

@ -99,7 +99,7 @@ class TeferiMageOfZhalfirAddFlashEffect extends ContinuousEffectImpl {
} }
} }
// commander in command zone // commander in command zone
for (UUID commanderId : controller.getCommandersIds()) { for (UUID commanderId : game.getCommandersIds(controller)) {
if (game.getState().getZone(commanderId) == Zone.COMMAND) { if (game.getState().getZone(commanderId) == Zone.COMMAND) {
Card card = game.getCard(commanderId); Card card = game.getCard(commanderId);
if (card != null && card.isCreature()) { if (card != null && card.isCreature()) {

View file

@ -750,7 +750,7 @@ public class TestPlayer implements Player {
// show command // show command
if (params[0].equals(SHOW_COMMAND_COMMAND) && params.length == 1) { if (params[0].equals(SHOW_COMMAND_COMMAND) && params.length == 1) {
printStart(action.getActionName()); printStart(action.getActionName());
CardsImpl cards = new CardsImpl(computerPlayer.getCommandersIds()); CardsImpl cards = new CardsImpl(game.getCommandersIds(computerPlayer));
printCards(cards.getCards(game)); printCards(cards.getCards(game));
printEnd(); printEnd();
actions.remove(action); actions.remove(action);

View file

@ -1,8 +1,8 @@
package mage.abilities.condition.common; package mage.abilities.condition.common;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.condition.Condition; import mage.abilities.condition.Condition;
import mage.constants.CommanderCardType;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
@ -22,7 +22,7 @@ public enum CommanderInPlayCondition implements Condition {
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
if (controller != null) { if (controller != null) {
for (UUID commanderId : controller.getCommandersIds()) { for (UUID commanderId : game.getCommandersIds(controller, CommanderCardType.COMMANDER_OR_OATHBREAKER)) {
Permanent commander = game.getPermanent(commanderId); Permanent commander = game.getPermanent(commanderId);
if (commander != null && commander.isControlledBy(source.getControllerId())) { if (commander != null && commander.isControlledBy(source.getControllerId())) {
return true; return true;

View file

@ -5,6 +5,7 @@ import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl; import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.Effect; import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.constants.CommanderCardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.Zone; import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
@ -83,7 +84,7 @@ class CommanderStormEffect extends OneShotEffect {
if (player == null) { if (player == null) {
return false; return false;
} }
stormCount = player.getCommandersIds().stream() stormCount = game.getCommandersIds(player, CommanderCardType.COMMANDER_OR_OATHBREAKER).stream()
.map((commanderId) -> game.getState().getWatcher(CommanderPlaysCountWatcher.class).getPlaysCount(commanderId)) .map((commanderId) -> game.getState().getWatcher(CommanderPlaysCountWatcher.class).getPlaysCount(commanderId))
.reduce(stormCount, Integer::sum); .reduce(stormCount, Integer::sum);
if (stormCount == 0) { if (stormCount == 0) {

View file

@ -1,6 +1,5 @@
package mage.abilities.keyword; package mage.abilities.keyword;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.ActivatedAbilityImpl; import mage.abilities.ActivatedAbilityImpl;
import mage.abilities.costs.Cost; import mage.abilities.costs.Cost;
@ -21,24 +20,25 @@ import mage.players.Player;
import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetControlledCreaturePermanent;
import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetControlledPermanent;
import java.util.UUID;
/** /**
* 702.47. Ninjutsu * 702.47. Ninjutsu
* * <p>
* 702.47a Ninjutsu is an activated ability that functions only while the card * 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 * 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 * 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 * to its owner's hand: Put this card onto the battlefield from your hand tapped
* and attacking." * and attacking."
* * <p>
* 702.47b The card with ninjutsu remains revealed from the time the ability is * 702.47b The card with ninjutsu remains revealed from the time the ability is
* announced until the ability leaves the stack. * announced until the ability leaves the stack.
* * <p>
* 702.47c A ninjutsu ability may be activated only while a creature on the * 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 * 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 * onto the battlefield unblocked. It will be attacking the same player or
* planeswalker as the creature that was returned to its owner's hand. * planeswalker as the creature that was returned to its owner's hand.
* *
*
* @author LevelX2 * @author LevelX2
*/ */
public class NinjutsuAbility extends ActivatedAbilityImpl { public class NinjutsuAbility extends ActivatedAbilityImpl {
@ -51,7 +51,6 @@ public class NinjutsuAbility extends ActivatedAbilityImpl {
} }
/** /**
*
* @param manaCost ninjutsu mana cost * @param manaCost ninjutsu mana cost
*/ */
public NinjutsuAbility(ManaCost manaCost) { public NinjutsuAbility(ManaCost manaCost) {
@ -195,7 +194,7 @@ class RevealNinjutsuCardCost extends CostImpl {
Card card = player.getHand().get(ability.getSourceId(), game); Card card = player.getHand().get(ability.getSourceId(), game);
if (card == null && commander if (card == null && commander
&& player.getCommandersIds().contains(ability.getSourceId())) { && game.getCommandersIds(player).contains(ability.getSourceId())) {
for (CommandObject coj : game.getState().getCommand()) { for (CommandObject coj : game.getState().getCommand()) {
if (coj != null && coj.getId().equals(ability.getSourceId())) { if (coj != null && coj.getId().equals(ability.getSourceId())) {
card = game.getCard(ability.getSourceId()); card = game.getCard(ability.getSourceId());

View file

@ -1,8 +1,5 @@
package mage.abilities.mana; package mage.abilities.mana;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.Mana; import mage.Mana;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.costs.Cost; import mage.abilities.costs.Cost;
@ -17,8 +14,11 @@ import mage.filter.FilterMana;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.players.Player;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/** /**
*
* @author LevelX2 * @author LevelX2
*/ */
public class CommanderColorIdentityManaAbility extends ActivatedManaAbilityImpl { public class CommanderColorIdentityManaAbility extends ActivatedManaAbilityImpl {
@ -46,7 +46,7 @@ public class CommanderColorIdentityManaAbility extends ActivatedManaAbilityImpl
if (netMana.isEmpty() && game != null) { if (netMana.isEmpty() && game != null) {
Player controller = game.getPlayer(getControllerId()); Player controller = game.getPlayer(getControllerId());
if (controller != null) { if (controller != null) {
for (UUID commanderId : controller.getCommandersIds()) { for (UUID commanderId : game.getCommandersIds(controller)) {
Card commander = game.getCard(commanderId); Card commander = game.getCard(commanderId);
if (commander != null) { if (commander != null) {
FilterMana commanderMana = commander.getColorIdentity(); FilterMana commanderMana = commander.getColorIdentity();
@ -114,7 +114,7 @@ class CommanderIdentityManaEffect extends ManaEffect {
if (controller != null) { if (controller != null) {
Choice choice = new ChoiceImpl(); Choice choice = new ChoiceImpl();
choice.setMessage("Pick a mana color"); choice.setMessage("Pick a mana color");
for (UUID commanderId : controller.getCommandersIds()) { for (UUID commanderId : game.getCommandersIds(controller)) {
Card commander = game.getCard(commanderId); Card commander = game.getCard(commanderId);
if (commander != null) { if (commander != null) {
FilterMana commanderMana = commander.getColorIdentity(); FilterMana commanderMana = commander.getColorIdentity();

View file

@ -0,0 +1,10 @@
package mage.constants;
/**
* @author JayDi85
*/
public enum CommanderCardType {
ANY,
COMMANDER_OR_OATHBREAKER,
SIGNATURE_SPELL
}

View file

@ -20,7 +20,7 @@ public enum CommanderPredicate implements Predicate<Permanent> {
public boolean apply(Permanent input, Game game) { public boolean apply(Permanent input, Game game) {
Player owner = game.getPlayer(input.getOwnerId()); Player owner = game.getPlayer(input.getOwnerId());
return owner != null return owner != null
&& owner.getCommandersIds().contains(input.getId()); && game.getCommandersIds(owner).contains(input.getId());
} }
@Override @Override

View file

@ -476,4 +476,9 @@ public interface Game extends MageItem, Serializable {
Mulligan getMulligan(); Mulligan getMulligan();
Set<UUID> getCommandersIds(Player player, CommanderCardType commanderCardType);
default Set<UUID> getCommandersIds(Player player) {
return getCommandersIds(player, CommanderCardType.ANY);
}
} }

View file

@ -59,7 +59,7 @@ public abstract class GameCommanderImpl extends GameImpl {
} }
// init commanders // init commanders
for (UUID commanderId : player.getCommandersIds()) { for (UUID commanderId : this.getCommandersIds(player)) {
Card commander = this.getCard(commanderId); Card commander = this.getCard(commanderId);
if (commander != null) { if (commander != null) {
initCommander(commander, player); initCommander(commander, player);
@ -183,7 +183,7 @@ public abstract class GameCommanderImpl extends GameImpl {
@Override @Override
protected boolean checkStateBasedActions() { protected boolean checkStateBasedActions() {
for (Player player : getPlayers().values()) { for (Player player : getPlayers().values()) {
for (UUID commanderId : player.getCommandersIds()) { for (UUID commanderId : this.getCommandersIds(player)) {
CommanderInfoWatcher damageWatcher = getState().getWatcher(CommanderInfoWatcher.class, commanderId); CommanderInfoWatcher damageWatcher = getState().getWatcher(CommanderInfoWatcher.class, commanderId);
if (damageWatcher == null) { if (damageWatcher == null) {
continue; continue;

View file

@ -3193,4 +3193,9 @@ public abstract class GameImpl implements Game, Serializable {
return mulligan; return mulligan;
} }
@Override
public Set<UUID> getCommandersIds(Player player, CommanderCardType commanderCardType) {
return player.getCommandersIds();
}
} }

View file

@ -696,9 +696,11 @@ public interface Player extends MageItem, Copyable<Player> {
/** /**
* Get the commanderIds of the player * Get the commanderIds of the player
* Deprecated, use game.getCommandersIds(xxx) instead
* *
* @return * @return
*/ */
@Deprecated
Set<UUID> getCommandersIds(); Set<UUID> getCommandersIds();
/** /**

View file

@ -302,7 +302,7 @@ public abstract class PlayerImpl implements Player, Serializable {
this.sideboard = player.getSideboard().copy(); this.sideboard = player.getSideboard().copy();
this.hand = player.getHand().copy(); this.hand = player.getHand().copy();
this.graveyard = player.getGraveyard().copy(); this.graveyard = player.getGraveyard().copy();
this.commandersIds = player.getCommandersIds(); this.commandersIds = new HashSet<>(player.getCommandersIds());
this.abilities = player.getAbilities().copy(); this.abilities = player.getAbilities().copy();
this.counters = player.getCounters().copy(); this.counters = player.getCounters().copy();

View file

@ -43,7 +43,7 @@ public class CommanderPlaysCountWatcher extends Watcher {
UUID possibleCommanderId = event.getSourceId(); UUID possibleCommanderId = event.getSourceId();
boolean isCommanderObject = false; boolean isCommanderObject = false;
for (Player player : game.getPlayers().values()) { for (Player player : game.getPlayers().values()) {
if (player.getCommandersIds().contains(possibleCommanderId)) { if (game.getCommandersIds(player).contains(possibleCommanderId)) {
isCommanderObject = true; isCommanderObject = true;
break; break;
} }