Add Subtype to the CardAttribute Framework

This is a massive change. I’ve refrained from unrelated refactoring
when possible but there are still a lot of changes here.
This commit is contained in:
Samuel Sandeen 2016-08-28 17:30:10 -04:00
parent a1a3c0c6a7
commit 282443c231
272 changed files with 514 additions and 493 deletions

View file

@ -24,9 +24,9 @@ public interface MageObject extends MageItem, Serializable {
List<CardType> getCardType();
List<String> getSubtype();
List<String> getSubtype(Game game);
boolean hasSubtype(String subtype);
boolean hasSubtype(String subtype, Game game);
List<String> getSupertype();

View file

@ -122,7 +122,7 @@ public abstract class MageObjectImpl implements MageObject {
}
@Override
public List<String> getSubtype() {
public List<String> getSubtype(Game game) {
return subtype;
}
@ -182,11 +182,12 @@ public abstract class MageObjectImpl implements MageObject {
}
@Override
public boolean hasSubtype(String value) {
public boolean hasSubtype(String value, Game game) {
if (value == null) {
return false;
}
if (this.subtype.contains(value)) {
List<String> subtypes = this.getSubtype(game);
if (subtypes.contains(value)) {
return true;
} else {
// checking for Changeling
@ -196,7 +197,7 @@ public abstract class MageObjectImpl implements MageObject {
return false;
}
// as it is creature subtype, then check the existence of Changeling
return abilities.contains(ChangelingAbility.getInstance()) || this.subtype.contains(ChangelingAbility.ALL_CREATURE_TYPE);
return abilities.contains(ChangelingAbility.getInstance()) || subtypes.contains(ChangelingAbility.ALL_CREATURE_TYPE);
}
}

View file

@ -126,7 +126,7 @@ class KinshipBaseEffect extends OneShotEffect {
if (card != null) {
Cards cards = new CardsImpl(card);
controller.lookAtCards(sourcePermanent.getName(), cards, game);
if (CardUtil.shareSubtypes(sourcePermanent, card)) {
if (CardUtil.shareSubtypes(sourcePermanent, card, game)) {
if (controller.chooseUse(outcome,new StringBuilder("Kinship - Reveal ").append(card.getLogName()).append("?").toString(), source, game)) {
controller.revealCards(sourcePermanent.getName(), cards, game);
for (Effect effect: kinshipEffects) {

View file

@ -58,7 +58,7 @@ public class AllyEntersBattlefieldTriggeredAbility extends TriggeredAbilityImpl
EntersTheBattlefieldEvent ebe = (EntersTheBattlefieldEvent) event;
if (ebe.getTarget().getControllerId().equals(this.controllerId)
&& (event.getTargetId().equals(this.getSourceId())
|| (ebe.getTarget().hasSubtype("Ally") && !event.getTargetId().equals(this.getSourceId())))) {
|| (ebe.getTarget().hasSubtype("Ally", game) && !event.getTargetId().equals(this.getSourceId())))) {
return true;
}
return false;

View file

@ -57,7 +57,7 @@ public class AuraAttachedTriggeredAbility extends TriggeredAbilityImpl {
public boolean checkTrigger(GameEvent event, Game game) {
if (event.getTargetId().equals(this.getSourceId())) {
Permanent attachment = game.getPermanent(event.getSourceId());
if (attachment != null && attachment.getSubtype().contains("Aura")) {
if (attachment != null && attachment.getSubtype(game).contains("Aura")) {
return true;
}
}

View file

@ -140,8 +140,8 @@ class LicidContinuousEffect extends ContinuousEffectImpl {
case TypeChangingEffects_4:
licid.getCardType().clear();
licid.getCardType().add(CardType.ENCHANTMENT);
licid.getSubtype().clear();
licid.getSubtype().add("Aura");
licid.getSubtype(game).clear();
licid.getSubtype(game).add("Aura");
break;
case AbilityAddingRemovingEffects_6:
for (Ability ability : licid.getAbilities(game)) {

View file

@ -61,12 +61,12 @@ public class EquippedHasSubtypeCondition implements Condition {
}
if (attachedTo != null) {
if (subType != null) {
if (attachedTo.hasSubtype(this.subType)) {
if (attachedTo.hasSubtype(this.subType, game)) {
return true;
}
} else {
for (String s : subTypes) {
if (attachedTo.hasSubtype(s)) {
if (attachedTo.hasSubtype(s, game)) {
return true;
}
}

View file

@ -52,7 +52,7 @@ public class EquippedSourceCondition implements Condition {
if (permanent != null) {
for (UUID uuid : permanent.getAttachments()) {
Permanent attached = game.getBattlefield().getPermanent(uuid);
if (attached != null && attached.getSubtype().contains("Equipment")) {
if (attached != null && attached.getSubtype(game).contains("Equipment")) {
return true;
}
}

View file

@ -21,7 +21,7 @@ public class SourceHasSubtypeCondition implements Condition {
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent != null) {
return permanent.hasSubtype(subtype);
return permanent.hasSubtype(subtype, game);
}
return false;
}

View file

@ -50,7 +50,7 @@ public class TargetHasSubtypeCondition implements Condition {
if (!source.getTargets().isEmpty()) {
Permanent permanent = game.getPermanent(source.getFirstTarget());
if (permanent != null) {
return permanent.hasSubtype(subtype);
return permanent.hasSubtype(subtype, game);
}
}
return false;

View file

@ -63,7 +63,7 @@ public class AuraAttachedCount implements DynamicValue {
List<UUID> attachments = p.getAttachments();
for (UUID attachmentId : attachments) {
Permanent attached = game.getPermanent(attachmentId);
if (attached != null && attached.getSubtype().contains("Aura")) {
if (attached != null && attached.getSubtype(game).contains("Aura")) {
count++;
}
}

View file

@ -62,19 +62,19 @@ public class DomainValue implements DynamicValue {
}
for (Permanent p : game.getBattlefield().getAllActivePermanents(targetPlayer)) {
if (p.getCardType().contains(CardType.LAND)) {
if (havePlains == 0 && p.getSubtype().contains("Plains")) {
if (havePlains == 0 && p.getSubtype(game).contains("Plains")) {
havePlains = 1;
}
if (haveIslands == 0 && p.getSubtype().contains("Island")) {
if (haveIslands == 0 && p.getSubtype(game).contains("Island")) {
haveIslands = 1;
}
if (haveMountains == 0 && p.getSubtype().contains("Mountain")) {
if (haveMountains == 0 && p.getSubtype(game).contains("Mountain")) {
haveMountains = 1;
}
if (haveSwamps == 0 && p.getSubtype().contains("Swamp")) {
if (haveSwamps == 0 && p.getSubtype(game).contains("Swamp")) {
haveSwamps = 1;
}
if (haveForests == 0 && p.getSubtype().contains("Forest")) {
if (haveForests == 0 && p.getSubtype(game).contains("Forest")) {
haveForests = 1;
}
}

View file

@ -63,7 +63,7 @@ public class EquipmentAttachedCount implements DynamicValue {
List<UUID> attachments = permanent.getAttachments();
for (UUID attachmentId : attachments) {
Permanent attached = game.getPermanent(attachmentId);
if (attached != null && attached.getSubtype().contains("Equipment")) {
if (attached != null && attached.getSubtype(game).contains("Equipment")) {
count++;
}
}

View file

@ -206,12 +206,12 @@ public class AuraReplacementEffect extends ReplacementEffectImpl {
if (((ZoneChangeEvent) event).getToZone().equals(Zone.BATTLEFIELD)
&& !(((ZoneChangeEvent) event).getFromZone().equals(Zone.STACK))) {
Card card = game.getCard(event.getTargetId());
if (card != null && (card.getCardType().contains(CardType.ENCHANTMENT) && card.hasSubtype("Aura")
if (card != null && (card.getCardType().contains(CardType.ENCHANTMENT) && card.hasSubtype("Aura", game)
|| // in case of transformable enchantments
(game.getState().getValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + card.getId()) != null
&& card.getSecondCardFace() != null
&& card.getSecondCardFace().getCardType().contains(CardType.ENCHANTMENT)
&& card.getSecondCardFace().hasSubtype("Aura")))) {
&& card.getSecondCardFace().hasSubtype("Aura", game)))) {
return true;
}
}

View file

@ -100,7 +100,7 @@ public class AmplifyEffect extends ReplacementEffectImpl {
if (controller != null && sourceCreature != null) {
FilterCreatureCard filter = new FilterCreatureCard("creatures cards to reveal");
List<SubtypePredicate> filterSubtypes = new ArrayList<>();
for (String subtype : sourceCreature.getSubtype()) {
for (String subtype : sourceCreature.getSubtype(game)) {
filterSubtypes.add(new SubtypePredicate((subtype)));
}
if (filterSubtypes.size() > 1) {

View file

@ -126,9 +126,9 @@ public class CopyEffect extends ContinuousEffectImpl {
for (CardType type : copyFromObject.getCardType()) {
permanent.getCardType().add(type);
}
permanent.getSubtype().clear();
for (String type : copyFromObject.getSubtype()) {
permanent.getSubtype().add(type);
permanent.getSubtype(game).clear();
for (String type : copyFromObject.getSubtype(game)) {
permanent.getSubtype(game).add(type);
}
permanent.getSupertype().clear();
for (String type : copyFromObject.getSupertype()) {

View file

@ -34,9 +34,9 @@ public class CopyTokenEffect extends ContinuousEffectImpl {
for (CardType type: token.getCardType()) {
permanent.getCardType().add(type);
}
permanent.getSubtype().clear();
for (String type: token.getSubtype()) {
permanent.getSubtype().add(type);
permanent.getSubtype(game).clear();
for (String type: token.getSubtype(game)) {
permanent.getSubtype(game).add(type);
}
permanent.getSupertype().clear();
for (String type: token.getSupertype()) {

View file

@ -150,7 +150,7 @@ public class DevourEffect extends ReplacementEffectImpl {
for (UUID targetId : target.getTargets()) {
Permanent targetCreature = game.getPermanent(targetId);
if (targetCreature != null) {
cardSubtypes.add((ArrayList<String>) targetCreature.getSubtype());
cardSubtypes.add((ArrayList<String>) targetCreature.getSubtype(game));
}
if (targetCreature == null || !targetCreature.sacrifice(source.getSourceId(), game)) {
return false;

View file

@ -198,8 +198,8 @@ public class PutTokenOntoBattlefieldCopyTargetEffect extends OneShotEffect {
if (tokenToughness != Integer.MIN_VALUE) {
token.setToughness(tokenToughness);
}
if (additionalSubType != null && !token.getSubtype().contains(additionalSubType)) {
token.getSubtype().add(additionalSubType);
if (additionalSubType != null && !token.getSubtype(game).contains(additionalSubType)) {
token.getSubtype(game).add(additionalSubType);
}
token.putOntoBattlefield(number, game, source.getSourceId(), playerId == null ? source.getControllerId() : playerId, tapped, attacking, attackedPlayer);

View file

@ -58,8 +58,8 @@ public class AddCardSubTypeTargetEffect extends ContinuousEffectImpl {
public boolean apply(Game game, Ability source) {
Permanent target = game.getPermanent(targetPointer.getFirst(game, source));
if (target != null) {
if (!target.hasSubtype(addedSubType)) {
target.getSubtype().add(addedSubType);
if (!target.hasSubtype(addedSubType, game)) {
target.getSubtype(game).add(addedSubType);
}
} else {
if (Duration.Custom.equals(duration)) {

View file

@ -59,8 +59,8 @@ public class AddCardSubtypeAttachedEffect extends ContinuousEffectImpl {
Permanent equipment = game.getPermanent(source.getSourceId());
if (equipment != null && equipment.getAttachedTo() != null) {
Permanent target = game.getPermanent(equipment.getAttachedTo());
if (target != null && !target.getSubtype().contains(addedSubtype))
target.getSubtype().add(addedSubtype);
if (target != null && !target.getSubtype(game).contains(addedSubtype))
target.getSubtype(game).add(addedSubtype);
}
return true;
}

View file

@ -83,8 +83,8 @@ public class BecomesAuraSourceEffect extends ContinuousEffectImpl implements Sou
switch (layer) {
case TypeChangingEffects_4:
if (sublayer == SubLayer.NA) {
if (!permanent.getSubtype().contains("Aura")) {
permanent.getSubtype().add("Aura");
if (!permanent.getSubtype(game).contains("Aura")) {
permanent.getSubtype(game).add("Aura");
}
}
break;

View file

@ -98,27 +98,27 @@ public class BecomesBasicLandEnchantedEffect extends ContinuousEffectImpl {
for (String landType : landTypes) {
switch (landType) {
case "Swamp":
if (permanent.getSubtype().contains("Swamp")) { // type can be removed by other effect with newer timestamp, so no ability adding
if (permanent.getSubtype(game).contains("Swamp")) { // type can be removed by other effect with newer timestamp, so no ability adding
permanent.addAbility(new BlackManaAbility(), source.getSourceId(), game);
}
break;
case "Mountain":
if (permanent.getSubtype().contains("Mountain")) {
if (permanent.getSubtype(game).contains("Mountain")) {
permanent.addAbility(new RedManaAbility(), source.getSourceId(), game);
}
break;
case "Forest":
if (permanent.getSubtype().contains("Forest")) {
if (permanent.getSubtype(game).contains("Forest")) {
permanent.addAbility(new GreenManaAbility(), source.getSourceId(), game);
}
break;
case "Island":
if (permanent.getSubtype().contains("Island")) {
if (permanent.getSubtype(game).contains("Island")) {
permanent.addAbility(new BlueManaAbility(), source.getSourceId(), game);
}
break;
case "Plains":
if (permanent.getSubtype().contains("Plains")) {
if (permanent.getSubtype(game).contains("Plains")) {
permanent.addAbility(new WhiteManaAbility(), source.getSourceId(), game);
}
break;
@ -127,8 +127,8 @@ public class BecomesBasicLandEnchantedEffect extends ContinuousEffectImpl {
break;
case TypeChangingEffects_4:
// subtypes are all removed by changing the subtype to a land type.
permanent.getSubtype().removeAll(allLandTypes);
permanent.getSubtype().addAll(landTypes);
permanent.getSubtype(game).removeAll(allLandTypes);
permanent.getSubtype(game).addAll(landTypes);
break;
}
return true;

View file

@ -132,7 +132,7 @@ public class BecomesBasicLandTargetEffect extends ContinuousEffectImpl {
for (UUID targetPermanent : targetPointer.getTargets(game, source)) {
Permanent land = game.getPermanent(targetPermanent);
if (land != null) {
for (String type : land.getSubtype()) {
for (String type : land.getSubtype(game)) {
if (!landTypes.contains(type)) {
landTypes.add(type);
}
@ -157,8 +157,8 @@ public class BecomesBasicLandTargetEffect extends ContinuousEffectImpl {
// So the ability removing has to be done before Layer 6
land.removeAllAbilities(source.getSourceId(), game);
// 305.7
land.getSubtype().removeAll(CardRepository.instance.getLandTypes());
land.getSubtype().addAll(landTypes);
land.getSubtype(game).removeAll(CardRepository.instance.getLandTypes());
land.getSubtype(game).addAll(landTypes);
break;
case AbilityAddingRemovingEffects_6:
for (String landType : landTypes) {

View file

@ -84,10 +84,10 @@ public class BecomesCreatureAllEffect extends ContinuousEffectImpl {
}
}
if (type == null) {
permanent.getSubtype().clear();
permanent.getSubtype(game).clear();
}
if (token.getSubtype().size() > 0) {
permanent.getSubtype().addAll(token.getSubtype());
if (token.getSubtype(game).size() > 0) {
permanent.getSubtype(game).addAll(token.getSubtype(game));
}
}
break;

View file

@ -112,13 +112,13 @@ public class BecomesCreatureAttachedEffect extends ContinuousEffectImpl {
case ALL:
case ALL_BUT_COLOR:
case ABILITIES_SUBTYPE_AND_PT:
permanent.getSubtype().retainAll(CardRepository.instance.getLandTypes());
permanent.getSubtype(game).retainAll(CardRepository.instance.getLandTypes());
break;
}
if (token.getSubtype().size() > 0) {
for (String t : token.getSubtype()) {
if (!permanent.getSubtype().contains(t)) {
permanent.getSubtype().add(t);
if (token.getSubtype(game).size() > 0) {
for (String t : token.getSubtype(game)) {
if (!permanent.getSubtype(game).contains(t)) {
permanent.getSubtype(game).add(t);
}
}
}

View file

@ -121,10 +121,10 @@ public class BecomesCreatureSourceEffect extends ContinuousEffectImpl implements
}
}
if ("".equals(type) || type == null && permanent.getCardType().contains(CardType.LAND)) {
permanent.getSubtype().retainAll(CardRepository.instance.getLandTypes());
permanent.getSubtype(game).retainAll(CardRepository.instance.getLandTypes());
}
if (token.getSubtype().size() > 0) {
permanent.getSubtype().addAll(token.getSubtype());
if (token.getSubtype(game).size() > 0) {
permanent.getSubtype(game).addAll(token.getSubtype(game));
}
}
break;

View file

@ -88,13 +88,13 @@ public class BecomesCreatureTargetEffect extends ContinuousEffectImpl {
case TypeChangingEffects_4:
if (sublayer == SubLayer.NA) {
if (loseAllAbilities) {
permanent.getSubtype().retainAll(CardRepository.instance.getLandTypes());
permanent.getSubtype().addAll(token.getSubtype());
permanent.getSubtype(game).retainAll(CardRepository.instance.getLandTypes());
permanent.getSubtype(game).addAll(token.getSubtype(game));
} else {
if (token.getSubtype().size() > 0) {
for (String subtype : token.getSubtype()) {
if (!permanent.getSubtype().contains(subtype)) {
permanent.getSubtype().add(subtype);
if (token.getSubtype(game).size() > 0) {
for (String subtype : token.getSubtype(game)) {
if (!permanent.getSubtype(game).contains(subtype)) {
permanent.getSubtype(game).add(subtype);
}
}

View file

@ -72,12 +72,12 @@ public class BecomesCreatureTypeTargetEffect extends ContinuousEffectImpl {
switch (layer) {
case TypeChangingEffects_4:
if (loseOther) {
permanent.getSubtype().retainAll(CardRepository.instance.getLandTypes());
permanent.getSubtype().addAll(subtypes);
permanent.getSubtype(game).retainAll(CardRepository.instance.getLandTypes());
permanent.getSubtype(game).addAll(subtypes);
} else {
for (String subtype : subtypes) {
if (!permanent.getSubtype().contains(subtype)) {
permanent.getSubtype().add(subtype);
if (!permanent.getSubtype(game).contains(subtype)) {
permanent.getSubtype(game).add(subtype);
}
}
}

View file

@ -110,7 +110,7 @@ public class BecomesFaceDownCreatureAllEffect extends ContinuousEffectImpl imple
permanent.getSupertype().clear();
permanent.getCardType().clear();
permanent.getCardType().add(CardType.CREATURE);
permanent.getSubtype().clear();
permanent.getSubtype(game).clear();
permanent.getManaCost().clear();
break;
case ColorChangingEffects_5:

View file

@ -166,7 +166,7 @@ public class BecomesFaceDownCreatureEffect extends ContinuousEffectImpl implemen
permanent.getSupertype().clear();
permanent.getCardType().clear();
permanent.getCardType().add(CardType.CREATURE);
permanent.getSubtype().clear();
permanent.getSubtype(game).clear();
break;
case ColorChangingEffects_5:
permanent.getColor(game).setColor(new ObjectColor());

View file

@ -75,12 +75,12 @@ public class BecomesSubtypeAllEffect extends ContinuousEffectImpl {
switch (layer) {
case TypeChangingEffects_4:
if (loseOther) {
permanent.getSubtype().retainAll(CardRepository.instance.getLandTypes());
permanent.getSubtype().addAll(subtypes);
permanent.getSubtype(game).retainAll(CardRepository.instance.getLandTypes());
permanent.getSubtype(game).addAll(subtypes);
} else {
for (String subtype : subtypes) {
if (!permanent.getSubtype().contains(subtype)) {
permanent.getSubtype().add(subtype);
if (!permanent.getSubtype(game).contains(subtype)) {
permanent.getSubtype(game).add(subtype);
}
}
}

View file

@ -40,7 +40,7 @@ public class BoostAllOfChosenSubtypeEffect extends BoostAllEffect {
@Override
protected boolean selectedByRuntimeData(Permanent permanent, Ability source, Game game) {
if (subtype != null) {
return permanent.hasSubtype(subtype);
return permanent.hasSubtype(subtype, game);
}
return false;
}

View file

@ -36,7 +36,7 @@ public class GainAbilityAllOfChosenSubtypeEffect extends GainAbilityAllEffect {
@Override
protected boolean selectedByRuntimeData(Permanent permanent, Ability source, Game game) {
if (subtype != null) {
return permanent.hasSubtype(subtype);
return permanent.hasSubtype(subtype, game);
}
return false;
}

View file

@ -61,7 +61,7 @@ public class LoseAllCreatureTypesTargetEffect extends ContinuousEffectImpl {
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (permanent != null) {
return permanent.getSubtype().retainAll(CardRepository.instance.getLandTypes());
return permanent.getSubtype(game).retainAll(CardRepository.instance.getLandTypes());
}
return false;
}

View file

@ -85,7 +85,7 @@ public class LoseCreatureTypeSourceEffect extends ContinuousEffectImpl implement
case TypeChangingEffects_4:
if (sublayer == SubLayer.NA) {
permanent.getCardType().remove(CardType.CREATURE);
permanent.getSubtype().retainAll(CardRepository.instance.getLandTypes());
permanent.getSubtype(game).retainAll(CardRepository.instance.getLandTypes());
if (permanent.isAttacking() || permanent.getBlocking() > 0) {
permanent.removeFromCombat(game);
}

View file

@ -74,8 +74,8 @@ public class SetCardSubtypeAttachedEffect extends ContinuousEffectImpl {
if (equipment != null && equipment.getAttachedTo() != null) {
Permanent target = game.getPermanent(equipment.getAttachedTo());
if (target != null) {
target.getSubtype().retainAll(CardRepository.instance.getLandTypes());
target.getSubtype().addAll(setSubtypes);
target.getSubtype(game).retainAll(CardRepository.instance.getLandTypes());
target.getSubtype(game).addAll(setSubtypes);
}
}
return true;

View file

@ -33,7 +33,7 @@ public class SpellsCostReductionAllOfChosenSubtypeEffect extends SpellsCostReduc
protected boolean selectedByRuntimeData(Card card, Ability source, Game game) {
String subtype = (String) game.getState().getValue(source.getSourceId() + "_type");
if (subtype != null) {
return card.hasSubtype(subtype);
return card.hasSubtype(subtype, game);
}
return false;
}

View file

@ -93,7 +93,7 @@ class AuraSwapEffect extends OneShotEffect {
if (controller != null) {
Permanent auraSourcePermanent = game.getPermanent(source.getSourceId());
if (auraSourcePermanent != null
&& auraSourcePermanent.getSubtype().contains("Aura")
&& auraSourcePermanent.getSubtype(game).contains("Aura")
&& auraSourcePermanent.getOwnerId().equals(source.getControllerId())) {
Permanent enchantedPermanent = game.getPermanent(auraSourcePermanent.getAttachedTo());
filterCardToCheck.add(new AuraCardCanAttachToPermanentId(enchantedPermanent.getId()));

View file

@ -175,15 +175,15 @@ public class BestowAbility extends SpellAbility {
case TypeChangingEffects_4:
if (sublayer == SubLayer.NA) {
if (permanent.getAttachedTo() == null) {
if (wasAttached && permanent.getSubtype().contains("Aura")) {
permanent.getSubtype().remove("Aura");
if (wasAttached && permanent.getSubtype(game).contains("Aura")) {
permanent.getSubtype(game).remove("Aura");
wasAttached = false;
}
} else {
permanent.getCardType().remove(CardType.CREATURE);
permanent.getSubtype().retainAll(CardRepository.instance.getLandTypes());
if (!permanent.getSubtype().contains("Aura")) {
permanent.getSubtype().add("Aura");
permanent.getSubtype(game).retainAll(CardRepository.instance.getLandTypes());
if (!permanent.getSubtype(game).contains("Aura")) {
permanent.getSubtype(game).add("Aura");
}
wasAttached = true;
}

View file

@ -59,7 +59,7 @@ public class EquipAbility extends ActivatedAbilityImpl {
public boolean canActivate(UUID playerId, Game game) {
if(super.canActivate(playerId, game)){
Permanent permanent = game.getPermanent(sourceId);
if(permanent != null && permanent.hasSubtype("Equipment")){
if(permanent != null && permanent.hasSubtype("Equipment", game)){
return true;
}
}

View file

@ -90,7 +90,7 @@ class FlyingEffect extends RestrictionEffect implements MageSingleton {
public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) {
return blocker.getAbilities().containsKey(FlyingAbility.getInstance().getId())
|| blocker.getAbilities().containsKey(ReachAbility.getInstance().getId())
|| (game.getContinuousEffects().asThough(blocker.getId(), AsThoughEffectType.BLOCK_DRAGON, source, blocker.getControllerId(), game) && attacker.hasSubtype("Dragon")) ;
|| (game.getContinuousEffects().asThough(blocker.getId(), AsThoughEffectType.BLOCK_DRAGON, source, blocker.getControllerId(), game) && attacker.hasSubtype("Dragon", game)) ;
}
@Override

View file

@ -302,7 +302,7 @@ public class MorphAbility extends StaticAbility implements AlternativeSourceCost
mageObject.setName("");
mageObject.getCardType().clear();
mageObject.getCardType().add(CardType.CREATURE);
mageObject.getSubtype().clear();
mageObject.getSubtype(null).clear();
mageObject.getSupertype().clear();
mageObject.getManaCost().clear();
if (mageObject instanceof Permanent) {

View file

@ -123,7 +123,7 @@ public class ProwlAbility extends StaticAbility implements AlternativeSourceCost
throw new IllegalArgumentException("Params can't be null");
}
boolean canProwl = false;
for (String subtype : card.getSubtype()) {
for (String subtype : card.getSubtype(game)) {
if (prowlWatcher.hasSubtypeMadeCombatDamage(ability.getControllerId(), subtype)) {
canProwl = true;
break;
@ -187,18 +187,8 @@ public class ProwlAbility extends StaticAbility implements AlternativeSourceCost
}
private void setReminderText(Card card) {
StringBuilder sb = new StringBuilder("(You may cast this for its prowl cost if you dealt combat damage to a player this turn with a ");
int i = 0;
for (String subtype : card.getSubtype()) {
i++;
sb.append(subtype);
if (card.getSubtype().size() > 1 && i < card.getSubtype().size()) {
sb.append(" or ");
}
}
sb.append(".)");
reminderText = sb.toString();
reminderText =
"(You may cast this for its prowl cost if you dealt combat damage to a player this turn with a creature that shared a creature type with {this}";
}
@Override

View file

@ -182,7 +182,7 @@ class SpliceOntoArcaneEffect extends SpliceCardEffectImpl {
@Override
public boolean applies(Ability abilityToModify, Ability source, Game game) {
MageObject object = game.getObject(abilityToModify.getSourceId());
if (object != null && object.getSubtype().contains("Arcane")) {
if (object != null && object.getSubtype(game).contains("Arcane")) {
return spliceSpellCanBeActivated(source, game);
}
return false;

View file

@ -79,9 +79,9 @@ public class TransformAbility extends SimpleStaticAbility {
for (CardType type : sourceCard.getCardType()) {
permanent.getCardType().add(type);
}
permanent.getSubtype().clear();
for (String type : sourceCard.getSubtype()) {
permanent.getSubtype().add(type);
permanent.getSubtype(game).clear();
for (String type : sourceCard.getSubtype(game)) {
permanent.getSubtype(game).add(type);
}
permanent.getSupertype().clear();
for (String type : sourceCard.getSupertype()) {

View file

@ -756,6 +756,17 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
return cardAttribute.getColor();
}
}
return super.getColor(game); //To change body of generated methods, choose Tools | Templates.
return super.getColor(game);
}
@Override
public List<String> getSubtype(Game game) {
if (game != null) {
CardAttribute cardAttribute = game.getState().getCardAttribute(getId());
if (cardAttribute != null) {
return cardAttribute.getSubtype();
}
}
return super.getSubtype(game);
}
}

View file

@ -139,7 +139,7 @@ public class CardInfo {
this.white = card.getColor(null).isWhite();
this.setTypes(card.getCardType());
this.setSubtypes(card.getSubtype());
this.setSubtypes(card.getSubtype(null));
this.setSuperTypes(card.getSupertype());
this.setManaCosts(card.getManaCost().getSymbols());

View file

@ -47,7 +47,7 @@ public class ChosenSubtypePredicate implements Predicate<MageObject> {
@Override
public boolean apply(MageObject input, Game game) {
String subtype = (String) game.getState().getValue(cardID + "_type");
return input.hasSubtype(subtype);
return input.hasSubtype(subtype, game);
}
@Override

View file

@ -45,7 +45,7 @@ public class SubtypePredicate implements Predicate<MageObject> {
@Override
public boolean apply(MageObject input, Game game) {
return input.hasSubtype(subtype);
return input.hasSubtype(subtype, game);
}
@Override

View file

@ -66,7 +66,7 @@ public class CardTextPredicate implements Predicate<Card> {
}
}
for (String subType : input.getSubtype()) {
for (String subType : input.getSubtype(game)) {
if (subType.equalsIgnoreCase(token)) {
found = true;
break;

View file

@ -20,7 +20,7 @@ public class EquippedPredicate implements Predicate<Permanent> {
public boolean apply(Permanent input, Game game) {
for (UUID attachmentId : input.getAttachments()) {
Permanent attachment = game.getPermanent(attachmentId);
if (attachment != null && attachment.getSubtype().contains("Equipment")) {
if (attachment != null && attachment.getSubtype(game).contains("Equipment")) {
return true;
}
}

View file

@ -6,6 +6,8 @@
package mage.game;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import mage.ObjectColor;
import mage.cards.Card;
@ -17,13 +19,16 @@ import mage.cards.Card;
public class CardAttribute implements Serializable {
protected ObjectColor color;
protected List<String> subtype;
public CardAttribute(Card card) {
color = card.getColor(null).copy();
subtype = new ArrayList<String>(card.getSubtype(null));
}
public CardAttribute(CardAttribute cardAttribute) {
this.color = cardAttribute.color;
this.subtype = cardAttribute.subtype;
}
public CardAttribute copy() {
@ -34,4 +39,8 @@ public class CardAttribute implements Serializable {
return color;
}
public List<String> getSubtype() {
return subtype;
}
}

View file

@ -1848,9 +1848,9 @@ public abstract class GameImpl implements Game, Serializable {
Permanent attachment = getPermanent(attachmentId);
if (attachment != null
&& (attachment.getCardType().contains(CardType.CREATURE)
|| !(attachment.getSubtype().contains("Aura")
|| attachment.getSubtype().contains("Equipment")
|| attachment.getSubtype().contains("Fortification")))) {
|| !(attachment.getSubtype(this).contains("Aura")
|| attachment.getSubtype(this).contains("Equipment")
|| attachment.getSubtype(this).contains("Fortification")))) {
if (perm.removeAttachment(attachment.getId(), this)) {
somethingHappened = true;
break;
@ -1875,7 +1875,7 @@ public abstract class GameImpl implements Game, Serializable {
// This is called the "planeswalker uniqueness rule."
if (planeswalkers.size() > 1) { //don't bother checking if less than 2 planeswalkers in play
for (Permanent planeswalker : planeswalkers) {
for (String planeswalkertype : planeswalker.getSubtype()) {
for (String planeswalkertype : planeswalker.getSubtype(this)) {
FilterPlaneswalkerPermanent filterPlaneswalker = new FilterPlaneswalkerPermanent();
filterPlaneswalker.add(new SubtypePredicate(planeswalkertype));
filterPlaneswalker.add(new ControllerIdPredicate(planeswalker.getControllerId()));

View file

@ -112,18 +112,18 @@ public class Commander implements CommandObject {
}
@Override
public List<String> getSubtype() {
return card.getSubtype();
public List<String> getSubtype(Game game) {
return card.getSubtype(game);
}
@Override
public boolean hasSubtype(String subtype) {
return card.hasSubtype(subtype);
public boolean hasSubtype(String subtype, Game game) {
return card.hasSubtype(subtype, game);
}
@Override
public List<String> getSupertype() {
return card.getSubtype();
return card.getSupertype();
}
@Override

View file

@ -125,12 +125,12 @@ public class Emblem implements CommandObject {
}
@Override
public List<String> getSubtype() {
public List<String> getSubtype(Game game) {
return emptyList;
}
@Override
public boolean hasSubtype(String subtype) {
public boolean hasSubtype(String subtype, Game game) {
return false;
}

View file

@ -63,7 +63,7 @@ public class PermanentCard extends PermanentImpl {
private void init(Card card, Game game) {
power = card.getPower().copy();
toughness = card.getToughness().copy();
copyFromCard(card);
copyFromCard(card, game);
// if temporary added abilities to the spell/card exist, you need to add it to the permanent derived from that card
Abilities<Ability> otherAbilities = game.getState().getAllOtherAbilities(card.getId());
if (otherAbilities != null) {
@ -95,13 +95,13 @@ public class PermanentCard extends PermanentImpl {
public void reset(Game game) {
// when the permanent is reset, copy all original values from the card
// must copy card each reset so that the original values don't get modified
copyFromCard(card);
copyFromCard(card, game);
power.resetToBaseValue();
toughness.resetToBaseValue();
super.reset(game);
}
protected void copyFromCard(final Card card) {
protected void copyFromCard(final Card card, final Game game) {
this.name = card.getName();
this.abilities.clear();
if (this.faceDown) {
@ -123,7 +123,7 @@ public class PermanentCard extends PermanentImpl {
this.maxLevelCounters = ((PermanentCard) card).maxLevelCounters;
}
this.subtype.clear();
this.subtype.addAll(card.getSubtype());
this.subtype.addAll(card.getSubtype(game));
this.supertype.clear();
this.supertype.addAll(card.getSupertype());
this.expansionSetCode = card.getExpansionSetCode();

View file

@ -992,7 +992,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
@Override
public boolean cantBeEnchantedBy(MageObject source, Game game) {
for (ProtectionAbility ability : abilities.getProtectionAbilities()) {
if (!(source.getSubtype().contains("Aura")
if (!(source.getSubtype(game).contains("Aura")
&& !ability.removesAuras())
&& !source.getId().equals(ability.getAuraIdNotToBeRemoved())
&& !ability.canTarget(source, game)) {

View file

@ -85,7 +85,7 @@ public class PermanentToken extends PermanentImpl {
this.power.modifyBaseValue(token.getPower().getBaseValueModified());
this.toughness.modifyBaseValue(token.getToughness().getBaseValueModified());
this.supertype = token.getSupertype();
this.subtype = token.getSubtype();
this.subtype = token.getSubtype(game);
}
@Override

View file

@ -223,7 +223,7 @@ public class Spell extends StackObjImpl implements Card {
}
counter(null, game);
return false;
} else if (this.getCardType().contains(CardType.ENCHANTMENT) && this.getSubtype().contains("Aura")) {
} else if (this.getCardType().contains(CardType.ENCHANTMENT) && this.getSubtype(game).contains("Aura")) {
if (ability.getTargets().stillLegal(ability, game)) {
updateOptionalCosts(0);
boolean bestow = ability instanceof BestowAbility;
@ -231,7 +231,7 @@ public class Spell extends StackObjImpl implements Card {
// Must be removed first time, after that will be removed by continous effect
// Otherwise effects like evolve trigger from creature comes into play event
card.getCardType().remove(CardType.CREATURE);
card.getSubtype().add("Aura");
card.getSubtype(game).add("Aura");
}
if (controller.moveCards(card, Zone.BATTLEFIELD, ability, game, false, faceDown, false, null)) {
if (bestow) {
@ -241,7 +241,7 @@ public class Spell extends StackObjImpl implements Card {
if (permanent != null && permanent instanceof PermanentCard) {
permanent.setSpellAbility(ability); // otherwise spell ability without bestow will be set
((PermanentCard) permanent).getCard().getCardType().add(CardType.CREATURE);
((PermanentCard) permanent).getCard().getSubtype().remove("Aura");
((PermanentCard) permanent).getCard().getSubtype(game).remove("Aura");
}
}
return ability.resolve(game);
@ -431,27 +431,27 @@ public class Spell extends StackObjImpl implements Card {
}
@Override
public List<String> getSubtype() {
public List<String> getSubtype(Game game) {
if (this.getSpellAbility() instanceof BestowAbility) {
List<String> subtypes = new ArrayList<>();
subtypes.addAll(card.getSubtype());
subtypes.addAll(card.getSubtype(game));
subtypes.add("Aura");
return subtypes;
}
return card.getSubtype();
return card.getSubtype(game);
}
@Override
public boolean hasSubtype(String subtype) {
public boolean hasSubtype(String subtype, Game game) {
if (this.getSpellAbility() instanceof BestowAbility) { // workaround for Bestow (don't like it)
List<String> subtypes = new ArrayList<>();
subtypes.addAll(card.getSubtype());
subtypes.addAll(card.getSubtype(game));
subtypes.add("Aura");
if (subtypes.contains(subtype)) {
return true;
}
}
return card.hasSubtype(subtype);
return card.hasSubtype(subtype, game);
}
@Override

View file

@ -162,12 +162,12 @@ public class StackAbility extends StackObjImpl implements Ability {
}
@Override
public List<String> getSubtype() {
public List<String> getSubtype(Game game) {
return emptyString;
}
@Override
public boolean hasSubtype(String subtype) {
public boolean hasSubtype(String subtype, Game game) {
return false;
}

View file

@ -118,7 +118,7 @@ public class CardUtil {
* @param card2
* @return
*/
public static boolean shareSubtypes(Card card1, Card card2) {
public static boolean shareSubtypes(Card card1, Card card2, Game game) {
if (card1 == null || card2 == null) {
throw new IllegalArgumentException("Params can't be null");
@ -126,14 +126,14 @@ public class CardUtil {
if (card1.getCardType().contains(CardType.CREATURE) && card2.getCardType().contains(CardType.CREATURE)) {
if (card1.getAbilities().contains(ChangelingAbility.getInstance())
|| card1.getSubtype().contains(ChangelingAbility.ALL_CREATURE_TYPE)
|| card1.getSubtype(game).contains(ChangelingAbility.ALL_CREATURE_TYPE)
|| card2.getAbilities().contains(ChangelingAbility.getInstance())
|| card2.getSubtype().contains(ChangelingAbility.ALL_CREATURE_TYPE)) {
|| card2.getSubtype(game).contains(ChangelingAbility.ALL_CREATURE_TYPE)) {
return true;
}
}
for (String subtype : card1.getSubtype()) {
if (card2.getSubtype().contains(subtype)) {
for (String subtype : card1.getSubtype(game)) {
if (card2.getSubtype(game).contains(subtype)) {
return true;
}
}

View file

@ -23,16 +23,16 @@ public class AddSubtypeApplier extends ApplyToPermanent {
@Override
public Boolean apply(Game game, Permanent permanent) {
if (!permanent.getSubtype().contains(subtype)) {
permanent.getSubtype().add(subtype);
if (!permanent.getSubtype(game).contains(subtype)) {
permanent.getSubtype(game).add(subtype);
}
return true;
}
@Override
public Boolean apply(Game game, MageObject mageObject) {
if (!mageObject.getSubtype().contains(subtype)) {
mageObject.getSubtype().add(subtype);
if (!mageObject.getSubtype(game).contains(subtype)) {
mageObject.getSubtype(game).add(subtype);
}
return true;
}

View file

@ -96,9 +96,9 @@ public class CopyTokenFunction implements Function<Token, Card> {
for (CardType type : sourceObj.getCardType()) {
target.getCardType().add(type);
}
target.getSubtype().clear();
for (String type : sourceObj.getSubtype()) {
target.getSubtype().add(type);
target.getSubtype(null).clear();
for (String type : sourceObj.getSubtype(null)) {
target.getSubtype(null).add(type);
}
target.getSupertype().clear();
for (String type : sourceObj.getSupertype()) {

View file

@ -77,14 +77,14 @@ public class ProwlWatcher extends Watcher {
if (dEvent.isCombatDamage()) {
Permanent creature = game.getPermanent(dEvent.getSourceId());
if (creature != null && !allSubtypes.contains(creature.getControllerId())) {
if (creature.getAbilities().containsKey(ChangelingAbility.getInstance().getId()) || creature.getSubtype().contains(ChangelingAbility.ALL_CREATURE_TYPE)) {
if (creature.getAbilities().containsKey(ChangelingAbility.getInstance().getId()) || creature.getSubtype(game).contains(ChangelingAbility.ALL_CREATURE_TYPE)) {
allSubtypes.add(creature.getControllerId());
} else {
Set<String> subtypes = damagingSubtypes.get(creature.getControllerId());
if (subtypes == null) {
subtypes = new LinkedHashSet<>();
}
subtypes.addAll(creature.getSubtype());
subtypes.addAll(creature.getSubtype(game));
damagingSubtypes.put(creature.getControllerId(), subtypes);
}
}