diff --git a/Mage.Common/src/mage/view/CardView.java b/Mage.Common/src/mage/view/CardView.java index 9648daba66d..1211594b2e1 100644 --- a/Mage.Common/src/mage/view/CardView.java +++ b/Mage.Common/src/mage/view/CardView.java @@ -134,7 +134,7 @@ public class CardView extends SimpleCardView { * * @param card * @param game - * @param cardId + * @param cardId not used? * @param controlled is the card view created for the card controller - used for morph / face down cards to know which player may see information for the card */ public CardView(Card card, Game game, UUID cardId, boolean controlled) { diff --git a/Mage.Common/src/mage/view/CommanderView.java b/Mage.Common/src/mage/view/CommanderView.java index b104d9a4962..46e012b374c 100644 --- a/Mage.Common/src/mage/view/CommanderView.java +++ b/Mage.Common/src/mage/view/CommanderView.java @@ -27,22 +27,20 @@ */ package mage.view; +import java.io.Serializable; import mage.cards.Card; import mage.constants.MageObjectType; +import mage.game.Game; import mage.game.command.Commander; -import java.io.Serializable; - /** * * @author Plopman */ public class CommanderView extends CardView implements CommandObjectView, Serializable{ - public CommanderView(Commander commander, Card sourceCard) { - super(sourceCard); + public CommanderView(Commander commander, Card sourceCard, Game game) { + super(sourceCard, game, null, false); this.mageObjectType = MageObjectType.COMMANDER; - } - - + } } diff --git a/Mage.Common/src/mage/view/PlayerView.java b/Mage.Common/src/mage/view/PlayerView.java index 67379692644..b843c768231 100644 --- a/Mage.Common/src/mage/view/PlayerView.java +++ b/Mage.Common/src/mage/view/PlayerView.java @@ -132,7 +132,7 @@ public class PlayerView implements Serializable { if(commander.getControllerId().equals(this.playerId)){ Card sourceCard = game.getCard(commander.getSourceId()); if(sourceCard != null){ - commandList.add(new CommanderView(commander, sourceCard)); + commandList.add(new CommanderView(commander, sourceCard, game)); } } } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/TinyLeaders.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/TinyLeaders.java index d425a8bf318..471ccaedf2f 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/TinyLeaders.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/TinyLeaders.java @@ -38,6 +38,7 @@ import mage.cards.decks.Deck; import mage.cards.decks.DeckValidator; import mage.constants.CardType; import mage.filter.FilterMana; +import mage.game.GameTinyLeadersImpl; import mage.util.CardUtil; /** @@ -121,6 +122,7 @@ public class TinyLeaders extends DeckValidator { List basicLandNames = new ArrayList<>(Arrays.asList("Forest", "Island", "Mountain", "Swamp", "Plains", "Snow-Covered Forest", "Snow-Covered Island", "Snow-Covered Mountain", "Snow-Covered Swamp", "Snow-Covered Plains")); Map counts = new HashMap<>(); + counts.put(deck.getName(), 1); // add the commander to the counts, so it can't be in the deck or sideboard again countCards(counts, deck.getCards()); countCards(counts, deck.getSideboard()); for (Map.Entry entry : counts.entrySet()) { @@ -139,15 +141,8 @@ public class TinyLeaders extends DeckValidator { } } - if (deck.getSideboard().size() <= 11) { - Card commander = null; - - for (Card card : deck.getSideboard()) { - if (card.getName().equalsIgnoreCase(deck.getName())) { - commander = card; - } - } - + if (deck.getSideboard().size() <= 10) { + Card commander = GameTinyLeadersImpl.getCommanderCard(deck.getName(), null); /** * 905.5b - Each card must have a converted mana cost of three of less. * Cards with {X} in their mana cost count X as zero. @@ -156,10 +151,10 @@ public class TinyLeaders extends DeckValidator { if (commander == null || commander.getManaCost().convertedManaCost() > 3) { if (commander == null) { - invalid.put("Leader", "Please be sure to set your leader in the NAME field in the DECK EDITOR"); + invalid.put("Leader", "Please be sure to set your leader in the NAME field in the DECK EDITOR (use the names Mardu, Sultai or Jeskai as default Commanders)"); } if (commander != null && commander.getManaCost().convertedManaCost() > 3) { - invalid.put("Leader", "Commander CMC is Greater than 3"); + invalid.put("Leader", "Commanders converted mana cost is greater than 3"); } return false; } @@ -188,7 +183,7 @@ public class TinyLeaders extends DeckValidator { valid = false; } } else { - invalid.put("Commander", "Sideboard must contain only the commander and a maximum of 10 sideboard cards"); + invalid.put("Commander", "Sideboard must contain only a maximum of 10 sideboard cards (the Tiny Leader name must be written to the deck name)"); valid = false; } diff --git a/Mage/src/mage/game/GameCommanderImpl.java b/Mage/src/mage/game/GameCommanderImpl.java index accb5d52c2b..19541ff2ee0 100644 --- a/Mage/src/mage/game/GameCommanderImpl.java +++ b/Mage/src/mage/game/GameCommanderImpl.java @@ -52,12 +52,12 @@ import mage.game.turn.TurnMod; import mage.players.Player; import mage.target.common.TargetCardInHand; import mage.util.CardUtil; -import mage.watchers.common.CommanderCombatDamageWatcher; +import mage.watchers.common.CommanderInfoWatcher; public abstract class GameCommanderImpl extends GameImpl { private final Map mulliganedCards = new HashMap<>(); - private final Set commanderCombatWatcher = new HashSet<>(); + private final Set commanderCombatWatcher = new HashSet<>(); protected boolean alsoLibrary; // replace also commander going to library protected boolean startingPlayerSkipsDraw = true; @@ -88,7 +88,7 @@ public abstract class GameCommanderImpl extends GameImpl { ability.addEffect(new CommanderCostModification(commander.getId())); ability.addEffect(new CommanderManaReplacementEffect(player.getId(), CardUtil.getColorIdentity(commander))); getState().setValue(commander.getId() + "_castCount", 0); - CommanderCombatDamageWatcher watcher = new CommanderCombatDamageWatcher(commander.getId()); + CommanderInfoWatcher watcher = new CommanderInfoWatcher(commander.getId(), true); getState().getWatchers().add(watcher); this.commanderCombatWatcher.add(watcher); watcher.addCardInfoToCommander(this); @@ -182,7 +182,7 @@ public abstract class GameCommanderImpl extends GameImpl { */ @Override protected boolean checkStateBasedActions() { - for (CommanderCombatDamageWatcher damageWatcher: commanderCombatWatcher) { + for (CommanderInfoWatcher damageWatcher: commanderCombatWatcher) { for(Map.Entry entrySet : damageWatcher.getDamageToPlayer().entrySet()){ if (entrySet.getValue() > 20) { Player player = getPlayer(entrySet.getKey()); diff --git a/Mage/src/mage/game/GameTinyLeadersImpl.java b/Mage/src/mage/game/GameTinyLeadersImpl.java index 809d7fb7d24..095d9f0141d 100644 --- a/Mage/src/mage/game/GameTinyLeadersImpl.java +++ b/Mage/src/mage/game/GameTinyLeadersImpl.java @@ -31,6 +31,7 @@ package mage.game; import java.util.HashSet; import java.util.Set; import java.util.UUID; +import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.InfoEffect; @@ -38,15 +39,19 @@ import mage.abilities.effects.common.continuous.CommanderManaReplacementEffect; import mage.abilities.effects.common.continuous.CommanderReplacementEffect; import mage.abilities.effects.common.cost.CommanderCostModification; import mage.cards.Card; +import mage.cards.CardImpl; import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; +import mage.constants.CardType; import mage.constants.MultiplayerAttackOption; import mage.constants.PhaseStep; import mage.constants.RangeOfInfluence; +import mage.constants.Rarity; import mage.constants.Zone; import mage.game.turn.TurnMod; import mage.players.Player; import mage.util.CardUtil; +import mage.watchers.common.CommanderInfoWatcher; /** * @@ -74,22 +79,22 @@ public abstract class GameTinyLeadersImpl extends GameImpl{ for (UUID playerId: state.getPlayerList(startingPlayerId)) { Player player = getPlayer(playerId); if (player != null){ - if (player.getSideboard().size() > 0){ - CardInfo cardInfo = CardRepository.instance.findCard(player.getMatchPlayer().getDeck().getName()); - if (cardInfo != null) { - Card commander = cardInfo.getCard(); - Set cards = new HashSet<>(); - cards.add(commander); - this.loadCards(cards, playerId); - if (commander != null) { - player.setCommanderId(commander.getId()); - commander.moveToZone(Zone.COMMAND, null, this, true); - ability.addEffect(new CommanderReplacementEffect(commander.getId(), alsoLibrary)); - ability.addEffect(new CommanderCostModification(commander.getId())); - ability.addEffect(new CommanderManaReplacementEffect(player.getId(), CardUtil.getColorIdentity(commander))); - getState().setValue(commander.getId() + "_castCount", 0); - } - } + Card commander = getCommanderCard(player.getMatchPlayer().getDeck().getName(), player.getId()); + if (commander != null) { + Set cards = new HashSet<>(); + cards.add(commander); + this.loadCards(cards, playerId); + player.setCommanderId(commander.getId()); + commander.moveToZone(Zone.COMMAND, null, this, true); + ability.addEffect(new CommanderReplacementEffect(commander.getId(), alsoLibrary)); + ability.addEffect(new CommanderCostModification(commander.getId())); + ability.addEffect(new CommanderManaReplacementEffect(player.getId(), CardUtil.getColorIdentity(commander))); + getState().setValue(commander.getId() + "_castCount", 0); + CommanderInfoWatcher watcher = new CommanderInfoWatcher(commander.getId(), false); + getState().getWatchers().add(watcher); + watcher.addCardInfoToCommander(this); + } else { + throw new UnknownError("Commander card could not be created"); } } @@ -101,6 +106,34 @@ public abstract class GameTinyLeadersImpl extends GameImpl{ } } + /** + * Name of Tiny Leader comes from the deck name (it's not in the sideboard) + * Additionally, it was taken into account that WOTC had missed a few color combinations + * when making Legendary Creatures at 3 CMC. There are three Commanders available to use + * for the missing color identities: + * Mardu [WBR 2/2], + * Sultai [UBG 2/2], and + * Jeskai [WUR 2/2]. + * + * @param commanderName + * @param ownerId + * @return + */ + public static Card getCommanderCard(String commanderName, UUID ownerId) { + Card commander = null; + switch (commanderName) { + case "Sultai": + commander = new DefaultCommander(ownerId, commanderName, "{U}{B}{G}"); + break; + default: + CardInfo cardInfo = CardRepository.instance.findCard(commanderName); + if (cardInfo != null) { + commander = cardInfo.getCard(); + } + } + return commander; + } + @Override public Set getOpponents(UUID playerId) { Set opponents = new HashSet<>(); @@ -122,3 +155,42 @@ public abstract class GameTinyLeadersImpl extends GameImpl{ } } + +class DefaultCommander extends CardImpl { + + public DefaultCommander(UUID ownerId, String commanderName, String manaString) { + super(ownerId, 999, commanderName, Rarity.RARE, new CardType[]{CardType.CREATURE}, manaString); + this.expansionSetCode = ""; + this.supertype.add("Legendary"); + //this.subtype.add("Human"); + this.subtype.add("Soldier"); + + if (manaString.contains("{G}")) { + this.color.setGreen(true); + } + if (manaString.contains("{W}")) { + this.color.setWhite(true); + } + if (manaString.contains("{U}")) { + this.color.setBlue(true); + } + if (manaString.contains("{B}")) { + this.color.setBlack(true); + } + if (manaString.contains("{R}")) { + this.color.setRed(true); + } + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + } + + public DefaultCommander(final DefaultCommander card) { + super(card); + } + + @Override + public DefaultCommander copy() { + return new DefaultCommander(this); + } +} diff --git a/Mage/src/mage/watchers/common/CommanderCombatDamageWatcher.java b/Mage/src/mage/watchers/common/CommanderInfoWatcher.java similarity index 75% rename from Mage/src/mage/watchers/common/CommanderCombatDamageWatcher.java rename to Mage/src/mage/watchers/common/CommanderInfoWatcher.java index f0a0f5c9aee..eccce0af197 100644 --- a/Mage/src/mage/watchers/common/CommanderCombatDamageWatcher.java +++ b/Mage/src/mage/watchers/common/CommanderInfoWatcher.java @@ -48,29 +48,33 @@ import mage.watchers.Watcher; * * @author Plopman */ -public class CommanderCombatDamageWatcher extends Watcher { - public Map damageToPlayer = new HashMap(); +public class CommanderInfoWatcher extends Watcher { - public CommanderCombatDamageWatcher(UUID commander) { + public Map damageToPlayer = new HashMap<>(); + public boolean checkCommanderDamage; + + public CommanderInfoWatcher(UUID commander, boolean checkCommanderDamage) { super("CommanderCombatDamageWatcher", WatcherScope.CARD); this.sourceId = commander; + this.checkCommanderDamage = checkCommanderDamage; } - public CommanderCombatDamageWatcher(final CommanderCombatDamageWatcher watcher) { + public CommanderInfoWatcher(final CommanderInfoWatcher watcher) { super(watcher); this.damageToPlayer.putAll(watcher.damageToPlayer); + this.checkCommanderDamage = watcher.checkCommanderDamage; } @Override - public CommanderCombatDamageWatcher copy() { - return new CommanderCombatDamageWatcher(this); + public CommanderInfoWatcher copy() { + return new CommanderInfoWatcher(this); } @Override public void watch(GameEvent event, Game game) { - if (event.getType() == EventType.DAMAGED_PLAYER && event instanceof DamagedPlayerEvent) { + if (checkCommanderDamage && event.getType() == EventType.DAMAGED_PLAYER && event instanceof DamagedPlayerEvent) { if (sourceId.equals(event.getSourceId())) { DamagedPlayerEvent damageEvent = (DamagedPlayerEvent)event; if (damageEvent.isCombatDamage()) { @@ -106,22 +110,24 @@ public class CommanderCombatDamageWatcher extends Watcher { sb.append("Commander"); Integer castCount = (Integer)game.getState().getValue(sourceId + "_castCount"); if (castCount != null) { - sb.append(" ").append(castCount).append(castCount.intValue() == 1 ? " time":" times").append(" casted from the command zone."); + sb.append(" ").append(castCount).append(castCount == 1 ? " time":" times").append(" casted from the command zone."); } this.addInfo(object, "Commander",sb.toString(), game); - for (Map.Entry entry : damageToPlayer.entrySet()) { - Player damagedPlayer = game.getPlayer(entry.getKey()); - sb.setLength(0); - sb.append("Commander did ").append(entry.getValue()).append(" combat damage to player ").append(damagedPlayer.getName()).append("."); - this.addInfo(object, new StringBuilder("Commander").append(entry.getKey()).toString(),sb.toString(), game); + + if (checkCommanderDamage) { + for (Map.Entry entry : damageToPlayer.entrySet()) { + Player damagedPlayer = game.getPlayer(entry.getKey()); + sb.setLength(0); + sb.append("Commander did ").append(entry.getValue()).append(" combat damage to player ").append(damagedPlayer.getName()).append("."); + this.addInfo(object, new StringBuilder("Commander").append(entry.getKey()).toString(),sb.toString(), game); + } } } } private void addInfo(MageObject object, String key, String value, Game game) { - if (object instanceof Card) { - ((Card) object).addInfo(key, value, game); - } else if (object instanceof Permanent) { + ((Card) object).addInfo(key, value, game); + if (object instanceof Permanent) { ((Permanent) object).addInfo(key, value, game); } }