2012-09-22 19:05:32 -07:00
|
|
|
package magic.model;
|
|
|
|
|
|
|
|
import magic.ai.ArtificialScoringSystem;
|
|
|
|
import magic.data.IconImages;
|
|
|
|
import magic.model.action.MagicAttachEquipmentAction;
|
2012-09-26 23:11:44 -07:00
|
|
|
import magic.model.action.MagicChangeControlAction;
|
2012-09-22 19:05:32 -07:00
|
|
|
import magic.model.action.MagicChangeCountersAction;
|
|
|
|
import magic.model.action.MagicChangeStateAction;
|
|
|
|
import magic.model.action.MagicDestroyAction;
|
|
|
|
import magic.model.action.MagicGainControlAction;
|
|
|
|
import magic.model.action.MagicRemoveFromPlayAction;
|
|
|
|
import magic.model.action.MagicSacrificeAction;
|
|
|
|
import magic.model.action.MagicSoulbondAction;
|
2012-09-26 23:11:44 -07:00
|
|
|
import magic.model.choice.MagicTargetChoice;
|
2012-09-22 19:05:32 -07:00
|
|
|
import magic.model.event.MagicActivation;
|
2013-01-19 18:28:58 -08:00
|
|
|
import magic.model.event.MagicManaActivation;
|
2012-10-08 07:18:01 -07:00
|
|
|
import magic.model.event.MagicPermanentActivation;
|
2013-07-07 06:16:11 -07:00
|
|
|
import magic.model.event.MagicSourceActivation;
|
2012-09-22 19:05:32 -07:00
|
|
|
import magic.model.event.MagicPlayAuraEvent;
|
2012-10-08 07:18:01 -07:00
|
|
|
import magic.model.event.MagicEvent;
|
2012-09-22 19:05:32 -07:00
|
|
|
import magic.model.mstatic.MagicLayer;
|
|
|
|
import magic.model.mstatic.MagicPermanentStatic;
|
2012-09-26 23:11:44 -07:00
|
|
|
import magic.model.mstatic.MagicStatic;
|
2013-01-19 18:02:09 -08:00
|
|
|
import magic.model.trigger.MagicTrigger;
|
2013-01-19 22:52:37 -08:00
|
|
|
import magic.model.trigger.MagicWhenComesIntoPlayTrigger;
|
2012-09-26 23:11:44 -07:00
|
|
|
import magic.model.target.MagicTarget;
|
2013-03-24 06:10:00 -07:00
|
|
|
import magic.model.target.MagicTargetNone;
|
2012-10-21 02:59:46 -07:00
|
|
|
import magic.model.target.MagicTargetFilter;
|
2012-09-22 19:05:32 -07:00
|
|
|
|
|
|
|
import javax.swing.ImageIcon;
|
2013-01-19 01:02:56 -08:00
|
|
|
|
2013-07-13 07:41:20 -07:00
|
|
|
import java.util.List;
|
2013-07-12 05:40:56 -07:00
|
|
|
import java.util.LinkedList;
|
2012-09-22 19:05:32 -07:00
|
|
|
import java.util.Arrays;
|
|
|
|
import java.util.Collection;
|
2013-01-19 01:02:56 -08:00
|
|
|
import java.util.Set;
|
2013-07-07 06:16:11 -07:00
|
|
|
import java.util.TreeSet;
|
2013-01-19 01:02:56 -08:00
|
|
|
import java.util.Collections;
|
2012-09-22 19:05:32 -07:00
|
|
|
|
2013-07-08 19:52:50 -07:00
|
|
|
public class MagicPermanent implements MagicSource,MagicTarget,Comparable<MagicPermanent>,MagicMappable<MagicPermanent> {
|
2012-09-22 19:05:32 -07:00
|
|
|
|
|
|
|
public static final int NO_COLOR_FLAGS=-1;
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
private final long id;
|
|
|
|
private final MagicCardDefinition cardDefinition;
|
|
|
|
private final MagicCard card;
|
|
|
|
private final MagicPlayer firstController;
|
|
|
|
private MagicPermanent equippedCreature = MagicPermanent.NONE;
|
2013-06-23 18:33:35 -07:00
|
|
|
private final MagicPermanentSet equipmentPermanents;
|
2012-09-22 19:05:32 -07:00
|
|
|
private MagicPermanent enchantedCreature = MagicPermanent.NONE;
|
2013-06-23 18:33:35 -07:00
|
|
|
private final MagicPermanentSet auraPermanents;
|
2012-09-22 19:05:32 -07:00
|
|
|
private MagicPermanent blockedCreature = MagicPermanent.NONE;
|
2013-06-23 18:33:35 -07:00
|
|
|
private final MagicPermanentList blockingCreatures;
|
2012-09-22 19:05:32 -07:00
|
|
|
private MagicPermanent pairedCreature = MagicPermanent.NONE;
|
2012-09-28 00:59:14 -07:00
|
|
|
private final MagicCardList exiledCards;
|
2013-07-08 19:52:50 -07:00
|
|
|
private MagicPlayer chosenPlayer = MagicPlayer.NONE;
|
2012-09-28 01:09:47 -07:00
|
|
|
private int[] counters=new int[MagicCounterType.NR_COUNTERS];
|
2013-06-23 18:33:35 -07:00
|
|
|
private int stateFlags =
|
2012-09-22 19:05:32 -07:00
|
|
|
MagicPermanentState.Summoned.getMask() |
|
|
|
|
MagicPermanentState.MustPayEchoCost.getMask();
|
2012-10-03 01:17:01 -07:00
|
|
|
private int abilityPlayedThisTurn;
|
|
|
|
private int damage;
|
|
|
|
private int preventDamage;
|
2013-03-26 07:32:58 -07:00
|
|
|
private int fixedScore;
|
2012-09-22 19:05:32 -07:00
|
|
|
private int score;
|
|
|
|
|
|
|
|
// Allows cached retrieval of controller, type, subtype, color, abilites, and p/t
|
|
|
|
// also acts as last known information
|
|
|
|
private MagicPlayer cachedController;
|
2012-10-03 01:17:01 -07:00
|
|
|
private int cachedTypeFlags;
|
2013-01-26 06:08:41 -08:00
|
|
|
private Set<MagicSubType> cachedSubTypeFlags;
|
2012-10-03 01:17:01 -07:00
|
|
|
private int cachedColorFlags;
|
2013-01-19 01:02:56 -08:00
|
|
|
private Set<MagicAbility> cachedAbilityFlags;
|
2012-09-22 19:05:32 -07:00
|
|
|
private MagicPowerToughness cachedPowerToughness;
|
2013-07-12 06:05:06 -07:00
|
|
|
private final Set<MagicActivation<MagicPermanent>> cachedActivations;
|
2013-07-13 07:41:20 -07:00
|
|
|
private final List<MagicTrigger<?>> cachedTriggers;
|
2012-09-22 19:05:32 -07:00
|
|
|
|
|
|
|
// remember order among blockers (blockedName + id + block order)
|
|
|
|
private String blockedName;
|
2013-03-27 07:14:20 -07:00
|
|
|
private long stateId;
|
2012-09-22 19:05:32 -07:00
|
|
|
|
|
|
|
public MagicPermanent(final long aId,final MagicCard aCard,final MagicPlayer aController) {
|
|
|
|
id = aId;
|
|
|
|
card = aCard;
|
|
|
|
cardDefinition = card.getCardDefinition();
|
|
|
|
firstController = aController;
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
equipmentPermanents=new MagicPermanentSet();
|
|
|
|
auraPermanents=new MagicPermanentSet();
|
|
|
|
blockingCreatures=new MagicPermanentList();
|
|
|
|
exiledCards = new MagicCardList();
|
2013-07-12 06:05:06 -07:00
|
|
|
cachedActivations = new TreeSet<MagicActivation<MagicPermanent>>();
|
2013-07-13 07:41:20 -07:00
|
|
|
cachedTriggers = new LinkedList<MagicTrigger<?>>();
|
2012-09-22 19:05:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
private MagicPermanent(final MagicCopyMap copyMap, final MagicPermanent sourcePermanent) {
|
|
|
|
id = sourcePermanent.id;
|
|
|
|
cardDefinition = sourcePermanent.cardDefinition;
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
copyMap.put(sourcePermanent, this);
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
card = copyMap.copy(sourcePermanent.card);
|
|
|
|
firstController = copyMap.copy(sourcePermanent.firstController);
|
|
|
|
stateFlags=sourcePermanent.stateFlags;
|
|
|
|
counters=Arrays.copyOf(sourcePermanent.counters,MagicCounterType.NR_COUNTERS);
|
|
|
|
abilityPlayedThisTurn=sourcePermanent.abilityPlayedThisTurn;
|
|
|
|
equippedCreature=copyMap.copy(sourcePermanent.equippedCreature);
|
|
|
|
equipmentPermanents=new MagicPermanentSet(copyMap,sourcePermanent.equipmentPermanents);
|
|
|
|
enchantedCreature=copyMap.copy(sourcePermanent.enchantedCreature);
|
|
|
|
auraPermanents=new MagicPermanentSet(copyMap,sourcePermanent.auraPermanents);
|
|
|
|
blockedCreature=copyMap.copy(sourcePermanent.blockedCreature);
|
|
|
|
blockingCreatures=new MagicPermanentList(copyMap,sourcePermanent.blockingCreatures);
|
|
|
|
pairedCreature = copyMap.copy(sourcePermanent.pairedCreature);
|
|
|
|
exiledCards = new MagicCardList(copyMap,sourcePermanent.exiledCards);
|
2013-07-08 19:52:50 -07:00
|
|
|
chosenPlayer = copyMap.copy(sourcePermanent.chosenPlayer);
|
2012-09-22 19:05:32 -07:00
|
|
|
damage=sourcePermanent.damage;
|
|
|
|
preventDamage=sourcePermanent.preventDamage;
|
|
|
|
fixedScore=sourcePermanent.fixedScore;
|
2013-03-28 06:35:43 -07:00
|
|
|
score=sourcePermanent.score;
|
|
|
|
stateId=sourcePermanent.stateId;
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
cachedController = copyMap.copy(sourcePermanent.cachedController);
|
|
|
|
cachedTypeFlags = sourcePermanent.cachedTypeFlags;
|
|
|
|
cachedSubTypeFlags = sourcePermanent.cachedSubTypeFlags;
|
|
|
|
cachedColorFlags = sourcePermanent.cachedColorFlags;
|
|
|
|
cachedAbilityFlags = sourcePermanent.cachedAbilityFlags;
|
|
|
|
cachedPowerToughness = sourcePermanent.cachedPowerToughness;
|
2013-07-12 06:05:06 -07:00
|
|
|
cachedActivations = new TreeSet<MagicActivation<MagicPermanent>>(sourcePermanent.cachedActivations);
|
2013-07-13 07:41:20 -07:00
|
|
|
cachedTriggers = new LinkedList<MagicTrigger<?>>(sourcePermanent.cachedTriggers);
|
2012-09-22 19:05:32 -07:00
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
@Override
|
|
|
|
public MagicPermanent copy(final MagicCopyMap copyMap) {
|
|
|
|
return new MagicPermanent(copyMap, this);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
@Override
|
|
|
|
public MagicPermanent map(final MagicGame game) {
|
|
|
|
final MagicPlayer mappedController=getController().map(game);
|
|
|
|
return mappedController.getPermanents().getPermanent(id);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public long getId() {
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean isValid() {
|
2013-07-02 22:30:21 -07:00
|
|
|
return getController().controlsPermanent(this);
|
2012-09-22 19:05:32 -07:00
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public boolean isInvalid() {
|
|
|
|
return !isValid();
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-03-27 07:14:20 -07:00
|
|
|
public long getStateId() {
|
|
|
|
stateId = stateId != 0 ? stateId : magic.MurmurHash3.hash(new long[] {
|
2012-09-22 19:05:32 -07:00
|
|
|
cardDefinition.getIndex(),
|
|
|
|
stateFlags,
|
|
|
|
damage,
|
|
|
|
preventDamage,
|
2013-03-27 07:14:20 -07:00
|
|
|
equippedCreature.getStateId(),
|
|
|
|
enchantedCreature.getStateId(),
|
|
|
|
blockedCreature.getStateId(),
|
|
|
|
//pairedCreature.getStateId(),
|
2013-03-30 05:05:06 -07:00
|
|
|
exiledCards.getUnorderedStateId(),
|
2013-07-08 19:52:50 -07:00
|
|
|
chosenPlayer.getId(),
|
2012-09-22 19:05:32 -07:00
|
|
|
counters[0],
|
|
|
|
counters[1],
|
|
|
|
counters[2],
|
|
|
|
counters[3],
|
2013-03-24 06:10:00 -07:00
|
|
|
counters[4],
|
2013-03-26 01:58:15 -07:00
|
|
|
counters[5],
|
2012-09-22 19:05:32 -07:00
|
|
|
abilityPlayedThisTurn,
|
|
|
|
cachedTypeFlags,
|
2013-01-19 01:02:56 -08:00
|
|
|
cachedSubTypeFlags.hashCode(),
|
2012-09-22 19:05:32 -07:00
|
|
|
cachedColorFlags,
|
2013-01-19 01:02:56 -08:00
|
|
|
cachedAbilityFlags.hashCode(),
|
2012-09-22 19:05:32 -07:00
|
|
|
cachedPowerToughness.power(),
|
|
|
|
cachedPowerToughness.toughness(),
|
2013-07-13 07:41:20 -07:00
|
|
|
cachedActivations.hashCode(),
|
|
|
|
cachedTriggers.hashCode()
|
2013-03-27 07:14:20 -07:00
|
|
|
});
|
|
|
|
return stateId;
|
2012-09-22 19:05:32 -07:00
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
/** Determines uniqueness of a mana permanent, e.g. for producing mana, all Mountains are equal. */
|
|
|
|
public int getManaId() {
|
|
|
|
// Creatures or lands that can be animated are unique by default.
|
|
|
|
if (cardDefinition.hasExcludeManaOrCombat()) {
|
|
|
|
return (int)id;
|
2013-06-23 18:33:35 -07:00
|
|
|
}
|
2012-09-22 19:05:32 -07:00
|
|
|
// Uniqueness is determined by card definition and number of charge counters.
|
|
|
|
return -((cardDefinition.getIndex()<<16)+getCounters(MagicCounterType.Charge));
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public MagicCard getCard() {
|
|
|
|
return card;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public boolean isToken() {
|
|
|
|
return card.isToken();
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public boolean isNonToken() {
|
|
|
|
return !card.isToken();
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
@Override
|
|
|
|
public MagicCardDefinition getCardDefinition() {
|
|
|
|
return cardDefinition;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
@Override
|
2013-07-07 06:16:11 -07:00
|
|
|
public Collection<MagicSourceActivation<? extends MagicSource>> getSourceActivations() {
|
|
|
|
Set<MagicSourceActivation<? extends MagicSource>> sorted = new TreeSet<MagicSourceActivation<? extends MagicSource>>();
|
2013-07-12 05:40:56 -07:00
|
|
|
for (final MagicActivation<MagicPermanent> act : cachedActivations) {
|
|
|
|
sorted.add(MagicSourceActivation.create(this, act));
|
|
|
|
}
|
2013-07-07 06:16:11 -07:00
|
|
|
return sorted;
|
|
|
|
}
|
2013-07-12 05:40:56 -07:00
|
|
|
|
2013-07-12 06:05:06 -07:00
|
|
|
public void addActivation(final MagicActivation<MagicPermanent> act) {
|
2013-07-12 05:40:56 -07:00
|
|
|
cachedActivations.add(act);
|
|
|
|
}
|
2013-07-07 06:16:11 -07:00
|
|
|
|
2013-07-13 07:41:20 -07:00
|
|
|
public void addTrigger(final MagicTrigger<?> trig) {
|
|
|
|
cachedTriggers.add(trig);
|
|
|
|
}
|
|
|
|
|
2013-07-07 06:16:11 -07:00
|
|
|
public Collection<MagicActivation<MagicPermanent>> getActivations() {
|
2013-07-12 06:05:06 -07:00
|
|
|
return cachedActivations;
|
2012-09-22 19:05:32 -07:00
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-01-19 18:28:58 -08:00
|
|
|
public Collection<MagicManaActivation> getManaActivations() {
|
|
|
|
return cardDefinition.getManaActivations();
|
|
|
|
}
|
2012-09-22 19:05:32 -07:00
|
|
|
|
2013-01-19 18:02:09 -08:00
|
|
|
public Collection<MagicStatic> getStatics() {
|
|
|
|
return cardDefinition.getStatics();
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-01-19 18:02:09 -08:00
|
|
|
public Collection<MagicTrigger<?>> getTriggers() {
|
2013-07-13 07:41:20 -07:00
|
|
|
return cachedTriggers;
|
2013-01-19 18:02:09 -08:00
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-01-19 22:52:37 -08:00
|
|
|
public Collection<MagicWhenComesIntoPlayTrigger> getComeIntoPlayTriggers() {
|
|
|
|
return cardDefinition.getComeIntoPlayTriggers();
|
|
|
|
}
|
2013-01-19 18:02:09 -08:00
|
|
|
|
2013-01-19 18:28:58 -08:00
|
|
|
public int getConvertedCost() {
|
|
|
|
return cardDefinition.getConvertedCost();
|
|
|
|
}
|
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public boolean producesMana() {
|
|
|
|
return !cardDefinition.getManaActivations().isEmpty();
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-01-05 19:14:06 -08:00
|
|
|
public int countManaActivations() {
|
|
|
|
return cardDefinition.getManaActivations().size();
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public String getName() {
|
|
|
|
return card.getName();
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
@Override
|
|
|
|
public String toString() {
|
|
|
|
return getName();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public MagicGame getGame() {
|
|
|
|
return getOwner().getGame();
|
|
|
|
}
|
|
|
|
|
|
|
|
public MagicPlayer getOwner() {
|
|
|
|
return card.getOwner();
|
|
|
|
}
|
|
|
|
|
|
|
|
public MagicPlayer getFirstController() {
|
|
|
|
return firstController;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-07-08 23:41:55 -07:00
|
|
|
@Override
|
2012-09-22 19:05:32 -07:00
|
|
|
public MagicPlayer getController() {
|
|
|
|
assert cachedController != null : "cachedController is null in " + this;
|
|
|
|
return cachedController;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-07-08 23:41:55 -07:00
|
|
|
@Override
|
2012-10-07 02:00:35 -07:00
|
|
|
public MagicPlayer getOpponent() {
|
|
|
|
return getController().getOpponent();
|
|
|
|
}
|
2012-09-22 19:05:32 -07:00
|
|
|
|
2013-07-08 23:41:55 -07:00
|
|
|
@Override
|
2012-10-04 06:16:35 -07:00
|
|
|
public boolean isFriend(final MagicObject other) {
|
2012-09-22 19:05:32 -07:00
|
|
|
return getController() == other.getController();
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-07-08 23:41:55 -07:00
|
|
|
@Override
|
2012-10-04 06:16:35 -07:00
|
|
|
public boolean isEnemy(final MagicObject other) {
|
2013-07-08 23:41:55 -07:00
|
|
|
return getOpponent() == other.getController();
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean isOwner(final MagicTarget player) {
|
|
|
|
return getOwner() == player;
|
2012-09-22 19:05:32 -07:00
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public boolean isController(final MagicTarget player) {
|
|
|
|
return getController() == player;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public boolean isOpponent(final MagicTarget player) {
|
2012-10-07 02:00:35 -07:00
|
|
|
return getOpponent() == player;
|
2012-09-22 19:05:32 -07:00
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public static void update(final MagicGame game) {
|
|
|
|
MagicPermanent.updateProperties(game);
|
|
|
|
MagicPermanent.updateScoreFixController(game);
|
|
|
|
}
|
2013-07-13 07:41:20 -07:00
|
|
|
|
|
|
|
private static void updateScoreFixController(final MagicGame game) {
|
2012-09-22 19:05:32 -07:00
|
|
|
for (final MagicPlayer player : game.getPlayers()) {
|
|
|
|
for (final MagicPermanent perm : player.getPermanents()) {
|
|
|
|
final MagicPlayer curr = perm.getController();
|
|
|
|
if (!curr.controlsPermanent(perm)) {
|
|
|
|
game.addDelayedAction(new MagicChangeControlAction(curr, perm, perm.getScore()));
|
2013-06-23 18:33:35 -07:00
|
|
|
}
|
2012-09-22 19:05:32 -07:00
|
|
|
perm.updateScore();
|
|
|
|
}}
|
|
|
|
}
|
|
|
|
|
2013-07-13 07:41:20 -07:00
|
|
|
private static void updateProperties(final MagicGame game) {
|
2013-02-09 20:35:06 -08:00
|
|
|
for (final MagicLayer layer : MagicLayer.PermanentLayers) {
|
2012-09-22 19:05:32 -07:00
|
|
|
for (final MagicPlayer player : game.getPlayers()) {
|
2013-01-19 23:44:37 -08:00
|
|
|
for (final MagicPermanent perm : player.getPermanents()) {
|
|
|
|
perm.apply(layer);
|
|
|
|
}
|
|
|
|
}
|
2012-09-22 19:05:32 -07:00
|
|
|
for (final MagicPermanentStatic mpstatic : game.getStatics(layer)) {
|
|
|
|
final MagicStatic mstatic = mpstatic.getStatic();
|
|
|
|
final MagicPermanent source = mpstatic.getPermanent();
|
|
|
|
for (final MagicPlayer player : game.getPlayers()) {
|
|
|
|
for (final MagicPermanent perm : player.getPermanents()) {
|
|
|
|
if (mstatic.accept(game, source, perm)) {
|
|
|
|
perm.apply(source, mstatic);
|
|
|
|
}
|
|
|
|
}}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
private void apply(final MagicLayer layer) {
|
|
|
|
switch (layer) {
|
|
|
|
case Card:
|
|
|
|
cachedController = firstController;
|
2013-01-19 18:28:58 -08:00
|
|
|
cachedTypeFlags = cardDefinition.getTypeFlags();
|
|
|
|
cachedSubTypeFlags = cardDefinition.genSubTypeFlags();
|
|
|
|
cachedColorFlags = cardDefinition.getColorFlags();
|
|
|
|
cachedAbilityFlags = cardDefinition.genAbilityFlags();
|
|
|
|
cachedPowerToughness = cardDefinition.genPowerToughness();
|
2013-07-12 05:40:56 -07:00
|
|
|
cachedActivations.clear();
|
2013-07-12 06:05:06 -07:00
|
|
|
cachedActivations.addAll(cardDefinition.getActivations());
|
2013-07-13 07:41:20 -07:00
|
|
|
cachedTriggers.clear();
|
|
|
|
cachedTriggers.addAll(cardDefinition.getTriggers());
|
2012-09-22 19:05:32 -07:00
|
|
|
break;
|
|
|
|
case CDASubtype:
|
2013-01-19 18:28:58 -08:00
|
|
|
cardDefinition.applyCDASubType(getGame(), getController(), cachedSubTypeFlags);
|
2012-09-22 19:05:32 -07:00
|
|
|
break;
|
|
|
|
case CDAPT:
|
2013-01-19 18:28:58 -08:00
|
|
|
cardDefinition.applyCDAPowerToughness(getGame(), getController(), this, cachedPowerToughness);
|
2012-09-22 19:05:32 -07:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void apply(final MagicPermanent source, final MagicStatic mstatic) {
|
|
|
|
final MagicLayer layer = mstatic.getLayer();
|
|
|
|
switch (layer) {
|
|
|
|
case Control:
|
|
|
|
cachedController = mstatic.getController(source, this, cachedController);
|
|
|
|
break;
|
|
|
|
case Type:
|
|
|
|
cachedTypeFlags = mstatic.getTypeFlags(this, cachedTypeFlags);
|
|
|
|
mstatic.modSubTypeFlags(this, cachedSubTypeFlags);
|
|
|
|
break;
|
|
|
|
case Color:
|
|
|
|
cachedColorFlags = mstatic.getColorFlags(this, cachedColorFlags);
|
|
|
|
break;
|
|
|
|
case Ability:
|
2013-01-19 01:02:56 -08:00
|
|
|
mstatic.modAbilityFlags(source, this, cachedAbilityFlags);
|
2012-09-22 19:05:32 -07:00
|
|
|
break;
|
|
|
|
case SetPT:
|
|
|
|
case ModPT:
|
|
|
|
case CountersPT:
|
|
|
|
case SwitchPT:
|
|
|
|
mstatic.modPowerToughness(source, this, cachedPowerToughness);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
throw new RuntimeException("No case for " + layer + " in MagicPermanent.apply");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setState(final MagicPermanentState state) {
|
|
|
|
stateFlags|=state.getMask();
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public void clearState(final MagicPermanentState state) {
|
|
|
|
stateFlags&=Integer.MAX_VALUE-state.getMask();
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public boolean hasState(final MagicPermanentState state) {
|
|
|
|
return state.hasState(stateFlags);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public int getStateFlags() {
|
|
|
|
return stateFlags;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public void setStateFlags(final int flags) {
|
|
|
|
stateFlags=flags;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public boolean isTapped() {
|
|
|
|
return hasState(MagicPermanentState.Tapped);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public boolean isUntapped() {
|
|
|
|
return !hasState(MagicPermanentState.Tapped);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-10-09 07:42:34 -07:00
|
|
|
private int getColorFlags() {
|
2012-09-22 19:05:32 -07:00
|
|
|
return cachedColorFlags;
|
|
|
|
}
|
2012-10-09 02:16:11 -07:00
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean hasColor(final MagicColor color) {
|
2013-06-23 18:33:35 -07:00
|
|
|
return color.hasColor(getColorFlags());
|
2012-10-09 02:16:11 -07:00
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public void changeCounters(final MagicCounterType counterType,final int amount) {
|
|
|
|
counters[counterType.ordinal()]+=amount;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public int getCounters(final MagicCounterType counterType) {
|
|
|
|
return counters[counterType.ordinal()];
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public boolean hasCounters() {
|
|
|
|
for (final int amount : counters) {
|
|
|
|
if (amount>0) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-10-13 19:43:09 -07:00
|
|
|
public boolean hasSubType(final MagicSubType subType) {
|
2013-01-26 06:08:41 -08:00
|
|
|
return cachedSubTypeFlags.contains(subType);
|
2012-09-22 19:05:32 -07:00
|
|
|
}
|
|
|
|
|
2012-10-13 19:43:09 -07:00
|
|
|
public boolean hasAllCreatureTypes() {
|
|
|
|
return cachedSubTypeFlags.equals(MagicSubType.ALL_CREATURES);
|
2012-09-22 19:05:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
public MagicPowerToughness getPowerToughness() {
|
|
|
|
return cachedPowerToughness;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public int getPower() {
|
|
|
|
return getPowerToughness().getPositivePower();
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public int getToughness() {
|
|
|
|
return getPowerToughness().getPositiveToughness();
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-01-19 01:02:56 -08:00
|
|
|
public Set<MagicAbility> getAbilityFlags() {
|
2012-09-22 19:05:32 -07:00
|
|
|
return cachedAbilityFlags;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean hasAbility(final MagicAbility ability) {
|
2013-01-19 01:02:56 -08:00
|
|
|
return cachedAbilityFlags.contains(ability);
|
2012-09-22 19:05:32 -07:00
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
private void updateScore() {
|
2013-03-27 07:14:20 -07:00
|
|
|
stateId = 0;
|
2013-03-26 07:32:58 -07:00
|
|
|
fixedScore = ArtificialScoringSystem.getFixedPermanentScore(this);
|
2012-09-22 19:05:32 -07:00
|
|
|
score = fixedScore + ArtificialScoringSystem.getVariablePermanentScore(this);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public int getScore() {
|
|
|
|
return score;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public int getStaticScore() {
|
|
|
|
return cardDefinition.getStaticType().getScore(this);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-01-19 18:28:58 -08:00
|
|
|
public int getCardScore() {
|
|
|
|
return cardDefinition.getScore();
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public int getDamage() {
|
|
|
|
return damage;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public void setDamage(final int damage) {
|
|
|
|
this.damage=damage;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
@Override
|
|
|
|
public int getPreventDamage() {
|
|
|
|
return preventDamage;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void setPreventDamage(final int amount) {
|
|
|
|
preventDamage=amount;
|
|
|
|
}
|
|
|
|
|
|
|
|
public int getLethalDamage(final int toughness) {
|
|
|
|
return toughness<=damage?0:toughness-damage;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
// Tap symbol.
|
|
|
|
public boolean canTap() {
|
2013-06-23 18:33:35 -07:00
|
|
|
return !hasState(MagicPermanentState.Tapped) &&
|
|
|
|
(!hasState(MagicPermanentState.Summoned) ||
|
|
|
|
!isCreature() ||
|
2012-09-22 19:05:32 -07:00
|
|
|
hasAbility(MagicAbility.Haste)
|
|
|
|
);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
// Untap symbol.
|
|
|
|
public boolean canUntap() {
|
2013-06-23 18:33:35 -07:00
|
|
|
return hasState(MagicPermanentState.Tapped) &&
|
|
|
|
(!hasState(MagicPermanentState.Summoned) ||
|
|
|
|
!isCreature() ||
|
2012-09-22 19:05:32 -07:00
|
|
|
hasAbility(MagicAbility.Haste)
|
2013-06-23 18:33:35 -07:00
|
|
|
);
|
2012-09-22 19:05:32 -07:00
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public boolean canRegenerate() {
|
|
|
|
return !hasState(MagicPermanentState.Regenerated)&&!hasState(MagicPermanentState.CannotBeRegenerated);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public boolean isRegenerated() {
|
|
|
|
return hasState(MagicPermanentState.Regenerated)&&!hasState(MagicPermanentState.CannotBeRegenerated);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public boolean isAttacking() {
|
|
|
|
return hasState(MagicPermanentState.Attacking);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public boolean isBlocked() {
|
|
|
|
return hasState(MagicPermanentState.Blocked);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public boolean isBlocking() {
|
|
|
|
return hasState(MagicPermanentState.Blocking);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public MagicPermanent getBlockedCreature() {
|
|
|
|
return blockedCreature;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public void setBlockedCreature(final MagicPermanent creature) {
|
|
|
|
if (creature.isValid()) {
|
|
|
|
blockedName = creature.getName() + creature.getId() + (100 + creature.numBlockingCreatures());
|
|
|
|
}
|
|
|
|
blockedCreature = creature;
|
|
|
|
}
|
|
|
|
|
|
|
|
public String getBlockedName() {
|
|
|
|
return blockedName;
|
|
|
|
}
|
|
|
|
|
|
|
|
public MagicPermanentList getBlockingCreatures() {
|
|
|
|
return blockingCreatures;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public int numBlockingCreatures() {
|
|
|
|
return blockingCreatures.size();
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public void setBlockingCreatures(final MagicPermanentList creatures) {
|
|
|
|
blockingCreatures.clear();
|
|
|
|
blockingCreatures.addAll(creatures);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public void addBlockingCreature(final MagicPermanent creature) {
|
|
|
|
blockingCreatures.add(creature);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public void removeBlockingCreature(final MagicPermanent creature) {
|
|
|
|
blockingCreatures.remove(creature);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public void removeBlockingCreatures() {
|
|
|
|
blockingCreatures.clear();
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public MagicPermanent getPairedCreature() {
|
|
|
|
return pairedCreature;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public void setPairedCreature(final MagicPermanent creature) {
|
|
|
|
pairedCreature = creature;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public boolean isPaired() {
|
|
|
|
return pairedCreature != MagicPermanent.NONE;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public MagicCardList getExiledCards() {
|
|
|
|
return exiledCards;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public void addExiledCard(final MagicCard card) {
|
|
|
|
// only non tokens can be added
|
|
|
|
if (!card.isToken()) {
|
|
|
|
exiledCards.add(card);
|
|
|
|
}
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public void removeExiledCard(final MagicCard card) {
|
|
|
|
exiledCards.remove(card);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-03-22 23:30:23 -07:00
|
|
|
public MagicPlayer getChosenPlayer() {
|
2013-07-08 19:52:50 -07:00
|
|
|
return chosenPlayer;
|
2013-03-22 23:30:23 -07:00
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-07-08 19:52:50 -07:00
|
|
|
public void setChosenPlayer(final MagicPlayer player) {
|
|
|
|
chosenPlayer = player;
|
2012-09-22 19:05:32 -07:00
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-11-13 04:34:28 -08:00
|
|
|
void generateStateBasedActions() {
|
2012-09-22 19:05:32 -07:00
|
|
|
final MagicGame game = getGame();
|
|
|
|
if (isCreature()) {
|
|
|
|
final int toughness=getToughness();
|
|
|
|
if (toughness<=0) {
|
|
|
|
game.logAppendMessage(getController(),getName()+" is put into its owner's graveyard.");
|
|
|
|
game.addDelayedAction(new MagicRemoveFromPlayAction(this,MagicLocationType.Graveyard));
|
|
|
|
} else if (hasState(MagicPermanentState.Destroyed)) {
|
2013-06-21 23:40:39 -07:00
|
|
|
game.addDelayedAction(MagicChangeStateAction.Clear(this,MagicPermanentState.Destroyed));
|
2012-09-22 19:05:32 -07:00
|
|
|
game.addDelayedAction(new MagicDestroyAction(this));
|
|
|
|
} else if (toughness-damage<=0) {
|
|
|
|
game.addDelayedAction(new MagicDestroyAction(this));
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
// Soulbond
|
|
|
|
if (pairedCreature.isValid() &&
|
|
|
|
!pairedCreature.isCreature()) {
|
|
|
|
game.doAction(new MagicSoulbondAction(this,pairedCreature,false));
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
}
|
|
|
|
|
2013-02-24 05:00:49 -08:00
|
|
|
if (isAura()) {
|
2012-09-22 19:05:32 -07:00
|
|
|
final MagicPlayAuraEvent auraEvent = (MagicPlayAuraEvent)cardDefinition.getCardEvent();
|
|
|
|
//not targeting since Aura is already attached
|
|
|
|
final MagicTargetChoice tchoice = new MagicTargetChoice(auraEvent.getTargetChoice(), false);
|
2013-06-23 18:33:35 -07:00
|
|
|
if (!enchantedCreature.isValid() ||
|
2012-09-22 19:05:32 -07:00
|
|
|
!game.isLegalTarget(getController(),this,tchoice,enchantedCreature) ||
|
|
|
|
enchantedCreature.hasProtectionFrom(this)) {
|
|
|
|
game.logAppendMessage(getController(),getName()+" is put into its owner's graveyard.");
|
|
|
|
game.addDelayedAction(new MagicRemoveFromPlayAction(this,MagicLocationType.Graveyard));
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
}
|
|
|
|
|
2013-02-24 05:00:49 -08:00
|
|
|
if (isEquipment() && equippedCreature.isValid()) {
|
2012-09-22 19:05:32 -07:00
|
|
|
if (isCreature() || !equippedCreature.isCreature() || equippedCreature.hasProtectionFrom(this)) {
|
|
|
|
game.addDelayedAction(new MagicAttachEquipmentAction(this,MagicPermanent.NONE));
|
|
|
|
}
|
|
|
|
}
|
2013-02-23 23:38:42 -08:00
|
|
|
|
|
|
|
// rule 704.5i If a planeswalker has loyalty 0, it's put into its owner's graveyard.
|
2013-02-24 05:00:49 -08:00
|
|
|
if (isPlaneswalker() && getCounters(MagicCounterType.Charge) == 0) {
|
2013-02-23 23:38:42 -08:00
|
|
|
game.logAppendMessage(getController(),getName()+" is put into its owner's graveyard.");
|
|
|
|
game.addDelayedAction(new MagicRemoveFromPlayAction(this,MagicLocationType.Graveyard));
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
// +1/+1 and -1/-1 counters cancel each other out.
|
|
|
|
final int plusCounters=getCounters(MagicCounterType.PlusOne);
|
|
|
|
if (plusCounters>0) {
|
|
|
|
final int minusCounters=getCounters(MagicCounterType.MinusOne);
|
|
|
|
if (minusCounters>0) {
|
|
|
|
final int amount=-Math.min(plusCounters,minusCounters);
|
|
|
|
game.addDelayedAction(new MagicChangeCountersAction(this,MagicCounterType.PlusOne,amount,false));
|
|
|
|
game.addDelayedAction(new MagicChangeCountersAction(this,MagicCounterType.MinusOne,amount,false));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-10-12 20:24:37 -07:00
|
|
|
public boolean hasProtectionFrom(final MagicSource source) {
|
2013-07-19 21:00:37 -07:00
|
|
|
// From everything
|
|
|
|
if (hasAbility(MagicAbility.ProtectionFromEverything)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-10-09 02:16:11 -07:00
|
|
|
// From a color.
|
|
|
|
int numColors = 0;
|
|
|
|
for (final MagicColor color : MagicColor.values()) {
|
|
|
|
if (source.hasColor(color)) {
|
|
|
|
numColors++;
|
2012-10-12 20:24:37 -07:00
|
|
|
if (hasAbility(color.getProtectionAbility()) ||
|
|
|
|
hasAbility(MagicAbility.ProtectionFromAllColors)) {
|
2012-10-09 02:16:11 -07:00
|
|
|
return true;
|
2013-07-19 21:00:37 -07:00
|
|
|
} else if (source.isSpell() && hasAbility(MagicAbility.ProtectionFromColoredSpells)) {
|
|
|
|
return true;
|
2012-10-09 02:16:11 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
// From monocolored.
|
2012-10-09 02:16:11 -07:00
|
|
|
if (numColors == 1 &&
|
2012-10-12 20:24:37 -07:00
|
|
|
hasAbility(MagicAbility.ProtectionFromMonoColored)) {
|
2012-09-22 19:05:32 -07:00
|
|
|
return true;
|
|
|
|
}
|
2012-10-09 02:16:11 -07:00
|
|
|
|
|
|
|
if (!source.isCreature()) {
|
|
|
|
return false;
|
2012-09-22 19:05:32 -07:00
|
|
|
}
|
2012-10-09 02:16:11 -07:00
|
|
|
|
|
|
|
final MagicPermanent creature = (MagicPermanent)source;
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-10-09 02:16:11 -07:00
|
|
|
// From creatures.
|
2013-03-05 21:50:06 -08:00
|
|
|
if (creature.hasType(MagicType.Creature) &&
|
|
|
|
hasAbility(MagicAbility.ProtectionFromCreatures)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// From Artifacts
|
|
|
|
if (creature.hasType(MagicType.Artifact) &&
|
|
|
|
hasAbility(MagicAbility.ProtectionFromArtifacts)) {
|
2012-10-09 02:16:11 -07:00
|
|
|
return true;
|
2012-09-22 19:05:32 -07:00
|
|
|
}
|
2012-10-09 02:16:11 -07:00
|
|
|
// From Demons.
|
|
|
|
if (creature.hasSubType(MagicSubType.Demon) &&
|
2012-10-12 20:24:37 -07:00
|
|
|
hasAbility(MagicAbility.ProtectionFromDemons)) {
|
2012-10-09 02:16:11 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// From Dragons.
|
|
|
|
if (creature.hasSubType(MagicSubType.Dragon) &&
|
2012-10-12 20:24:37 -07:00
|
|
|
hasAbility(MagicAbility.ProtectionFromDragons)) {
|
2012-10-09 02:16:11 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// From Vampires.
|
|
|
|
if (creature.hasSubType(MagicSubType.Vampire) &&
|
2012-10-12 20:24:37 -07:00
|
|
|
hasAbility(MagicAbility.ProtectionFromVampires)) {
|
2012-10-09 02:16:11 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// From Werewolves.
|
|
|
|
if (creature.hasSubType(MagicSubType.Werewolf) &&
|
2012-10-12 20:24:37 -07:00
|
|
|
hasAbility(MagicAbility.ProtectionFromWerewolves)) {
|
2012-10-09 02:16:11 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// From Zombies.
|
|
|
|
if (creature.hasSubType(MagicSubType.Zombie) &&
|
2012-10-12 20:24:37 -07:00
|
|
|
hasAbility(MagicAbility.ProtectionFromZombies)) {
|
2012-10-09 02:16:11 -07:00
|
|
|
return true;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
return false;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public boolean canAttack() {
|
2013-06-23 18:33:35 -07:00
|
|
|
if (!isCreature() ||
|
|
|
|
!canTap() ||
|
2012-09-22 19:05:32 -07:00
|
|
|
hasState(MagicPermanentState.ExcludeFromCombat) ||
|
|
|
|
hasState(MagicPermanentState.CannotAttack)) {
|
|
|
|
return false;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
return !hasAbility(MagicAbility.CannotAttackOrBlock) &&
|
2012-10-12 20:24:37 -07:00
|
|
|
!hasAbility(MagicAbility.Defender);
|
2012-09-22 19:05:32 -07:00
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-10-12 20:24:37 -07:00
|
|
|
public boolean canBlock() {
|
2013-06-23 18:33:35 -07:00
|
|
|
if (!isCreature() ||
|
|
|
|
isTapped() ||
|
2012-10-12 20:24:37 -07:00
|
|
|
hasState(MagicPermanentState.ExcludeFromCombat)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return !hasAbility(MagicAbility.CannotAttackOrBlock) &&
|
|
|
|
!hasAbility(MagicAbility.CannotBlock);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-10-12 20:24:37 -07:00
|
|
|
public boolean canBeBlocked(final MagicPlayer defendingPlayer) {
|
2012-09-22 19:05:32 -07:00
|
|
|
// Unblockable
|
2012-10-12 20:24:37 -07:00
|
|
|
if (hasAbility(MagicAbility.Unblockable)) {
|
2012-09-22 19:05:32 -07:00
|
|
|
return false;
|
2013-06-23 18:33:35 -07:00
|
|
|
}
|
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
// Landwalk
|
|
|
|
for (final MagicColor color : MagicColor.values()) {
|
2013-06-23 18:33:35 -07:00
|
|
|
if (hasAbility(color.getLandwalkAbility()) &&
|
2013-06-02 22:29:24 -07:00
|
|
|
defendingPlayer.controlsPermanent(color.getLandSubType())) {
|
2012-09-22 19:05:32 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
return true;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public boolean canBlock(final MagicPermanent attacker) {
|
|
|
|
// Fear and Intimidate
|
|
|
|
if (!isArtifact()) {
|
2012-10-12 20:24:37 -07:00
|
|
|
if (attacker.hasAbility(MagicAbility.Fear) &&
|
|
|
|
!hasColor(MagicColor.Black)) {
|
2012-09-22 19:05:32 -07:00
|
|
|
return false;
|
|
|
|
}
|
2012-10-12 20:24:37 -07:00
|
|
|
if (attacker.hasAbility(MagicAbility.Intimidate) &&
|
|
|
|
((getColorFlags() & attacker.getColorFlags())==0)) {
|
2012-09-22 19:05:32 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
// Shadow
|
2012-10-12 20:24:37 -07:00
|
|
|
if (attacker.hasAbility(MagicAbility.Shadow)) {
|
|
|
|
if (!hasAbility(MagicAbility.Shadow) &&
|
|
|
|
!hasAbility(MagicAbility.CanBlockShadow)) {
|
2012-09-22 19:05:32 -07:00
|
|
|
return false;
|
|
|
|
}
|
2012-10-12 20:24:37 -07:00
|
|
|
} else if (hasAbility(MagicAbility.Shadow)) {
|
2012-09-22 19:05:32 -07:00
|
|
|
return false;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-10-12 20:24:37 -07:00
|
|
|
// Flying
|
|
|
|
if (attacker.hasAbility(MagicAbility.CannotBeBlockedByFlying) &&
|
|
|
|
hasAbility(MagicAbility.Flying)) {
|
|
|
|
return false;
|
2012-09-22 19:05:32 -07:00
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-10-12 20:24:37 -07:00
|
|
|
if (attacker.hasAbility(MagicAbility.CannotBeBlockedExceptWithFlying) &&
|
|
|
|
!hasAbility(MagicAbility.Flying)) {
|
|
|
|
return false;
|
2012-09-22 19:05:32 -07:00
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-10-12 20:24:37 -07:00
|
|
|
if (!attacker.hasAbility(MagicAbility.Flying) &&
|
|
|
|
hasAbility(MagicAbility.CannotBlockWithoutFlying)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reach
|
|
|
|
if (attacker.hasAbility(MagicAbility.Flying) &&
|
|
|
|
!hasAbility(MagicAbility.Flying) &&
|
|
|
|
!hasAbility(MagicAbility.Reach)) {
|
|
|
|
return false;
|
2013-06-23 18:33:35 -07:00
|
|
|
}
|
2012-10-12 20:24:37 -07:00
|
|
|
|
|
|
|
if (attacker.hasAbility(MagicAbility.CannotBeBlockedExceptWithFlyingOrReach) &&
|
|
|
|
!hasAbility(MagicAbility.Flying) &&
|
|
|
|
!hasAbility(MagicAbility.Reach)) {
|
|
|
|
return false;
|
2012-09-22 19:05:32 -07:00
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
// Subtype
|
2012-10-12 20:24:37 -07:00
|
|
|
if (attacker.hasAbility(MagicAbility.CannotBeBlockedByHumans) &&
|
|
|
|
hasSubType(MagicSubType.Human)) {
|
|
|
|
return false;
|
2012-09-22 19:05:32 -07:00
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-10-12 20:24:37 -07:00
|
|
|
if (attacker.hasAbility(MagicAbility.CannotBeBlockedExceptBySliver) &&
|
|
|
|
!hasSubType(MagicSubType.Sliver)) {
|
|
|
|
return false;
|
2012-09-22 19:05:32 -07:00
|
|
|
}
|
|
|
|
|
2013-02-16 19:12:36 -08:00
|
|
|
// Tokens
|
|
|
|
if (attacker.hasAbility(MagicAbility.CannotBeBlockedByTokens) &&
|
|
|
|
isToken()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
// Can't be blocked by a color
|
|
|
|
for (final MagicColor color : MagicColor.values()) {
|
2012-10-12 20:24:37 -07:00
|
|
|
if (attacker.hasAbility(color.getCannotBeBlockedByAbility()) &&
|
|
|
|
hasColor(color)) {
|
2012-09-22 19:05:32 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
// Protection
|
2012-10-12 20:24:37 -07:00
|
|
|
return !attacker.hasProtectionFrom(this);
|
2012-09-22 19:05:32 -07:00
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public MagicPermanent getEquippedCreature() {
|
|
|
|
return equippedCreature;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setEquippedCreature(final MagicPermanent creature) {
|
|
|
|
equippedCreature=creature;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public MagicPermanentSet getEquipmentPermanents() {
|
|
|
|
return equipmentPermanents;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public void addEquipment(final MagicPermanent equipment) {
|
|
|
|
equipmentPermanents.add(equipment);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public void removeEquipment(final MagicPermanent equipment) {
|
|
|
|
equipmentPermanents.remove(equipment);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public boolean isEquipped() {
|
|
|
|
return equipmentPermanents.size()>0;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public MagicPermanent getEnchantedCreature() {
|
|
|
|
return enchantedCreature;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setEnchantedCreature(final MagicPermanent creature) {
|
|
|
|
enchantedCreature=creature;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public MagicPermanentSet getAuraPermanents() {
|
|
|
|
return auraPermanents;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public void addAura(final MagicPermanent aura) {
|
|
|
|
auraPermanents.add(aura);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public void removeAura(final MagicPermanent aura) {
|
|
|
|
auraPermanents.remove(aura);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public boolean isEnchanted() {
|
|
|
|
return auraPermanents.size()>0;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public int getAbilityPlayedThisTurn() {
|
|
|
|
return abilityPlayedThisTurn;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public void setAbilityPlayedThisTurn(final int amount) {
|
|
|
|
abilityPlayedThisTurn=amount;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public void incrementAbilityPlayedThisTurn() {
|
|
|
|
abilityPlayedThisTurn++;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void decrementAbilityPlayedThisTurn() {
|
|
|
|
abilityPlayedThisTurn--;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
private int getTypeFlags() {
|
|
|
|
return cachedTypeFlags;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public boolean hasType(final MagicType type) {
|
|
|
|
return type.hasType(getTypeFlags());
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public boolean isBasic() {
|
|
|
|
return hasType(MagicType.Basic);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public boolean isLand() {
|
|
|
|
return hasType(MagicType.Land);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public boolean isCreature() {
|
|
|
|
return hasType(MagicType.Creature);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public boolean isEquipment() {
|
|
|
|
return isArtifact() && hasSubType(MagicSubType.Equipment);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public boolean isArtifact() {
|
|
|
|
return hasType(MagicType.Artifact);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
public boolean isEnchantment() {
|
|
|
|
return hasType(MagicType.Enchantment);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-02-24 05:00:49 -08:00
|
|
|
public boolean isAura() {
|
|
|
|
return isEnchantment() && hasSubType(MagicSubType.Aura);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-02-24 05:00:49 -08:00
|
|
|
public boolean isPlaneswalker() {
|
|
|
|
return hasType(MagicType.Planeswalker);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
@Override
|
|
|
|
public boolean isSpell() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean isPlayer() {
|
|
|
|
return false;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
@Override
|
|
|
|
public boolean isPermanent() {
|
|
|
|
return true;
|
2013-06-23 18:33:35 -07:00
|
|
|
}
|
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
@Override
|
|
|
|
public boolean isValidTarget(final MagicSource source) {
|
|
|
|
// Can't be the target of spells or abilities.
|
2012-10-12 20:24:37 -07:00
|
|
|
if (hasAbility(MagicAbility.Shroud)) {
|
2012-09-22 19:05:32 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Can't be the target of spells or abilities your opponents controls.
|
2012-10-12 20:24:37 -07:00
|
|
|
if (hasAbility(MagicAbility.Hexproof) && source.getController() != getController()) {
|
2012-09-22 19:05:32 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Can't be the target of spells or abilities player 0 controls.
|
2012-10-12 20:24:37 -07:00
|
|
|
if (hasAbility(MagicAbility.CannotBeTheTarget0) && source.getController().getIndex() == 0) {
|
2012-09-22 19:05:32 -07:00
|
|
|
return false;
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-09-22 19:05:32 -07:00
|
|
|
// Can't be the target of spells or abilities player 1 controls.
|
2012-10-12 20:24:37 -07:00
|
|
|
if (hasAbility(MagicAbility.CannotBeTheTarget1) && source.getController().getIndex() == 1) {
|
2012-09-22 19:05:32 -07:00
|
|
|
return false;
|
|
|
|
}
|
2013-07-10 23:11:31 -07:00
|
|
|
|
|
|
|
// Can't be the target of nongreen spells or abilities from nongreen sources
|
|
|
|
if (hasAbility(MagicAbility.CannotBeTheTargetOfNonGreen) && source.hasColor(MagicColor.Green)) {
|
|
|
|
return false;
|
|
|
|
}
|
2012-09-22 19:05:32 -07:00
|
|
|
|
|
|
|
// Protection.
|
2012-10-12 20:24:37 -07:00
|
|
|
return !hasProtectionFrom(source);
|
2012-09-22 19:05:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int compareTo(final MagicPermanent permanent) {
|
|
|
|
// Important for sorting of permanent mana activations.
|
2012-10-06 18:37:03 -07:00
|
|
|
final int diff = cardDefinition.getIndex() - permanent.cardDefinition.getIndex();
|
|
|
|
if (diff != 0) {
|
|
|
|
return diff;
|
2012-09-22 19:05:32 -07:00
|
|
|
} else {
|
2012-10-06 18:37:03 -07:00
|
|
|
return Long.signum(id - permanent.id);
|
2012-09-22 19:05:32 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public ImageIcon getIcon() {
|
|
|
|
if (isAttacking()) {
|
|
|
|
return IconImages.ATTACK;
|
2013-06-23 18:33:35 -07:00
|
|
|
}
|
2012-09-22 19:05:32 -07:00
|
|
|
if (isBlocking()) {
|
|
|
|
return IconImages.BLOCK;
|
|
|
|
}
|
|
|
|
if (isCreature()) {
|
|
|
|
return IconImages.CREATURE;
|
|
|
|
}
|
|
|
|
return cardDefinition.getIcon();
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2012-10-21 02:59:46 -07:00
|
|
|
@Override
|
|
|
|
public boolean isLegalTarget(final MagicPlayer player, final MagicTargetFilter<? extends MagicTarget> targetFilter) {
|
|
|
|
return getController().controlsPermanent(this);
|
|
|
|
}
|
2013-06-23 18:33:35 -07:00
|
|
|
|
2013-02-24 05:59:10 -08:00
|
|
|
public static final MagicPermanent NONE = new MagicPermanent(-1L, MagicCard.NONE, MagicPlayer.NONE) {
|
|
|
|
@Override
|
|
|
|
public boolean isValid() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
@Override
|
|
|
|
public String toString() {
|
|
|
|
return "MagicPermanent.NONE";
|
|
|
|
}
|
|
|
|
@Override
|
|
|
|
public MagicPermanent copy(final MagicCopyMap copyMap) {
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
@Override
|
|
|
|
public MagicPowerToughness getPowerToughness() {
|
|
|
|
return new MagicPowerToughness(0,0);
|
|
|
|
}
|
|
|
|
@Override
|
|
|
|
public MagicPlayer getController() {
|
|
|
|
return MagicPlayer.NONE;
|
|
|
|
}
|
|
|
|
@Override
|
|
|
|
public boolean hasColor(final MagicColor color) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
@Override
|
|
|
|
public boolean hasType(final MagicType type) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
@Override
|
|
|
|
public boolean hasSubType(final MagicSubType type) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
@Override
|
|
|
|
public Set<MagicAbility> getAbilityFlags() {
|
|
|
|
return Collections.emptySet();
|
|
|
|
}
|
|
|
|
@Override
|
|
|
|
public boolean hasAbility(final MagicAbility ability) {
|
|
|
|
return false;
|
|
|
|
}
|
2013-03-27 07:14:20 -07:00
|
|
|
@Override
|
|
|
|
public long getStateId() {
|
|
|
|
return hashCode();
|
|
|
|
}
|
2013-02-24 05:59:10 -08:00
|
|
|
};
|
2012-09-22 19:05:32 -07:00
|
|
|
}
|