Refactoring subtypes to make Maskwood Nexus work (ready for review) (#7432)

* removed and renamed SubTypeList

* updated subtype test

* refactored Changeling to be an ability that actually does something

* moved isAllCreatureTypes into SubTypes class

* renamed copyTo method to copyFrom

* added removeAllCreatureTypes where usable

* replaced some subtype methods

* replaced some more subtype methods

* replaced subtype mass add/remove methods

* updated more subtype methods

* fixed some errors

* made common shared creature type predicate

* refactored another card involving subtypes

* Added usage of object attribute in subTypes's write operations;

* Refactor: use same param styles in subtype methods

* Refactor: simplified usage of copy appliers;

* Refactor: fixed code usage in CopyApplier

Co-authored-by: Oleg Agafonov <jaydi85@gmail.com>
This commit is contained in:
Evan Kranzler 2021-01-26 08:52:35 -05:00 committed by GitHub
parent 6f42b90305
commit dacf30f4b9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
259 changed files with 1857 additions and 1922 deletions

View file

@ -13,10 +13,11 @@ import mage.constants.SubTypeSet;
import mage.constants.SuperType;
import mage.game.Game;
import mage.game.events.ZoneChangeEvent;
import mage.util.SubTypeList;
import mage.util.SubTypes;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
@ -34,7 +35,20 @@ public interface MageObject extends MageItem, Serializable {
ArrayList<CardType> getCardType();
SubTypeList getSubtype(Game game);
/**
* Return original object's subtypes
*
* @return
*/
SubTypes getSubtype();
/**
* Return full subtypes list (from object, from effects)
*
* @param game
* @return
*/
SubTypes getSubtype(Game game);
boolean hasSubtype(SubType subtype, Game game);
@ -50,6 +64,8 @@ public interface MageObject extends MageItem, Serializable {
boolean hasAbility(Ability ability, Game game);
ObjectColor getColor();
ObjectColor getColor(Game game);
ObjectColor getFrameColor(Game game);
@ -91,7 +107,7 @@ public interface MageObject extends MageItem, Serializable {
default boolean isHistoric() {
return getCardType().contains(CardType.ARTIFACT)
|| getSuperType().contains(SuperType.LEGENDARY)
|| hasSubtype(SubType.SAGA, null);
|| getSubtype().contains(SubType.SAGA);
}
default boolean isCreature() {
@ -164,23 +180,104 @@ public interface MageObject extends MageItem, Serializable {
getCardType().add(cardType);
}
/**
* Add subtype temporary, for continuous effects only
*
* @param game
* @param subTypes
*/
default void addSubType(Game game, Collection<SubType> subTypes) {
for (SubType subType : subTypes) {
addSubType(game, subType);
}
}
/**
* Add subtype permanently, for one shot effects and tokens setup
*
* @param subTypes
*/
default void addSubType(SubType... subTypes) {
for (SubType subType : subTypes) {
if (subType.canGain(this)
&& !getSubtype().contains(subType)) {
getSubtype().add(subType);
}
}
}
/**
* Add subtype temporary, for continuous effects only
*
* @param game
* @param subTypes
*/
default void addSubType(Game game, SubType... subTypes) {
for (SubType subType : subTypes) {
if (subType.canGain(this)
&& !hasSubtype(subType, game)) {
getSubtype(game).add(subType);
game.getState().getCreateMageObjectAttribute(this, game).getSubtype().add(subType);
}
}
}
default void copySubTypesFrom(Game game, MageObject mageObject) {
copySubTypesFrom(game, mageObject, null);
}
default void copySubTypesFrom(Game game, MageObject mageObject, SubTypeSet subTypeSet) {
if (subTypeSet == SubTypeSet.CreatureType || subTypeSet == null) {
this.setIsAllCreatureTypes(game, mageObject.isAllCreatureTypes(game));
}
for (SubType subType : mageObject.getSubtype(game)) {
if (subType.getSubTypeSet() == subTypeSet || subTypeSet == null) {
this.addSubType(game, subType);
}
}
}
default void removeAllSubTypes(Game game) {
getSubtype(game).clear();
setIsAllCreatureTypes(false);
removeAllSubTypes(game, null);
}
default void removeAllCreatureTypes(Game game) {
getSubtype(game).removeAll(SubType.getCreatureTypes());
default void removeAllSubTypes(Game game, SubTypeSet subTypeSet) {
if (subTypeSet == null) {
setIsAllCreatureTypes(game, false);
game.getState().getCreateMageObjectAttribute(this, game).getSubtype().clear();
} else if (subTypeSet == SubTypeSet.CreatureType) {
removeAllCreatureTypes(game);
} else if (subTypeSet == SubTypeSet.NonBasicLandType) {
game.getState().getCreateMageObjectAttribute(this, game).getSubtype().removeAll(SubType.getLandTypes());
} else {
game.getState().getCreateMageObjectAttribute(this, game).getSubtype().removeAll(SubType.getBySubTypeSet(subTypeSet));
}
}
default void retainAllEnchantmentSubTypes(Game game) {
setIsAllCreatureTypes(game, false);
game.getState().getCreateMageObjectAttribute(this, game).getSubtype().retainAll(SubType.getEnchantmentTypes());
}
/**
* Remove object's own creature types forever (for copy effects usage)
*/
default void removeAllCreatureTypes() {
setIsAllCreatureTypes(false);
getSubtype().removeAll(SubType.getCreatureTypes());
}
/**
* Remove object attribute's creature types temporary (for continuous effects usage)
*
* @param game
*/
default void removeAllCreatureTypes(Game game) {
setIsAllCreatureTypes(game, false);
game.getState().getCreateMageObjectAttribute(this, game).getSubtype().removeAll(SubType.getCreatureTypes());
}
default void removeSubType(Game game, SubType subType) {
game.getState().getCreateMageObjectAttribute(this, game).getSubtype().remove(subType);
}
/**
@ -209,19 +306,19 @@ public interface MageObject extends MageItem, Serializable {
return false;
}
default boolean shareCreatureTypes(Card otherCard, Game game) {
default boolean shareCreatureTypes(Game game, MageObject otherCard) {
if (!isCreature() && !isTribal()) {
return false;
}
if (!otherCard.isCreature() && !otherCard.isTribal()) {
return false;
}
boolean isAllA = this.isAllCreatureTypes();
boolean isAllA = this.isAllCreatureTypes(game);
boolean isAnyA = isAllA || this.getSubtype(game)
.stream()
.map(SubType::getSubTypeSet)
.anyMatch(SubTypeSet.CreatureType::equals);
boolean isAllB = otherCard.isAllCreatureTypes();
boolean isAllB = otherCard.isAllCreatureTypes(game);
boolean isAnyB = isAllB || otherCard
.getSubtype(game)
.stream()
@ -241,10 +338,18 @@ public interface MageObject extends MageItem, Serializable {
.anyMatch(subType -> otherCard.hasSubtype(subType, game)));
}
boolean isAllCreatureTypes();
boolean isAllCreatureTypes(Game game);
void setIsAllCreatureTypes(boolean value);
/**
* Change all creature type mark temporary, for continuous effects only
*
* @param game
* @param value
*/
void setIsAllCreatureTypes(Game game, boolean value);
default void addCardTypes(ArrayList<CardType> cardType) {
getCardType().addAll(cardType);
}

View file

@ -1,6 +1,5 @@
package mage;
import java.util.*;
import mage.abilities.Abilities;
import mage.abilities.AbilitiesImpl;
import mage.abilities.Ability;
@ -20,7 +19,9 @@ import mage.game.Game;
import mage.game.MageObjectAttribute;
import mage.game.events.ZoneChangeEvent;
import mage.util.GameLog;
import mage.util.SubTypeList;
import mage.util.SubTypes;
import java.util.*;
public abstract class MageObjectImpl implements MageObject {
@ -32,8 +33,7 @@ public abstract class MageObjectImpl implements MageObject {
protected ObjectColor frameColor;
protected FrameStyle frameStyle;
protected ArrayList<CardType> cardType = new ArrayList<>();
protected SubTypeList subtype = new SubTypeList();
protected boolean isAllCreatureTypes;
protected SubTypes subtype = new SubTypes();
protected Set<SuperType> supertype = EnumSet.noneOf(SuperType.class);
protected Abilities<Ability> abilities;
protected String text;
@ -71,8 +71,7 @@ public abstract class MageObjectImpl implements MageObject {
toughness = object.toughness.copy();
abilities = object.abilities.copy();
this.cardType.addAll(object.cardType);
this.subtype.addAll(object.subtype);
isAllCreatureTypes = object.isAllCreatureTypes;
this.subtype.copyFrom(object.subtype);
supertype.addAll(object.supertype);
this.copy = object.copy;
this.copyFrom = (object.copyFrom != null ? object.copyFrom.copy() : null);
@ -116,13 +115,18 @@ public abstract class MageObjectImpl implements MageObject {
}
@Override
public SubTypeList getSubtype(Game game) {
public SubTypes getSubtype() {
return subtype;
}
@Override
public SubTypes getSubtype(Game game) {
if (game != null) {
MageObjectAttribute mageObjectAttribute = game.getState().getMageObjectAttribute(getId());
if (mageObjectAttribute != null) {
return mageObjectAttribute.getSubtype();
}
}
}
return subtype;
}
@ -174,6 +178,11 @@ public abstract class MageObjectImpl implements MageObject {
}
}
@Override
public ObjectColor getColor() {
return color;
}
@Override
public ObjectColor getColor(Game game) {
if (game != null) {
@ -181,7 +190,7 @@ public abstract class MageObjectImpl implements MageObject {
if (mageObjectAttribute != null) {
return mageObjectAttribute.getColor();
}
}
}
return color;
}
@ -240,7 +249,7 @@ public abstract class MageObjectImpl implements MageObject {
if (value == null) {
return false;
}
if (value.getSubTypeSet() == SubTypeSet.CreatureType && isAllCreatureTypes()) {
if (value.getSubTypeSet() == SubTypeSet.CreatureType && isAllCreatureTypes(game)) {
return true;
}
return getSubtype(game).contains(value);
@ -278,13 +287,18 @@ public abstract class MageObjectImpl implements MageObject {
}
@Override
public boolean isAllCreatureTypes() {
return isAllCreatureTypes;
public boolean isAllCreatureTypes(Game game) {
return this.getSubtype(game).isAllCreatureTypes();
}
@Override
public void setIsAllCreatureTypes(boolean value) {
isAllCreatureTypes = value && (this.isTribal() || this.isCreature());
this.getSubtype().setIsAllCreatureTypes(value && (this.isTribal() || this.isCreature()));
}
@Override
public void setIsAllCreatureTypes(Game game, boolean value) {
this.getSubtype(game).setIsAllCreatureTypes(value && (this.isTribal() || this.isCreature()));
}
@Override

View file

@ -96,7 +96,7 @@ class KinshipBaseEffect extends OneShotEffect {
if (card != null) {
Cards cards = new CardsImpl(card);
controller.lookAtCards(sourcePermanent.getName(), cards, game);
if (sourcePermanent.shareCreatureTypes(card, game)) {
if (sourcePermanent.shareCreatureTypes(game, card)) {
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

@ -7,7 +7,9 @@ import mage.constants.SubType;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.util.SubTypeList;
import java.util.ArrayList;
import java.util.List;
/**
* Describes condition when equipped permanent has subType
@ -16,35 +18,31 @@ import mage.util.SubTypeList;
*/
public class EquippedHasSubtypeCondition implements Condition {
private SubTypeList subTypes; // scope = Any
private final List<SubType> subTypes = new ArrayList<>(); // scope = Any
public EquippedHasSubtypeCondition(SubTypeList subType) {
this.subTypes = subType;
}
public EquippedHasSubtypeCondition(SubType subType){
subTypes = new SubTypeList();
subTypes.add(subType);
public EquippedHasSubtypeCondition(SubType... subTypes) {
for (SubType subType : subTypes) {
this.subTypes.add(subType);
}
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getBattlefield().getPermanent(source.getSourceId());
if (permanent != null && permanent.getAttachedTo() != null) {
Permanent attachedTo = game.getBattlefield().getPermanent(permanent.getAttachedTo());
if (attachedTo == null) {
attachedTo = (Permanent) game.getLastKnownInformation(permanent.getAttachedTo(), Zone.BATTLEFIELD);
}
if (attachedTo != null) {
for (SubType s : subTypes) {
if (attachedTo.hasSubtype(s, game)) {
return true;
}
}
if (permanent == null || permanent.getAttachedTo() == null) {
return false;
}
Permanent attachedTo = game.getBattlefield().getPermanent(permanent.getAttachedTo());
if (attachedTo == null) {
attachedTo = (Permanent) game.getLastKnownInformation(permanent.getAttachedTo(), Zone.BATTLEFIELD);
}
if (attachedTo == null) {
return false;
}
for (SubType s : subTypes) {
if (attachedTo.hasSubtype(s, game)) {
return true;
}
}
return false;

View file

@ -3,7 +3,6 @@ package mage.abilities.condition.common;
import mage.abilities.Ability;
import mage.abilities.condition.Condition;
import mage.cards.Card;
import mage.constants.SubType;
import mage.game.Game;
import mage.watchers.common.ProwlWatcher;
@ -20,13 +19,8 @@ public enum ProwlCondition implements Condition {
public boolean apply(Game game, Ability source) {
ProwlWatcher watcher = game.getState().getWatcher(ProwlWatcher.class);
Card card = game.getCard(source.getSourceId());
if (watcher != null && card != null) {
for (SubType subtype : card.getSubtype(game)) {
if (watcher.hasSubtypeMadeCombatDamage(source.getControllerId(), subtype)) {
return true;
}
}
}
return false;
return watcher != null
&& card != null
&& watcher.hasSubtypeMadeCombatDamage(source.getControllerId(), card, game);
}
}

View file

@ -5,33 +5,31 @@ import mage.abilities.condition.Condition;
import mage.constants.SubType;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.util.SubTypeList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
*
* @author Quercitron
*/
public class SourceHasSubtypeCondition implements Condition {
private final SubTypeList subtypes;
private final List<SubType> subtypes = new ArrayList<>();
public SourceHasSubtypeCondition(SubTypeList subtypes) {
this.subtypes = subtypes;
}
public SourceHasSubtypeCondition(SubType subType){
subtypes = new SubTypeList();
subtypes.add(subType);
public SourceHasSubtypeCondition(SubType... subTypes) {
this.subtypes.addAll(Arrays.asList(subTypes));
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent != null) {
for (SubType subtype : subtypes) {
if (permanent.hasSubtype(subtype, game)) {
return true;
}
if (permanent == null) {
return false;
}
for (SubType subtype : subtypes) {
if (permanent.hasSubtype(subtype, game)) {
return true;
}
}
return false;

View file

@ -1,6 +1,5 @@
package mage.abilities.dynamicvalue.common;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.Effect;
@ -34,10 +33,10 @@ public enum GreatestSharedCreatureTypeCount implements DynamicValue {
int changelings = permanentList
.stream()
.filter(Objects::nonNull)
.filter(MageObject::isAllCreatureTypes)
.filter(permanent1 -> permanent1.isAllCreatureTypes(game))
.mapToInt(x -> 1)
.sum();
permanentList.removeIf(MageObject::isAllCreatureTypes);
permanentList.removeIf(permanent1 -> permanent1.isAllCreatureTypes(game));
Map<SubType, Integer> typeMap = new HashMap<>();
permanentList
.stream()

View file

@ -8,13 +8,14 @@ package mage.abilities.effects.common;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.effects.ReplacementEffectImpl;
import mage.cards.Card;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.counters.CounterType;
import mage.filter.common.FilterCreatureCard;
import mage.filter.predicate.Predicate;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.CardIdPredicate;
import mage.game.Game;
@ -24,9 +25,6 @@ import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetCardInHand;
import java.util.ArrayList;
import java.util.List;
/**
* Effect for the AmplifyAbility
* <p>
@ -74,6 +72,19 @@ public class AmplifyEffect extends ReplacementEffectImpl {
}
}
private static class AmplifyPredicate implements Predicate<Card> {
private final Card card;
private AmplifyPredicate(Card card) {
this.card = card;
}
@Override
public boolean apply(Card input, Game game) {
return input.shareCreatureTypes(game, card);
}
}
public AmplifyEffect(AmplifyFactor amplifyFactor) {
super(Duration.EndOfGame, Outcome.BoostCreature);
this.amplifyFactor = amplifyFactor;
@ -98,36 +109,31 @@ public class AmplifyEffect extends ReplacementEffectImpl {
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
Permanent sourceCreature = ((EntersTheBattlefieldEvent) event).getTarget();
Player controller = game.getPlayer(source.getControllerId());
if (controller != null && sourceCreature != null) {
FilterCreatureCard filter = new FilterCreatureCard("creatures cards to reveal");
List<SubType.SubTypePredicate> filterSubtypes = new ArrayList<>();
for (SubType subtype : sourceCreature.getSubtype(game)) {
filterSubtypes.add(subtype.getPredicate());
}
if (filterSubtypes.size() > 1) {
filter.add(Predicates.or(filterSubtypes));
} else if (filterSubtypes.size() == 1) {
filter.add(filterSubtypes.get(0));
}
if (controller == null || sourceCreature == null) {
return false;
}
FilterCreatureCard filter = new FilterCreatureCard("creatures cards to reveal");
filter.add(new AmplifyPredicate(sourceCreature));
// You cant reveal this card or any other cards that are entering the battlefield at the same time as this card.
filter.add(Predicates.not(new CardIdPredicate(source.getSourceId())));
for (Permanent enteringPermanent : game.getPermanentsEntering().values()) {
filter.add(Predicates.not(new CardIdPredicate(enteringPermanent.getId())));
}
// You cant reveal this card or any other cards that are entering the battlefield at the same time as this card.
filter.add(Predicates.not(new CardIdPredicate(source.getSourceId())));
for (Permanent enteringPermanent : game.getPermanentsEntering().values()) {
filter.add(Predicates.not(new CardIdPredicate(enteringPermanent.getId())));
}
if (controller.getHand().count(filter, source.getSourceId(), source.getControllerId(), game) > 0) {
if (controller.chooseUse(outcome, "Reveal cards to Amplify?", source, game)) {
TargetCardInHand target = new TargetCardInHand(0, Integer.MAX_VALUE, filter);
if (controller.chooseTarget(outcome, target, source, game) && !target.getTargets().isEmpty()) {
Cards cards = new CardsImpl();
cards.addAll(target.getTargets());
int amountCounters = cards.size() * amplifyFactor.getFactor();
sourceCreature.addCounters(CounterType.P1P1.createInstance(amountCounters), source, game);
controller.revealCards(sourceCreature.getIdName(), cards, game);
}
}
}
if (controller.getHand().count(filter, source.getSourceId(), source.getControllerId(), game) <= 0) {
return false;
}
if (!controller.chooseUse(outcome, "Reveal cards to Amplify?", source, game)) {
return false;
}
TargetCardInHand target = new TargetCardInHand(0, Integer.MAX_VALUE, filter);
if (controller.chooseTarget(outcome, target, source, game) && !target.getTargets().isEmpty()) {
Cards cards = new CardsImpl();
cards.addAll(target.getTargets());
int amountCounters = cards.size() * amplifyFactor.getFactor();
sourceCreature.addCounters(CounterType.P1P1.createInstance(amountCounters), source, game);
controller.revealCards(sourceCreature.getIdName(), cards, game);
}
return false;
}

View file

@ -10,7 +10,7 @@ import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.game.permanent.PermanentCard;
import mage.game.permanent.PermanentToken;
import mage.util.functions.ApplyToPermanent;
import mage.util.functions.CopyApplier;
import java.util.UUID;
@ -25,7 +25,7 @@ public class CopyEffect extends ContinuousEffectImpl {
protected MageObject copyFromObject;
protected UUID copyToObjectId;
protected ApplyToPermanent applier;
protected CopyApplier applier;
public CopyEffect(MageObject copyFromObject, UUID copyToObjectId) {
this(Duration.Custom, copyFromObject, copyToObjectId);
@ -105,8 +105,7 @@ public class CopyEffect extends ContinuousEffectImpl {
}
permanent.removeAllSubTypes(game);
permanent.getSubtype(game).addAll(copyFromObject.getSubtype(game));
permanent.setIsAllCreatureTypes(copyFromObject.isAllCreatureTypes());
permanent.copySubTypesFrom(game, copyFromObject);
permanent.getSuperType().clear();
for (SuperType type : copyFromObject.getSuperType()) {
@ -165,11 +164,11 @@ public class CopyEffect extends ContinuousEffectImpl {
return copyToObjectId;
}
public ApplyToPermanent getApplier() {
public CopyApplier getApplier() {
return applier;
}
public void setApplier(ApplyToPermanent applier) {
public void setApplier(CopyApplier applier) {
this.applier = applier;
}

View file

@ -16,8 +16,8 @@ import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.Target;
import mage.target.TargetPermanent;
import mage.util.functions.ApplyToPermanent;
import mage.util.functions.EmptyApplyToPermanent;
import mage.util.functions.CopyApplier;
import mage.util.functions.EmptyCopyApplier;
import java.util.UUID;
@ -27,7 +27,7 @@ import java.util.UUID;
public class CopyPermanentEffect extends OneShotEffect {
private final FilterPermanent filter;
private final ApplyToPermanent applier;
private final CopyApplier applier;
private final boolean useTargetOfAbility;
private Permanent bluePrintPermanent;
private Duration duration = Duration.Custom;
@ -36,19 +36,19 @@ public class CopyPermanentEffect extends OneShotEffect {
this(StaticFilters.FILTER_PERMANENT_CREATURE);
}
public CopyPermanentEffect(ApplyToPermanent applier) {
public CopyPermanentEffect(CopyApplier applier) {
this(StaticFilters.FILTER_PERMANENT_CREATURE, applier);
}
public CopyPermanentEffect(FilterPermanent filter) {
this(filter, new EmptyApplyToPermanent());
this(filter, new EmptyCopyApplier());
}
public CopyPermanentEffect(FilterPermanent filter, ApplyToPermanent applier) {
public CopyPermanentEffect(FilterPermanent filter, CopyApplier applier) {
this(filter, applier, false);
}
public CopyPermanentEffect(FilterPermanent filter, ApplyToPermanent applier, boolean useTarget) {
public CopyPermanentEffect(FilterPermanent filter, CopyApplier applier, boolean useTarget) {
super(Outcome.Copy);
this.applier = applier;
this.filter = filter;

View file

@ -32,10 +32,7 @@ public class CopyTokenEffect extends ContinuousEffectImpl {
permanent.addCardType(type);
}
permanent.removeAllSubTypes(game);
for (SubType type : token.getSubtype(game)) {
permanent.addSubType(game, type);
}
permanent.setIsAllCreatureTypes(token.isAllCreatureTypes());
permanent.copySubTypesFrom(game, token);
permanent.getSuperType().clear();
for (SuperType type : token.getSuperType()) {
permanent.addSuperType(type);

View file

@ -17,8 +17,8 @@ import mage.game.permanent.Permanent;
import mage.game.permanent.token.EmptyToken;
import mage.target.targetpointer.FixedTarget;
import mage.util.CardUtil;
import mage.util.functions.ApplyToPermanent;
import mage.util.functions.EmptyApplyToPermanent;
import mage.util.functions.CopyApplier;
import mage.util.functions.EmptyCopyApplier;
import java.util.ArrayList;
import java.util.Arrays;
@ -141,7 +141,7 @@ public class CreateTokenCopyTargetEffect extends OneShotEffect {
// can target card or permanent
Card copyFrom;
ApplyToPermanent applier = new EmptyApplyToPermanent();
CopyApplier applier = new EmptyCopyApplier();
if (permanent != null) {
// handle copies of copies
Permanent copyFromPermanent = permanent;
@ -169,6 +169,7 @@ public class CreateTokenCopyTargetEffect extends OneShotEffect {
return false;
}
// create token and modify all attributes permanently (without game usage)
EmptyToken token = new EmptyToken();
CardUtil.copyTo(token).from(copyFrom, game); // needed so that entersBattlefied triggered abilities see the attributes (e.g. Master Biomancer)
applier.apply(game, token, source, targetId);
@ -200,14 +201,14 @@ public class CreateTokenCopyTargetEffect extends OneShotEffect {
token.getToughness().modifyBaseValue(tokenToughness);
}
if (onlySubType != null) {
token.removeAllCreatureTypes(game);
token.addSubType(game, onlySubType);
token.removeAllCreatureTypes();
token.addSubType(onlySubType);
}
if (additionalSubType != null && !token.hasSubtype(additionalSubType, game)) {
token.addSubType(game, additionalSubType);
if (additionalSubType != null) {
token.addSubType(additionalSubType);
}
if (color != null) {
token.getColor(game).setColor(color);
token.getColor().setColor(color);
}
additionalAbilities.stream().forEach(token::addAbility);

View file

@ -15,7 +15,6 @@ import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.Target;
import mage.target.common.TargetControlledCreaturePermanent;
import mage.util.SubTypeList;
import java.util.ArrayList;
import java.util.Collections;
@ -87,12 +86,12 @@ public class DevourEffect extends ReplacementEffectImpl {
if (controller.chooseUse(Outcome.Detriment, "Devour creatures?", source, game)) {
controller.chooseTarget(Outcome.Detriment, target, source, game);
if (!target.getTargets().isEmpty()) {
List<SubTypeList> cardSubtypes = new ArrayList<>();
List<Permanent> creaturesDevoured = new ArrayList<>();
int devouredCreatures = 0;
for (UUID targetId : target.getTargets()) {
Permanent targetCreature = game.getPermanent(targetId);
if (targetCreature != null && targetCreature.sacrifice(source, game)) {
cardSubtypes.add(targetCreature.getSubtype(game));
creaturesDevoured.add(targetCreature);
devouredCreatures++;
}
}
@ -108,7 +107,7 @@ public class DevourEffect extends ReplacementEffectImpl {
amountCounters = devouredCreatures * devourFactor.getFactor();
}
creature.addCounters(CounterType.P1P1.createInstance(amountCounters), source, game);
game.getState().setValue(creature.getId().toString() + "devoured", cardSubtypes);
game.getState().setValue(creature.getId().toString() + "devoured", creaturesDevoured);
}
}
@ -124,10 +123,10 @@ public class DevourEffect extends ReplacementEffectImpl {
return sb.toString();
}
public List<SubTypeList> getSubtypes(Game game, UUID permanentId) {
public List<Permanent> getDevouredCreatures(Game game, UUID permanentId) {
Object object = game.getState().getValue(permanentId.toString() + "devoured");
if (object != null) {
return (List<SubTypeList>) object;
return (List<Permanent>) object;
}
return Collections.emptyList();
}
@ -135,7 +134,7 @@ public class DevourEffect extends ReplacementEffectImpl {
public int getDevouredCreaturesAmount(Game game, UUID permanentId) {
Object object = game.getState().getValue(permanentId.toString() + "devoured");
if (object != null) {
return ((List<SubTypeList>) object).size();
return ((List<Permanent>) object).size();
}
return 0;
}

View file

@ -42,8 +42,8 @@ public class BecomesBasicLandEnchantedEffect extends ContinuousEffectImpl {
return false;
}
// lands intrictically have the mana ability associated with their type, so added here in layer 4
permanent.getSubtype(game).removeAll(SubType.getLandTypes());
permanent.getSubtype(game).addAll(landTypes);
permanent.removeAllSubTypes(game, SubTypeSet.NonBasicLandType);
permanent.addSubType(game, landTypes);
permanent.removeAllAbilities(source.getSourceId(), game);
for (SubType landType : landTypes) {
switch (landType) {

View file

@ -117,8 +117,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(game).removeAll(SubType.getLandTypes());
land.getSubtype(game).addAll(landTypes);
land.removeAllSubTypes(game, SubTypeSet.NonBasicLandType);
land.addSubType(game, landTypes);
} else {
landTypesToAdd.clear();
for (SubType subtype : landTypes) {

View file

@ -104,10 +104,7 @@ public class BecomesCreatureAllEffect extends ContinuousEffectImpl {
if (theyAreStillType != null || loseTypes) {
permanent.removeAllCreatureTypes(game);
}
for (SubType t : token.getSubtype(game)) {
permanent.addSubType(game, t);
}
permanent.setIsAllCreatureTypes(token.isAllCreatureTypes());
permanent.copySubTypesFrom(game, token);
for (SuperType t : token.getSuperType()) {
if (!permanent.getSuperType().contains(t)) {

View file

@ -53,85 +53,78 @@ public class BecomesCreatureAttachedEffect extends ContinuousEffectImpl {
@Override
public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) {
Permanent enchantment = game.getPermanent(source.getSourceId());
if (enchantment != null) {
Permanent permanent = game.getPermanent(enchantment.getAttachedTo());
if (permanent != null) {
switch (layer) {
case TypeChangingEffects_4:
if (sublayer == SubLayer.NA) {
for (SuperType t : token.getSuperType()) {
permanent.addSuperType(t);
}
// card type
switch (loseType) {
case ALL:
case ALL_BUT_COLOR:
permanent.getCardType().clear();
break;
}
for (CardType t : token.getCardType()) {
permanent.addCardType(t);
}
// sub type
switch (loseType) {
case ALL:
case ALL_BUT_COLOR:
permanent.removeAllSubTypes(game);
break;
case ABILITIES_SUBTYPE:
permanent.removeAllCreatureTypes(game);
break;
}
for (SubType t : token.getSubtype(game)) {
permanent.addSubType(game, t);
}
}
break;
case ColorChangingEffects_5:
if (sublayer == SubLayer.NA) {
if (loseType == LoseType.ALL || loseType == LoseType.COLOR) {
permanent.getColor(game).setWhite(false);
permanent.getColor(game).setBlue(false);
permanent.getColor(game).setBlack(false);
permanent.getColor(game).setRed(false);
permanent.getColor(game).setGreen(false);
}
if (token.getColor(game).hasColor()) {
permanent.getColor(game).addColor(token.getColor(game));
}
}
break;
case AbilityAddingRemovingEffects_6:
if (sublayer == SubLayer.NA) {
switch (loseType) {
case ALL:
case ALL_BUT_COLOR:
case ABILITIES:
case ABILITIES_SUBTYPE:
permanent.removeAllAbilities(source.getSourceId(), game);
break;
}
for (Ability ability : token.getAbilities()) {
permanent.addAbility(ability, source.getSourceId(), game);
}
}
break;
case PTChangingEffects_7:
if (sublayer == SubLayer.SetPT_7b) {
permanent.getPower().setValue(token.getPower().getValue());
permanent.getToughness().setValue(token.getToughness().getValue());
}
break;
}
}
if (enchantment == null) {
return false;
}
Permanent permanent = game.getPermanent(enchantment.getAttachedTo());
if (permanent == null) {
return true;
}
return false;
switch (layer) {
case TypeChangingEffects_4:
for (SuperType t : token.getSuperType()) {
permanent.addSuperType(t);
}
// card type
switch (loseType) {
case ALL:
case ALL_BUT_COLOR:
permanent.getCardType().clear();
break;
}
for (CardType t : token.getCardType()) {
permanent.addCardType(t);
}
// sub type
switch (loseType) {
case ALL:
case ALL_BUT_COLOR:
permanent.removeAllSubTypes(game);
break;
case ABILITIES_SUBTYPE:
permanent.removeAllCreatureTypes(game);
break;
}
permanent.copySubTypesFrom(game, token);
break;
case ColorChangingEffects_5:
if (loseType == LoseType.ALL || loseType == LoseType.COLOR) {
permanent.getColor(game).setWhite(false);
permanent.getColor(game).setBlue(false);
permanent.getColor(game).setBlack(false);
permanent.getColor(game).setRed(false);
permanent.getColor(game).setGreen(false);
}
if (token.getColor(game).hasColor()) {
permanent.getColor(game).addColor(token.getColor(game));
}
break;
case AbilityAddingRemovingEffects_6:
switch (loseType) {
case ALL:
case ALL_BUT_COLOR:
case ABILITIES:
case ABILITIES_SUBTYPE:
permanent.removeAllAbilities(source.getSourceId(), game);
break;
}
for (Ability ability : token.getAbilities()) {
permanent.addAbility(ability, source.getSourceId(), game);
}
break;
case PTChangingEffects_7:
if (sublayer == SubLayer.SetPT_7b) {
permanent.getPower().setValue(token.getPower().getValue());
permanent.getToughness().setValue(token.getToughness().getValue());
}
break;
}
return true;
}
@Override

View file

@ -101,12 +101,7 @@ public class BecomesCreatureSourceEffect extends ContinuousEffectImpl implements
|| theyAreStillType == null && permanent.isLand()) {
permanent.removeAllCreatureTypes(game);
}
if (!token.getSubtype(game).isEmpty()) {
for (SubType subType : token.getSubtype(game)) {
permanent.addSubType(game, subType);
}
}
permanent.setIsAllCreatureTypes(token.isAllCreatureTypes());
permanent.copySubTypesFrom(game, token);
break;
case ColorChangingEffects_5:

View file

@ -87,9 +87,7 @@ public class BecomesCreatureTargetEffect extends ContinuousEffectImpl {
if (loseAllAbilities || removeSubtypes) {
permanent.removeAllCreatureTypes(game);
}
for (SubType t : token.getSubtype(game)) {
permanent.addSubType(game, t);
}
permanent.copySubTypesFrom(game, token);
for (SuperType t : token.getSuperType()) {
if (!permanent.getSuperType().contains(t)) {

View file

@ -5,8 +5,10 @@ import mage.abilities.effects.ContinuousEffectImpl;
import mage.constants.*;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.util.SubTypeList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
/**
@ -14,22 +16,22 @@ import java.util.UUID;
*/
public class BecomesCreatureTypeTargetEffect extends ContinuousEffectImpl {
private final SubTypeList subtypes = new SubTypeList();
private final List<SubType> subtypes = new ArrayList<>();
private final boolean loseOther; // loses other creature types
public BecomesCreatureTypeTargetEffect(Duration duration, SubType subtype) {
this(duration, new SubTypeList(subtype));
this(duration, Arrays.asList(subtype));
}
public BecomesCreatureTypeTargetEffect(Duration duration, SubType subtype, boolean loseOther) {
this(duration, new SubTypeList(subtype), loseOther);
this(duration, Arrays.asList(subtype), loseOther);
}
public BecomesCreatureTypeTargetEffect(Duration duration, SubTypeList subtypes) {
public BecomesCreatureTypeTargetEffect(Duration duration, List<SubType> subtypes) {
this(duration, subtypes, true);
}
public BecomesCreatureTypeTargetEffect(Duration duration, SubTypeList subtypes, boolean loseOther) {
public BecomesCreatureTypeTargetEffect(Duration duration, List<SubType> subtypes, boolean loseOther) {
super(duration, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Detriment);
this.subtypes.addAll(subtypes);
this.staticText = setText();

View file

@ -42,8 +42,8 @@ public class BecomesEnchantmentSourceEffect extends ContinuousEffectImpl impleme
}
permanent.getCardType().clear();
permanent.getCardType().add(CardType.ENCHANTMENT);
permanent.getSubtype(game).retainAll(SubType.getEnchantmentTypes());
permanent.setIsAllCreatureTypes(false);
permanent.retainAllEnchantmentSubTypes(game);
permanent.setIsAllCreatureTypes(game, false);
return true;
}
}

View file

@ -12,26 +12,29 @@ import mage.filter.StaticFilters;
import mage.filter.common.FilterCreaturePermanent;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.util.SubTypeList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @author LevelX2
*/
public class BecomesSubtypeAllEffect extends ContinuousEffectImpl {
private final SubTypeList subtypes = new SubTypeList();
private final List<SubType> subtypes = new ArrayList<>();
private final boolean loseOther; // loses other subtypes
private final FilterCreaturePermanent filter;
public BecomesSubtypeAllEffect(Duration duration, SubType subtype) {
this(duration, new SubTypeList(subtype));
this(duration, Arrays.asList(subtype));
}
public BecomesSubtypeAllEffect(Duration duration, SubTypeList subtypes) {
public BecomesSubtypeAllEffect(Duration duration, List<SubType> subtypes) {
this(duration, subtypes, StaticFilters.FILTER_PERMANENT_CREATURE, true);
}
public BecomesSubtypeAllEffect(Duration duration, SubTypeList subtypes, FilterCreaturePermanent filter, boolean loseOther) {
public BecomesSubtypeAllEffect(Duration duration, List<SubType> subtypes, FilterCreaturePermanent filter, boolean loseOther) {
super(duration, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Detriment);
this.subtypes.addAll(subtypes);
this.staticText = setText();

View file

@ -38,7 +38,7 @@ public class GainAllCreatureTypesAttachedEffect extends ContinuousEffectImpl {
if (permanent == null) {
return false;
}
permanent.setIsAllCreatureTypes(true);
permanent.setIsAllCreatureTypes(game, true);
return true;
}
}

View file

@ -36,7 +36,7 @@ public class GainAllCreatureTypesTargetEffect extends ContinuousEffectImpl {
for (UUID permanentId : targetPointer.getTargets(game, source)) {
Permanent target = game.getPermanent(permanentId);
if (target != null) {
target.setIsAllCreatureTypes(true);
target.setIsAllCreatureTypes(game, true);
affectedTargets++;
}
}

View file

@ -5,18 +5,21 @@ import mage.abilities.Ability;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.constants.*;
import mage.game.Game;
import mage.util.SubTypeList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @author TheElk801
*/
public class HasSubtypesSourceEffect extends ContinuousEffectImpl {
private final SubTypeList subtypes = new SubTypeList();
private final List<SubType> subtypes = new ArrayList<>();
public HasSubtypesSourceEffect(SubType... subTypes) {
super(Duration.EndOfGame, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit);
subtypes.add(subTypes);
subtypes.addAll(Arrays.asList(subTypes));
this.staticText = setText();
}

View file

@ -0,0 +1,40 @@
package mage.abilities.effects.common.continuous;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.constants.Duration;
import mage.constants.Layer;
import mage.constants.Outcome;
import mage.constants.SubLayer;
import mage.game.Game;
/**
* @author TheElk801
*/
public class IsAllCreatureTypesSourceEffect extends ContinuousEffectImpl {
public IsAllCreatureTypesSourceEffect() {
super(Duration.Custom, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit);
this.staticText = "{this} is every creature type <i>(even if this card isn't on the battlefield)</i>.";
}
private IsAllCreatureTypesSourceEffect(final IsAllCreatureTypesSourceEffect effect) {
super(effect);
}
@Override
public IsAllCreatureTypesSourceEffect copy() {
return new IsAllCreatureTypesSourceEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
MageObject sourceObject = game.getObject(source.getSourceId());
if (sourceObject == null) {
return false;
}
sourceObject.setIsAllCreatureTypes(game, true);
return true;
}
}

View file

@ -40,34 +40,19 @@ public class LoseArtifactTypeTargetEffect extends ContinuousEffectImpl {
}
@Override
public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) {
public boolean apply(Game game, Ability source) {
for (UUID targetId : targetPointer.getTargets(game, source)) {
if (targetId != null) {
Permanent permanent = game.getPermanent(targetId);
if (permanent != null) {
switch (layer) {
case TypeChangingEffects_4:
if (sublayer == SubLayer.NA) {
permanent.getCardType().remove(CardType.ARTIFACT);
permanent.getSubtype(game).removeAll(SubType.getArtifactTypes());
}
break;
}
return true;
}
if (targetId == null) {
continue;
}
Permanent permanent = game.getPermanent(targetId);
if (permanent == null) {
continue;
}
permanent.getCardType().remove(CardType.ARTIFACT);
permanent.removeAllSubTypes(game, SubTypeSet.ArtifactType);
return true;
}
return false;
}
@Override
public boolean apply(Game game, Ability source) {
return false;
}
@Override
public boolean hasLayer(Layer layer) {
return layer == Layer.TypeChangingEffects_4;
}
}

View file

@ -5,19 +5,22 @@ import mage.abilities.effects.ContinuousEffectImpl;
import mage.constants.*;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.util.SubTypeList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @author nantuko
*/
public class SetCardSubtypeAttachedEffect extends ContinuousEffectImpl {
private SubTypeList setSubtypes = new SubTypeList();
private List<SubType> setSubtypes = new ArrayList<>();
private final AttachmentType attachmentType;
public SetCardSubtypeAttachedEffect(Duration duration, AttachmentType attachmentType, SubType... setSubtype) {
super(duration, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit);
this.setSubtypes.add(setSubtype);
this.setSubtypes.addAll(Arrays.asList(setSubtype));
this.attachmentType = attachmentType;
this.setText();
}
@ -39,7 +42,7 @@ public class SetCardSubtypeAttachedEffect extends ContinuousEffectImpl {
return true;
}
target.removeAllCreatureTypes(game);
target.getSubtype(game).addAll(setSubtypes);
target.addSubType(game, setSubtypes);
return true;
}

View file

@ -122,15 +122,16 @@ public class BestowAbility extends SpellAbility {
}
static public void becomeCreature(Permanent permanent, Game game) {
// permanently changes to the object
if (permanent != null) {
MageObject basicObject = permanent.getBasicMageObject(game);
if (basicObject != null) {
basicObject.getSubtype(null).remove(SubType.AURA);
basicObject.getSubtype().remove(SubType.AURA);
if (!basicObject.isCreature()) {
basicObject.addCardType(CardType.CREATURE);
}
}
permanent.getSubtype(null).remove(SubType.AURA);
permanent.getSubtype().remove(SubType.AURA);
if (!permanent.isCreature()) {
permanent.addCardType(CardType.CREATURE);
}
@ -139,8 +140,9 @@ public class BestowAbility extends SpellAbility {
}
static public void becomeAura(Card card) {
// permanently changes to the object
if (card != null) {
card.getSubtype(null).add(SubType.AURA);
card.addSubType(SubType.AURA);
card.getCardType().remove(CardType.CREATURE);
card.getCardType().add(CardType.ENCHANTMENT);
}
@ -173,7 +175,7 @@ class BestowEntersBattlefieldEffect extends ReplacementEffectImpl {
if (bestowPermanent != null) {
if (bestowPermanent.hasSubtype(SubType.AURA, game)) {
MageObject basicObject = bestowPermanent.getBasicMageObject(game);
if (basicObject != null && !basicObject.getSubtype(null).contains(SubType.AURA)) {
if (basicObject != null && !basicObject.getSubtype().contains(SubType.AURA)) {
basicObject.getSubtype(null).add(SubType.AURA);
basicObject.getCardType().remove(CardType.CREATURE);
}

View file

@ -1,36 +1,27 @@
package mage.abilities.keyword;
import mage.abilities.MageSingleton;
import mage.abilities.StaticAbility;
import mage.abilities.effects.common.continuous.IsAllCreatureTypesSourceEffect;
import mage.constants.Zone;
import java.io.ObjectStreamException;
/**
* October 1, 2012
* 702.71. Changeling
* 702.71a Changeling is a characteristic-defining ability. "Changeling" means "This object
* is every creature type." This ability works everywhere, even outside the game. See rule 604.3.
* 702.71b Multiple instances of changeling on the same object are redundant.
* 702.71a Changeling is a characteristic-defining ability. "Changeling" means "This object
* is every creature type." This ability works everywhere, even outside the game. See rule 604.3.
* 702.71b Multiple instances of changeling on the same object are redundant.
*
* @author nantuko
*/
public class ChangelingAbility extends StaticAbility implements MageSingleton {
private static final ChangelingAbility instance = new ChangelingAbility();
public class ChangelingAbility extends StaticAbility {
private Object readResolve() throws ObjectStreamException {
return instance;
public ChangelingAbility() {
super(Zone.ALL, new IsAllCreatureTypesSourceEffect());
}
public static ChangelingAbility getInstance() {
return instance;
}
private ChangelingAbility() {
super(Zone.ALL, null);
private ChangelingAbility(final ChangelingAbility ability) {
super(ability);
}
@Override
@ -40,6 +31,6 @@ public class ChangelingAbility extends StaticAbility implements MageSingleton {
@Override
public ChangelingAbility copy() {
return instance;
return new ChangelingAbility(this);
}
}

View file

@ -51,7 +51,7 @@ public class EmbalmAbility extends ActivatedAbilityImpl {
StringBuilder sb = new StringBuilder("Embalm ").append(cost.getText());
sb.append(" <i>(").append(cost.getText());
sb.append(", Exile this card from your graveyard: Create a token that's a copy of it, except it's a white Zombie ");
for (SubType subtype : card.getSubtype(null)) {
for (SubType subtype : card.getSubtype()) {
sb.append(subtype).append(" ");
}
sb.append(" with no mana cost. Embalm only as a sorcery.)</i>");
@ -84,10 +84,12 @@ class EmbalmEffect extends OneShotEffect {
if (controller == null) {
return false;
}
// create token and modify all attributes permanently (without game usage)
EmptyToken token = new EmptyToken();
CardUtil.copyTo(token).from(card, game); // needed so that entersBattlefied triggered abilities see the attributes (e.g. Master Biomancer)
token.getColor(game).setColor(ObjectColor.WHITE);
token.addSubType(game, SubType.ZOMBIE);
token.getColor().setColor(ObjectColor.WHITE);
token.addSubType(SubType.ZOMBIE);
token.getManaCost().clear();
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.EMBALMED_CREATURE, token.getId(), source, controller.getId()));
token.putOntoBattlefield(1, game, source, controller.getId(), false, false, null);

View file

@ -56,7 +56,7 @@ public class EternalizeAbility extends ActivatedAbilityImpl {
StringBuilder sb = new StringBuilder("Eternalize ").append(cost.getText());
sb.append(" <i>(").append(cost.getText());
sb.append(", Exile this card from your graveyard: Create a token that's a copy of it, except it's a 4/4 black Zombie ");
for (SubType subtype : card.getSubtype(null)) {
for (SubType subtype : card.getSubtype()) {
sb.append(subtype).append(" ");
}
sb.append(" with no mana cost. Eternalize only as a sorcery.)</i>");
@ -89,10 +89,12 @@ class EternalizeEffect extends OneShotEffect {
if (controller == null) {
return false;
}
// create token and modify all attributes permanently (without game usage)
EmptyToken token = new EmptyToken();
CardUtil.copyTo(token).from(card, game); // needed so that entersBattlefied triggered abilities see the attributes (e.g. Master Biomancer)
token.getColor(game).setColor(ObjectColor.BLACK);
token.addSubType(game, SubType.ZOMBIE);
token.getColor().setColor(ObjectColor.BLACK);
token.addSubType(SubType.ZOMBIE);
token.getManaCost().clear();
token.removePTCDA();
token.getPower().modifyBaseValue(4);

View file

@ -285,11 +285,11 @@ public class MorphAbility extends StaticAbility implements AlternativeSourceCost
mageObject.getPower().modifyBaseValue(2);
mageObject.getToughness().modifyBaseValue(2);
mageObject.getAbilities().clear();
mageObject.getColor(null).setColor(new ObjectColor());
mageObject.getColor().setColor(new ObjectColor());
mageObject.setName("");
mageObject.getCardType().clear();
mageObject.addCardType(CardType.CREATURE);
mageObject.getSubtype(null).clear();
mageObject.getSubtype().clear();
mageObject.getSuperType().clear();
mageObject.getManaCost().clear();
if (mageObject instanceof Permanent) {

View file

@ -53,10 +53,7 @@ public class TransformAbility extends SimpleStaticAbility {
permanent.addCardType(type);
}
permanent.removeAllSubTypes(game);
permanent.setIsAllCreatureTypes(sourceCard.isAllCreatureTypes());
for (SubType type : sourceCard.getSubtype(game)) {
permanent.addSubType(game, type);
}
permanent.copySubTypesFrom(game, sourceCard);
permanent.getSuperType().clear();
for (SuperType type : sourceCard.getSuperType()) {
permanent.addSuperType(type);

View file

@ -10,7 +10,7 @@ import mage.constants.*;
import mage.game.Game;
import mage.game.events.ZoneChangeEvent;
import mage.util.CardUtil;
import mage.util.SubTypeList;
import mage.util.SubTypes;
import java.util.ArrayList;
import java.util.EnumSet;
@ -136,9 +136,15 @@ public abstract class ModalDoubleFacesCard extends CardImpl {
}
@Override
public SubTypeList getSubtype(Game game) {
public SubTypes getSubtype() {
// rules: While a double-faced card isnt on the stack or battlefield, consider only the characteristics of its front face.
// CardImpl's constructor can call some code on init, so you must check left/right before
return leftHalfCard != null ? leftHalfCard.getSubtype() : subtype;
}
@Override
public SubTypes getSubtype(Game game) {
// rules: While a double-faced card isnt on the stack or battlefield, consider only the characteristics of its front face.
// CardImpl's constructor can call some code on init, so you must check left/right before
return leftHalfCard != null ? leftHalfCard.getSubtype(game) : subtype;
}
@ -240,6 +246,11 @@ public abstract class ModalDoubleFacesCard extends CardImpl {
return super.hasAbility(ability, game);
}
@Override
public ObjectColor getColor() {
return leftHalfCard.getColor();
}
@Override
public ObjectColor getColor(Game game) {
return leftHalfCard.getColor(game);

View file

@ -12,7 +12,7 @@ import mage.cards.mock.MockCard;
import mage.cards.mock.MockSplitCard;
import mage.constants.*;
import mage.util.CardUtil;
import mage.util.SubTypeList;
import mage.util.SubTypes;
import org.apache.log4j.Logger;
import java.util.*;
@ -162,7 +162,7 @@ public class CardInfo {
this.white = card.getColor(null).isWhite();
this.setTypes(card.getCardType());
this.setSubtypes(card.getSubtype(null).stream().map(SubType::toString).collect(Collectors.toList()));
this.setSubtypes(card.getSubtype().stream().map(SubType::toString).collect(Collectors.toList()));
this.setSuperTypes(card.getSuperType());
// mana cost can contains multiple cards (split left/right, modal double faces, card/adventure)
@ -367,8 +367,8 @@ public class CardInfo {
this.rules = joinList(rules);
}
public final SubTypeList getSubTypes() {
SubTypeList sl = new SubTypeList();
public final SubTypes getSubTypes() {
SubTypes sl = new SubTypes();
if (subtypes.trim().isEmpty()) {
return sl;
}

View file

@ -594,4 +594,8 @@ public enum SubType {
public static Set<SubType> getLandTypes() {
return landTypes;
}
public static Set<SubType> getBySubTypeSet(SubTypeSet subTypeSet) {
return subTypeSetMap.get(subTypeSet);
}
}

View file

@ -18,7 +18,7 @@ import mage.game.Game;
import mage.game.events.ZoneChangeEvent;
import mage.util.Copyable;
import mage.util.GameLog;
import mage.util.SubTypeList;
import mage.util.SubTypes;
import java.util.ArrayList;
import java.util.EnumSet;
@ -156,8 +156,13 @@ public abstract class Designation implements MageObject, Copyable<Designation> {
}
@Override
public SubTypeList getSubtype(Game game) {
return new SubTypeList();
public SubTypes getSubtype() {
return new SubTypes();
}
@Override
public SubTypes getSubtype(Game game) {
return new SubTypes();
}
@Override
@ -175,6 +180,11 @@ public abstract class Designation implements MageObject, Copyable<Designation> {
return this.getAbilities().contains(ability);
}
@Override
public ObjectColor getColor() {
return emptyColor;
}
@Override
public ObjectColor getColor(Game game) {
return emptyColor;
@ -245,13 +255,16 @@ public abstract class Designation implements MageObject, Copyable<Designation> {
}
@Override
public boolean isAllCreatureTypes() {
public boolean isAllCreatureTypes(Game game) {
return false;
}
@Override
public void setIsAllCreatureTypes(boolean value) {
}
@Override
public void setIsAllCreatureTypes(Game game, boolean value) {
}
@Override

View file

@ -1,44 +0,0 @@
package mage.filter.common;
import java.util.ArrayList;
import java.util.List;
import mage.constants.SubType;
import mage.constants.SubTypeSet;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.permanent.PermanentIdPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
/**
*
* @author tschroeder
*/
public class FilterOtherCreatureSharingCreatureSubtype extends FilterCreaturePermanent {
public FilterOtherCreatureSharingCreatureSubtype(Permanent creature, Game game) {
super("creature sharing a creature type with " + creature.toString());
List<SubType.SubTypePredicate> subtypePredicates = new ArrayList<>();
for (SubType subtype : creature.getSubtype(game)) {
if (subtype.getSubTypeSet() == SubTypeSet.CreatureType) {
subtypePredicates.add(subtype.getPredicate());
}
}
this.add(Predicates.and(
Predicates.or(subtypePredicates),
Predicates.not(new PermanentIdPredicate(creature.getId()))
));
}
public FilterOtherCreatureSharingCreatureSubtype(final FilterOtherCreatureSharingCreatureSubtype filter) {
super(filter);
}
@Override
public FilterOtherCreatureSharingCreatureSubtype copy() {
return new FilterOtherCreatureSharingCreatureSubtype(this);
}
}

View file

@ -0,0 +1,23 @@
package mage.filter.predicate.permanent;
import mage.MageObject;
import mage.filter.predicate.Predicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
/**
* @author TheElk801
*/
public class SharesCreatureTypePredicate implements Predicate<MageObject> {
private final MageObject mageObject;
public SharesCreatureTypePredicate(Permanent permanent) {
this.mageObject = permanent;
}
@Override
public boolean apply(MageObject input, Game game) {
return mageObject != null && mageObject.shareCreatureTypes(game, input);
}
}

View file

@ -41,7 +41,7 @@ import mage.players.Player;
import mage.players.PlayerList;
import mage.players.Players;
import mage.util.MessageToClient;
import mage.util.functions.ApplyToPermanent;
import mage.util.functions.CopyApplier;
import java.io.Serializable;
import java.util.*;
@ -411,9 +411,9 @@ public interface Game extends MageItem, Serializable {
* @param applier
* @return
*/
Permanent copyPermanent(Permanent copyFromPermanent, UUID copyToPermanentId, Ability source, ApplyToPermanent applier);
Permanent copyPermanent(Permanent copyFromPermanent, UUID copyToPermanentId, Ability source, CopyApplier applier);
Permanent copyPermanent(Duration duration, Permanent copyFromPermanent, UUID copyToPermanentId, Ability source, ApplyToPermanent applier);
Permanent copyPermanent(Duration duration, Permanent copyFromPermanent, UUID copyToPermanentId, Ability source, CopyApplier applier);
Card copyCard(Card cardToCopy, Ability source, UUID newController);

View file

@ -66,7 +66,7 @@ import mage.util.CardUtil;
import mage.util.GameLog;
import mage.util.MessageToClient;
import mage.util.RandomUtil;
import mage.util.functions.ApplyToPermanent;
import mage.util.functions.CopyApplier;
import mage.watchers.common.*;
import org.apache.log4j.Logger;
@ -1651,12 +1651,12 @@ public abstract class GameImpl implements Game, Serializable {
}
@Override
public Permanent copyPermanent(Permanent copyFromPermanent, UUID copyToPermanentId, Ability source, ApplyToPermanent applier) {
public Permanent copyPermanent(Permanent copyFromPermanent, UUID copyToPermanentId, Ability source, CopyApplier applier) {
return copyPermanent(Duration.Custom, copyFromPermanent, copyToPermanentId, source, applier);
}
@Override
public Permanent copyPermanent(Duration duration, Permanent copyFromPermanent, UUID copyToPermanentId, Ability source, ApplyToPermanent applier) {
public Permanent copyPermanent(Duration duration, Permanent copyFromPermanent, UUID copyToPermanentId, Ability source, CopyApplier applier) {
Permanent newBluePrint = null;
// handle copies of copies
for (Effect effect : getState().getContinuousEffects().getLayeredEffects(this)) {
@ -2231,9 +2231,9 @@ public abstract class GameImpl implements Game, Serializable {
Permanent attachment = getPermanent(attachmentId);
if (attachment != null
&& (attachment.isCreature()
|| !(attachment.getSubtype(this).contains(SubType.AURA)
|| attachment.getSubtype(this).contains(SubType.EQUIPMENT)
|| attachment.getSubtype(this).contains(SubType.FORTIFICATION)))) {
|| !(attachment.hasSubtype(SubType.AURA, this)
|| attachment.hasSubtype(SubType.EQUIPMENT, this)
|| attachment.hasSubtype(SubType.FORTIFICATION, this)))) {
if (perm.removeAttachment(attachment.getId(), null, this)) {
somethingHappened = true;
break;

View file

@ -1,14 +1,10 @@
/*
* 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.game;
import java.io.Serializable;
import mage.MageObject;
import mage.ObjectColor;
import mage.util.SubTypeList;
import mage.util.SubTypes;
import java.io.Serializable;
/**
* This class saves changed attributes of mage objects (e.g. in command zone, graveyard, exile or
@ -19,12 +15,11 @@ import mage.util.SubTypeList;
public class MageObjectAttribute implements Serializable {
protected ObjectColor color;
protected SubTypeList subtype;
protected SubTypes subtype;
public MageObjectAttribute(MageObject mageObject, Game game) {
color = mageObject.getColor(null).copy();
subtype = new SubTypeList();
subtype.addAll(mageObject.getSubtype(game));
color = mageObject.getColor().copy();
subtype = new SubTypes(mageObject.getSubtype(game));
}
public MageObjectAttribute(MageObjectAttribute mageObjectAttribute) {
@ -40,7 +35,7 @@ public class MageObjectAttribute implements Serializable {
return color;
}
public SubTypeList getSubtype() {
public SubTypes getSubtype() {
return subtype;
}

View file

@ -18,7 +18,7 @@ import mage.constants.SuperType;
import mage.game.Game;
import mage.game.events.ZoneChangeEvent;
import mage.util.GameLog;
import mage.util.SubTypeList;
import mage.util.SubTypes;
import java.util.ArrayList;
import java.util.List;
@ -130,7 +130,6 @@ public class Commander implements CommandObject {
@Override
public void setName(String name) {
}
@Override
@ -139,7 +138,12 @@ public class Commander implements CommandObject {
}
@Override
public SubTypeList getSubtype(Game game) {
public SubTypes getSubtype() {
return sourceObject.getSubtype();
}
@Override
public SubTypes getSubtype(Game game) {
return sourceObject.getSubtype(game);
}
@ -167,6 +171,11 @@ public class Commander implements CommandObject {
return otherAbilities != null && otherAbilities.contains(ability);
}
@Override
public ObjectColor getColor() {
return sourceObject.getColor();
}
@Override
public ObjectColor getColor(Game game) {
return sourceObject.getColor(game);
@ -245,7 +254,7 @@ public class Commander implements CommandObject {
}
@Override
public boolean isAllCreatureTypes() {
public boolean isAllCreatureTypes(Game game) {
return false;
}
@ -253,6 +262,10 @@ public class Commander implements CommandObject {
public void setIsAllCreatureTypes(boolean value) {
}
@Override
public void setIsAllCreatureTypes(Game game, boolean value) {
}
@Override
public List<TextPart> getTextParts() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.

View file

@ -20,7 +20,7 @@ import mage.constants.SuperType;
import mage.game.Game;
import mage.game.events.ZoneChangeEvent;
import mage.util.GameLog;
import mage.util.SubTypeList;
import mage.util.SubTypes;
import java.util.ArrayList;
import java.util.EnumSet;
@ -76,7 +76,7 @@ public class Emblem implements CommandObject {
this.sourceObject = sourceObject;
if (sourceObject instanceof Card) {
if (name.isEmpty()) {
name = sourceObject.getSubtype(null).toString();
name = sourceObject.getSubtype().toString();
}
if (expansionSetCodeForImage.isEmpty()) {
expansionSetCodeForImage = ((Card) sourceObject).getExpansionSetCode();
@ -154,8 +154,13 @@ public class Emblem implements CommandObject {
}
@Override
public SubTypeList getSubtype(Game game) {
return new SubTypeList();
public SubTypes getSubtype() {
return new SubTypes();
}
@Override
public SubTypes getSubtype(Game game) {
return new SubTypes();
}
@Override
@ -178,6 +183,11 @@ public class Emblem implements CommandObject {
return getAbilities().contains(ability);
}
@Override
public ObjectColor getColor() {
return emptyColor;
}
@Override
public ObjectColor getColor(Game game) {
return emptyColor;
@ -258,13 +268,19 @@ public class Emblem implements CommandObject {
throw new UnsupportedOperationException("Unsupported operation");
}
public boolean isAllCreatureTypes() {
@Override
public boolean isAllCreatureTypes(Game game) {
return false;
}
@Override
public void setIsAllCreatureTypes(boolean value) {
}
@Override
public void setIsAllCreatureTypes(Game game, boolean value) {
}
public void discardEffects() {
for (Ability ability : abilites) {
for (Effect effect : ability.getEffects()) {

View file

@ -22,7 +22,7 @@ import mage.game.Game;
import mage.game.events.ZoneChangeEvent;
import mage.util.GameLog;
import mage.util.RandomUtil;
import mage.util.SubTypeList;
import mage.util.SubTypes;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
@ -163,8 +163,13 @@ public class Plane implements CommandObject {
}
@Override
public SubTypeList getSubtype(Game game) {
return new SubTypeList();
public SubTypes getSubtype() {
return new SubTypes();
}
@Override
public SubTypes getSubtype(Game game) {
return new SubTypes();
}
@Override
@ -187,6 +192,11 @@ public class Plane implements CommandObject {
return getAbilities().contains(ability);
}
@Override
public ObjectColor getColor() {
return emptyColor;
}
@Override
public ObjectColor getColor(Game game) {
return emptyColor;
@ -267,13 +277,19 @@ public class Plane implements CommandObject {
throw new UnsupportedOperationException("Unsupported operation");
}
public boolean isAllCreatureTypes() {
@Override
public boolean isAllCreatureTypes(Game game) {
return false;
}
@Override
public void setIsAllCreatureTypes(boolean value) {
}
@Override
public void setIsAllCreatureTypes(Game game, boolean value) {
}
public void discardEffects() {
for (Ability ability : abilites) {
for (Effect effect : ability.getEffects()) {

View file

@ -91,9 +91,9 @@ public final class RateCard {
type = 15;
} else if (card.isCreature()) {
type = 10;
} else if (card.getSubtype(null).contains(SubType.EQUIPMENT)) {
} else if (card.getSubtype().contains(SubType.EQUIPMENT)) {
type = 8;
} else if (card.getSubtype(null).contains(SubType.AURA)) {
} else if (card.getSubtype().contains(SubType.AURA)) {
type = 5;
} else if (card.isInstant()) {
type = 7;

View file

@ -1,21 +1,20 @@
package mage.game.permanent;
import java.util.UUID;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import mage.MageObject;
import mage.abilities.Abilities;
import mage.abilities.Ability;
import mage.abilities.costs.mana.ManaCost;
import mage.abilities.costs.mana.ManaCosts;
import mage.abilities.keyword.EnchantAbility;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.TransformAbility;
import mage.cards.Card;
import mage.cards.LevelerCard;
import mage.game.Game;
import mage.game.events.ZoneChangeEvent;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import java.util.UUID;
/**
* @author BetaSteward_at_googlemail.com
*/
@ -105,9 +104,7 @@ public class PermanentCard extends PermanentImpl {
if (card instanceof PermanentCard) {
this.maxLevelCounters = ((PermanentCard) card).maxLevelCounters;
}
this.subtype.clear();
this.subtype.addAll(card.getSubtype(game));
this.isAllCreatureTypes = card.isAllCreatureTypes();
this.subtype.copyFrom(card.getSubtype(game));
this.supertype.clear();
supertype.addAll(card.getSuperType());
this.expansionSetCode = card.getExpansionSetCode();

View file

@ -1634,6 +1634,11 @@ public abstract class PermanentImpl extends CardImpl implements Permanent {
this.createOrder = createOrder;
}
@Override
public ObjectColor getColor() {
return color;
}
@Override
public ObjectColor getColor(Game game) {
return color;

View file

@ -58,6 +58,7 @@ public class PermanentToken extends PermanentImpl {
}
private void copyFromToken(Token token, Game game, boolean reset) {
// modify all attributes permanently (without game usage)
this.name = token.getName();
this.abilities.clear();
if (reset) {
@ -81,9 +82,7 @@ public class PermanentToken extends PermanentImpl {
this.frameStyle = token.getFrameStyle();
this.supertype.clear();
this.supertype.addAll(token.getSuperType());
this.subtype.clear();
this.subtype.addAll(token.getSubtype(game));
this.isAllCreatureTypes = token.isAllCreatureTypes();
this.subtype.copyFrom(token.getSubtype(game));
this.tokenDescriptor = token.getTokenDescriptor();
}

View file

@ -16,8 +16,8 @@ public final class CamaridToken extends TokenImpl {
this.getPower().modifyBaseValue(1);
this.getToughness().modifyBaseValue(1);
this.color.setBlue(true);
this.getSubtype(null).add(SubType.CAMARID);
this.addCardType(CardType.CREATURE);
this.subtype.add(SubType.CAMARID);
this.cardType.add(CardType.CREATURE);
}
public CamaridToken(final CamaridToken token) {

View file

@ -27,9 +27,9 @@ public final class CatWarriorToken extends TokenImpl {
this.getPower().modifyBaseValue(2);
this.getToughness().modifyBaseValue(2);
this.color.setGreen(true);
this.getSubtype(null).add(SubType.CAT);
this.getSubtype(null).add(SubType.WARRIOR);
this.addCardType(CardType.CREATURE);
this.subtype.add(SubType.CAT);
this.subtype.add(SubType.WARRIOR);
this.cardType.add(CardType.CREATURE);
this.addAbility(new ForestwalkAbility());
}

View file

@ -17,8 +17,7 @@ public final class CribSwapShapeshifterWhiteToken extends TokenImpl {
subtype.add(SubType.SHAPESHIFTER);
power = new MageInt(1);
toughness = new MageInt(1);
setIsAllCreatureTypes(true);
addAbility(ChangelingAbility.getInstance());
addAbility(new ChangelingAbility());
}
public CribSwapShapeshifterWhiteToken(final CribSwapShapeshifterWhiteToken token) {

View file

@ -14,12 +14,12 @@ public final class NissaSageAnimistToken extends TokenImpl {
public NissaSageAnimistToken() {
super("Ashaya, the Awoken World", "legendary 4/4 green Elemental creature token named Ashaya, the Awoken World");
this.setOriginalExpansionSetCode("ORI");
this.addSuperType(SuperType.LEGENDARY);
this.supertype.add(SuperType.LEGENDARY);
this.getPower().modifyBaseValue(4);
this.getToughness().modifyBaseValue(4);
this.color.setGreen(true);
this.getSubtype(null).add(SubType.ELEMENTAL);
this.addCardType(CardType.CREATURE);
this.subtype.add(SubType.ELEMENTAL);
this.cardType.add(CardType.CREATURE);
}
public NissaSageAnimistToken(final NissaSageAnimistToken token) {

View file

@ -14,12 +14,12 @@ public final class RagavanToken extends TokenImpl {
public RagavanToken() {
super("Ragavan", "legendary 2/1 red Monkey creature token named Ragavan");
this.setOriginalExpansionSetCode("AER");
this.addSuperType(SuperType.LEGENDARY);
this.supertype.add(SuperType.LEGENDARY);
this.getPower().modifyBaseValue(2);
this.getToughness().modifyBaseValue(1);
this.color.setRed(true);
this.getSubtype(null).add(SubType.MONKEY);
this.addCardType(CardType.CREATURE);
this.subtype.add(SubType.MONKEY);
this.cardType.add(CardType.CREATURE);
}
public RagavanToken(final RagavanToken token) {

View file

@ -17,8 +17,7 @@ public final class ShapeshifterBlueToken extends TokenImpl {
color.setBlue(true);
power = new MageInt(2);
toughness = new MageInt(2);
setIsAllCreatureTypes(true);
addAbility(ChangelingAbility.getInstance());
addAbility(new ChangelingAbility());
}
private ShapeshifterBlueToken(final ShapeshifterBlueToken token) {

View file

@ -27,8 +27,7 @@ public final class ShapeshifterToken extends TokenImpl {
subtype.add(SubType.SHAPESHIFTER);
power = new MageInt(2);
toughness = new MageInt(2);
setIsAllCreatureTypes(true);
addAbility(ChangelingAbility.getInstance());
addAbility(new ChangelingAbility());
}
public ShapeshifterToken(final ShapeshifterToken token) {

View file

@ -75,7 +75,6 @@ public abstract class TokenImpl extends MageObjectImpl implements Token {
this.expansionSetCodeChecked = token.expansionSetCodeChecked;
this.copySourceCard = token.copySourceCard; // will never be changed
this.availableImageSetCodes = token.availableImageSetCodes;
this.isAllCreatureTypes = token.isAllCreatureTypes;
}
@Override

View file

@ -16,9 +16,9 @@ public final class WireflyToken extends TokenImpl {
this.setOriginalExpansionSetCode("DST");
this.getPower().modifyBaseValue(2);
this.getToughness().modifyBaseValue(2);
this.getSubtype(null).add(SubType.INSECT);
this.addCardType(CardType.ARTIFACT);
this.addCardType(CardType.CREATURE);
this.subtype.add(SubType.INSECT);
this.cardType.add(CardType.ARTIFACT);
this.cardType.add(CardType.CREATURE);
this.addAbility(FlyingAbility.getInstance());
}

View file

@ -6,10 +6,10 @@ import mage.abilities.Ability;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.game.permanent.token.TokenImpl;
import mage.util.SubTypeList;
import java.util.Arrays;
/**
*
* @author JayDi85
*/
public final class CreatureToken extends TokenImpl {
@ -23,21 +23,17 @@ public final class CreatureToken extends TokenImpl {
}
public CreatureToken(int power, int toughness, String description) {
this(power, toughness, description, (SubTypeList) null);
this(power, toughness, description, null);
}
public CreatureToken(int power, int toughness, String description, SubType extraSubType) {
this(power, toughness, description, new SubTypeList(extraSubType));
}
public CreatureToken(int power, int toughness, String description, SubTypeList extraSubTypes) {
public CreatureToken(int power, int toughness, String description, SubType... extraSubTypes) {
super("", description);
this.cardType.add(CardType.CREATURE);
this.power = new MageInt(power);
this.toughness = new MageInt(toughness);
if (extraSubTypes != null) {
this.subtype.addAll(extraSubTypes);
this.subtype.addAll(Arrays.asList(extraSubTypes));
}
}

View file

@ -34,7 +34,7 @@ import mage.game.permanent.token.EmptyToken;
import mage.players.Player;
import mage.util.CardUtil;
import mage.util.GameLog;
import mage.util.SubTypeList;
import mage.util.SubTypes;
/**
* @author BetaSteward_at_googlemail.com
@ -253,10 +253,11 @@ public class Spell extends StackObjImpl implements Card {
if (ability.getTargets().stillLegal(ability, game)) {
boolean bestow = SpellAbilityCastMode.BESTOW.equals(ability.getSpellAbilityCastMode());
if (bestow) {
// before put to play:
// 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);
if (!card.getSubtype(game).contains(SubType.AURA)) {
if (!card.hasSubtype(SubType.AURA, game)) {
card.addSubType(game, SubType.AURA);
}
}
@ -280,9 +281,11 @@ public class Spell extends StackObjImpl implements Card {
// TODO: Find a better way to prevent bestow creatures from being effected by creature affecting abilities
Permanent permanent = game.getPermanent(permId);
if (permanent instanceof PermanentCard) {
// after put to play:
// restore removed stats (see "before put to play" above)
permanent.setSpellAbility(ability); // otherwise spell ability without bestow will be set
card.addCardType(CardType.CREATURE);
card.getSubtype(game).remove(SubType.AURA);
card.removeSubType(game, SubType.AURA);
}
}
if (isCopy()) {
@ -312,7 +315,7 @@ public class Spell extends StackObjImpl implements Card {
Permanent permanent = game.getPermanent(card.getId());
if (permanent instanceof PermanentCard) {
((PermanentCard) permanent).getCard().addCardType(CardType.CREATURE);
((PermanentCard) permanent).getCard().getSubtype(game).remove(SubType.AURA);
((PermanentCard) permanent).getCard().removeSubType(game, SubType.AURA);
return true;
}
}
@ -524,9 +527,14 @@ public class Spell extends StackObjImpl implements Card {
}
@Override
public SubTypeList getSubtype(Game game) {
public SubTypes getSubtype() {
return card.getSubtype();
}
@Override
public SubTypes getSubtype(Game game) {
if (SpellAbilityCastMode.BESTOW.equals(this.getSpellAbility().getSpellAbilityCastMode())) {
SubTypeList subtypes = card.getSubtype(game);
SubTypes subtypes = card.getSubtype(game);
if (!subtypes.contains(SubType.AURA)) { // do it only once
subtypes.add(SubType.AURA);
}
@ -538,7 +546,7 @@ public class Spell extends StackObjImpl implements Card {
@Override
public boolean hasSubtype(SubType subtype, Game game) {
if (SpellAbilityCastMode.BESTOW.equals(this.getSpellAbility().getSpellAbilityCastMode())) { // workaround for Bestow (don't like it)
SubTypeList subtypes = card.getSubtype(game);
SubTypes subtypes = card.getSubtype(game);
if (!subtypes.contains(SubType.AURA)) { // do it only once
subtypes.add(SubType.AURA);
}
@ -573,6 +581,11 @@ public class Spell extends StackObjImpl implements Card {
return card.hasAbility(ability, game);
}
@Override
public ObjectColor getColor() {
return color;
}
@Override
public ObjectColor getColor(Game game) {
if (game != null) {
@ -1090,7 +1103,7 @@ public class Spell extends StackObjImpl implements Card {
}
@Override
public boolean isAllCreatureTypes() {
public boolean isAllCreatureTypes(Game game) {
return false;
}
@ -1098,6 +1111,10 @@ public class Spell extends StackObjImpl implements Card {
public void setIsAllCreatureTypes(boolean value) {
}
@Override
public void setIsAllCreatureTypes(Game game, boolean value) {
}
@Override
public List<TextPart> getTextParts() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.

View file

@ -30,7 +30,7 @@ import mage.target.Target;
import mage.target.Targets;
import mage.target.targetadjustment.TargetAdjuster;
import mage.util.GameLog;
import mage.util.SubTypeList;
import mage.util.SubTypes;
import mage.watchers.Watcher;
import java.util.ArrayList;
@ -161,8 +161,13 @@ public class StackAbility extends StackObjImpl implements Ability {
}
@Override
public SubTypeList getSubtype(Game game) {
return new SubTypeList();
public SubTypes getSubtype() {
return new SubTypes();
}
@Override
public SubTypes getSubtype(Game game) {
return new SubTypes();
}
@Override
@ -185,6 +190,11 @@ public class StackAbility extends StackObjImpl implements Ability {
return false;
}
@Override
public ObjectColor getColor() {
return emptyColor;
}
@Override
public ObjectColor getColor(Game game) {
return emptyColor;
@ -604,7 +614,7 @@ public class StackAbility extends StackObjImpl implements Ability {
}
@Override
public boolean isAllCreatureTypes() {
public boolean isAllCreatureTypes(Game game) {
return false;
}
@ -612,6 +622,10 @@ public class StackAbility extends StackObjImpl implements Ability {
public void setIsAllCreatureTypes(boolean value) {
}
@Override
public void setIsAllCreatureTypes(Game game, boolean value) {
}
@Override
public List<TextPart> getTextParts() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.

View file

@ -37,7 +37,7 @@ public class TargetCreaturePermanentWithDifferentTypes extends TargetCreaturePer
Permanent selectedCreature = game.getPermanent(targetId);
if (selectedCreature != null
&& !creature.getId().equals(selectedCreature.getId())) {
if (creature.shareCreatureTypes(selectedCreature, game)) {
if (creature.shareCreatureTypes(game, selectedCreature)) {
return false;
}
}

View file

@ -1,34 +0,0 @@
package mage.util;
import mage.constants.SubType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.stream.Collectors;
public class SubTypeList extends ArrayList<SubType> {
public SubTypeList(SubType firstSubType) {
super();
this.add(firstSubType);
}
public SubTypeList(SubType... subTypesList) {
super();
Collections.addAll(this, subTypesList);
}
public SubTypeList(final SubTypeList list) {
this.addAll(list);
}
public boolean add(SubType... subTypes) {
return Collections.addAll(this, subTypes);
}
public boolean removeAll(SubType... subTypes) {
return super.removeAll(Arrays.stream(subTypes)
.collect(Collectors.toList()));
}
}

View file

@ -0,0 +1,44 @@
package mage.util;
import mage.constants.SubType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
public class SubTypes extends ArrayList<SubType> {
private boolean isAllCreatureTypes = false;
public SubTypes(SubType... subTypes) {
super();
Collections.addAll(this, subTypes);
}
public SubTypes(final SubTypes list) {
this.addAll(list);
this.isAllCreatureTypes = list.isAllCreatureTypes;
}
public boolean add(SubType... subTypes) {
return Collections.addAll(this, subTypes);
}
public void copyFrom(SubTypes subtypes) {
this.clear();
this.addAll(subtypes);
this.isAllCreatureTypes = subtypes.isAllCreatureTypes;
}
public boolean removeAll(SubType... subTypes) {
return super.removeAll(Arrays.asList(subTypes));
}
public void setIsAllCreatureTypes(boolean allCreatureTypes) {
isAllCreatureTypes = allCreatureTypes;
}
public boolean isAllCreatureTypes() {
return isAllCreatureTypes;
}
}

View file

@ -1,34 +0,0 @@
package mage.util.functions;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.game.Game;
import mage.game.permanent.Permanent;
/**
*
* @author LevelX2
*/
public class AbilityApplier extends ApplyToPermanent {
private final Ability ability;
public AbilityApplier(Ability ability) {
this.ability = ability;
}
@Override
public boolean apply(Game game, Permanent permanent, Ability source, UUID copyToObjectId) {
permanent.addAbility(ability, source.getSourceId(), game);
return true;
}
@Override
public boolean apply(Game game, MageObject mageObject, Ability source, UUID copyToObjectId) {
mageObject.getAbilities().add(ability);
return true;
}
}

View file

@ -0,0 +1,27 @@
package mage.util.functions;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.game.Game;
import mage.game.permanent.Permanent;
/**
*
* @author LevelX2
*/
public class AbilityCopyApplier extends CopyApplier {
private final Ability ability;
public AbilityCopyApplier(Ability ability) {
this.ability = ability;
}
@Override
public boolean apply(Game game, MageObject blueprint, Ability source, UUID copyToObjectId) {
blueprint.getAbilities().add(ability);
return true;
}
}

View file

@ -1,44 +0,0 @@
/*
* 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.util.functions;
import mage.MageObject;
import mage.abilities.Ability;
import mage.constants.SubType;
import mage.game.Game;
import mage.game.permanent.Permanent;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public class AddSubtypeApplier extends ApplyToPermanent {
private final SubType subtype;
public AddSubtypeApplier(SubType subtype) {
this.subtype = subtype;
}
@Override
public boolean apply(Game game, Permanent permanent, Ability source, UUID copyToObjectId) {
if (!permanent.hasSubtype(subtype, game)) {
permanent.addSubType(game, subtype);
}
return true;
}
@Override
public boolean apply(Game game, MageObject mageObject, Ability source, UUID copyToObjectId) {
if (!mageObject.hasSubtype(subtype, game)) {
mageObject.addSubType(game, subtype);
}
return true;
}
}

View file

@ -0,0 +1,31 @@
package mage.util.functions;
import mage.MageObject;
import mage.abilities.Ability;
import mage.constants.SubType;
import mage.game.Game;
import mage.game.permanent.Permanent;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public class AddSubtypeCopyApplier extends CopyApplier {
private final SubType subtype;
public AddSubtypeCopyApplier(SubType subtype) {
this.subtype = subtype;
}
@Override
public boolean apply(Game game, MageObject blueprint, Ability source, UUID copyToObjectId) {
if (!blueprint.getSubtype().contains(subtype)) {
blueprint.getSubtype().add(subtype);
}
return true;
}
}

View file

@ -1,17 +0,0 @@
package mage.util.functions;
import mage.abilities.Ability;
import mage.game.Game;
import mage.game.permanent.Permanent;
import java.io.Serializable;
import java.util.UUID;
/**
* @author noxx
*/
public abstract class ApplyToPermanent extends ApplyToMageObject implements Serializable {
// WARNING: see comments in ApplyToMageObject
public abstract boolean apply(Game game, Permanent permanent, Ability source, UUID targetObjectId);
}

View file

@ -1,34 +0,0 @@
package mage.util.functions;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.constants.CardType;
import mage.game.Game;
import mage.game.permanent.Permanent;
/**
*
* @author LevelX2
*/
public class CardTypeApplier extends ApplyToPermanent {
private final CardType cardType;
public CardTypeApplier(CardType cardType) {
this.cardType = cardType;
}
@Override
public boolean apply(Game game, Permanent permanent, Ability source, UUID copyToObjectId) {
permanent.addCardType(cardType);
return true;
}
@Override
public boolean apply(Game game, MageObject mageObject, Ability source, UUID copyToObjectId) {
mageObject.addCardType(cardType);
return true;
}
}

View file

@ -0,0 +1,28 @@
package mage.util.functions;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.constants.CardType;
import mage.game.Game;
import mage.game.permanent.Permanent;
/**
*
* @author LevelX2
*/
public class CardTypeCopyApplier extends CopyApplier {
private final CardType cardType;
public CardTypeCopyApplier(CardType cardType) {
this.cardType = cardType;
}
@Override
public boolean apply(Game game, MageObject blueprint, Ability source, UUID copyToObjectId) {
blueprint.addCardType(cardType);
return true;
}
}

View file

@ -3,13 +3,17 @@ package mage.util.functions;
import mage.MageObject;
import mage.abilities.Ability;
import mage.game.Game;
import java.io.Serializable;
import java.util.Objects;
import java.util.UUID;
/**
* Apply additional modifications for blueprint of the copy permanent
*
* @author LevelX2
*/
public abstract class ApplyToMageObject {
public abstract class CopyApplier implements Serializable {
// WARNING:
// 1. Applier uses for copy effects only;
@ -17,8 +21,7 @@ public abstract class ApplyToMageObject {
// 3. "source" is the current copy ability and can be different from the original copy ability (copy of copy);
// 4. Don't use "source" param at all;
// 5. Use isCopyOfCopy() to detect it (some effects can apply to copy of copy, but others can't -- see Spark Double as an example).
// TODO: check all applier implementations - remove source uses, add isCopyOfCopy processing
public abstract boolean apply(Game game, MageObject mageObject, Ability source, UUID targetObjectId);
public abstract boolean apply(Game game, MageObject blueprint, Ability source, UUID targetObjectId);
public boolean isCopyOfCopy(Ability source, UUID targetObjectId) {
return !Objects.equals(targetObjectId, source.getSourceId());

View file

@ -63,18 +63,16 @@ public class CopyTokenFunction implements Function<Token, Card> {
target.setCopySourceCard(source);
}
// modify all attributes permanently (without game usage)
target.setName(sourceObj.getName());
target.getColor(null).setColor(sourceObj.getColor(null));
target.getColor().setColor(sourceObj.getColor());
target.getManaCost().clear();
target.getManaCost().add(sourceObj.getManaCost());
target.getCardType().clear();
for (CardType type : sourceObj.getCardType()) {
target.addCardType(type);
}
target.getSubtype(null).clear();
for (SubType type : sourceObj.getSubtype(null)) {
target.getSubtype(null).add(type);
}
target.getSubtype().copyFrom(sourceObj.getSubtype());
target.getSuperType().clear();
for (SuperType type : sourceObj.getSuperType()) {
target.addSuperType(type);

View file

@ -1,25 +0,0 @@
package mage.util.functions;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.game.Game;
import mage.game.permanent.Permanent;
/**
* @author noxx
*/
public class EmptyApplyToPermanent extends ApplyToPermanent {
@Override
public boolean apply(Game game, Permanent permanent, Ability source, UUID copyToObjectId) {
// do nothing
return true;
}
@Override
public boolean apply(Game game, MageObject mageObject, Ability source, UUID copyToObjectId) {
return true;
}
}

View file

@ -0,0 +1,19 @@
package mage.util.functions;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.game.Game;
import mage.game.permanent.Permanent;
/**
* @author noxx
*/
public class EmptyCopyApplier extends CopyApplier {
@Override
public boolean apply(Game game, MageObject blueprint, Ability source, UUID copyToObjectId) {
return true;
}
}

View file

@ -1,6 +1,8 @@
package mage.watchers.common;
import mage.cards.Card;
import mage.constants.SubType;
import mage.constants.SubTypeSet;
import mage.constants.WatcherScope;
import mage.game.Game;
import mage.game.events.DamagedPlayerEvent;
@ -39,7 +41,7 @@ public class ProwlWatcher extends Watcher {
if (creature == null || allSubtypes.contains(creature.getControllerId())) {
return;
}
if (creature.isAllCreatureTypes()) {
if (creature.isAllCreatureTypes(game)) {
allSubtypes.add(creature.getControllerId());
return;
}
@ -55,12 +57,16 @@ public class ProwlWatcher extends Watcher {
allSubtypes.clear();
}
public boolean hasSubtypeMadeCombatDamage(UUID playerId, SubType subtype) {
public boolean hasSubtypeMadeCombatDamage(UUID playerId, Card card, Game game) {
if (allSubtypes.contains(playerId)) {
return true;
}
Set<SubType> subtypes = damagingSubtypes.get(playerId);
return subtypes != null && subtypes.contains(subtype);
return subtypes != null
&& subtypes
.stream()
.filter(subType -> subType.getSubTypeSet() == SubTypeSet.CreatureType)
.anyMatch(subType -> card.hasSubtype(subType, game));
}
}