mirror of
https://github.com/correl/mage.git
synced 2025-01-12 19:25:44 +00:00
* Added Morph ability.
This commit is contained in:
parent
b1de70a3bf
commit
d244551e3b
45 changed files with 929 additions and 191 deletions
|
@ -6,6 +6,7 @@ import java.util.ArrayList;
|
||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
import javax.swing.SwingConstants;
|
import javax.swing.SwingConstants;
|
||||||
|
import mage.client.cards.Permanent;
|
||||||
|
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
import mage.constants.MageObjectType;
|
import mage.constants.MageObjectType;
|
||||||
|
@ -221,7 +222,11 @@ public class GuiDisplayUtil {
|
||||||
buffer.append(pt).append("</b></td>");
|
buffer.append(pt).append("</b></td>");
|
||||||
buffer.append("<td align='right'>");
|
buffer.append("<td align='right'>");
|
||||||
if (!card.isControlledByOwner()) {
|
if (!card.isControlledByOwner()) {
|
||||||
buffer.append("[only controlled] ");
|
if (card instanceof PermanentView) {
|
||||||
|
buffer.append("[").append(((PermanentView) card).getNameOwner()).append("] ");
|
||||||
|
} else {
|
||||||
|
buffer.append("[only controlled] ");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
buffer.append(card.getMageObjectType().toString()).append("</td>");
|
buffer.append(card.getMageObjectType().toString()).append("</td>");
|
||||||
buffer.append("</tr></table>");
|
buffer.append("</tr></table>");
|
||||||
|
|
|
@ -703,7 +703,7 @@ public class CardPanel extends MagePermanent implements MouseListener, MouseMoti
|
||||||
}
|
}
|
||||||
setText(card);
|
setText(card);
|
||||||
|
|
||||||
boolean updateImage = !gameCard.getName().equals(card.getName()); // update after e.g. turning a night/day card
|
boolean updateImage = !gameCard.getName().equals(card.getName()) || gameCard.isFaceDown() != card.isFaceDown(); // update after e.g. turning a night/day card
|
||||||
this.gameCard = card;
|
this.gameCard = card;
|
||||||
|
|
||||||
String cardType = getType(card);
|
String cardType = getType(card);
|
||||||
|
@ -776,7 +776,7 @@ public class CardPanel extends MagePermanent implements MouseListener, MouseMoti
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mouseEntered(MouseEvent e) {
|
public void mouseEntered(MouseEvent e) {
|
||||||
if (gameCard.isFaceDown()) {
|
if (gameCard.hideInfo()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!popupShowing) {
|
if (!popupShowing) {
|
||||||
|
@ -798,7 +798,7 @@ public class CardPanel extends MagePermanent implements MouseListener, MouseMoti
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mouseMoved(MouseEvent e) {
|
public void mouseMoved(MouseEvent e) {
|
||||||
if (gameCard.isFaceDown()) {
|
if (gameCard.hideInfo()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
data.component = this;
|
data.component = this;
|
||||||
|
@ -807,7 +807,7 @@ public class CardPanel extends MagePermanent implements MouseListener, MouseMoti
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mouseExited(MouseEvent e) {
|
public void mouseExited(MouseEvent e) {
|
||||||
if (gameCard.isFaceDown()) {
|
if (gameCard.hideInfo()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (getMousePosition(true) != null) {
|
if (getMousePosition(true) != null) {
|
||||||
|
@ -974,10 +974,11 @@ public class CardPanel extends MagePermanent implements MouseListener, MouseMoti
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mouseWheelMoved(MouseWheelEvent e) {
|
public void mouseWheelMoved(MouseWheelEvent e) {
|
||||||
if (gameCard.isFaceDown()) {
|
if (gameCard.hideInfo()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
data.component = this;
|
data.component = this;
|
||||||
callback.mouseWheelMoved(e, data);
|
callback.mouseWheelMoved(e, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,7 +83,7 @@ public class ImageCache {
|
||||||
info.setToken(true);
|
info.setToken(true);
|
||||||
path = CardImageUtils.generateTokenImagePath(info);
|
path = CardImageUtils.generateTokenImagePath(info);
|
||||||
if (path == null) {
|
if (path == null) {
|
||||||
path = DirectLinksForDownload.outDir + File.separator + DirectLinksForDownload.tokenFrameFilename;
|
path = DirectLinksForDownload.outDir + File.separator + DirectLinksForDownload.cardbackFilename;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
path = CardImageUtils.generateImagePath(info);
|
path = CardImageUtils.generateImagePath(info);
|
||||||
|
@ -180,21 +180,21 @@ public class ImageCache {
|
||||||
return getImage(key);
|
return getImage(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* Returns the Image corresponding to the Path
|
// * Returns the Image corresponding to the Path
|
||||||
*/
|
// */
|
||||||
private static BufferedImage getImageByPath(String path) {
|
// private static BufferedImage getImageByPath(String path) {
|
||||||
if (path == null) {
|
// if (path == null) {
|
||||||
return null;
|
// return null;
|
||||||
}
|
// }
|
||||||
TFile file = new TFile(path);
|
// TFile file = new TFile(path);
|
||||||
if (!file.exists()) {
|
// if (!file.exists()) {
|
||||||
log.warn("File does not exist: " + file.toString());
|
// log.warn("File does not exist: " + file.toString());
|
||||||
return null;
|
// return null;
|
||||||
}
|
// }
|
||||||
return getWizardsCard(loadImage(file));
|
// return getWizardsCard(loadImage(file));
|
||||||
|
//
|
||||||
}
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the Image corresponding to the key
|
* Returns the Image corresponding to the key
|
||||||
|
|
|
@ -9,11 +9,12 @@ import org.mage.plugins.card.properties.SettingsManager;
|
||||||
|
|
||||||
public class CardImageUtils {
|
public class CardImageUtils {
|
||||||
|
|
||||||
private static HashMap<CardDownloadData, String> pathCache = new HashMap<CardDownloadData, String>();
|
private static final HashMap<CardDownloadData, String> pathCache = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
* @param card
|
||||||
* @return String if image exists, else null
|
* @return String if image exists, else null
|
||||||
*/
|
*/
|
||||||
public static String generateTokenImagePath(CardDownloadData card) {
|
public static String generateTokenImagePath(CardDownloadData card) {
|
||||||
|
|
|
@ -29,7 +29,6 @@
|
||||||
package mage.view;
|
package mage.view;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import mage.constants.CardType;
|
|
||||||
import mage.ObjectColor;
|
import mage.ObjectColor;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
|
|
||||||
|
@ -38,24 +37,25 @@ import mage.abilities.Ability;
|
||||||
* @author BetaSteward_at_googlemail.com
|
* @author BetaSteward_at_googlemail.com
|
||||||
*/
|
*/
|
||||||
public class AbilityView extends CardView {
|
public class AbilityView extends CardView {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private String sourceName;
|
private final String sourceName;
|
||||||
private CardView sourceCard;
|
private final CardView sourceCard;
|
||||||
|
|
||||||
public AbilityView(Ability ability, String sourceName, CardView sourceCard) {
|
public AbilityView(Ability ability, String sourceName, CardView sourceCard) {
|
||||||
this.id = ability.getId();
|
this.id = ability.getId();
|
||||||
this.name = "Ability";
|
this.name = "Ability";
|
||||||
this.sourceName = sourceName;
|
this.sourceName = sourceName;
|
||||||
this.sourceCard = sourceCard;
|
this.sourceCard = sourceCard;
|
||||||
this.rules = new ArrayList<String>();
|
this.rules = new ArrayList<>();
|
||||||
rules.add(ability.getRule());
|
rules.add(ability.getRule());
|
||||||
this.power = "";
|
this.power = "";
|
||||||
this.toughness = "";
|
this.toughness = "";
|
||||||
this.loyalty = "";
|
this.loyalty = "";
|
||||||
this.cardTypes = new ArrayList<CardType>();
|
this.cardTypes = new ArrayList<>();
|
||||||
this.subTypes = new ArrayList<String>();
|
this.subTypes = new ArrayList<>();
|
||||||
this.superTypes = new ArrayList<String>();
|
this.superTypes = new ArrayList<>();
|
||||||
this.color = new ObjectColor();
|
this.color = new ObjectColor();
|
||||||
this.manaCost = ability.getManaCosts().getSymbols();
|
this.manaCost = ability.getManaCosts().getSymbols();
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,9 +33,12 @@ import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import mage.MageObject;
|
import mage.MageObject;
|
||||||
import mage.ObjectColor;
|
import mage.ObjectColor;
|
||||||
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.Modes;
|
import mage.abilities.Modes;
|
||||||
import mage.abilities.SpellAbility;
|
import mage.abilities.SpellAbility;
|
||||||
|
import mage.abilities.common.TurnFaceUpAbility;
|
||||||
import mage.abilities.costs.mana.ManaCosts;
|
import mage.abilities.costs.mana.ManaCosts;
|
||||||
|
import mage.abilities.keyword.MorphAbility;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
import mage.cards.SplitCard;
|
import mage.cards.SplitCard;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
|
@ -46,6 +49,7 @@ import mage.counters.Counter;
|
||||||
import mage.counters.CounterType;
|
import mage.counters.CounterType;
|
||||||
import mage.game.command.Emblem;
|
import mage.game.command.Emblem;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
|
import mage.game.permanent.PermanentCard;
|
||||||
import mage.game.permanent.PermanentToken;
|
import mage.game.permanent.PermanentToken;
|
||||||
import mage.game.permanent.token.Token;
|
import mage.game.permanent.token.Token;
|
||||||
import mage.game.stack.Spell;
|
import mage.game.stack.Spell;
|
||||||
|
@ -108,19 +112,48 @@ public class CardView extends SimpleCardView {
|
||||||
protected boolean controlledByOwner = true;
|
protected boolean controlledByOwner = true;
|
||||||
|
|
||||||
protected boolean rotate;
|
protected boolean rotate;
|
||||||
|
protected boolean hideInfo; // controlls if the tooltip window is shown (eg. controlled face down morph card)
|
||||||
|
|
||||||
|
public CardView(Card card) {
|
||||||
|
this(card, null, false);
|
||||||
|
}
|
||||||
|
|
||||||
public CardView(Card card, UUID cardId) {
|
public CardView(Card card, UUID cardId) {
|
||||||
this(card);
|
this(card, null, false);
|
||||||
this.id = cardId;
|
this.id = cardId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CardView(Card card) {
|
/**
|
||||||
|
*
|
||||||
|
* @param card
|
||||||
|
* @param cardId
|
||||||
|
* @param controlled is the card view created for the card controller - used for morph cards to know which player may see information for the card
|
||||||
|
*/
|
||||||
|
public CardView(Card card, UUID cardId, boolean controlled) {
|
||||||
super(card.getId(), card.getExpansionSetCode(), card.getCardNumber(), card.isFaceDown(), card.getUsesVariousArt(), card.getTokenSetCode());
|
super(card.getId(), card.getExpansionSetCode(), card.getCardNumber(), card.isFaceDown(), card.getUsesVariousArt(), card.getTokenSetCode());
|
||||||
|
|
||||||
// no information available for face down cards
|
// no information available for face down cards as long it's not a controlled face down morph card
|
||||||
if (this.faceDown) {
|
// TODO: Better handle this in Framework (but currently I'm not sure how to do it there) LevelX2
|
||||||
fillEmpty();
|
if (card.isFaceDown()) {
|
||||||
return;
|
if (card.isMorphCard()) {
|
||||||
|
// special handling for Morph cards
|
||||||
|
this.fillEmpty(card, controlled);
|
||||||
|
if (card instanceof Spell) {
|
||||||
|
if (controlled) {
|
||||||
|
this.name = card.getName();
|
||||||
|
this.displayName = card.getName();
|
||||||
|
}
|
||||||
|
this.power = "2";
|
||||||
|
this.toughness = "2";
|
||||||
|
this.rules.add("You may cast this card as a 2/2 face-down creature, with no text," +
|
||||||
|
" no name, no subtypes, and no mana cost by paying {3} rather than paying its mana cost.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.fillEmpty(card, false);
|
||||||
|
this.hideInfo = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SplitCard splitCard = null;
|
SplitCard splitCard = null;
|
||||||
|
@ -241,8 +274,7 @@ public class CardView extends SimpleCardView {
|
||||||
this.rules.add("<span color='green'><i>Chosen mode: " + spell.getSpellAbility().getEffects().getText(modes.get(modeId))+"</i></span>");
|
this.rules.add("<span color='green'><i>Chosen mode: " + spell.getSpellAbility().getEffects().getText(modes.get(modeId))+"</i></span>");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public CardView(MageObject object) {
|
public CardView(MageObject object) {
|
||||||
|
@ -309,7 +341,7 @@ public class CardView extends SimpleCardView {
|
||||||
if (!empty) {
|
if (!empty) {
|
||||||
throw new IllegalArgumentException("Not supported.");
|
throw new IllegalArgumentException("Not supported.");
|
||||||
}
|
}
|
||||||
fillEmpty();
|
fillEmpty(null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -319,8 +351,9 @@ public class CardView extends SimpleCardView {
|
||||||
this.displayName = name;
|
this.displayName = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fillEmpty() {
|
private void fillEmpty(Card card, boolean controlled) {
|
||||||
this.name = "Face Down";
|
this.name = "Face Down";
|
||||||
|
this.displayName = name;
|
||||||
this.rules = new ArrayList<>();
|
this.rules = new ArrayList<>();
|
||||||
this.power = "";
|
this.power = "";
|
||||||
this.toughness = "";
|
this.toughness = "";
|
||||||
|
@ -331,9 +364,34 @@ public class CardView extends SimpleCardView {
|
||||||
this.color = new ObjectColor();
|
this.color = new ObjectColor();
|
||||||
this.manaCost = new ArrayList<>();
|
this.manaCost = new ArrayList<>();
|
||||||
this.convertedManaCost = 0;
|
this.convertedManaCost = 0;
|
||||||
this.rarity = Rarity.COMMON;
|
|
||||||
this.expansionSetCode = "";
|
// the controller can see more information (e.g. enlarged image) than other players for face down cards (e.g. Morph played face down)
|
||||||
this.cardNumber = 0;
|
if (!controlled) {
|
||||||
|
this.rarity = Rarity.COMMON;
|
||||||
|
this.expansionSetCode = "";
|
||||||
|
this.cardNumber = 0;
|
||||||
|
} else {
|
||||||
|
this.rarity = card.getRarity();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (card != null) {
|
||||||
|
if (card instanceof Permanent) {
|
||||||
|
this.mageObjectType = MageObjectType.PERMANENT;
|
||||||
|
} else {
|
||||||
|
if (card.isCopy()) {
|
||||||
|
this.mageObjectType = MageObjectType.COPY_CARD;
|
||||||
|
} else {
|
||||||
|
this.mageObjectType = MageObjectType.CARD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (card instanceof PermanentToken) {
|
||||||
|
this.mageObjectType = MageObjectType.TOKEN;
|
||||||
|
}
|
||||||
|
if (card instanceof Spell) {
|
||||||
|
this.mageObjectType = MageObjectType.SPELL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CardView(Token token) {
|
CardView(Token token) {
|
||||||
|
@ -611,5 +669,9 @@ public class CardView extends SimpleCardView {
|
||||||
public boolean isToRotate() {
|
public boolean isToRotate() {
|
||||||
return rotate;
|
return rotate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hideInfo() {
|
||||||
|
return hideInfo;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,10 +43,10 @@ import java.util.UUID;
|
||||||
public class CombatGroupView implements Serializable {
|
public class CombatGroupView implements Serializable {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private CardsView attackers = new CardsView();
|
private final CardsView attackers = new CardsView();
|
||||||
private CardsView blockers = new CardsView();
|
private final CardsView blockers = new CardsView();
|
||||||
private String defenderName = "";
|
private String defenderName = "";
|
||||||
private UUID defenderId;
|
private final UUID defenderId;
|
||||||
|
|
||||||
public CombatGroupView(CombatGroup combatGroup, Game game) {
|
public CombatGroupView(CombatGroup combatGroup, Game game) {
|
||||||
Player player = game.getPlayer(combatGroup.getDefenderId());
|
Player player = game.getPlayer(combatGroup.getDefenderId());
|
||||||
|
@ -55,19 +55,22 @@ public class CombatGroupView implements Serializable {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Permanent perm = game.getPermanent(combatGroup.getDefenderId());
|
Permanent perm = game.getPermanent(combatGroup.getDefenderId());
|
||||||
if (perm != null)
|
if (perm != null) {
|
||||||
this.defenderName = perm.getName();
|
this.defenderName = perm.getName();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.defenderId = combatGroup.getDefenderId();
|
this.defenderId = combatGroup.getDefenderId();
|
||||||
for (UUID id: combatGroup.getAttackers()) {
|
for (UUID id: combatGroup.getAttackers()) {
|
||||||
Permanent attacker = game.getPermanent(id);
|
Permanent attacker = game.getPermanent(id);
|
||||||
if (attacker != null)
|
if (attacker != null) {
|
||||||
attackers.put(id, new PermanentView(attacker, game.getCard(attacker.getId())));
|
attackers.put(id, new PermanentView(attacker, game.getCard(attacker.getId()),null, game));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (UUID id: combatGroup.getBlockerOrder()) {
|
for (UUID id: combatGroup.getBlockerOrder()) {
|
||||||
Permanent blocker = game.getPermanent(id);
|
Permanent blocker = game.getPermanent(id);
|
||||||
if (blocker != null)
|
if (blocker != null) {
|
||||||
blockers.put(id, new PermanentView(blocker, game.getCard(blocker.getId())));
|
blockers.put(id, new PermanentView(blocker, game.getCard(blocker.getId()), null, game));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,7 +65,7 @@ public class GameEndView implements Serializable {
|
||||||
int winner = 0;
|
int winner = 0;
|
||||||
Player you = null;
|
Player you = null;
|
||||||
for (Player player: state.getPlayers().values()) {
|
for (Player player: state.getPlayers().values()) {
|
||||||
PlayerView playerView = new PlayerView(player, state, game);
|
PlayerView playerView = new PlayerView(player, state, game, playerId);
|
||||||
if (playerView.getPlayerId().equals(playerId)) {
|
if (playerView.getPlayerId().equals(playerId)) {
|
||||||
clientPlayer = playerView;
|
clientPlayer = playerView;
|
||||||
you = player;
|
you = player;
|
||||||
|
|
|
@ -60,14 +60,14 @@ public class GameView implements Serializable {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private final int priorityTime;
|
private final int priorityTime;
|
||||||
private final List<PlayerView> players = new ArrayList<PlayerView>();
|
private final List<PlayerView> players = new ArrayList<>();
|
||||||
private SimpleCardsView hand;
|
private SimpleCardsView hand;
|
||||||
private Map<String, SimpleCardsView> opponentHands;
|
private Map<String, SimpleCardsView> opponentHands;
|
||||||
private final CardsView stack = new CardsView();
|
private final CardsView stack = new CardsView();
|
||||||
private final List<ExileView> exiles = new ArrayList<ExileView>();
|
private final List<ExileView> exiles = new ArrayList<>();
|
||||||
private final List<RevealedView> revealed = new ArrayList<RevealedView>();
|
private final List<RevealedView> revealed = new ArrayList<>();
|
||||||
private List<LookedAtView> lookedAt = new ArrayList<LookedAtView>();
|
private List<LookedAtView> lookedAt = new ArrayList<>();
|
||||||
private final List<CombatGroupView> combat = new ArrayList<CombatGroupView>();
|
private final List<CombatGroupView> combat = new ArrayList<>();
|
||||||
private final TurnPhase phase;
|
private final TurnPhase phase;
|
||||||
private final PhaseStep step;
|
private final PhaseStep step;
|
||||||
private final UUID activePlayerId;
|
private final UUID activePlayerId;
|
||||||
|
@ -78,11 +78,11 @@ public class GameView implements Serializable {
|
||||||
private final boolean isPlayer;
|
private final boolean isPlayer;
|
||||||
|
|
||||||
|
|
||||||
public GameView(GameState state, Game game, boolean isPlayer) {
|
public GameView(GameState state, Game game, UUID createdForPlayerId) {
|
||||||
this.isPlayer = isPlayer;
|
this.isPlayer = createdForPlayerId != null;
|
||||||
this.priorityTime = game.getPriorityTime();
|
this.priorityTime = game.getPriorityTime();
|
||||||
for (Player player: state.getPlayers().values()) {
|
for (Player player: state.getPlayers().values()) {
|
||||||
players.add(new PlayerView(player, state, game));
|
players.add(new PlayerView(player, state, game, createdForPlayerId));
|
||||||
}
|
}
|
||||||
for (StackObject stackObject: state.getStack()) {
|
for (StackObject stackObject: state.getStack()) {
|
||||||
if (stackObject instanceof StackAbility) {
|
if (stackObject instanceof StackAbility) {
|
||||||
|
@ -127,7 +127,7 @@ public class GameView implements Serializable {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Spell
|
// Spell
|
||||||
stack.put(stackObject.getId(), new CardView((Spell)stackObject));
|
stack.put(stackObject.getId(), new CardView((Spell)stackObject, null, stackObject.getControllerId().equals(createdForPlayerId)));
|
||||||
checkPaid(stackObject.getId(), (Spell)stackObject);
|
checkPaid(stackObject.getId(), (Spell)stackObject);
|
||||||
}
|
}
|
||||||
//stackOrder.add(stackObject.getId());
|
//stackOrder.add(stackObject.getId());
|
||||||
|
|
|
@ -31,9 +31,16 @@ package mage.view;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.common.TurnFaceUpAbility;
|
||||||
|
import mage.abilities.common.TurnedFaceUpTriggeredAbility;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
|
import mage.constants.Rarity;
|
||||||
|
import mage.game.Game;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
|
import mage.game.permanent.PermanentCard;
|
||||||
import mage.game.permanent.PermanentToken;
|
import mage.game.permanent.PermanentToken;
|
||||||
|
import mage.players.Player;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -45,20 +52,21 @@ public class PermanentView extends CardView {
|
||||||
private boolean tapped;
|
private boolean tapped;
|
||||||
private final boolean flipped;
|
private final boolean flipped;
|
||||||
private final boolean phasedIn;
|
private final boolean phasedIn;
|
||||||
private final boolean faceUp;
|
|
||||||
private final boolean summoningSickness;
|
private final boolean summoningSickness;
|
||||||
private final int damage;
|
private final int damage;
|
||||||
private List<UUID> attachments;
|
private List<UUID> attachments;
|
||||||
private final CardView original;
|
private final CardView original;
|
||||||
private final boolean copy;
|
private final boolean copy;
|
||||||
|
private final String nameOwner; // only filled if != controller
|
||||||
|
private final boolean controlled;
|
||||||
|
|
||||||
public PermanentView(Permanent permanent, Card card) {
|
public PermanentView(Permanent permanent, Card card, UUID createdForPlayerId, Game game) {
|
||||||
super(permanent);
|
super(permanent, null, permanent.getControllerId().equals(createdForPlayerId));
|
||||||
|
this.controlled = permanent.getControllerId().equals(createdForPlayerId);
|
||||||
this.rules = permanent.getRules();
|
this.rules = permanent.getRules();
|
||||||
this.tapped = permanent.isTapped();
|
this.tapped = permanent.isTapped();
|
||||||
this.flipped = permanent.isFlipped();
|
this.flipped = permanent.isFlipped();
|
||||||
this.phasedIn = permanent.isPhasedIn();
|
this.phasedIn = permanent.isPhasedIn();
|
||||||
this.faceUp = permanent.isFaceUp();
|
|
||||||
this.summoningSickness = permanent.hasSummoningSickness();
|
this.summoningSickness = permanent.hasSummoningSickness();
|
||||||
this.damage = permanent.getDamage();
|
this.damage = permanent.getDamage();
|
||||||
if (permanent.getAttachments().size() > 0) {
|
if (permanent.getAttachments().size() > 0) {
|
||||||
|
@ -90,6 +98,41 @@ public class PermanentView extends CardView {
|
||||||
this.originalName = this.getName();
|
this.originalName = this.getName();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!permanent.getOwnerId().equals(permanent.getControllerId())) {
|
||||||
|
Player owner = game.getPlayer(permanent.getOwnerId());
|
||||||
|
if (owner != null) {
|
||||||
|
this.nameOwner = owner.getName();
|
||||||
|
} else {
|
||||||
|
this.nameOwner = "";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.nameOwner = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (permanent.isFaceDown() && permanent.isMorphCard()) {
|
||||||
|
// add morph rule text
|
||||||
|
if (card != null) {
|
||||||
|
if (controlled) {
|
||||||
|
for (Ability permanentAbility : permanent.getAbilities()) {
|
||||||
|
if (permanentAbility instanceof TurnFaceUpAbility && !permanentAbility.getRuleVisible()) {
|
||||||
|
this.rules.add(permanentAbility.getRule(true));
|
||||||
|
}
|
||||||
|
if (permanentAbility instanceof TurnedFaceUpTriggeredAbility) {
|
||||||
|
this.rules.add(permanentAbility.getRule());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.name = card.getName();
|
||||||
|
this.expansionSetCode = card.getExpansionSetCode();
|
||||||
|
this.cardNumber = card.getCardNumber();
|
||||||
|
} else {
|
||||||
|
this.rules.add("If the controller has priority, he or she may turn this permanent face up." +
|
||||||
|
" This is a special action; it doesnt use the stack. To do this he or she pays the morph costs," +
|
||||||
|
" then turns this permanent face up.");
|
||||||
|
this.rarity = Rarity.COMMON;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,10 +156,6 @@ public class PermanentView extends CardView {
|
||||||
return phasedIn;
|
return phasedIn;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isFaceUp() {
|
|
||||||
return faceUp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasSummoningSickness(){
|
public boolean hasSummoningSickness(){
|
||||||
return summoningSickness;
|
return summoningSickness;
|
||||||
}
|
}
|
||||||
|
@ -132,4 +171,13 @@ public class PermanentView extends CardView {
|
||||||
public void overrideTapped(boolean tapped) {
|
public void overrideTapped(boolean tapped) {
|
||||||
this.tapped = tapped;
|
this.tapped = tapped;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getNameOwner() {
|
||||||
|
return nameOwner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isControlled() {
|
||||||
|
return controlled;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,7 @@ public class PlayerView implements Serializable {
|
||||||
private final int statesSavedSize;
|
private final int statesSavedSize;
|
||||||
private final int priorityTimeLeft;
|
private final int priorityTimeLeft;
|
||||||
|
|
||||||
public PlayerView(Player player, GameState state, Game game) {
|
public PlayerView(Player player, GameState state, Game game, UUID createdForPlayerId) {
|
||||||
this.playerId = player.getId();
|
this.playerId = player.getId();
|
||||||
this.name = player.getName();
|
this.name = player.getName();
|
||||||
this.life = player.getLife();
|
this.life = player.getLife();
|
||||||
|
@ -83,7 +83,7 @@ public class PlayerView implements Serializable {
|
||||||
}
|
}
|
||||||
for (Permanent permanent: state.getBattlefield().getAllPermanents()) {
|
for (Permanent permanent: state.getBattlefield().getAllPermanents()) {
|
||||||
if (showInBattlefield(permanent, state)) {
|
if (showInBattlefield(permanent, state)) {
|
||||||
PermanentView view = new PermanentView(permanent, game.getCard(permanent.getId()));
|
PermanentView view = new PermanentView(permanent, game.getCard(permanent.getId()), createdForPlayerId, game);
|
||||||
battlefield.put(view.getId(), view);
|
battlefield.put(view.getId(), view);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -597,7 +597,7 @@ public class GameController implements GameCallback {
|
||||||
} else if (perms != null) {
|
} else if (perms != null) {
|
||||||
CardsView permsView = new CardsView();
|
CardsView permsView = new CardsView();
|
||||||
for (Permanent perm: perms) {
|
for (Permanent perm: perms) {
|
||||||
permsView.put(perm.getId(), new PermanentView(perm, game.getCard(perm.getId())));
|
permsView.put(perm.getId(), new PermanentView(perm, game.getCard(perm.getId()), playerId, game));
|
||||||
}
|
}
|
||||||
getGameSession(playerId).target(question, permsView, targets, required, options);
|
getGameSession(playerId).target(question, permsView, targets, required, options);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -240,7 +240,7 @@ public class GameSession extends GameWatcher {
|
||||||
public GameView getGameView() {
|
public GameView getGameView() {
|
||||||
Player player = game.getPlayer(playerId);
|
Player player = game.getPlayer(playerId);
|
||||||
player.setUserData(this.userData);
|
player.setUserData(this.userData);
|
||||||
GameView gameView = new GameView(game.getState(), game, this.isPlayer);
|
GameView gameView = new GameView(game.getState(), game, playerId);
|
||||||
gameView.setHand(new SimpleCardsView(player.getHand().getCards(game)));
|
gameView.setHand(new SimpleCardsView(player.getHand().getCards(game)));
|
||||||
|
|
||||||
if (player.getPlayersUnderYourControl().size() > 0) {
|
if (player.getPlayersUnderYourControl().size() > 0) {
|
||||||
|
|
|
@ -120,7 +120,7 @@ public class GameWatcher {
|
||||||
}
|
}
|
||||||
|
|
||||||
public GameView getGameView() {
|
public GameView getGameView() {
|
||||||
return new GameView(game.getState(), game, this.isPlayer);
|
return new GameView(game.getState(), game, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public GameEndView getGameEndView(UUID playerId, Match match) {
|
public GameEndView getGameEndView(UUID playerId, Match match) {
|
||||||
|
|
|
@ -54,7 +54,7 @@ public class ReplaySession implements GameCallback {
|
||||||
replay.start();
|
replay.start();
|
||||||
User user = UserManager.getInstance().getUser(userId);
|
User user = UserManager.getInstance().getUser(userId);
|
||||||
if (user != null) {
|
if (user != null) {
|
||||||
user.fireCallback(new ClientCallback("replayInit", replay.getGame().getId(), new GameView(replay.next(), replay.getGame(), false)));
|
user.fireCallback(new ClientCallback("replayInit", replay.getGame().getId(), new GameView(replay.next(), replay.getGame(), null)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ public class ReplaySession implements GameCallback {
|
||||||
else {
|
else {
|
||||||
User user = UserManager.getInstance().getUser(userId);
|
User user = UserManager.getInstance().getUser(userId);
|
||||||
if (user != null) {
|
if (user != null) {
|
||||||
user.fireCallback(new ClientCallback("replayUpdate", replay.getGame().getId(), new GameView(state, game, false)));
|
user.fireCallback(new ClientCallback("replayUpdate", replay.getGame().getId(), new GameView(state, game, null)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,9 +28,6 @@
|
||||||
package mage.sets.newphyrexia;
|
package mage.sets.newphyrexia;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import mage.constants.CardType;
|
|
||||||
import mage.constants.Rarity;
|
|
||||||
import mage.constants.Zone;
|
|
||||||
import mage.MageInt;
|
import mage.MageInt;
|
||||||
import mage.Mana;
|
import mage.Mana;
|
||||||
import mage.abilities.Abilities;
|
import mage.abilities.Abilities;
|
||||||
|
@ -44,6 +41,9 @@ import mage.abilities.mana.TriggeredManaAbility;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.choices.Choice;
|
import mage.choices.Choice;
|
||||||
import mage.choices.ChoiceImpl;
|
import mage.choices.ChoiceImpl;
|
||||||
|
import mage.constants.CardType;
|
||||||
|
import mage.constants.Rarity;
|
||||||
|
import mage.constants.Zone;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.events.GameEvent;
|
import mage.game.events.GameEvent;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
|
@ -99,10 +99,7 @@ class VorinclexTriggeredAbility1 extends TriggeredManaAbility {
|
||||||
@Override
|
@Override
|
||||||
public boolean checkTrigger(GameEvent event, Game game) {
|
public boolean checkTrigger(GameEvent event, Game game) {
|
||||||
if (event.getType() == GameEvent.EventType.TAPPED_FOR_MANA && event.getPlayerId().equals(controllerId)) {
|
if (event.getType() == GameEvent.EventType.TAPPED_FOR_MANA && event.getPlayerId().equals(controllerId)) {
|
||||||
Permanent permanent = game.getPermanent(event.getSourceId());
|
Permanent permanent = game.getPermanentOrLKIBattlefield(event.getSourceId());
|
||||||
if (permanent == null) {
|
|
||||||
permanent = (Permanent) game.getLastKnownInformation(event.getSourceId(), Zone.BATTLEFIELD);
|
|
||||||
}
|
|
||||||
if (permanent != null && permanent.getCardType().contains(CardType.LAND)) {
|
if (permanent != null && permanent.getCardType().contains(CardType.LAND)) {
|
||||||
getEffects().get(0).setTargetPointer(new FixedTarget(permanent.getId()));
|
getEffects().get(0).setTargetPointer(new FixedTarget(permanent.getId()));
|
||||||
return true;
|
return true;
|
||||||
|
@ -136,7 +133,7 @@ class VorinclexEffect extends ManaEffect {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Permanent land = game.getPermanent(this.targetPointer.getFirst(game, source));
|
Permanent land = game.getPermanentOrLKIBattlefield(this.targetPointer.getFirst(game, source));
|
||||||
Abilities<ManaAbility> mana = land.getAbilities().getManaAbilities(Zone.BATTLEFIELD);
|
Abilities<ManaAbility> mana = land.getAbilities().getManaAbilities(Zone.BATTLEFIELD);
|
||||||
Mana types = new Mana();
|
Mana types = new Mana();
|
||||||
for (ManaAbility ability: mana) {
|
for (ManaAbility ability: mana) {
|
||||||
|
@ -144,47 +141,50 @@ class VorinclexEffect extends ManaEffect {
|
||||||
}
|
}
|
||||||
Choice choice = new ChoiceImpl(true);
|
Choice choice = new ChoiceImpl(true);
|
||||||
choice.setMessage("Pick a mana color");
|
choice.setMessage("Pick a mana color");
|
||||||
if (types.getBlack() > 0)
|
if (types.getBlack() > 0) {
|
||||||
choice.getChoices().add("Black");
|
choice.getChoices().add("Black");
|
||||||
if (types.getRed() > 0)
|
}
|
||||||
|
if (types.getRed() > 0) {
|
||||||
choice.getChoices().add("Red");
|
choice.getChoices().add("Red");
|
||||||
if (types.getBlue() > 0)
|
}
|
||||||
|
if (types.getBlue() > 0) {
|
||||||
choice.getChoices().add("Blue");
|
choice.getChoices().add("Blue");
|
||||||
if (types.getGreen() > 0)
|
}
|
||||||
|
if (types.getGreen() > 0) {
|
||||||
choice.getChoices().add("Green");
|
choice.getChoices().add("Green");
|
||||||
if (types.getWhite() > 0)
|
}
|
||||||
|
if (types.getWhite() > 0) {
|
||||||
choice.getChoices().add("White");
|
choice.getChoices().add("White");
|
||||||
if (types.getColorless() > 0)
|
}
|
||||||
|
if (types.getColorless() > 0) {
|
||||||
choice.getChoices().add("Colorless");
|
choice.getChoices().add("Colorless");
|
||||||
|
}
|
||||||
if (choice.getChoices().size() > 0) {
|
if (choice.getChoices().size() > 0) {
|
||||||
Player player = game.getPlayer(source.getControllerId());
|
Player player = game.getPlayer(source.getControllerId());
|
||||||
if (choice.getChoices().size() == 1)
|
if (choice.getChoices().size() == 1) {
|
||||||
choice.setChoice(choice.getChoices().iterator().next());
|
choice.setChoice(choice.getChoices().iterator().next());
|
||||||
else
|
} else {
|
||||||
player.choose(outcome, choice, game);
|
player.choose(outcome, choice, game);
|
||||||
if (choice.getChoice().equals("Black")) {
|
|
||||||
player.getManaPool().addMana(Mana.BlackMana, game, source);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
else if (choice.getChoice().equals("Blue")) {
|
switch (choice.getChoice()) {
|
||||||
player.getManaPool().addMana(Mana.BlueMana, game, source);
|
case "Black":
|
||||||
return true;
|
player.getManaPool().addMana(Mana.BlackMana, game, source);
|
||||||
}
|
return true;
|
||||||
else if (choice.getChoice().equals("Red")) {
|
case "Blue":
|
||||||
player.getManaPool().addMana(Mana.RedMana, game, source);
|
player.getManaPool().addMana(Mana.BlueMana, game, source);
|
||||||
return true;
|
return true;
|
||||||
}
|
case "Red":
|
||||||
else if (choice.getChoice().equals("Green")) {
|
player.getManaPool().addMana(Mana.RedMana, game, source);
|
||||||
player.getManaPool().addMana(Mana.GreenMana, game, source);
|
return true;
|
||||||
return true;
|
case "Green":
|
||||||
}
|
player.getManaPool().addMana(Mana.GreenMana, game, source);
|
||||||
else if (choice.getChoice().equals("White")) {
|
return true;
|
||||||
player.getManaPool().addMana(Mana.WhiteMana, game, source);
|
case "White":
|
||||||
return true;
|
player.getManaPool().addMana(Mana.WhiteMana, game, source);
|
||||||
}
|
return true;
|
||||||
else if (choice.getChoice().equals("Colorless")) {
|
case "Colorless":
|
||||||
player.getManaPool().addMana(Mana.ColorlessMana, game, source);
|
player.getManaPool().addMana(Mana.ColorlessMana, game, source);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -13,6 +13,7 @@ import mage.game.Game;
|
||||||
public interface MageObject extends MageItem, Serializable {
|
public interface MageObject extends MageItem, Serializable {
|
||||||
|
|
||||||
String getName();
|
String getName();
|
||||||
|
String getLogName();
|
||||||
String getImageName();
|
String getImageName();
|
||||||
void setName(String name);
|
void setName(String name);
|
||||||
|
|
||||||
|
|
|
@ -94,6 +94,10 @@ public abstract class MageObjectImpl implements MageObject {
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
@Override
|
||||||
|
public String getLogName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getImageName() {
|
public String getImageName() {
|
||||||
|
|
|
@ -821,14 +821,14 @@ public abstract class AbilityImpl implements Ability {
|
||||||
if (object instanceof StackAbility) {
|
if (object instanceof StackAbility) {
|
||||||
Card card = game.getCard(((StackAbility) object).getSourceId());
|
Card card = game.getCard(((StackAbility) object).getSourceId());
|
||||||
if (card != null) {
|
if (card != null) {
|
||||||
sb.append(card.getName());
|
sb.append(card.getLogName());
|
||||||
} else {
|
} else {
|
||||||
sb.append(object.getName());
|
sb.append(object.getName());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (object instanceof Spell) {
|
if (object instanceof Spell) {
|
||||||
Spell spell = (Spell) object;
|
Spell spell = (Spell) object;
|
||||||
String castText = spell.getSpellAbility().toString();
|
String castText = spell.getSpellCastText(game);
|
||||||
sb.append((castText.startsWith("Cast ") ? castText.substring(5):castText));
|
sb.append((castText.startsWith("Cast ") ? castText.substring(5):castText));
|
||||||
if (spell.getFromZone() == Zone.GRAVEYARD) {
|
if (spell.getFromZone() == Zone.GRAVEYARD) {
|
||||||
sb.append(" from graveyard");
|
sb.append(" from graveyard");
|
||||||
|
|
|
@ -82,8 +82,8 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
|
||||||
Player player = game.getPlayer(this.getControllerId());
|
Player player = game.getPlayer(this.getControllerId());
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
if (object != null) {
|
if (object != null) {
|
||||||
sb.append("Use the following ability from ").append(object.getName()).append("? ");
|
sb.append("Use the following ability from ").append(object.getLogName()).append("? ");
|
||||||
sb.append(this.getRule(object.getName()));
|
sb.append(this.getRule(object.getLogName()));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
sb.append("Use the following ability? ").append(this.getRule());
|
sb.append("Use the following ability? ").append(this.getRule());
|
||||||
|
@ -104,7 +104,7 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
|
||||||
MageObject object = game.getObject(sourceId);
|
MageObject object = game.getObject(sourceId);
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
if (object != null) {
|
if (object != null) {
|
||||||
sb.append("Ability triggers: ").append(object.getName()).append(" - ").append(this.getRule(object.getName()));
|
sb.append("Ability triggers: ").append(object.getLogName()).append(" - ").append(this.getRule(object.getLogName()));
|
||||||
} else {
|
} else {
|
||||||
sb.append("Ability triggers: ").append(this.getRule());
|
sb.append("Ability triggers: ").append(this.getRule());
|
||||||
}
|
}
|
||||||
|
|
97
Mage/src/mage/abilities/common/TurnFaceUpAbility.java
Normal file
97
Mage/src/mage/abilities/common/TurnFaceUpAbility.java
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification, are
|
||||||
|
* permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||||
|
* conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||||
|
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* The views and conclusions contained in the software and documentation are those of the
|
||||||
|
* authors and should not be interpreted as representing official policies, either expressed
|
||||||
|
* or implied, of BetaSteward_at_googlemail.com.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package mage.abilities.common;
|
||||||
|
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.ActivatedAbilityImpl;
|
||||||
|
import mage.abilities.costs.Costs;
|
||||||
|
import mage.abilities.effects.OneShotEffect;
|
||||||
|
import mage.cards.Card;
|
||||||
|
import mage.constants.Outcome;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.game.permanent.Permanent;
|
||||||
|
import mage.players.Player;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author LevelX2
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class TurnFaceUpAbility extends ActivatedAbilityImpl {
|
||||||
|
|
||||||
|
public TurnFaceUpAbility(Costs costs) {
|
||||||
|
super(Zone.BATTLEFIELD, new TurnFaceUpEffect(), costs);
|
||||||
|
this.usesStack = false;
|
||||||
|
this.setRuleVisible(false); // will be made visible only to controller in CardView
|
||||||
|
}
|
||||||
|
|
||||||
|
public TurnFaceUpAbility(final TurnFaceUpAbility ability) {
|
||||||
|
super(ability);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TurnFaceUpAbility copy() {
|
||||||
|
return new TurnFaceUpAbility(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TurnFaceUpEffect extends OneShotEffect {
|
||||||
|
|
||||||
|
public TurnFaceUpEffect() {
|
||||||
|
super(Outcome.Benefit);
|
||||||
|
this.staticText = "Turn this face-down permanent face up";
|
||||||
|
}
|
||||||
|
|
||||||
|
public TurnFaceUpEffect(final TurnFaceUpEffect effect) {
|
||||||
|
super(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TurnFaceUpEffect copy() {
|
||||||
|
return new TurnFaceUpEffect(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
Player controller = game.getPlayer(source.getControllerId());
|
||||||
|
Card card = game.getCard(source.getSourceId());
|
||||||
|
if (controller != null && card !=null) {
|
||||||
|
Permanent sourcePermanent = game.getPermanent(source.getSourceId());
|
||||||
|
if (sourcePermanent != null) {
|
||||||
|
if (sourcePermanent.turnFaceUp(game, source.getControllerId())) {
|
||||||
|
game.informPlayers(controller.getName() + " pays the costs of " + card.getLogName() + " to turn it face up");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package mage.abilities.common;
|
||||||
|
|
||||||
|
import mage.abilities.TriggeredAbilityImpl;
|
||||||
|
import mage.abilities.effects.Effect;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.game.events.GameEvent;
|
||||||
|
import mage.game.events.GameEvent.EventType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author LevelX2
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class TurnedFaceUpTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
|
public TurnedFaceUpTriggeredAbility(Effect effect) {
|
||||||
|
super(Zone.BATTLEFIELD, effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TurnedFaceUpTriggeredAbility(final TurnedFaceUpTriggeredAbility ability) {
|
||||||
|
super(ability);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TurnedFaceUpTriggeredAbility copy() {
|
||||||
|
return new TurnedFaceUpTriggeredAbility(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkTrigger(GameEvent event, Game game) {
|
||||||
|
return EventType.TURNEDFACEUP.equals(event.getType()) && event.getTargetId().equals(this.getSourceId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRule() {
|
||||||
|
return "When {this} is turned face up, " + super.getRule();
|
||||||
|
}
|
||||||
|
}
|
|
@ -105,7 +105,7 @@ public class RemoveCounterCost extends CostImpl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
choice.setChoices(choices);
|
choice.setChoices(choices);
|
||||||
choice.setMessage("Choose a counter to remove from " + permanent.getName());
|
choice.setMessage("Choose a counter to remove from " + permanent.getLogName());
|
||||||
controller.choose(Outcome.UnboostCreature, choice, game);
|
controller.choose(Outcome.UnboostCreature, choice, game);
|
||||||
counterName = choice.getChoice();
|
counterName = choice.getChoice();
|
||||||
} else {
|
} else {
|
||||||
|
@ -122,7 +122,7 @@ public class RemoveCounterCost extends CostImpl {
|
||||||
int numberOfCountersSelected = 1;
|
int numberOfCountersSelected = 1;
|
||||||
if (countersLeft > 1 && countersOnPermanent > 1) {
|
if (countersLeft > 1 && countersOnPermanent > 1) {
|
||||||
numberOfCountersSelected = controller.getAmount(1, Math.min(countersLeft, countersOnPermanent),
|
numberOfCountersSelected = controller.getAmount(1, Math.min(countersLeft, countersOnPermanent),
|
||||||
new StringBuilder("Remove how many counters from ").append(permanent.getName()).toString(), game);
|
new StringBuilder("Remove how many counters from ").append(permanent.getLogName()).toString(), game);
|
||||||
}
|
}
|
||||||
permanent.removeCounters(counterName, numberOfCountersSelected, game);
|
permanent.removeCounters(counterName, numberOfCountersSelected, game);
|
||||||
if (permanent.getCounters().getCount(counterName) == 0 ){
|
if (permanent.getCounters().getCount(counterName) == 0 ){
|
||||||
|
|
|
@ -911,7 +911,7 @@ public class ContinuousEffects implements Serializable {
|
||||||
for (Ability ability :(HashSet<Ability>) entry.getValue()) {
|
for (Ability ability :(HashSet<Ability>) entry.getValue()) {
|
||||||
MageObject object = game.getObject(ability.getSourceId());
|
MageObject object = game.getObject(ability.getSourceId());
|
||||||
if (object != null) {
|
if (object != null) {
|
||||||
texts.add(ability.getRule(object.getName()));
|
texts.add(ability.getRule(object.getLogName()));
|
||||||
} else {
|
} else {
|
||||||
texts.add(((ReplacementEffect)entry.getKey()).getText(null));
|
texts.add(((ReplacementEffect)entry.getKey()).getText(null));
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,7 +113,7 @@ public class EntersBattlefieldEffect extends ReplacementEffectImpl {
|
||||||
if (controller == null || object == null) {
|
if (controller == null || object == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!controller.chooseUse(outcome, new StringBuilder("Use effect of ").append(object.getName()).append("?").toString(), game)) {
|
if (!controller.chooseUse(outcome, new StringBuilder("Use effect of ").append(object.getLogName()).append("?").toString(), game)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,7 +85,7 @@ public class PlaneswalkerRedirectionEffect extends RedirectionEffect {
|
||||||
game.informPlayers(new StringBuilder(player.getName()).append(" redirects ")
|
game.informPlayers(new StringBuilder(player.getName()).append(" redirects ")
|
||||||
.append(event.getAmount())
|
.append(event.getAmount())
|
||||||
.append(" damage to ")
|
.append(" damage to ")
|
||||||
.append(game.getPermanent(redirectTarget.getFirstTarget()).getName()).toString());
|
.append(game.getPermanent(redirectTarget.getFirstTarget()).getLogName()).toString());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@ public class ChooseColorEffect extends OneShotEffect {
|
||||||
if (player != null && permanent != null) {
|
if (player != null && permanent != null) {
|
||||||
ChoiceColor colorChoice = new ChoiceColor();
|
ChoiceColor colorChoice = new ChoiceColor();
|
||||||
if (player.choose(outcome, colorChoice, game)) {
|
if (player.choose(outcome, colorChoice, game)) {
|
||||||
game.informPlayers(new StringBuilder(permanent.getName()).append(": ").append(player.getName()).append(" has chosen ").append(colorChoice.getChoice()).toString());
|
game.informPlayers(new StringBuilder(permanent.getLogName()).append(": ").append(player.getName()).append(" has chosen ").append(colorChoice.getChoice()).toString());
|
||||||
game.getState().setValue(source.getSourceId() + "_color", colorChoice.getColor());
|
game.getState().setValue(source.getSourceId() + "_color", colorChoice.getColor());
|
||||||
permanent.addInfo("chosen color", "<font color = 'blue'>Chosen color: " + colorChoice.getColor().getDescription() + "</font>");
|
permanent.addInfo("chosen color", "<font color = 'blue'>Chosen color: " + colorChoice.getColor().getDescription() + "</font>");
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,12 +94,12 @@ public class CipherEffect extends OneShotEffect {
|
||||||
Card sourceCard = game.getCard(source.getSourceId());
|
Card sourceCard = game.getCard(source.getSourceId());
|
||||||
Permanent targetCreature = game.getPermanent(target.getFirstTarget());
|
Permanent targetCreature = game.getPermanent(target.getFirstTarget());
|
||||||
if (targetCreature != null && sourceCard != null) {
|
if (targetCreature != null && sourceCard != null) {
|
||||||
String ruleText = new StringBuilder("you may cast a copy of ").append(sourceCard.getName()).append(" without paying its mana cost").toString();
|
String ruleText = new StringBuilder("you may cast a copy of ").append(sourceCard.getLogName()).append(" without paying its mana cost").toString();
|
||||||
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new CipherStoreEffect(source.getSourceId(), ruleText), true);
|
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new CipherStoreEffect(source.getSourceId(), ruleText), true);
|
||||||
ContinuousEffect effect = new GainAbilityTargetEffect(ability, Duration.Custom);
|
ContinuousEffect effect = new GainAbilityTargetEffect(ability, Duration.Custom);
|
||||||
effect.setTargetPointer(new FixedTarget(target.getFirstTarget()));
|
effect.setTargetPointer(new FixedTarget(target.getFirstTarget()));
|
||||||
game.addEffect(effect, source);
|
game.addEffect(effect, source);
|
||||||
game.informPlayers(new StringBuilder(sourceCard.getName()).append(": Spell ciphered to ").append(targetCreature.getName()).toString());
|
game.informPlayers(new StringBuilder(sourceCard.getLogName()).append(": Spell ciphered to ").append(targetCreature.getLogName()).toString());
|
||||||
return sourceCard.moveToExile(null, "", source.getId(), game);
|
return sourceCard.moveToExile(null, "", source.getId(), game);
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -104,7 +104,7 @@ public class AddCountersSourceEffect extends OneShotEffect {
|
||||||
if (informPlayers) {
|
if (informPlayers) {
|
||||||
Player player = game.getPlayer(source.getControllerId());
|
Player player = game.getPlayer(source.getControllerId());
|
||||||
if (player != null) {
|
if (player != null) {
|
||||||
game.informPlayers(new StringBuilder(player.getName()).append(" puts ").append(newCounter.getCount()).append(" ").append(newCounter.getName().toLowerCase()).append(" counter on ").append(card.getName()).toString());
|
game.informPlayers(new StringBuilder(player.getName()).append(" puts ").append(newCounter.getCount()).append(" ").append(newCounter.getName().toLowerCase()).append(" counter on ").append(card.getLogName()).toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -124,7 +124,7 @@ public class AddCountersSourceEffect extends OneShotEffect {
|
||||||
if (informPlayers) {
|
if (informPlayers) {
|
||||||
Player player = game.getPlayer(source.getControllerId());
|
Player player = game.getPlayer(source.getControllerId());
|
||||||
if (player != null) {
|
if (player != null) {
|
||||||
game.informPlayers(new StringBuilder(player.getName()).append(" puts ").append(newCounter.getCount()).append(" ").append(newCounter.getName().toLowerCase()).append(" counter on ").append(permanent.getName()).toString());
|
game.informPlayers(new StringBuilder(player.getName()).append(" puts ").append(newCounter.getCount()).append(" ").append(newCounter.getName().toLowerCase()).append(" counter on ").append(permanent.getLogName()).toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,10 +93,10 @@ public class AddCountersTargetEffect extends OneShotEffect {
|
||||||
newCounter.add(amount.calculate(game, source));
|
newCounter.add(amount.calculate(game, source));
|
||||||
permanent.addCounters(newCounter, game);
|
permanent.addCounters(newCounter, game);
|
||||||
affectedTargets ++;
|
affectedTargets ++;
|
||||||
game.informPlayers(new StringBuilder(sourceObject.getName()).append(": ")
|
game.informPlayers(new StringBuilder(sourceObject.getLogName()).append(": ")
|
||||||
.append(controller.getName()).append(" puts ")
|
.append(controller.getName()).append(" puts ")
|
||||||
.append(counter.getCount()).append(" ").append(counter.getName().toLowerCase())
|
.append(counter.getCount()).append(" ").append(counter.getName().toLowerCase())
|
||||||
.append(" counter on ").append(permanent.getName()).toString());
|
.append(" counter on ").append(permanent.getLogName()).toString());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Player player = game.getPlayer(uuid);
|
Player player = game.getPlayer(uuid);
|
||||||
|
@ -105,7 +105,7 @@ public class AddCountersTargetEffect extends OneShotEffect {
|
||||||
newCounter.add(amount.calculate(game, source));
|
newCounter.add(amount.calculate(game, source));
|
||||||
player.addCounters(newCounter, game);
|
player.addCounters(newCounter, game);
|
||||||
affectedTargets ++;
|
affectedTargets ++;
|
||||||
game.informPlayers(new StringBuilder(sourceObject.getName()).append(": ")
|
game.informPlayers(new StringBuilder(sourceObject.getLogName()).append(": ")
|
||||||
.append(controller.getName()).append(" puts ")
|
.append(controller.getName()).append(" puts ")
|
||||||
.append(counter.getCount()).append(" ").append(counter.getName().toLowerCase())
|
.append(counter.getCount()).append(" ").append(counter.getName().toLowerCase())
|
||||||
.append(" counter on ").append(player.getName()).toString());
|
.append(" counter on ").append(player.getName()).toString());
|
||||||
|
|
348
Mage/src/mage/abilities/keyword/MorphAbility.java
Normal file
348
Mage/src/mage/abilities/keyword/MorphAbility.java
Normal file
|
@ -0,0 +1,348 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification, are
|
||||||
|
* permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
||||||
|
* conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
||||||
|
* of conditions and the following disclaimer in the documentation and/or other materials
|
||||||
|
* provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* The views and conclusions contained in the software and documentation are those of the
|
||||||
|
* authors and should not be interpreted as representing official policies, either expressed
|
||||||
|
* or implied, of BetaSteward_at_googlemail.com.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package mage.abilities.keyword;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import mage.ObjectColor;
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.SpellAbility;
|
||||||
|
import mage.abilities.StaticAbility;
|
||||||
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
|
import mage.abilities.common.TurnFaceUpAbility;
|
||||||
|
import mage.abilities.common.TurnedFaceUpTriggeredAbility;
|
||||||
|
import mage.abilities.costs.AlternativeCost2;
|
||||||
|
import mage.abilities.costs.AlternativeCost2Impl;
|
||||||
|
import mage.abilities.costs.AlternativeSourceCosts;
|
||||||
|
import mage.abilities.costs.Cost;
|
||||||
|
import mage.abilities.costs.Costs;
|
||||||
|
import mage.abilities.costs.CostsImpl;
|
||||||
|
import mage.abilities.costs.mana.GenericManaCost;
|
||||||
|
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||||
|
import mage.abilities.effects.ContinuousEffectImpl;
|
||||||
|
import mage.abilities.effects.common.continious.SourceEffect;
|
||||||
|
import mage.cards.Card;
|
||||||
|
import mage.constants.Duration;
|
||||||
|
import mage.constants.Layer;
|
||||||
|
import mage.constants.Outcome;
|
||||||
|
import mage.constants.SubLayer;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.game.permanent.Permanent;
|
||||||
|
import mage.game.stack.Spell;
|
||||||
|
import mage.players.Player;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 702.36. Morph
|
||||||
|
*
|
||||||
|
* 702.36a Morph is a static ability that functions in any zone from which you could play
|
||||||
|
* the card its on, and the morph effect works any time the card is face down.
|
||||||
|
* "Morph [cost]" means "You may cast this card as a 2/2 face-down creature, with no text,
|
||||||
|
* no name, no subtypes, and no mana cost by paying {3} rather than paying its mana cost."
|
||||||
|
* (See rule 707, "Face-Down Spells and Permanents.")
|
||||||
|
*
|
||||||
|
* 702.36b To cast a card using its morph ability, turn it face down. It becomes a 2/2
|
||||||
|
* face-down creature card, with no text, no name, no subtypes, and no mana cost. Any
|
||||||
|
* effects or prohibitions that would apply to casting a card with these characteristics
|
||||||
|
* (and not the face-up cards characteristics) are applied to casting this card. These
|
||||||
|
* values are the copiable values of that objects characteristics. (See rule 613,
|
||||||
|
* "Interaction of Continuous Effects," and rule 706, "Copying Objects.") Put it onto the
|
||||||
|
* stack (as a face-down spell with the same characteristics), and pay {3} rather than pay
|
||||||
|
* its mana cost. This follows the rules for paying alternative costs. You can use morph
|
||||||
|
* to cast a card from any zone from which you could normally play it. When the spell
|
||||||
|
* resolves, it enters the battlefield with the same characteristics the spell had. The
|
||||||
|
* morph effect applies to the face-down object wherever it is, and it ends when the
|
||||||
|
* permanent is turned face up. #
|
||||||
|
*
|
||||||
|
* 702.36c You cant cast a card face down if it doesnt have morph.
|
||||||
|
*
|
||||||
|
* 702.36d If you have priority, you may turn a face-down permanent you control face up.
|
||||||
|
* This is a special action; it doesnt use the stack (see rule 115). To do this, show
|
||||||
|
* all players what the permanents morph cost would be if it were face up, pay that cost,
|
||||||
|
* then turn the permanent face up. (If the permanent wouldnt have a morph cost if it
|
||||||
|
* were face up, it cant be turned face up this way.) The morph effect on it ends, and
|
||||||
|
* it regains its normal characteristics. Any abilities relating to the permanent entering
|
||||||
|
* the battlefield dont trigger when its turned face up and dont have any effect, because
|
||||||
|
* the permanent has already entered the battlefield.
|
||||||
|
*
|
||||||
|
* 702.36e See rule 707, "Face-Down Spells and Permanents," for more information on how to
|
||||||
|
* cast cards with morph.
|
||||||
|
*
|
||||||
|
* @author LevelX2
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class MorphAbility extends StaticAbility implements AlternativeSourceCosts {
|
||||||
|
|
||||||
|
protected static final String ABILITY_KEYWORD = "Morph";
|
||||||
|
protected static final String REMINDER_TEXT = "(You may cast this face down as a 2/2 creature for {3}. Turn it face up any time for its morph cost.)";
|
||||||
|
protected String morphCostsText;
|
||||||
|
protected List<AlternativeCost2> alternateCosts = new LinkedList<>();
|
||||||
|
|
||||||
|
// needed to check activation status, if card changes zone after casting it
|
||||||
|
private int zoneChangeCounter = 0;
|
||||||
|
|
||||||
|
public MorphAbility(Card card, Cost morphCost) {
|
||||||
|
this(card, createCosts(morphCost));
|
||||||
|
}
|
||||||
|
|
||||||
|
public MorphAbility(Card card, Costs morphCosts) {
|
||||||
|
super(Zone.HAND, null);
|
||||||
|
card.setMorphCard(true);
|
||||||
|
name = ABILITY_KEYWORD;
|
||||||
|
morphCostsText = morphCosts.getText();
|
||||||
|
alternateCosts.add(new AlternativeCost2Impl(ABILITY_KEYWORD, REMINDER_TEXT, new GenericManaCost(3)));
|
||||||
|
|
||||||
|
Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BecomesFaceDownCreatureEffect(morphCosts));
|
||||||
|
ability.setRuleVisible(false);
|
||||||
|
card.addAbility(ability);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public MorphAbility(final MorphAbility ability) {
|
||||||
|
super(ability);
|
||||||
|
this.alternateCosts.addAll(ability.alternateCosts);
|
||||||
|
this.zoneChangeCounter = ability.zoneChangeCounter;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Costs createCosts(Cost cost) {
|
||||||
|
Costs costs = new CostsImpl();
|
||||||
|
costs.add(cost);
|
||||||
|
return costs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MorphAbility copy() {
|
||||||
|
return new MorphAbility(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resetMorph() {
|
||||||
|
for (AlternativeCost2 cost: alternateCosts) {
|
||||||
|
cost.reset();
|
||||||
|
}
|
||||||
|
zoneChangeCounter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isActivated(Ability ability, Game game) {
|
||||||
|
Card card = game.getCard(sourceId);
|
||||||
|
if (card != null && card.getZoneChangeCounter() <= zoneChangeCounter +1) {
|
||||||
|
for (AlternativeCost2 cost: alternateCosts) {
|
||||||
|
if(cost.isActivated(game)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAvailable(Ability source, Game game) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean askToActivateAlternativeCosts(Ability ability, Game game) {
|
||||||
|
if (ability instanceof SpellAbility) {
|
||||||
|
Player player = game.getPlayer(controllerId);
|
||||||
|
if (player != null) {
|
||||||
|
this.resetMorph();
|
||||||
|
for (AlternativeCost2 alternateCastingCost: alternateCosts) {
|
||||||
|
if (alternateCastingCost.canPay(sourceId, controllerId, game) &&
|
||||||
|
player.chooseUse(Outcome.Benefit, new StringBuilder("Cast this card as a 2/2 face-down creature for ").append(alternateCastingCost.getText(true)).append(" ?").toString(), game)) {
|
||||||
|
|
||||||
|
Spell spell = game.getStack().getSpell(ability.getId());
|
||||||
|
if (spell != null) {
|
||||||
|
spell.setFaceDown(true);
|
||||||
|
} activateMorph(alternateCastingCost, game);
|
||||||
|
ability.getManaCostsToPay().clear();
|
||||||
|
ability.getCosts().clear();
|
||||||
|
for (Iterator it = ((Costs) alternateCastingCost).iterator(); it.hasNext();) {
|
||||||
|
Cost cost = (Cost) it.next();
|
||||||
|
if (cost instanceof ManaCostsImpl) {
|
||||||
|
ability.getManaCostsToPay().add((ManaCostsImpl) cost.copy());
|
||||||
|
} else {
|
||||||
|
ability.getCosts().add(cost.copy());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Card card = game.getCard(getSourceId()); // face down was set to true in PlayerImpl.cast, reset it here if not cast face down
|
||||||
|
if (card != null) {
|
||||||
|
card.setFaceDown(false);
|
||||||
|
}
|
||||||
|
Spell spell = game.getStack().getSpell(ability.getId());
|
||||||
|
if (spell != null) {
|
||||||
|
spell.setFaceDown(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return isActivated(ability, game);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void activateMorph(AlternativeCost2 cost, Game game) {
|
||||||
|
cost.activate();
|
||||||
|
// remember zone change counter
|
||||||
|
if (zoneChangeCounter == 0) {
|
||||||
|
Card card = game.getCard(getSourceId());
|
||||||
|
if (card != null) {
|
||||||
|
zoneChangeCounter = card.getZoneChangeCounter();
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Morph source card not found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRule() {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
int numberCosts = 0;
|
||||||
|
String remarkText = "";
|
||||||
|
for (AlternativeCost2 alternateCastingCost: alternateCosts) {
|
||||||
|
if (numberCosts == 0) {
|
||||||
|
sb.append(alternateCastingCost.getText(false));
|
||||||
|
remarkText = alternateCastingCost.getReminderText();
|
||||||
|
} else {
|
||||||
|
sb.append(" and/or ").append(alternateCastingCost.getText(true));
|
||||||
|
}
|
||||||
|
++numberCosts;
|
||||||
|
}
|
||||||
|
if (numberCosts == 1) {
|
||||||
|
sb.append(" ").append(remarkText);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCastMessageSuffix(Game game) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
int position = 0;
|
||||||
|
for (AlternativeCost2 cost : alternateCosts) {
|
||||||
|
if (cost.isActivated(game)) {
|
||||||
|
sb.append(cost.getCastSuffixMessage(position));
|
||||||
|
++position;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This effect lets the creature always be a 2/2 face-down creature, with no text,
|
||||||
|
* no name, no subtypes, and no mana cost, if it's fac down on the battlefield.
|
||||||
|
* And it adds the MorphTurnFaceUpAbility ability.
|
||||||
|
* TODO: Check if it's better to create this effect always as a creature on the battelfield turns face down or
|
||||||
|
* a creature enters the battlefield face down. Then the effect could be removed as the permanent turns face up.
|
||||||
|
*
|
||||||
|
* @author LevelX2
|
||||||
|
*/
|
||||||
|
|
||||||
|
class BecomesFaceDownCreatureEffect extends ContinuousEffectImpl implements SourceEffect {
|
||||||
|
|
||||||
|
protected int zoneChangeCounter;
|
||||||
|
protected Ability turnFaceUpAbility = null;
|
||||||
|
|
||||||
|
public BecomesFaceDownCreatureEffect(Costs morphCosts) {
|
||||||
|
super(Duration.WhileOnBattlefield, Outcome.BecomeCreature);
|
||||||
|
this.zoneChangeCounter = Integer.MIN_VALUE;
|
||||||
|
if (morphCosts != null) {
|
||||||
|
this.turnFaceUpAbility = new TurnFaceUpAbility(morphCosts);
|
||||||
|
}
|
||||||
|
staticText = "{this} becomes a 2/2 face-down creature, with no text, no name, no subtypes, and no mana cost";
|
||||||
|
}
|
||||||
|
|
||||||
|
public BecomesFaceDownCreatureEffect(final BecomesFaceDownCreatureEffect effect) {
|
||||||
|
super(effect);
|
||||||
|
this.zoneChangeCounter = effect.zoneChangeCounter;
|
||||||
|
this.turnFaceUpAbility = effect.turnFaceUpAbility.copy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BecomesFaceDownCreatureEffect copy() {
|
||||||
|
return new BecomesFaceDownCreatureEffect(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) {
|
||||||
|
Permanent permanent = game.getPermanent(source.getSourceId());
|
||||||
|
if (permanent != null && permanent.isFaceDown()) {
|
||||||
|
switch (layer) {
|
||||||
|
case TypeChangingEffects_4:
|
||||||
|
permanent.setName("");
|
||||||
|
permanent.getSubtype().clear();
|
||||||
|
permanent.getManaCost().clear();
|
||||||
|
break;
|
||||||
|
case ColorChangingEffects_5:
|
||||||
|
permanent.getColor().setColor(new ObjectColor());
|
||||||
|
break;
|
||||||
|
case AbilityAddingRemovingEffects_6:
|
||||||
|
List<Ability> abilities = new ArrayList<>();
|
||||||
|
for (Ability ability : permanent.getAbilities()) {
|
||||||
|
// TODO: Add flag "works also face down" to ability and use it to control ability removement instead of instanceof check
|
||||||
|
if (ability instanceof TurnedFaceUpTriggeredAbility) {
|
||||||
|
ability.setRuleVisible(false);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!ability.getRuleVisible() && !ability.getEffects().isEmpty()) {
|
||||||
|
if (ability.getEffects().get(0) instanceof BecomesFaceDownCreatureEffect) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
abilities.add(ability);
|
||||||
|
}
|
||||||
|
permanent.getAbilities().removeAll(abilities);
|
||||||
|
if (turnFaceUpAbility != null) {
|
||||||
|
permanent.addAbility(turnFaceUpAbility, game);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PTChangingEffects_7:
|
||||||
|
if (sublayer == SubLayer.SetPT_7b) {
|
||||||
|
permanent.getPower().setValue(2);
|
||||||
|
permanent.getToughness().setValue(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasLayer(Layer layer) {
|
||||||
|
return layer == Layer.PTChangingEffects_7 || layer == Layer.AbilityAddingRemovingEffects_6 || layer == Layer.ColorChangingEffects_5 || layer == Layer.TypeChangingEffects_4;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -28,21 +28,20 @@
|
||||||
|
|
||||||
package mage.cards;
|
package mage.cards;
|
||||||
|
|
||||||
import mage.constants.Rarity;
|
import java.util.ArrayList;
|
||||||
import mage.constants.Zone;
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
import mage.MageObject;
|
import mage.MageObject;
|
||||||
import mage.Mana;
|
import mage.Mana;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.SpellAbility;
|
import mage.abilities.SpellAbility;
|
||||||
|
import mage.constants.Rarity;
|
||||||
|
import mage.constants.Zone;
|
||||||
import mage.counters.Counter;
|
import mage.counters.Counter;
|
||||||
import mage.counters.Counters;
|
import mage.counters.Counters;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.watchers.Watcher;
|
import mage.watchers.Watcher;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public interface Card extends MageObject {
|
public interface Card extends MageObject {
|
||||||
|
|
||||||
UUID getOwnerId();
|
UUID getOwnerId();
|
||||||
|
@ -62,6 +61,8 @@ public interface Card extends MageObject {
|
||||||
void setExpansionSetCode(String expansionSetCode);
|
void setExpansionSetCode(String expansionSetCode);
|
||||||
void setFaceDown(boolean value);
|
void setFaceDown(boolean value);
|
||||||
boolean isFaceDown();
|
boolean isFaceDown();
|
||||||
|
boolean turnFaceUp(Game game, UUID playerId);
|
||||||
|
boolean turnFaceDown(Game game, UUID playerId);
|
||||||
boolean isFlipCard();
|
boolean isFlipCard();
|
||||||
String getFlipCardName();
|
String getFlipCardName();
|
||||||
void setFlipCard(boolean flipCard);
|
void setFlipCard(boolean flipCard);
|
||||||
|
@ -132,6 +133,10 @@ public interface Card extends MageObject {
|
||||||
|
|
||||||
void removeCounters(String name, int amount, Game game);
|
void removeCounters(String name, int amount, Game game);
|
||||||
void removeCounters(Counter counter, Game game);
|
void removeCounters(Counter counter, Game game);
|
||||||
|
|
||||||
|
void setMorphCard(boolean morphCard);
|
||||||
|
boolean isMorphCard();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
Card copy();
|
Card copy();
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,18 +28,38 @@
|
||||||
|
|
||||||
package mage.cards;
|
package mage.cards;
|
||||||
|
|
||||||
import mage.constants.CardType;
|
import java.lang.reflect.Constructor;
|
||||||
import mage.constants.Rarity;
|
import java.util.ArrayList;
|
||||||
import mage.constants.Zone;
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
import mage.MageObject;
|
||||||
import mage.MageObjectImpl;
|
import mage.MageObjectImpl;
|
||||||
import mage.Mana;
|
import mage.Mana;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.PlayLandAbility;
|
import mage.abilities.PlayLandAbility;
|
||||||
import mage.abilities.SpellAbility;
|
import mage.abilities.SpellAbility;
|
||||||
import mage.abilities.mana.ManaAbility;
|
import mage.abilities.mana.ManaAbility;
|
||||||
|
import mage.constants.CardType;
|
||||||
|
import mage.constants.Rarity;
|
||||||
|
import mage.constants.SpellAbilityType;
|
||||||
|
import mage.constants.TimingRule;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import static mage.constants.Zone.BATTLEFIELD;
|
||||||
|
import static mage.constants.Zone.COMMAND;
|
||||||
|
import static mage.constants.Zone.EXILED;
|
||||||
|
import static mage.constants.Zone.GRAVEYARD;
|
||||||
|
import static mage.constants.Zone.HAND;
|
||||||
|
import static mage.constants.Zone.LIBRARY;
|
||||||
|
import static mage.constants.Zone.OUTSIDE;
|
||||||
|
import static mage.constants.Zone.PICK;
|
||||||
|
import static mage.constants.Zone.STACK;
|
||||||
import mage.counters.Counter;
|
import mage.counters.Counter;
|
||||||
import mage.counters.Counters;
|
import mage.counters.Counters;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
|
import mage.game.command.Commander;
|
||||||
import mage.game.events.GameEvent;
|
import mage.game.events.GameEvent;
|
||||||
import mage.game.events.ZoneChangeEvent;
|
import mage.game.events.ZoneChangeEvent;
|
||||||
import mage.game.permanent.PermanentCard;
|
import mage.game.permanent.PermanentCard;
|
||||||
|
@ -47,13 +67,6 @@ import mage.game.stack.Spell;
|
||||||
import mage.watchers.Watcher;
|
import mage.watchers.Watcher;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
import java.lang.reflect.Constructor;
|
|
||||||
import java.util.*;
|
|
||||||
import mage.MageObject;
|
|
||||||
import mage.constants.SpellAbilityType;
|
|
||||||
import mage.constants.TimingRule;
|
|
||||||
import mage.game.command.Commander;
|
|
||||||
|
|
||||||
public abstract class CardImpl extends MageObjectImpl implements Card {
|
public abstract class CardImpl extends MageObjectImpl implements Card {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@ -77,6 +90,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
||||||
protected boolean usesVariousArt = false;
|
protected boolean usesVariousArt = false;
|
||||||
protected Counters counters;
|
protected Counters counters;
|
||||||
protected boolean splitCard;
|
protected boolean splitCard;
|
||||||
|
protected boolean morphCard;
|
||||||
|
|
||||||
public CardImpl(UUID ownerId, int cardNumber, String name, Rarity rarity, CardType[] cardTypes, String costs) {
|
public CardImpl(UUID ownerId, int cardNumber, String name, Rarity rarity, CardType[] cardTypes, String costs) {
|
||||||
this(ownerId, cardNumber, name, rarity, cardTypes, costs, SpellAbilityType.BASE);
|
this(ownerId, cardNumber, name, rarity, cardTypes, costs, SpellAbilityType.BASE);
|
||||||
|
@ -103,6 +117,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
||||||
}
|
}
|
||||||
this.usesVariousArt = Character.isDigit(this.getClass().getName().charAt(this.getClass().getName().length()-1));
|
this.usesVariousArt = Character.isDigit(this.getClass().getName().charAt(this.getClass().getName().length()-1));
|
||||||
this.counters = new Counters();
|
this.counters = new Counters();
|
||||||
|
this.morphCard = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected CardImpl(UUID ownerId, String name) {
|
protected CardImpl(UUID ownerId, String name) {
|
||||||
|
@ -144,6 +159,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
||||||
splitCard = card.splitCard;
|
splitCard = card.splitCard;
|
||||||
usesVariousArt = card.usesVariousArt;
|
usesVariousArt = card.usesVariousArt;
|
||||||
counters = card.counters.copy();
|
counters = card.counters.copy();
|
||||||
|
morphCard = card.isMorphCard();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -532,12 +548,36 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setFaceDown(boolean value) {
|
public void setFaceDown(boolean value) {
|
||||||
this.faceDown = value;
|
faceDown = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isFaceDown() {
|
public boolean isFaceDown() {
|
||||||
return this.faceDown;
|
return faceDown;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean turnFaceUp(Game game, UUID playerId) {
|
||||||
|
GameEvent event = GameEvent.getEvent(GameEvent.EventType.TURNFACEUP, getId(), playerId);
|
||||||
|
if (!game.replaceEvent(event)) {
|
||||||
|
setFaceDown(false);
|
||||||
|
game.getCard(objectId).setFaceDown(false); // Another instance?
|
||||||
|
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.TURNEDFACEUP, getId(), playerId));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean turnFaceDown(Game game, UUID playerId) {
|
||||||
|
GameEvent event = GameEvent.getEvent(GameEvent.EventType.TURNFACEDOWN, getId(), playerId);
|
||||||
|
if (!game.replaceEvent(event)) {
|
||||||
|
setFaceDown(true);
|
||||||
|
game.getCard(objectId).setFaceDown(true); // Another instance?
|
||||||
|
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.TURNEDFACEDOWN, getId(), playerId));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -673,4 +713,16 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
||||||
public void removeCounters(Counter counter, Game game) {
|
public void removeCounters(Counter counter, Game game) {
|
||||||
removeCounters(counter.getName(), counter.getCount(), game);
|
removeCounters(counter.getName(), counter.getCount(), game);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setMorphCard(boolean morphCard) {
|
||||||
|
this.morphCard = morphCard;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMorphCard() {
|
||||||
|
return morphCard;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,6 +98,11 @@ public class Commander implements CommandObject{
|
||||||
return card.getName();
|
return card.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getLogName() {
|
||||||
|
return card.getName();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setName(String name) {
|
public void setName(String name) {
|
||||||
|
|
||||||
|
|
|
@ -97,6 +97,11 @@ public class Emblem implements CommandObject {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getLogName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getImageName() {
|
public String getImageName() {
|
||||||
return this.name;
|
return this.name;
|
||||||
|
|
|
@ -29,16 +29,15 @@
|
||||||
package mage.game.permanent;
|
package mage.game.permanent;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
import mage.MageObject;
|
import mage.MageObject;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
|
import mage.constants.Zone;
|
||||||
import mage.game.Controllable;
|
import mage.game.Controllable;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
import mage.constants.Zone;
|
|
||||||
|
|
||||||
public interface Permanent extends Card, Controllable {
|
public interface Permanent extends Card, Controllable {
|
||||||
|
|
||||||
boolean isTapped();
|
boolean isTapped();
|
||||||
|
@ -68,10 +67,6 @@ public interface Permanent extends Card, Controllable {
|
||||||
boolean phaseIn(Game game);
|
boolean phaseIn(Game game);
|
||||||
boolean phaseOut(Game game);
|
boolean phaseOut(Game game);
|
||||||
|
|
||||||
boolean isFaceUp();
|
|
||||||
boolean turnFaceUp(Game game);
|
|
||||||
boolean turnFaceDown(Game game);
|
|
||||||
|
|
||||||
boolean isMonstrous();
|
boolean isMonstrous();
|
||||||
void setMonstrous(boolean value);
|
void setMonstrous(boolean value);
|
||||||
|
|
||||||
|
@ -208,12 +203,14 @@ public interface Permanent extends Card, Controllable {
|
||||||
/**
|
/**
|
||||||
* Returns connected cards.
|
* Returns connected cards.
|
||||||
* Very similar to Imprint except that it is for internal use only.
|
* Very similar to Imprint except that it is for internal use only.
|
||||||
|
* @param key
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
List<UUID> getConnectedCards(String key);
|
List<UUID> getConnectedCards(String key);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear all connected cards.
|
* Clear all connected cards.
|
||||||
|
* @param key
|
||||||
*/
|
*/
|
||||||
void clearConnectedCards(String key);
|
void clearConnectedCards(String key);
|
||||||
|
|
||||||
|
|
|
@ -29,17 +29,15 @@
|
||||||
package mage.game.permanent;
|
package mage.game.permanent;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import mage.constants.Zone;
|
import java.util.UUID;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
import mage.cards.LevelerCard;
|
import mage.cards.LevelerCard;
|
||||||
|
import mage.constants.Zone;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
|
import mage.game.command.Commander;
|
||||||
import mage.game.events.ZoneChangeEvent;
|
import mage.game.events.ZoneChangeEvent;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
import mage.game.command.Commander;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author BetaSteward_at_googlemail.com
|
* @author BetaSteward_at_googlemail.com
|
||||||
*/
|
*/
|
||||||
|
@ -116,6 +114,8 @@ public class PermanentCard extends PermanentImpl {
|
||||||
}
|
}
|
||||||
this.flipCard = card.isFlipCard();
|
this.flipCard = card.isFlipCard();
|
||||||
this.flipCardName = card.getFlipCardName();
|
this.flipCardName = card.getFlipCardName();
|
||||||
|
this.morphCard = card.isMorphCard();
|
||||||
|
this.faceDown = card.isFaceDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Card getCard() {
|
public Card getCard() {
|
||||||
|
@ -205,4 +205,22 @@ public class PermanentCard extends PermanentImpl {
|
||||||
return this.maxLevelCounters;
|
return this.maxLevelCounters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean turnFaceUp(Game game, UUID playerId) {
|
||||||
|
if (super.turnFaceUp(game, playerId)) {
|
||||||
|
card.setFaceDown(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean turnFaceDown(Game game, UUID playerId) {
|
||||||
|
if (super.turnFaceDown(game, playerId)) {
|
||||||
|
card.setFaceDown(true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,7 +85,6 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
||||||
protected boolean controlledFromStartOfControllerTurn;
|
protected boolean controlledFromStartOfControllerTurn;
|
||||||
protected int turnsOnBattlefield;
|
protected int turnsOnBattlefield;
|
||||||
protected boolean phasedIn = true;
|
protected boolean phasedIn = true;
|
||||||
protected boolean faceUp = true;
|
|
||||||
protected boolean attacking;
|
protected boolean attacking;
|
||||||
protected int blocking;
|
protected int blocking;
|
||||||
// number of creatures the permanent can block
|
// number of creatures the permanent can block
|
||||||
|
@ -127,7 +126,6 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
||||||
this.controlledFromStartOfControllerTurn = permanent.controlledFromStartOfControllerTurn;
|
this.controlledFromStartOfControllerTurn = permanent.controlledFromStartOfControllerTurn;
|
||||||
this.turnsOnBattlefield = permanent.turnsOnBattlefield;
|
this.turnsOnBattlefield = permanent.turnsOnBattlefield;
|
||||||
this.phasedIn = permanent.phasedIn;
|
this.phasedIn = permanent.phasedIn;
|
||||||
this.faceUp = permanent.faceUp;
|
|
||||||
this.attacking = permanent.attacking;
|
this.attacking = permanent.attacking;
|
||||||
this.blocking = permanent.blocking;
|
this.blocking = permanent.blocking;
|
||||||
this.maxBlocks = permanent.maxBlocks;
|
this.maxBlocks = permanent.maxBlocks;
|
||||||
|
@ -213,7 +211,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
||||||
public void addAbility(Ability ability, UUID sourceId, Game game) {
|
public void addAbility(Ability ability, UUID sourceId, Game game) {
|
||||||
if (!abilities.containsKey(ability.getId())) {
|
if (!abilities.containsKey(ability.getId())) {
|
||||||
Ability copyAbility = ability.copy();
|
Ability copyAbility = ability.copy();
|
||||||
copyAbility.newId(); // needed so that sourc can get an ability multiple times (e.g. Raging Ravine)
|
copyAbility.newId(); // needed so that source can get an ability multiple times (e.g. Raging Ravine)
|
||||||
copyAbility.setControllerId(controllerId);
|
copyAbility.setControllerId(controllerId);
|
||||||
copyAbility.setSourceId(objectId);
|
copyAbility.setSourceId(objectId);
|
||||||
game.getState().addAbility(copyAbility, sourceId, this);
|
game.getState().addAbility(copyAbility, sourceId, this);
|
||||||
|
@ -411,23 +409,6 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isFaceUp() {
|
|
||||||
return faceUp;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean turnFaceUp(Game game) {
|
|
||||||
//TODO: implement this
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean turnFaceDown(Game game) {
|
|
||||||
//TODO: implement this
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeSummoningSickness() {
|
public void removeSummoningSickness() {
|
||||||
this.controlledFromStartOfControllerTurn = true;
|
this.controlledFromStartOfControllerTurn = true;
|
||||||
}
|
}
|
||||||
|
@ -1064,4 +1045,17 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
|
||||||
public void clearPairedCard() {
|
public void clearPairedCard() {
|
||||||
this.pairedCard = null;
|
this.pairedCard = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getLogName() {
|
||||||
|
if (name.isEmpty()) {
|
||||||
|
if (isFaceDown()) {
|
||||||
|
return "face down creature";
|
||||||
|
} else {
|
||||||
|
return "a creature without name";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ import mage.abilities.Abilities;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.Mode;
|
import mage.abilities.Mode;
|
||||||
import mage.abilities.SpellAbility;
|
import mage.abilities.SpellAbility;
|
||||||
|
import mage.abilities.costs.AlternativeSourceCosts;
|
||||||
import mage.abilities.costs.Cost;
|
import mage.abilities.costs.Cost;
|
||||||
import mage.abilities.costs.mana.ManaCost;
|
import mage.abilities.costs.mana.ManaCost;
|
||||||
import mage.abilities.costs.mana.ManaCosts;
|
import mage.abilities.costs.mana.ManaCosts;
|
||||||
|
@ -46,6 +47,7 @@ import mage.abilities.dynamicvalue.common.StaticValue;
|
||||||
import mage.abilities.effects.Effect;
|
import mage.abilities.effects.Effect;
|
||||||
import mage.abilities.effects.PostResolveEffect;
|
import mage.abilities.effects.PostResolveEffect;
|
||||||
import mage.abilities.keyword.BestowAbility;
|
import mage.abilities.keyword.BestowAbility;
|
||||||
|
import mage.abilities.keyword.MorphAbility;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
import mage.cards.SplitCard;
|
import mage.cards.SplitCard;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
|
@ -56,6 +58,7 @@ import mage.constants.Zone;
|
||||||
import mage.counters.Counter;
|
import mage.counters.Counter;
|
||||||
import mage.counters.Counters;
|
import mage.counters.Counters;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
|
import mage.game.events.GameEvent;
|
||||||
import mage.game.events.ZoneChangeEvent;
|
import mage.game.events.ZoneChangeEvent;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
import mage.game.permanent.PermanentCard;
|
import mage.game.permanent.PermanentCard;
|
||||||
|
@ -154,6 +157,17 @@ public class Spell implements StackObject, Card {
|
||||||
return sb.append(ability.getGameLogMessage(game)).toString();
|
return sb.append(ability.getGameLogMessage(game)).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getSpellCastText(Game game) {
|
||||||
|
for (Ability spellAbility : (Abilities<Ability>) getAbilities()) {
|
||||||
|
if (spellAbility instanceof MorphAbility
|
||||||
|
&& ((AlternativeSourceCosts) spellAbility).isActivated(getSpellAbility(), game)) {
|
||||||
|
return "a card face down";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return getSpellAbility().toString();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean resolve(Game game) {
|
public boolean resolve(Game game) {
|
||||||
boolean result;
|
boolean result;
|
||||||
|
@ -503,6 +517,11 @@ public class Spell implements StackObject, Card {
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return card.getName();
|
return card.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getLogName() {
|
||||||
|
return card.getName();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getImageName() {
|
public String getImageName() {
|
||||||
|
@ -649,12 +668,22 @@ public class Spell implements StackObject, Card {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setFaceDown(boolean value) {
|
public void setFaceDown(boolean value) {
|
||||||
throw new RuntimeException("Not implemented.");
|
card.setFaceDown(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean turnFaceUp(Game game, UUID playerId) {
|
||||||
|
return card.turnFaceUp(game, playerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean turnFaceDown(Game game, UUID playerId) {
|
||||||
|
return card.turnFaceDown(game, playerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isFaceDown() {
|
public boolean isFaceDown() {
|
||||||
return false;
|
return card.isFaceDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -893,4 +922,14 @@ public class Spell implements StackObject, Card {
|
||||||
return card;
|
return card;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setMorphCard(boolean morphCard) {
|
||||||
|
throw new UnsupportedOperationException("Not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMorphCard() {
|
||||||
|
return card.isMorphCard();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,6 +112,11 @@ public class StackAbility implements StackObject, Ability {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getLogName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getImageName() {
|
public String getImageName() {
|
||||||
return name;
|
return name;
|
||||||
|
|
|
@ -737,6 +737,9 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
//20091005 - 601.2a
|
//20091005 - 601.2a
|
||||||
Card card = game.getCard(ability.getSourceId());
|
Card card = game.getCard(ability.getSourceId());
|
||||||
if (card != null) {
|
if (card != null) {
|
||||||
|
if (card.isMorphCard()) {
|
||||||
|
card.setFaceDown(true);
|
||||||
|
}
|
||||||
if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.CAST_SPELL, ability.getId(), ability.getSourceId(), playerId))) {
|
if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.CAST_SPELL, ability.getId(), ability.getSourceId(), playerId))) {
|
||||||
int bookmark = game.bookmarkState();
|
int bookmark = game.bookmarkState();
|
||||||
Zone fromZone = game.getState().getZone(card.getId());
|
Zone fromZone = game.getState().getZone(card.getId());
|
||||||
|
|
|
@ -236,7 +236,7 @@ public class TargetSpellOrPermanent extends TargetImpl {
|
||||||
for (UUID targetId: getTargets()) {
|
for (UUID targetId: getTargets()) {
|
||||||
Permanent permanent = game.getPermanent(targetId);
|
Permanent permanent = game.getPermanent(targetId);
|
||||||
if (permanent != null) {
|
if (permanent != null) {
|
||||||
sb.append(permanent.getName()).append(" ");
|
sb.append(permanent.getLogName()).append(" ");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Spell spell = game.getStack().getSpell(targetId);
|
Spell spell = game.getStack().getSpell(targetId);
|
||||||
|
|
|
@ -126,7 +126,7 @@ public class TraceUtil {
|
||||||
String uuid = "[" + UUID.randomUUID() + "] ";
|
String uuid = "[" + UUID.randomUUID() + "] ";
|
||||||
log.error(uuid+"Tracing game state...");
|
log.error(uuid+"Tracing game state...");
|
||||||
if (blocker != null) {
|
if (blocker != null) {
|
||||||
log.error(uuid+blocker.getName() + " could block " + attacker.getName());
|
log.error(uuid+blocker.getLogName() + " could block " + attacker.getLogName());
|
||||||
}
|
}
|
||||||
|
|
||||||
log.error(uuid);
|
log.error(uuid);
|
||||||
|
|
|
@ -84,7 +84,7 @@ public class CommanderCombatDamageWatcher extends Watcher {
|
||||||
Player player = game.getPlayer(playerUUID);
|
Player player = game.getPlayer(playerUUID);
|
||||||
MageObject commander = game.getObject(sourceId);
|
MageObject commander = game.getObject(sourceId);
|
||||||
if (player != null && commander != null){
|
if (player != null && commander != null){
|
||||||
game.informPlayers(commander.getName() + " did " + damage + " combat damage to " + player.getName() + " during the game.");
|
game.informPlayers(commander.getLogName() + " did " + damage + " combat damage to " + player.getName() + " during the game.");
|
||||||
this.addCardInfoToCommander(game);
|
this.addCardInfoToCommander(game);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,7 +88,7 @@ public class SoulbondWatcher extends Watcher {
|
||||||
if (chosen != null) {
|
if (chosen != null) {
|
||||||
chosen.setPairedCard(permanent.getId());
|
chosen.setPairedCard(permanent.getId());
|
||||||
permanent.setPairedCard(chosen.getId());
|
permanent.setPairedCard(chosen.getId());
|
||||||
game.informPlayers(new StringBuilder(controller.getName()).append(" souldbonds ").append(permanent.getName()).append(" with ").append(chosen.getName()).toString());
|
game.informPlayers(new StringBuilder(controller.getName()).append(" souldbonds ").append(permanent.getLogName()).append(" with ").append(chosen.getName()).toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,10 +109,10 @@ public class SoulbondWatcher extends Watcher {
|
||||||
Cards cards = new CardsImpl(Zone.PICK);
|
Cards cards = new CardsImpl(Zone.PICK);
|
||||||
cards.add(chosen);
|
cards.add(chosen);
|
||||||
controller.lookAtCards("Soulbond", cards, game);
|
controller.lookAtCards("Soulbond", cards, game);
|
||||||
if (controller.chooseUse(Outcome.Benefit, "Use Soulbond for recent " + permanent.getName() + "?", game)) {
|
if (controller.chooseUse(Outcome.Benefit, "Use Soulbond for recent " + permanent.getLogName() + "?", game)) {
|
||||||
chosen.setPairedCard(permanent.getId());
|
chosen.setPairedCard(permanent.getId());
|
||||||
permanent.setPairedCard(chosen.getId());
|
permanent.setPairedCard(chosen.getId());
|
||||||
game.informPlayers(new StringBuilder(controller.getName()).append(" souldbonds ").append(permanent.getName()).append(" with ").append(chosen.getName()).toString());
|
game.informPlayers(new StringBuilder(controller.getName()).append(" souldbonds ").append(permanent.getLogName()).append(" with ").append(chosen.getName()).toString());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue