mirror of
https://github.com/magefree/mage.git
synced 2025-12-25 13:02:06 -08:00
Merge branch 'master' into refactor_promo_sets
This commit is contained in:
commit
9e6a348cb1
4098 changed files with 115584 additions and 60811 deletions
|
|
@ -1,5 +1,9 @@
|
|||
package mage;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import mage.abilities.Abilities;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.costs.mana.ManaCost;
|
||||
|
|
@ -15,12 +19,6 @@ import mage.game.Game;
|
|||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.util.SubTypeList;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface MageObject extends MageItem, Serializable {
|
||||
|
||||
String getName();
|
||||
|
|
@ -33,7 +31,7 @@ public interface MageObject extends MageItem, Serializable {
|
|||
|
||||
void setName(String name);
|
||||
|
||||
Set<CardType> getCardType();
|
||||
ArrayList<CardType> getCardType();
|
||||
|
||||
SubTypeList getSubtype(Game game);
|
||||
|
||||
|
|
@ -41,9 +39,15 @@ public interface MageObject extends MageItem, Serializable {
|
|||
|
||||
Set<SuperType> getSuperType();
|
||||
|
||||
/**
|
||||
* For cards: return basic abilities (without dynamic added) For permanents:
|
||||
* return all abilities (dynamic ability inserts into permanent)
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Abilities<Ability> getAbilities();
|
||||
|
||||
boolean hasAbility(UUID abilityId, Game game);
|
||||
boolean hasAbility(Ability ability, Game game);
|
||||
|
||||
ObjectColor getColor(Game game);
|
||||
|
||||
|
|
@ -180,9 +184,9 @@ public interface MageObject extends MageItem, Serializable {
|
|||
}
|
||||
|
||||
if (this.isCreature() && otherCard.isCreature()) {
|
||||
if (this.getAbilities().contains(ChangelingAbility.getInstance())
|
||||
if (this.hasAbility(ChangelingAbility.getInstance(), game)
|
||||
|| this.isAllCreatureTypes()
|
||||
|| otherCard.getAbilities().contains(ChangelingAbility.getInstance())
|
||||
|| otherCard.hasAbility(ChangelingAbility.getInstance(), game)
|
||||
|| otherCard.isAllCreatureTypes()) {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -200,7 +204,7 @@ public interface MageObject extends MageItem, Serializable {
|
|||
|
||||
void setIsAllCreatureTypes(boolean value);
|
||||
|
||||
default void addCardTypes(Set<CardType> cardType) {
|
||||
default void addCardTypes(ArrayList<CardType> cardType) {
|
||||
getCardType().addAll(cardType);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package mage;
|
||||
|
||||
import java.util.*;
|
||||
import mage.abilities.Abilities;
|
||||
import mage.abilities.AbilitiesImpl;
|
||||
import mage.abilities.Ability;
|
||||
|
|
@ -21,8 +22,6 @@ import mage.game.permanent.Permanent;
|
|||
import mage.util.GameLog;
|
||||
import mage.util.SubTypeList;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public abstract class MageObjectImpl implements MageObject {
|
||||
|
||||
protected UUID objectId;
|
||||
|
|
@ -32,7 +31,7 @@ public abstract class MageObjectImpl implements MageObject {
|
|||
protected ObjectColor color;
|
||||
protected ObjectColor frameColor;
|
||||
protected FrameStyle frameStyle;
|
||||
protected Set<CardType> cardType = EnumSet.noneOf(CardType.class);
|
||||
protected ArrayList<CardType> cardType = new ArrayList<>();
|
||||
protected SubTypeList subtype = new SubTypeList();
|
||||
protected boolean isAllCreatureTypes;
|
||||
protected Set<SuperType> supertype = EnumSet.noneOf(SuperType.class);
|
||||
|
|
@ -112,7 +111,7 @@ public abstract class MageObjectImpl implements MageObject {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Set<CardType> getCardType() {
|
||||
public ArrayList<CardType> getCardType() {
|
||||
return cardType;
|
||||
}
|
||||
|
||||
|
|
@ -132,12 +131,12 @@ public abstract class MageObjectImpl implements MageObject {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAbility(UUID abilityId, Game game) {
|
||||
if (this.getAbilities().containsKey(abilityId)) {
|
||||
public boolean hasAbility(Ability ability, Game game) {
|
||||
if (this.getAbilities().contains(ability)) {
|
||||
return true;
|
||||
}
|
||||
Abilities<Ability> otherAbilities = game.getState().getAllOtherAbilities(getId());
|
||||
return otherAbilities != null && otherAbilities.containsKey(abilityId);
|
||||
return otherAbilities != null && otherAbilities.contains(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -171,39 +170,22 @@ public abstract class MageObjectImpl implements MageObject {
|
|||
// its frame colors.
|
||||
if (this.isLand()) {
|
||||
ObjectColor cl = frameColor.copy();
|
||||
Set<ManaType> manaTypes = EnumSet.noneOf(ManaType.class);
|
||||
for (Ability ab : getAbilities()) {
|
||||
if (ab instanceof ActivatedManaAbilityImpl) {
|
||||
ActivatedManaAbilityImpl mana = (ActivatedManaAbilityImpl) ab;
|
||||
try {
|
||||
List<Mana> manaAdded = mana.getNetMana(game);
|
||||
for (Mana m : manaAdded) {
|
||||
if (m.getAny() > 0) {
|
||||
return new ObjectColor("WUBRG");
|
||||
}
|
||||
if (m.getWhite() > 0) {
|
||||
cl.setWhite(true);
|
||||
}
|
||||
if (m.getBlue() > 0) {
|
||||
cl.setBlue(true);
|
||||
}
|
||||
if (m.getBlack() > 0) {
|
||||
cl.setBlack(true);
|
||||
}
|
||||
if (m.getRed() > 0) {
|
||||
cl.setRed(true);
|
||||
}
|
||||
if (m.getGreen() > 0) {
|
||||
cl.setGreen(true);
|
||||
}
|
||||
}
|
||||
} catch (NullPointerException e) {
|
||||
// Ability depends on game
|
||||
// but no game passed
|
||||
// All such abilities are 5-color ones
|
||||
return new ObjectColor("WUBRG");
|
||||
}
|
||||
manaTypes.addAll(((ActivatedManaAbilityImpl) ab).getProducableManaTypes(game));
|
||||
}
|
||||
}
|
||||
cl.setWhite(manaTypes.contains(ManaType.WHITE));
|
||||
cl.setBlue(manaTypes.contains(ManaType.BLUE));
|
||||
cl.setBlack(manaTypes.contains(ManaType.BLACK));
|
||||
cl.setRed(manaTypes.contains(ManaType.RED));
|
||||
cl.setGreen(manaTypes.contains(ManaType.GREEN));
|
||||
|
||||
// // Ability depends on game
|
||||
// // but no game passed
|
||||
// // All such abilities are 5-color ones
|
||||
// return new ObjectColor("WUBRG");
|
||||
return cl;
|
||||
} else {
|
||||
// For everything else, just return the frame colors
|
||||
|
|
@ -329,7 +311,7 @@ public abstract class MageObjectImpl implements MageObject {
|
|||
*/
|
||||
@Override
|
||||
public void removePTCDA() {
|
||||
for (Iterator<Ability> iter = this.getAbilities().iterator(); iter.hasNext(); ) {
|
||||
for (Iterator<Ability> iter = this.getAbilities().iterator(); iter.hasNext();) {
|
||||
Ability ability = iter.next();
|
||||
for (Effect effect : ability.getEffects()) {
|
||||
if (effect instanceof ContinuousEffect && ((ContinuousEffect) effect).getSublayer() == SubLayer.CharacteristicDefining_7a) {
|
||||
|
|
|
|||
|
|
@ -43,13 +43,13 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
|
|||
* Creates a {@link Mana} object with the passed in values. Values can not
|
||||
* be less than 0. Any values less than 0 will be logged and set to 0.
|
||||
*
|
||||
* @param red total Red mana to have.
|
||||
* @param green total Green mana to have.
|
||||
* @param blue total Blue mana to have.
|
||||
* @param white total White mana to have.
|
||||
* @param black total Black mana to have.
|
||||
* @param generic total Generic mana to have.
|
||||
* @param any total Any mana to have.
|
||||
* @param red total Red mana to have.
|
||||
* @param green total Green mana to have.
|
||||
* @param blue total Blue mana to have.
|
||||
* @param white total White mana to have.
|
||||
* @param black total Black mana to have.
|
||||
* @param generic total Generic mana to have.
|
||||
* @param any total Any mana to have.
|
||||
* @param colorless total Colorless mana to have.
|
||||
*/
|
||||
public Mana(final int red, final int green, final int blue, final int white, final int black, final int generic, final int any, final int colorless) {
|
||||
|
|
@ -142,6 +142,35 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
|
|||
}
|
||||
}
|
||||
|
||||
public Mana(final ManaType manaType, int num) {
|
||||
Objects.requireNonNull(manaType, "The passed in ManaType can not be null");
|
||||
switch (manaType) {
|
||||
case GREEN:
|
||||
green = num;
|
||||
break;
|
||||
case RED:
|
||||
red = num;
|
||||
break;
|
||||
case BLACK:
|
||||
black = num;
|
||||
break;
|
||||
case BLUE:
|
||||
blue = num;
|
||||
break;
|
||||
case WHITE:
|
||||
white = num;
|
||||
break;
|
||||
case COLORLESS:
|
||||
colorless = num;
|
||||
break;
|
||||
case GENERIC:
|
||||
generic = num;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown manaType: " + manaType);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Mana} object with the passed in {@code num} of Red mana.
|
||||
* {@code num} can not be a negative value. Negative values will be logged
|
||||
|
|
@ -161,7 +190,7 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
|
|||
*
|
||||
* @param num value of Green mana to create.
|
||||
* @return a {@link Mana} object with the passed in {@code num} of Green
|
||||
* mana.
|
||||
* mana.
|
||||
*/
|
||||
public static Mana GreenMana(int num) {
|
||||
return new Mana(0, notNegative(num, "Green"), 0, 0, 0, 0, 0, 0);
|
||||
|
|
@ -174,7 +203,7 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
|
|||
*
|
||||
* @param num value of Blue mana to create.
|
||||
* @return a {@link Mana} object with the passed in {@code num} of Blue
|
||||
* mana.
|
||||
* mana.
|
||||
*/
|
||||
public static Mana BlueMana(int num) {
|
||||
return new Mana(0, 0, notNegative(num, "Blue"), 0, 0, 0, 0, 0);
|
||||
|
|
@ -187,7 +216,7 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
|
|||
*
|
||||
* @param num value of White mana to create.
|
||||
* @return a {@link Mana} object with the passed in {@code num} of White
|
||||
* mana.
|
||||
* mana.
|
||||
*/
|
||||
public static Mana WhiteMana(int num) {
|
||||
return new Mana(0, 0, 0, notNegative(num, "White"), 0, 0, 0, 0);
|
||||
|
|
@ -200,7 +229,7 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
|
|||
*
|
||||
* @param num value of Black mana to create.
|
||||
* @return a {@link Mana} object with the passed in {@code num} of Black
|
||||
* mana.
|
||||
* mana.
|
||||
*/
|
||||
public static Mana BlackMana(int num) {
|
||||
return new Mana(0, 0, 0, 0, notNegative(num, "Black"), 0, 0, 0);
|
||||
|
|
@ -213,7 +242,7 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
|
|||
*
|
||||
* @param num value of Generic mana to create.
|
||||
* @return a {@link Mana} object with the passed in {@code num} of Generic
|
||||
* mana.
|
||||
* mana.
|
||||
*/
|
||||
public static Mana GenericMana(int num) {
|
||||
return new Mana(0, 0, 0, 0, 0, notNegative(num, "Generic"), 0, 0);
|
||||
|
|
@ -226,7 +255,7 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
|
|||
*
|
||||
* @param num value of Colorless mana to create.
|
||||
* @return a {@link Mana} object with the passed in {@code num} of Colorless
|
||||
* mana.
|
||||
* mana.
|
||||
*/
|
||||
public static Mana ColorlessMana(int num) {
|
||||
return new Mana(0, 0, 0, 0, 0, 0, 0, notNegative(num, "Colorless"));
|
||||
|
|
@ -444,7 +473,7 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
|
|||
*
|
||||
* @param filter the colors of mana to return the count for.
|
||||
* @return the count of filtered mana provided by the passed in
|
||||
* {@link FilterMana}.
|
||||
* {@link FilterMana}.
|
||||
*/
|
||||
public int count(final FilterMana filter) {
|
||||
if (filter == null) {
|
||||
|
|
@ -898,10 +927,10 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
|
|||
* Returns if this objects mana contains any coloured mana the same as the
|
||||
* passed in {@link Mana}'s mana.
|
||||
*
|
||||
* @param mana the mana to check for
|
||||
* @param mana the mana to check for
|
||||
* @param includeColorless also check for colorless
|
||||
* @return true if this contains any of the same type of coloured mana that
|
||||
* this has
|
||||
* this has
|
||||
*/
|
||||
public boolean containsAny(final Mana mana, boolean includeColorless) {
|
||||
if (mana.black > 0 && this.black > 0) {
|
||||
|
|
@ -929,7 +958,7 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
|
|||
*
|
||||
* @param color the color to return the count for.
|
||||
* @return the total count of mana in this object as specified by the passed
|
||||
* in {@link ColoredManaSymbol}.
|
||||
* in {@link ColoredManaSymbol}.
|
||||
*/
|
||||
public int getColor(final ColoredManaSymbol color) {
|
||||
if (color == ColoredManaSymbol.G) {
|
||||
|
|
@ -956,7 +985,7 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
|
|||
*
|
||||
* @param manaType the type to return the count for.
|
||||
* @return the total count of mana in this object as specified by the passed
|
||||
* in {@link ManaType}.
|
||||
* in {@link ManaType}.
|
||||
*/
|
||||
public int get(final ManaType manaType) {
|
||||
switch (manaType) {
|
||||
|
|
@ -981,7 +1010,7 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
|
|||
* {@code amount} .
|
||||
*
|
||||
* @param manaType the color of the mana to set
|
||||
* @param amount the value to set the mana too
|
||||
* @param amount the value to set the mana too
|
||||
*/
|
||||
public void set(final ManaType manaType, final int amount) {
|
||||
switch (manaType) {
|
||||
|
|
@ -1056,7 +1085,7 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
|
|||
*
|
||||
* @param mana the mana to compare with
|
||||
* @return if this object has more than or equal mana to the passed in
|
||||
* {@link Mana}.
|
||||
* {@link Mana}.
|
||||
*/
|
||||
public boolean includesMana(Mana mana) {
|
||||
return this.green >= mana.green
|
||||
|
|
@ -1123,10 +1152,7 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
|
|||
}
|
||||
}
|
||||
if (lessMana.getColorless() > moreMana.getColorless()) {
|
||||
anyDiff -= lessMana.getColorless() - moreMana.getColorless();
|
||||
if (anyDiff < 0) {
|
||||
return null;
|
||||
}
|
||||
return null; // Any (color) can't produce colorless mana
|
||||
}
|
||||
if (lessMana.getAny() > moreMana.getAny()) {
|
||||
return null;
|
||||
|
|
@ -1217,10 +1243,10 @@ public class Mana implements Comparable<Mana>, Serializable, Copyable<Mana> {
|
|||
* is negative, it is logged and 0 is returned.
|
||||
*
|
||||
* @param value the value to check.
|
||||
* @param name the name of the value to check. Used to make logging of the
|
||||
* {@code value} easier
|
||||
* @param name the name of the value to check. Used to make logging of the
|
||||
* {@code value} easier
|
||||
* @return the {@code value} passed in, unless it is minus, in which case 0
|
||||
* is returned.
|
||||
* is returned.
|
||||
*/
|
||||
private static int notNegative(int value, final String name) {
|
||||
if (value < 0) {
|
||||
|
|
|
|||
|
|
@ -2,9 +2,12 @@
|
|||
package mage.abilities;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import mage.abilities.keyword.ProtectionAbility;
|
||||
import mage.abilities.mana.ActivatedManaAbilityImpl;
|
||||
import mage.constants.Zone;
|
||||
|
|
@ -255,7 +258,8 @@ public interface Abilities<T extends Ability> extends List<T>, Serializable {
|
|||
boolean containsAll(Abilities<T> abilities);
|
||||
|
||||
/**
|
||||
* Searches this set of abilities for the existence of the give class
|
||||
* Searches this set of abilities for the existence of the given class
|
||||
* Warning, it doesn't work with inherited classes (e.g. it's not equal to instanceOf command)
|
||||
*
|
||||
* @param classObject
|
||||
* @return True if the passed in class is also in this set of abilities.
|
||||
|
|
@ -271,4 +275,13 @@ public interface Abilities<T extends Ability> extends List<T>, Serializable {
|
|||
Abilities<T> copy();
|
||||
|
||||
String getValue();
|
||||
|
||||
@Deprecated // use permanent.removeAbility instead
|
||||
boolean remove(Object o);
|
||||
|
||||
@Deprecated // use permanent.removeAbility instead
|
||||
boolean removeAll(Collection<?> c);
|
||||
|
||||
@Deprecated // use permanent.removeAbility instead
|
||||
boolean removeIf(Predicate<? super T> filter);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,10 +73,14 @@ public class AbilitiesImpl<T extends Ability> extends ArrayList<T> implements Ab
|
|||
StringBuilder sbRule = threadLocalBuilder.get();
|
||||
for (Cost cost : ability.getCosts()) {
|
||||
if (cost.getText() != null && !cost.getText().isEmpty()) {
|
||||
String costText = cost.getText();
|
||||
if (!cost.getText().startsWith("As an additional cost")) {
|
||||
sbRule.append("As an additional cost to cast this spell, ");
|
||||
if (!costText.isEmpty()) {
|
||||
costText = Character.toLowerCase(costText.charAt(0)) + costText.substring(1);
|
||||
}
|
||||
}
|
||||
sbRule.append(cost.getText()).append(".<br>");
|
||||
sbRule.append(costText).append(".<br>");
|
||||
}
|
||||
}
|
||||
rules.add(sbRule.toString());
|
||||
|
|
@ -228,7 +232,8 @@ public class AbilitiesImpl<T extends Ability> extends ArrayList<T> implements Ab
|
|||
if (ability.getId().equals(test.getId())) {
|
||||
return true;
|
||||
}
|
||||
if (ability.getOriginalId().equals(test.getId())) {
|
||||
if (ability.getOriginalId().equals(test.getOriginalId())) {
|
||||
// on ability resolve: engine creates ability's copy and generates newId(), so you must use originalId to find that ability in card later
|
||||
return true;
|
||||
}
|
||||
if (ability instanceof MageSingleton && test instanceof MageSingleton && ability.getRule().equals(test.getRule())) {
|
||||
|
|
@ -239,7 +244,7 @@ public class AbilitiesImpl<T extends Ability> extends ArrayList<T> implements Ab
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean containsRule(T ability) {
|
||||
public boolean containsRule(T ability) { // TODO: remove
|
||||
return stream().anyMatch(rule -> rule.getRule().equals(ability.getRule()));
|
||||
}
|
||||
|
||||
|
|
@ -258,7 +263,7 @@ public class AbilitiesImpl<T extends Ability> extends ArrayList<T> implements Ab
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(UUID abilityId) {
|
||||
public boolean containsKey(UUID abilityId) { // TODO: remove
|
||||
return stream().anyMatch(ability -> abilityId.equals(ability.getId()));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import mage.watchers.Watcher;
|
|||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import mage.abilities.costs.common.TapSourceCost;
|
||||
|
||||
/**
|
||||
* Practically everything in the game is started from an Ability. This interface
|
||||
|
|
@ -190,13 +191,19 @@ public interface Ability extends Controllable, Serializable {
|
|||
|
||||
/**
|
||||
* Retrieves all targets that must be satisfied before this ability is put
|
||||
* onto the stack.
|
||||
* onto the stack. Warning, return targets from first/current mode only.
|
||||
*
|
||||
* @return All {@link Targets} that must be satisfied before this ability is
|
||||
* put onto the stack.
|
||||
*/
|
||||
Targets getTargets();
|
||||
|
||||
/**
|
||||
* Retrieves all selected targets, read only. Multi-modes return different targets.
|
||||
* Works on stack only (after real cast/activate)
|
||||
*/
|
||||
Targets getAllSelectedTargets();
|
||||
|
||||
/**
|
||||
* Retrieves the {@link Target} located at the 0th index in the
|
||||
* {@link Targets}. A call to the method is equivalent to
|
||||
|
|
@ -360,6 +367,19 @@ public interface Ability extends Controllable, Serializable {
|
|||
* @return
|
||||
*/
|
||||
boolean hasSourceObjectAbility(Game game, MageObject source, GameEvent event);
|
||||
|
||||
/**
|
||||
* Returns true if the ability has a tap itself in their costs
|
||||
* @return
|
||||
*/
|
||||
default boolean hasTapCost() {
|
||||
for (Cost cost : this.getCosts()) {
|
||||
if (cost instanceof TapSourceCost) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this ability has to be shown as topmost of all the rules
|
||||
|
|
@ -447,7 +467,7 @@ public interface Ability extends Controllable, Serializable {
|
|||
*
|
||||
* @param abilityWord
|
||||
*/
|
||||
void setAbilityWord(AbilityWord abilityWord);
|
||||
Ability setAbilityWord(AbilityWord abilityWord);
|
||||
|
||||
/**
|
||||
* Creates the message about the ability casting/triggering/activating to
|
||||
|
|
@ -522,4 +542,12 @@ public interface Ability extends Controllable, Serializable {
|
|||
Ability addCustomOutcome(Outcome customOutcome);
|
||||
|
||||
Outcome getCustomOutcome();
|
||||
|
||||
/**
|
||||
* For mtg's instances search, see rules example in 112.10b
|
||||
*
|
||||
* @param ability
|
||||
* @return
|
||||
*/
|
||||
boolean isSameInstance(Ability ability);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import mage.abilities.effects.ContinuousEffect;
|
|||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.Effects;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.ManaEffect;
|
||||
import mage.abilities.hint.Hint;
|
||||
import mage.abilities.mana.ActivatedManaAbilityImpl;
|
||||
import mage.cards.Card;
|
||||
|
|
@ -24,6 +25,7 @@ import mage.players.Player;
|
|||
import mage.target.Target;
|
||||
import mage.target.Targets;
|
||||
import mage.target.targetadjustment.TargetAdjuster;
|
||||
import mage.util.CardUtil;
|
||||
import mage.util.GameLog;
|
||||
import mage.util.ThreadLocalStringBuilder;
|
||||
import mage.watchers.Watcher;
|
||||
|
|
@ -33,6 +35,7 @@ import java.util.ArrayList;
|
|||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import mage.abilities.costs.common.TapSourceCost;
|
||||
|
||||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
|
|
@ -52,7 +55,7 @@ public abstract class AbilityImpl implements Ability {
|
|||
protected ManaCosts<ManaCost> manaCostsToPay;
|
||||
protected Costs<Cost> costs;
|
||||
protected Costs<Cost> optionalCosts;
|
||||
protected Modes modes; // access to it by GetModes only (it's can be override by some abilities)
|
||||
protected Modes modes; // access to it by GetModes only (it can be overridden by some abilities)
|
||||
protected Zone zone;
|
||||
protected String name;
|
||||
protected AbilityWord abilityWord;
|
||||
|
|
@ -63,7 +66,7 @@ public abstract class AbilityImpl implements Ability {
|
|||
protected boolean activated = false;
|
||||
protected boolean worksFaceDown = false;
|
||||
protected int sourceObjectZoneChangeCounter;
|
||||
protected List<Watcher> watchers = new ArrayList<>(); // access to it by GetWatchers only (it's can be override by some abilities)
|
||||
protected List<Watcher> watchers = new ArrayList<>(); // access to it by GetWatchers only (it can be overridden by some abilities)
|
||||
protected List<Ability> subAbilities = null;
|
||||
protected boolean canFizzle = true;
|
||||
protected TargetAdjuster targetAdjuster = null;
|
||||
|
|
@ -152,6 +155,9 @@ public abstract class AbilityImpl implements Ability {
|
|||
boolean result = true;
|
||||
//20100716 - 117.12
|
||||
if (checkIfClause(game)) {
|
||||
// Ability has started resolving. Fire event.
|
||||
// Used for abilities counting the number of resolutions like Ashling the Pilgrim.
|
||||
game.fireEvent(new GameEvent(GameEvent.EventType.RESOLVING_ABILITY, this.getOriginalId(), this.getSourceId(), this.getControllerId()));
|
||||
if (this instanceof TriggeredAbility) {
|
||||
for (UUID modeId : this.getModes().getSelectedModes()) {
|
||||
this.getModes().setActiveMode(modeId);
|
||||
|
|
@ -167,6 +173,9 @@ public abstract class AbilityImpl implements Ability {
|
|||
private boolean resolveMode(Game game) {
|
||||
boolean result = true;
|
||||
for (Effect effect : getEffects()) {
|
||||
if (game.inCheckPlayableState() && !(effect instanceof ManaEffect)) {
|
||||
continue; // Ignored non mana effects - see GameEvent.TAPPED_FOR_MANA
|
||||
}
|
||||
if (effect instanceof OneShotEffect) {
|
||||
boolean effectResult = effect.apply(game, this);
|
||||
result &= effectResult;
|
||||
|
|
@ -325,8 +334,9 @@ public abstract class AbilityImpl implements Ability {
|
|||
}
|
||||
if (!getTargets().isEmpty()) {
|
||||
Outcome outcome = getEffects().getOutcome(this);
|
||||
// only activated abilities can be canceled by user (not triggered)
|
||||
if (!getTargets().chooseTargets(outcome, this.controllerId, this, noMana, game, this instanceof ActivatedAbility)) {
|
||||
// only activated abilities can be canceled by human user (not triggered)
|
||||
boolean canCancel = this instanceof ActivatedAbility && controller.isHuman();
|
||||
if (!getTargets().chooseTargets(outcome, this.controllerId, this, noMana, game, canCancel)) {
|
||||
// was canceled during targer selection
|
||||
return false;
|
||||
}
|
||||
|
|
@ -349,8 +359,15 @@ public abstract class AbilityImpl implements Ability {
|
|||
return false;
|
||||
}
|
||||
|
||||
// fused spell contains 3 abilities (fused, left, right)
|
||||
// fused cost added to fused ability, so no need cost modification for other parts
|
||||
boolean needCostModification = true;
|
||||
if (CardUtil.isFusedPartAbility(this, game)) {
|
||||
needCostModification = false;
|
||||
}
|
||||
|
||||
//20101001 - 601.2e
|
||||
if (sourceObject != null) {
|
||||
if (needCostModification && sourceObject != null) {
|
||||
sourceObject.adjustCosts(this, game); // still needed
|
||||
game.getContinuousEffects().costModification(this, game);
|
||||
}
|
||||
|
|
@ -414,36 +431,28 @@ public abstract class AbilityImpl implements Ability {
|
|||
}
|
||||
}
|
||||
|
||||
boolean alternativeCostisUsed = false;
|
||||
boolean alternativeCostUsed = false;
|
||||
if (sourceObject != null && !(sourceObject instanceof Permanent)) {
|
||||
Abilities<Ability> abilities = null;
|
||||
if (sourceObject instanceof Card) {
|
||||
abilities = ((Card) sourceObject).getAbilities(game);
|
||||
} else {
|
||||
sourceObject.getAbilities();
|
||||
}
|
||||
|
||||
if (abilities != null) {
|
||||
for (Ability ability : abilities) {
|
||||
// if cast for noMana no Alternative costs are allowed
|
||||
if (canUseAlternativeCost && !noMana && ability instanceof AlternativeSourceCosts) {
|
||||
AlternativeSourceCosts alternativeSpellCosts = (AlternativeSourceCosts) ability;
|
||||
if (alternativeSpellCosts.isAvailable(this, game)) {
|
||||
if (alternativeSpellCosts.askToActivateAlternativeCosts(this, game)) {
|
||||
// only one alternative costs may be activated
|
||||
alternativeCostisUsed = true;
|
||||
break;
|
||||
}
|
||||
Abilities<Ability> abilities = CardUtil.getAbilities(sourceObject, game);
|
||||
for (Ability ability : abilities) {
|
||||
// if cast for noMana no Alternative costs are allowed
|
||||
if (canUseAlternativeCost && !noMana && ability instanceof AlternativeSourceCosts) {
|
||||
AlternativeSourceCosts alternativeSpellCosts = (AlternativeSourceCosts) ability;
|
||||
if (alternativeSpellCosts.isAvailable(this, game)) {
|
||||
if (alternativeSpellCosts.askToActivateAlternativeCosts(this, game)) {
|
||||
// only one alternative costs may be activated
|
||||
alternativeCostUsed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (canUseAdditionalCost && ability instanceof OptionalAdditionalSourceCosts) {
|
||||
((OptionalAdditionalSourceCosts) ability).addOptionalAdditionalCosts(this, game);
|
||||
}
|
||||
}
|
||||
if (canUseAdditionalCost && ability instanceof OptionalAdditionalSourceCosts) {
|
||||
((OptionalAdditionalSourceCosts) ability).addOptionalAdditionalCosts(this, game);
|
||||
}
|
||||
}
|
||||
|
||||
// controller specific alternate spell costs
|
||||
if (canUseAlternativeCost && !noMana && !alternativeCostisUsed) {
|
||||
if (canUseAlternativeCost && !noMana && !alternativeCostUsed) {
|
||||
if (this.getAbilityType() == AbilityType.SPELL
|
||||
// 117.9a Only one alternative cost can be applied to any one spell as it's being cast.
|
||||
// So an alternate spell ability can't be paid with Omniscience
|
||||
|
|
@ -452,7 +461,7 @@ public abstract class AbilityImpl implements Ability {
|
|||
if (alternativeSourceCosts.isAvailable(this, game)) {
|
||||
if (alternativeSourceCosts.askToActivateAlternativeCosts(this, game)) {
|
||||
// only one alternative costs may be activated
|
||||
alternativeCostisUsed = true;
|
||||
alternativeCostUsed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -461,7 +470,7 @@ public abstract class AbilityImpl implements Ability {
|
|||
}
|
||||
}
|
||||
|
||||
return alternativeCostisUsed;
|
||||
return alternativeCostUsed;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -706,7 +715,6 @@ public abstract class AbilityImpl implements Ability {
|
|||
|
||||
@Override
|
||||
public void addWatcher(Watcher watcher) {
|
||||
|
||||
watcher.setSourceId(this.sourceId);
|
||||
watcher.setControllerId(this.controllerId);
|
||||
getWatchers().add(watcher);
|
||||
|
|
@ -766,7 +774,7 @@ public abstract class AbilityImpl implements Ability {
|
|||
if (ruleStart.length() > 1) {
|
||||
String end = ruleStart.substring(ruleStart.length() - 2).trim();
|
||||
if (end.isEmpty() || end.equals(":") || end.equals(".")) {
|
||||
rule = ruleStart + Character.toUpperCase(text.charAt(0)) + text.substring(1);
|
||||
rule = ruleStart + CardUtil.getTextWithFirstCharUpperCase(text);
|
||||
} else {
|
||||
rule = ruleStart + text;
|
||||
}
|
||||
|
|
@ -844,6 +852,18 @@ public abstract class AbilityImpl implements Ability {
|
|||
return new Targets();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Targets getAllSelectedTargets() {
|
||||
Targets res = new Targets();
|
||||
for (UUID modeId : this.getModes().getSelectedModes()) {
|
||||
Mode mode = this.getModes().get(modeId);
|
||||
if (mode != null) {
|
||||
res.addAll(mode.getTargets());
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getFirstTarget() {
|
||||
return getTargets().getFirstTarget();
|
||||
|
|
@ -935,6 +955,10 @@ public abstract class AbilityImpl implements Ability {
|
|||
|
||||
@Override
|
||||
public boolean hasSourceObjectAbility(Game game, MageObject source, GameEvent event) {
|
||||
// if source object have this ability
|
||||
// uses for ability.isInUseableZone
|
||||
// replacement and other continues effects can be without source, but active (must return true)
|
||||
|
||||
MageObject object = source;
|
||||
// for singleton abilities like Flying we can't rely on abilities' source because it's only once in continuous effects
|
||||
// so will use the sourceId of the object itself that came as a parameter if it is not null
|
||||
|
|
@ -946,16 +970,10 @@ public abstract class AbilityImpl implements Ability {
|
|||
}
|
||||
if (object != null) {
|
||||
if (object instanceof Permanent) {
|
||||
if (!((Permanent) object).getAbilities(game).contains(this)) {
|
||||
return false;
|
||||
}
|
||||
return ((Permanent) object).isPhasedIn();
|
||||
} else if (object instanceof Card) {
|
||||
return ((Card) object).getAbilities(game).contains(this);
|
||||
} else if (!object.getAbilities().contains(this)) { // not sure which object it can still be
|
||||
// check if it's an ability that is temporary gained to a card
|
||||
Abilities<Ability> otherAbilities = game.getState().getAllOtherAbilities(this.getSourceId());
|
||||
return otherAbilities != null && otherAbilities.contains(this);
|
||||
return object.hasAbility(this, game) && ((Permanent) object).isPhasedIn();
|
||||
} else {
|
||||
// cards and other objects
|
||||
return object.hasAbility(this, game);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
@ -1005,8 +1023,9 @@ public abstract class AbilityImpl implements Ability {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void setAbilityWord(AbilityWord abilityWord) {
|
||||
public Ability setAbilityWord(AbilityWord abilityWord) {
|
||||
this.abilityWord = abilityWord;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -1115,6 +1134,7 @@ public abstract class AbilityImpl implements Ability {
|
|||
String usedVerb = null;
|
||||
for (Target target : targets) {
|
||||
if (!target.getTargets().isEmpty()) {
|
||||
String targetHintInfo = target.getChooseHint() == null ? "" : " (" + target.getChooseHint() + ")";
|
||||
if (!target.isNotTarget()) {
|
||||
if (usedVerb == null || usedVerb.equals(" choosing ")) {
|
||||
usedVerb = " targeting ";
|
||||
|
|
@ -1125,6 +1145,7 @@ public abstract class AbilityImpl implements Ability {
|
|||
sb.append(usedVerb);
|
||||
}
|
||||
sb.append(target.getTargetedName(game));
|
||||
sb.append(targetHintInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1223,6 +1244,17 @@ public abstract class AbilityImpl implements Ability {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamic cost modification for ability.<br>
|
||||
* Example: if it need stack related info (like real targets) then must
|
||||
* check two states (game.inCheckPlayableState): <br>
|
||||
* 1. In playable state it must check all possible use cases (e.g. allow to
|
||||
* reduce on any available target and modes) <br>
|
||||
* 2. In real cast state it must check current use case (e.g. real selected
|
||||
* targets and modes)
|
||||
*
|
||||
* @param costAdjuster
|
||||
*/
|
||||
@Override
|
||||
public void setCostAdjuster(CostAdjuster costAdjuster) {
|
||||
this.costAdjuster = costAdjuster;
|
||||
|
|
@ -1261,4 +1293,17 @@ public abstract class AbilityImpl implements Ability {
|
|||
public Outcome getCustomOutcome() {
|
||||
return this.customOutcome;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameInstance(Ability ability) {
|
||||
// same instance (by mtg rules) = same object, ID or class+text (you can't check class only cause it can be different by params/text)
|
||||
if (ability == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (this == ability)
|
||||
|| (this.getId().equals(ability.getId()))
|
||||
|| (this.getOriginalId().equals(ability.getOriginalId()))
|
||||
|| (this.getClass() == ability.getClass() && this.getRule(true).equals(ability.getRule(true)));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,19 @@
|
|||
package mage.abilities;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageObject;
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.mana.ManaOptions;
|
||||
import mage.constants.TargetController;
|
||||
import mage.game.Game;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public interface ActivatedAbility extends Ability {
|
||||
|
||||
final public class ActivationStatus {
|
||||
final class ActivationStatus {
|
||||
|
||||
private final boolean canActivate;
|
||||
private final MageObjectReference permittingObject;
|
||||
|
|
@ -34,8 +35,13 @@ public interface ActivatedAbility extends Ability {
|
|||
return new ActivationStatus(false, null);
|
||||
}
|
||||
|
||||
public static ActivationStatus getTrue() {
|
||||
return new ActivationStatus(true, null);
|
||||
/**
|
||||
* @param permittingObjectAbility card or permanent that allows to activate current ability
|
||||
*/
|
||||
public static ActivationStatus getTrue(Ability permittingObjectAbility, Game game) {
|
||||
MageObject object = permittingObjectAbility == null ? null : permittingObjectAbility.getSourceObject(game);
|
||||
MageObjectReference ref = object == null ? null : new MageObjectReference(object, game);
|
||||
return new ActivationStatus(true, ref);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package mage.abilities;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageObject;
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.condition.Condition;
|
||||
|
|
@ -12,11 +11,7 @@ import mage.abilities.effects.Effect;
|
|||
import mage.abilities.effects.Effects;
|
||||
import mage.abilities.mana.ManaOptions;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.AbilityType;
|
||||
import mage.constants.AsThoughEffectType;
|
||||
import mage.constants.TargetController;
|
||||
import mage.constants.TimingRule;
|
||||
import mage.constants.Zone;
|
||||
import mage.constants.*;
|
||||
import mage.game.Game;
|
||||
import mage.game.command.Commander;
|
||||
import mage.game.command.Emblem;
|
||||
|
|
@ -24,8 +19,9 @@ import mage.game.command.Plane;
|
|||
import mage.game.permanent.Permanent;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public abstract class ActivatedAbilityImpl extends AbilityImpl implements ActivatedAbility {
|
||||
|
|
@ -148,6 +144,34 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa
|
|||
@Override
|
||||
public abstract ActivatedAbilityImpl copy();
|
||||
|
||||
protected boolean checkTargetController(UUID playerId, Game game) {
|
||||
switch (mayActivate) {
|
||||
case ANY:
|
||||
return true;
|
||||
case ACTIVE:
|
||||
return game.getActivePlayerId() == playerId;
|
||||
case NOT_YOU:
|
||||
return !controlsAbility(playerId, game);
|
||||
case TEAM:
|
||||
return !game.getPlayer(controllerId).hasOpponent(playerId, game);
|
||||
case OPPONENT:
|
||||
return game.getPlayer(controllerId).hasOpponent(playerId, game);
|
||||
case OWNER:
|
||||
Permanent permanent = game.getPermanent(getSourceId());
|
||||
return permanent != null && permanent.isOwnedBy(playerId);
|
||||
case YOU:
|
||||
return controlsAbility(playerId, game);
|
||||
case CONTROLLER_ATTACHED_TO:
|
||||
Permanent enchantment = game.getPermanent(getSourceId());
|
||||
if (enchantment == null || enchantment.getAttachedTo() == null) {
|
||||
return false;
|
||||
}
|
||||
Permanent enchanted = game.getPermanent(enchantment.getAttachedTo());
|
||||
return enchanted != null && enchanted.isControlledBy(playerId);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActivationStatus canActivate(UUID playerId, Game game) {
|
||||
//20091005 - 602.2
|
||||
|
|
@ -156,49 +180,8 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa
|
|||
|| condition.apply(game, this)))) {
|
||||
return ActivationStatus.getFalse();
|
||||
}
|
||||
switch (mayActivate) {
|
||||
case ANY:
|
||||
break;
|
||||
case ACTIVE:
|
||||
if (game.getActivePlayerId() != playerId) {
|
||||
return ActivationStatus.getFalse();
|
||||
}
|
||||
break;
|
||||
case NOT_YOU:
|
||||
if (controlsAbility(playerId, game)) {
|
||||
return ActivationStatus.getFalse();
|
||||
}
|
||||
break;
|
||||
case TEAM:
|
||||
if (game.getPlayer(controllerId).hasOpponent(playerId, game)) {
|
||||
return ActivationStatus.getFalse();
|
||||
}
|
||||
break;
|
||||
case OPPONENT:
|
||||
if (!game.getPlayer(controllerId).hasOpponent(playerId, game)) {
|
||||
return ActivationStatus.getFalse();
|
||||
}
|
||||
break;
|
||||
case OWNER:
|
||||
Permanent permanent = game.getPermanent(getSourceId());
|
||||
if (!permanent.isOwnedBy(playerId)) {
|
||||
return ActivationStatus.getFalse();
|
||||
}
|
||||
break;
|
||||
case YOU:
|
||||
if (!controlsAbility(playerId, game)) {
|
||||
return ActivationStatus.getFalse();
|
||||
}
|
||||
break;
|
||||
case CONTROLLER_ATTACHED_TO:
|
||||
Permanent enchantment = game.getPermanent(getSourceId());
|
||||
if (enchantment != null && enchantment.getAttachedTo() != null) {
|
||||
Permanent enchanted = game.getPermanent(enchantment.getAttachedTo());
|
||||
if (enchanted != null && enchanted.isControlledBy(playerId)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ActivationStatus.getFalse();
|
||||
if (!this.checkTargetController(playerId, game)) {
|
||||
return ActivationStatus.getFalse();
|
||||
}
|
||||
//20091005 - 602.5d/602.5e
|
||||
MageObjectReference permittingObject = game.getContinuousEffects()
|
||||
|
|
@ -227,17 +210,16 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa
|
|||
protected boolean controlsAbility(UUID playerId, Game game) {
|
||||
if (this.controllerId != null && this.controllerId.equals(playerId)) {
|
||||
return true;
|
||||
} else {
|
||||
MageObject mageObject = game.getObject(this.sourceId);
|
||||
if (mageObject instanceof Emblem) {
|
||||
return ((Emblem) mageObject).isControlledBy(playerId);
|
||||
} else if (mageObject instanceof Plane) {
|
||||
return ((Plane) mageObject).isControlledBy(playerId);
|
||||
} else if (mageObject instanceof Commander) {
|
||||
return ((Commander) mageObject).isControlledBy(playerId);
|
||||
} else if (game.getState().getZone(this.sourceId) != Zone.BATTLEFIELD) {
|
||||
return ((Card) mageObject).isOwnedBy(playerId);
|
||||
}
|
||||
}
|
||||
MageObject mageObject = game.getObject(this.sourceId);
|
||||
if (mageObject instanceof Emblem) {
|
||||
return ((Emblem) mageObject).isControlledBy(playerId);
|
||||
} else if (mageObject instanceof Plane) {
|
||||
return ((Plane) mageObject).isControlledBy(playerId);
|
||||
} else if (mageObject instanceof Commander) {
|
||||
return ((Commander) mageObject).isControlledBy(playerId);
|
||||
} else if (game.getState().getZone(this.sourceId) != Zone.BATTLEFIELD) {
|
||||
return ((Card) mageObject).isOwnedBy(playerId);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -271,22 +253,20 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa
|
|||
|
||||
@Override
|
||||
public boolean activate(Game game, boolean noMana) {
|
||||
if (hasMoreActivationsThisTurn(game)) {
|
||||
if (super.activate(game, noMana)) {
|
||||
ActivationInfo activationInfo = getActivationInfo(game);
|
||||
if (activationInfo == null) {
|
||||
activationInfo = new ActivationInfo(game.getTurnNum(), 1);
|
||||
} else if (activationInfo.turnNum != game.getTurnNum()) {
|
||||
activationInfo.turnNum = game.getTurnNum();
|
||||
activationInfo.activationCounter = 1;
|
||||
} else {
|
||||
activationInfo.activationCounter++;
|
||||
}
|
||||
setActivationInfo(activationInfo, game);
|
||||
return true;
|
||||
}
|
||||
if (!hasMoreActivationsThisTurn(game) || !super.activate(game, noMana)) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
ActivationInfo activationInfo = getActivationInfo(game);
|
||||
if (activationInfo == null) {
|
||||
activationInfo = new ActivationInfo(game.getTurnNum(), 1);
|
||||
} else if (activationInfo.turnNum != game.getTurnNum()) {
|
||||
activationInfo.turnNum = game.getTurnNum();
|
||||
activationInfo.activationCounter = 1;
|
||||
} else {
|
||||
activationInfo.activationCounter++;
|
||||
}
|
||||
setActivationInfo(activationInfo, game);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -1,62 +1,62 @@
|
|||
|
||||
package mage.abilities;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
* The ActivationInfo class holds the information how often an ability of an
|
||||
* object was activated during a turn. It handles the check, if the object is
|
||||
* still the same, so for example if a permanent left battlefield and returns,
|
||||
* the counting of activations happens for each object.
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class ActivationInfo {
|
||||
|
||||
protected int turnNum = 0;
|
||||
protected int activationCounter = 0;
|
||||
protected String key;
|
||||
|
||||
public static ActivationInfo getInstance(Game game, UUID sourceId) {
|
||||
return ActivationInfo.getInstance(game, sourceId, game.getState().getZoneChangeCounter(sourceId));
|
||||
}
|
||||
|
||||
public static ActivationInfo getInstance(Game game, UUID sourceId, int zoneChangeCounter) {
|
||||
String key = "ActivationInfo" + sourceId.toString() + zoneChangeCounter;
|
||||
Integer activations = (Integer) game.getState().getValue(key);
|
||||
ActivationInfo activationInfo;
|
||||
if (activations != null) {
|
||||
Integer turnNum = (Integer) game.getState().getValue(key + 'T');
|
||||
activationInfo = new ActivationInfo(game, turnNum, activations);
|
||||
} else {
|
||||
activationInfo = new ActivationInfo(game, game.getTurnNum(), 0);
|
||||
}
|
||||
activationInfo.setKey(key);
|
||||
return activationInfo;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
protected ActivationInfo(Game game, int turnNum, int activationCounter) {
|
||||
this.turnNum = turnNum;
|
||||
this.activationCounter = activationCounter;
|
||||
}
|
||||
|
||||
public void addActivation(Game game) {
|
||||
if (game.getTurnNum() != turnNum) {
|
||||
activationCounter = 1;
|
||||
turnNum = game.getTurnNum();
|
||||
} else {
|
||||
activationCounter++;
|
||||
}
|
||||
game.getState().setValue(key, activationCounter);
|
||||
game.getState().setValue(key + 'T', turnNum);
|
||||
}
|
||||
|
||||
public int getActivationCounter() {
|
||||
return activationCounter;
|
||||
}
|
||||
}
|
||||
|
||||
package mage.abilities;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
* The ActivationInfo class holds the information how often an ability of an
|
||||
* object was activated during a turn. It handles the check, if the object is
|
||||
* still the same, so for example if a permanent left battlefield and returns,
|
||||
* the counting of activations happens for each object.
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class ActivationInfo {
|
||||
|
||||
protected int turnNum = 0;
|
||||
protected int activationCounter = 0;
|
||||
protected String key;
|
||||
|
||||
public static ActivationInfo getInstance(Game game, UUID sourceId) {
|
||||
return ActivationInfo.getInstance(game, sourceId, game.getState().getZoneChangeCounter(sourceId));
|
||||
}
|
||||
|
||||
public static ActivationInfo getInstance(Game game, UUID sourceId, int zoneChangeCounter) {
|
||||
String key = "ActivationInfo" + sourceId.toString() + zoneChangeCounter;
|
||||
Integer activations = (Integer) game.getState().getValue(key);
|
||||
ActivationInfo activationInfo;
|
||||
if (activations != null) {
|
||||
Integer turnNum = (Integer) game.getState().getValue(key + 'T');
|
||||
activationInfo = new ActivationInfo(game, turnNum, activations);
|
||||
} else {
|
||||
activationInfo = new ActivationInfo(game, game.getTurnNum(), 0);
|
||||
}
|
||||
activationInfo.setKey(key);
|
||||
return activationInfo;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
protected ActivationInfo(Game game, int turnNum, int activationCounter) {
|
||||
this.turnNum = turnNum;
|
||||
this.activationCounter = activationCounter;
|
||||
}
|
||||
|
||||
public void addActivation(Game game) {
|
||||
if (game.getTurnNum() != turnNum) {
|
||||
activationCounter = 1;
|
||||
turnNum = game.getTurnNum();
|
||||
} else {
|
||||
activationCounter++;
|
||||
}
|
||||
game.getState().setValue(key, activationCounter);
|
||||
game.getState().setValue(key + 'T', turnNum);
|
||||
}
|
||||
|
||||
public int getActivationCounter() {
|
||||
return activationCounter;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,9 +23,9 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
|||
public static final UUID CHOOSE_OPTION_CANCEL_ID = UUID.fromString("0125bd0c-5610-4eba-bc80-fc6d0a7b9de6");
|
||||
|
||||
private Mode currentMode; // the current mode of the selected modes
|
||||
private final List<UUID> selectedModes = new ArrayList<>(); // all selected modes (this + duplicate)
|
||||
private final Map<UUID, Mode> duplicateModes = new LinkedHashMap<>(); // for 2x selects: copy mode and put it to duplicate list
|
||||
private final Map<UUID, UUID> duplicateToOriginalModeRefs = new LinkedHashMap<>(); // for 2x selects: stores ref from duplicate to original mode
|
||||
private final List<UUID> selectedModes = new ArrayList<>(); // all selected modes (this + duplicate), use getSelectedModes all the time to keep modes order
|
||||
private final Map<UUID, Mode> selectedDuplicateModes = new LinkedHashMap<>(); // for 2x selects: copy mode and put it to duplicate list
|
||||
private final Map<UUID, UUID> selectedDuplicateToOriginalModeRefs = new LinkedHashMap<>(); // for 2x selects: stores ref from duplicate to original mode
|
||||
|
||||
private int minModes;
|
||||
private int maxModes;
|
||||
|
|
@ -52,10 +52,10 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
|||
for (Map.Entry<UUID, Mode> entry : modes.entrySet()) {
|
||||
this.put(entry.getKey(), entry.getValue().copy());
|
||||
}
|
||||
for (Map.Entry<UUID, Mode> entry : modes.duplicateModes.entrySet()) {
|
||||
duplicateModes.put(entry.getKey(), entry.getValue().copy());
|
||||
for (Map.Entry<UUID, Mode> entry : modes.selectedDuplicateModes.entrySet()) {
|
||||
selectedDuplicateModes.put(entry.getKey(), entry.getValue().copy());
|
||||
}
|
||||
duplicateToOriginalModeRefs.putAll(modes.duplicateToOriginalModeRefs);
|
||||
selectedDuplicateToOriginalModeRefs.putAll(modes.selectedDuplicateToOriginalModeRefs);
|
||||
|
||||
this.minModes = modes.minModes;
|
||||
this.maxModes = modes.maxModes;
|
||||
|
|
@ -72,7 +72,7 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
|||
if (modes.getSelectedModes().isEmpty()) {
|
||||
this.currentMode = values().iterator().next();
|
||||
} else {
|
||||
this.currentMode = get(modes.getMode().getId());
|
||||
this.currentMode = get(modes.getMode().getId()); // need fix?
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -84,7 +84,7 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
|||
public Mode get(Object key) {
|
||||
Mode modeToGet = super.get(key);
|
||||
if (modeToGet == null && eachModeMoreThanOnce) {
|
||||
modeToGet = duplicateModes.get(key);
|
||||
modeToGet = selectedDuplicateModes.get(key);
|
||||
}
|
||||
return modeToGet;
|
||||
}
|
||||
|
|
@ -103,7 +103,7 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
|||
public UUID getModeId(int index) {
|
||||
int idx = 0;
|
||||
if (eachModeMoreThanOnce) {
|
||||
for (UUID modeId : this.selectedModes) {
|
||||
for (UUID modeId : this.getSelectedModes()) {
|
||||
idx++;
|
||||
if (idx == index) {
|
||||
return modeId;
|
||||
|
|
@ -121,7 +121,25 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
|||
}
|
||||
|
||||
public List<UUID> getSelectedModes() {
|
||||
return selectedModes;
|
||||
// sorted as original modes
|
||||
List<UUID> res = new ArrayList<>();
|
||||
for (Mode mode : this.values()) {
|
||||
for (UUID selectedId : this.selectedModes) {
|
||||
// selectedModes contains original mode and 2+ selected as duplicates (new modes)
|
||||
UUID selectedOriginalId = this.selectedDuplicateToOriginalModeRefs.get(selectedId);
|
||||
if (Objects.equals(mode.getId(), selectedId)
|
||||
|| Objects.equals(mode.getId(), selectedOriginalId)) {
|
||||
res.add(selectedId);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public void clearSelectedModes() {
|
||||
this.selectedModes.clear();
|
||||
this.selectedDuplicateModes.clear();
|
||||
this.selectedDuplicateToOriginalModeRefs.clear();
|
||||
}
|
||||
|
||||
public int getSelectedStats(UUID modeId) {
|
||||
|
|
@ -133,14 +151,14 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
|||
|
||||
// multiple select (all 2x select generate new duplicate mode)
|
||||
UUID originalId;
|
||||
if (this.duplicateModes.containsKey(modeId)) {
|
||||
if (this.selectedDuplicateModes.containsKey(modeId)) {
|
||||
// modeId is duplicate
|
||||
originalId = this.duplicateToOriginalModeRefs.get(modeId);
|
||||
originalId = this.selectedDuplicateToOriginalModeRefs.get(modeId);
|
||||
} else {
|
||||
// modeId is original
|
||||
originalId = modeId;
|
||||
}
|
||||
for (UUID id : this.duplicateToOriginalModeRefs.values()) {
|
||||
for (UUID id : this.selectedDuplicateToOriginalModeRefs.values()) {
|
||||
if (id.equals(originalId)) {
|
||||
count++;
|
||||
}
|
||||
|
|
@ -183,9 +201,7 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
|||
}
|
||||
|
||||
public void setActiveMode(Mode mode) {
|
||||
if (selectedModes.contains(mode.getId())) {
|
||||
this.currentMode = mode;
|
||||
}
|
||||
setActiveMode(mode.getId());
|
||||
}
|
||||
|
||||
public void setActiveMode(UUID modeId) {
|
||||
|
|
@ -200,9 +216,7 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
|||
|
||||
public boolean choose(Game game, Ability source) {
|
||||
if (this.size() > 1) {
|
||||
this.selectedModes.clear();
|
||||
this.duplicateModes.clear();
|
||||
this.duplicateToOriginalModeRefs.clear();
|
||||
this.clearSelectedModes();
|
||||
if (this.isRandom) {
|
||||
List<Mode> modes = getAvailableModes(source, game);
|
||||
this.addSelectedMode(modes.get(RandomUtil.nextInt(modes.size())).getId());
|
||||
|
|
@ -230,7 +244,7 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
|||
}
|
||||
}
|
||||
if (isEachModeOnlyOnce()) {
|
||||
setAlreadySelectedModes(selectedModes, source, game);
|
||||
setAlreadySelectedModes(source, game);
|
||||
}
|
||||
return !selectedModes.isEmpty();
|
||||
}
|
||||
|
|
@ -274,7 +288,7 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
|||
Mode choice = player.chooseMode(this, source, game);
|
||||
if (choice == null) {
|
||||
if (isEachModeOnlyOnce()) {
|
||||
setAlreadySelectedModes(selectedModes, source, game);
|
||||
setAlreadySelectedModes(source, game);
|
||||
}
|
||||
return this.selectedModes.size() >= this.getMinModes();
|
||||
}
|
||||
|
|
@ -284,12 +298,13 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
|||
}
|
||||
}
|
||||
if (isEachModeOnlyOnce()) {
|
||||
setAlreadySelectedModes(selectedModes, source, game);
|
||||
setAlreadySelectedModes(source, game);
|
||||
}
|
||||
return true;
|
||||
} else { // only one mode
|
||||
} else {
|
||||
// only one mode available
|
||||
if (currentMode == null) {
|
||||
this.selectedModes.clear();
|
||||
this.clearSelectedModes();
|
||||
Mode mode = this.values().iterator().next();
|
||||
this.addSelectedMode(mode.getId());
|
||||
this.setActiveMode(mode);
|
||||
|
|
@ -301,12 +316,11 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
|||
/**
|
||||
* Saves the already selected modes to the state value
|
||||
*
|
||||
* @param selectedModes
|
||||
* @param source
|
||||
* @param game
|
||||
*/
|
||||
private void setAlreadySelectedModes(List<UUID> selectedModes, Ability source, Game game) {
|
||||
for (UUID modeId : selectedModes) {
|
||||
private void setAlreadySelectedModes(Ability source, Game game) {
|
||||
for (UUID modeId : getSelectedModes()) {
|
||||
String key = getKey(source, game, modeId);
|
||||
game.getState().setValue(key, true);
|
||||
}
|
||||
|
|
@ -318,19 +332,29 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
|||
*
|
||||
* @param modeId
|
||||
*/
|
||||
private void addSelectedMode(UUID modeId) {
|
||||
public void addSelectedMode(UUID modeId) {
|
||||
if (!this.containsKey(modeId)) {
|
||||
throw new IllegalArgumentException("Unknown modeId to select");
|
||||
}
|
||||
|
||||
if (selectedModes.contains(modeId) && eachModeMoreThanOnce) {
|
||||
Mode duplicateMode = get(modeId).copy();
|
||||
UUID originalId = modeId;
|
||||
duplicateMode.setRandomId();
|
||||
modeId = duplicateMode.getId();
|
||||
duplicateModes.put(modeId, duplicateMode);
|
||||
duplicateToOriginalModeRefs.put(duplicateMode.getId(), originalId);
|
||||
selectedDuplicateModes.put(modeId, duplicateMode);
|
||||
selectedDuplicateToOriginalModeRefs.put(duplicateMode.getId(), originalId);
|
||||
|
||||
}
|
||||
this.selectedModes.add(modeId);
|
||||
}
|
||||
|
||||
public void removeSelectedMode(UUID modeId) {
|
||||
this.selectedModes.remove(modeId);
|
||||
this.selectedDuplicateModes.remove(modeId);
|
||||
this.selectedDuplicateToOriginalModeRefs.remove(modeId);
|
||||
}
|
||||
|
||||
// The already once selected modes for a modal card are stored as a state value
|
||||
// That's important for modal abilities with modes that can only selected once while the object stays in its zone
|
||||
@SuppressWarnings("unchecked")
|
||||
|
|
|
|||
|
|
@ -1,18 +1,22 @@
|
|||
|
||||
|
||||
package mage.abilities;
|
||||
|
||||
import mage.abilities.costs.mana.AlternateManaPaymentAbility;
|
||||
import mage.abilities.costs.mana.ManaCost;
|
||||
import mage.abilities.mana.ManaOptions;
|
||||
import mage.constants.AbilityType;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.stack.Spell;
|
||||
import mage.game.stack.StackObject;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
* @author BetaSteward_at_googlemail.com, JayDi85
|
||||
*/
|
||||
public abstract class SpecialAction extends ActivatedAbilityImpl {
|
||||
|
||||
private boolean manaAction;
|
||||
private final AlternateManaPaymentAbility manaAbility; // mana actions generates on every pay cycle, no need to copy it
|
||||
protected ManaCost unpaidMana;
|
||||
|
||||
public SpecialAction() {
|
||||
|
|
@ -20,22 +24,23 @@ public abstract class SpecialAction extends ActivatedAbilityImpl {
|
|||
}
|
||||
|
||||
public SpecialAction(Zone zone) {
|
||||
this(zone, false);
|
||||
this(zone, null);
|
||||
}
|
||||
public SpecialAction(Zone zone, boolean manaAction) {
|
||||
|
||||
public SpecialAction(Zone zone, AlternateManaPaymentAbility manaAbility) {
|
||||
super(AbilityType.SPECIAL_ACTION, zone);
|
||||
this.usesStack = false;
|
||||
this.manaAction = manaAction;
|
||||
this.manaAbility = manaAbility;
|
||||
}
|
||||
|
||||
public SpecialAction(final SpecialAction action) {
|
||||
super(action);
|
||||
this.manaAction = action.manaAction;
|
||||
this.unpaidMana = action.unpaidMana;
|
||||
this.manaAbility = action.manaAbility;
|
||||
}
|
||||
|
||||
public boolean isManaAction() {
|
||||
return manaAction;
|
||||
return manaAbility != null;
|
||||
}
|
||||
|
||||
public void setUnpaidMana(ManaCost manaCost) {
|
||||
|
|
@ -45,4 +50,29 @@ public abstract class SpecialAction extends ActivatedAbilityImpl {
|
|||
public ManaCost getUnpaidMana() {
|
||||
return unpaidMana;
|
||||
}
|
||||
|
||||
public ManaOptions getManaOptions(Ability source, Game game, ManaCost unpaid) {
|
||||
if (manaAbility != null) {
|
||||
return manaAbility.getManaOptions(source, game, unpaid);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActivationStatus canActivate(UUID playerId, Game game) {
|
||||
if (isManaAction()) {
|
||||
// limit play mana abilities by steps
|
||||
int currentStepOrder = 0;
|
||||
if (!game.getStack().isEmpty()) {
|
||||
StackObject stackObject = game.getStack().getFirst();
|
||||
if (stackObject instanceof Spell) {
|
||||
currentStepOrder = ((Spell) stackObject).getCurrentActivatingManaAbilitiesStep().getStepOrder();
|
||||
}
|
||||
}
|
||||
if (currentStepOrder > manaAbility.useOnActivationManaAbilityStep().getStepOrder()) {
|
||||
return ActivationStatus.getFalse();
|
||||
}
|
||||
}
|
||||
return super.canActivate(playerId, game);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
package mage.abilities;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import mage.MageObject;
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.costs.Cost;
|
||||
|
|
@ -14,9 +12,12 @@ import mage.cards.SplitCard;
|
|||
import mage.constants.*;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.stack.Spell;
|
||||
import mage.players.Player;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import javax.naming.directory.InvalidAttributesException;
|
||||
|
||||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
|
|
@ -70,7 +71,7 @@ public class SpellAbility extends ActivatedAbilityImpl {
|
|||
}
|
||||
return null != game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.CAST_AS_INSTANT, this, playerId, game) // check this first to allow Offering in main phase
|
||||
|| timing == TimingRule.INSTANT
|
||||
|| object.hasAbility(FlashAbility.getInstance().getId(), game)
|
||||
|| object.hasAbility(FlashAbility.getInstance(), game)
|
||||
|| game.canPlaySorcery(playerId);
|
||||
}
|
||||
|
||||
|
|
@ -104,12 +105,16 @@ public class SpellAbility extends ActivatedAbilityImpl {
|
|||
return ActivationStatus.getFalse();
|
||||
}
|
||||
}
|
||||
if (costs.canPay(this, sourceId, controllerId, game)) {
|
||||
if (costs.canPay(this, sourceId, playerId, game)) {
|
||||
if (getSpellAbilityType() == SpellAbilityType.SPLIT_FUSED) {
|
||||
SplitCard splitCard = (SplitCard) game.getCard(getSourceId());
|
||||
if (splitCard != null) {
|
||||
return new ActivationStatus(splitCard.getLeftHalfCard().getSpellAbility().canChooseTarget(game)
|
||||
&& splitCard.getRightHalfCard().getSpellAbility().canChooseTarget(game), null);
|
||||
// fused can be called from hand only, so not permitting object allows or other zones checks
|
||||
// see https://www.mtgsalvation.com/forums/magic-fundamentals/magic-rulings/magic-rulings-archives/251926-snapcaster-mage-and-fuse
|
||||
if (game.getState().getZone(splitCard.getId()) == Zone.HAND) {
|
||||
return new ActivationStatus(splitCard.getLeftHalfCard().getSpellAbility().canChooseTarget(game)
|
||||
&& splitCard.getRightHalfCard().getSpellAbility().canChooseTarget(game), null);
|
||||
}
|
||||
}
|
||||
return ActivationStatus.getFalse();
|
||||
|
||||
|
|
@ -140,9 +145,13 @@ public class SpellAbility extends ActivatedAbilityImpl {
|
|||
this.costs.clearPaid();
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.name;
|
||||
return getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -227,12 +236,25 @@ public class SpellAbility extends ActivatedAbilityImpl {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a card object with the spell characteristics like calor, types,
|
||||
* subtypes etc. E.g. if you cast a Bestow card as enchantment, the
|
||||
* characteristics don't include the creature type.
|
||||
*
|
||||
* @param game
|
||||
* @return card object with the spell characteristics
|
||||
*/
|
||||
public Card getCharacteristics(Game game) {
|
||||
Spell spell = game.getSpell(this.getId());
|
||||
if (spell != null) {
|
||||
return spell;
|
||||
Card spellCharacteristics = game.getSpell(this.getId());
|
||||
if (spellCharacteristics == null) {
|
||||
spellCharacteristics = game.getCard(this.getSourceId());
|
||||
}
|
||||
return game.getCard(this.getSourceId());
|
||||
if (spellCharacteristics != null) {
|
||||
if (getSpellAbilityCastMode() != SpellAbilityCastMode.NORMAL) {
|
||||
spellCharacteristics = getSpellAbilityCastMode().getTypeModifiedCardObjectCopy(spellCharacteristics, game);
|
||||
}
|
||||
}
|
||||
return spellCharacteristics;
|
||||
}
|
||||
|
||||
public static SpellAbility getSpellAbilityFromEvent(GameEvent event, Game game) {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import mage.constants.AbilityType;
|
|||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.players.Player;
|
||||
import mage.util.CardUtil;
|
||||
|
|
@ -171,21 +170,24 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
|
|||
}
|
||||
}
|
||||
}
|
||||
if (isLeavesTheBattlefieldTrigger()) {
|
||||
source = zce.getTarget();
|
||||
}
|
||||
break;
|
||||
case DESTROYED_PERMANENT:
|
||||
if (isLeavesTheBattlefieldTrigger()) {
|
||||
if (event.getType() == EventType.DESTROYED_PERMANENT) {
|
||||
source = game.getLastKnownInformation(getSourceId(), Zone.BATTLEFIELD);
|
||||
} else if (((ZoneChangeEvent) event).getTarget() != null) {
|
||||
source = ((ZoneChangeEvent) event).getTarget();
|
||||
} else {
|
||||
source = game.getLastKnownInformation(getSourceId(), event.getZone());
|
||||
}
|
||||
source = game.getLastKnownInformation(getSourceId(), Zone.BATTLEFIELD);
|
||||
}
|
||||
break;
|
||||
case PHASED_OUT:
|
||||
case PHASED_IN:
|
||||
if (isLeavesTheBattlefieldTrigger()) {
|
||||
source = game.getLastKnownInformation(getSourceId(), event.getZone());
|
||||
}
|
||||
if (this.zone == Zone.ALL || game.getLastKnownInformation(getSourceId(), zone) != null) {
|
||||
return this.hasSourceObjectAbility(game, source, event);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return super.isInUseableZone(game, source, event);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ public class ConstellationAbility extends TriggeredAbilityImpl {
|
|||
return false;
|
||||
}
|
||||
Permanent permanent = game.getPermanent(event.getTargetId());
|
||||
return permanent != null && permanent.isEnchantment();
|
||||
return permanent != null && ((thisOr && permanent.getId().equals(getSourceId())) || permanent.isEnchantment());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
|
||||
|
||||
package mage.abilities.abilityword;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
|
|
@ -16,14 +14,13 @@ import mage.target.Target;
|
|||
import mage.util.ManaUtil;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
|
||||
public class StriveAbility extends SimpleStaticAbility {
|
||||
|
||||
private final String striveCost;
|
||||
|
||||
|
||||
public StriveAbility(String manaString) {
|
||||
super(Zone.STACK, new StriveCostIncreasingEffect(new ManaCostsImpl(manaString)));
|
||||
setRuleAtTheTop(true);
|
||||
|
|
@ -63,7 +60,7 @@ class StriveCostIncreasingEffect extends CostModificationEffectImpl {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source, Ability abilityToModify) {
|
||||
for (Target target : abilityToModify.getTargets()) {
|
||||
if (target.getMaxNumberOfTargets() == Integer.MAX_VALUE) {
|
||||
if (target.getMaxNumberOfTargets() == Integer.MAX_VALUE) { // strive works with "any number of target" only
|
||||
int additionalTargets = target.getTargets().size() - 1;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < additionalTargets; i++) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,61 @@
|
|||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.LoyaltyAbility;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.stack.StackAbility;
|
||||
|
||||
public class ActivatePlaneswalkerLoyaltyAbilityTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
private final SubType planeswalkerSubType;
|
||||
|
||||
public ActivatePlaneswalkerLoyaltyAbilityTriggeredAbility(Effect effect, SubType planeswalkerSubType) {
|
||||
super(Zone.BATTLEFIELD, effect, false);
|
||||
this.planeswalkerSubType = planeswalkerSubType;
|
||||
}
|
||||
|
||||
private ActivatePlaneswalkerLoyaltyAbilityTriggeredAbility(final ActivatePlaneswalkerLoyaltyAbilityTriggeredAbility ability) {
|
||||
super(ability);
|
||||
this.planeswalkerSubType = ability.planeswalkerSubType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActivatePlaneswalkerLoyaltyAbilityTriggeredAbility copy() {
|
||||
return new ActivatePlaneswalkerLoyaltyAbilityTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.ACTIVATED_ABILITY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (!event.getPlayerId().equals(getControllerId())) {
|
||||
return false;
|
||||
}
|
||||
StackAbility stackAbility = (StackAbility) game.getStack().getStackObject(event.getSourceId());
|
||||
if (stackAbility == null || !(stackAbility.getStackAbility() instanceof LoyaltyAbility)) {
|
||||
return false;
|
||||
}
|
||||
Permanent permanent = stackAbility.getSourcePermanentOrLKI(game);
|
||||
if (permanent == null || !permanent.isPlaneswalker()
|
||||
|| !permanent.hasSubtype(planeswalkerSubType, game)) {
|
||||
return false;
|
||||
}
|
||||
Effect effect = this.getEffects().get(0);
|
||||
effect.setValue("stackAbility", stackAbility);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever you activate a loyalty ability of a " + planeswalkerSubType.getDescription() + " planeswalker, " +
|
||||
this.getEffects().get(0).getText(getModes().getMode()) + ".";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
import static mage.constants.CardType.CREATURE;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author htrajan
|
||||
*/
|
||||
public class AttachedToCreatureSourceTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
public AttachedToCreatureSourceTriggeredAbility(Effect effect, boolean optional) {
|
||||
super(Zone.BATTLEFIELD, effect, optional);
|
||||
}
|
||||
|
||||
public AttachedToCreatureSourceTriggeredAbility(final AttachedToCreatureSourceTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.ATTACHED
|
||||
&& event.getSourceId() != null
|
||||
&& event.getSourceId().equals(this.getSourceId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
Permanent attachedPermanent = game.getPermanent(event.getTargetId());
|
||||
return attachedPermanent != null && attachedPermanent.getCardType().contains(CREATURE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "As {this} becomes attached to a creature, " + super.getRule();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttachedToCreatureSourceTriggeredAbility copy() {
|
||||
return new AttachedToCreatureSourceTriggeredAbility(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -77,7 +77,7 @@ public class AttacksAllTriggeredAbility extends TriggeredAbilityImpl {
|
|||
switch (setTargetPointer) {
|
||||
case PERMANENT:
|
||||
for (Effect effect : getEffects()) {
|
||||
effect.setTargetPointer(new FixedTarget(permanent.getId()));
|
||||
effect.setTargetPointer(new FixedTarget(permanent, game));
|
||||
}
|
||||
break;
|
||||
case PLAYER:
|
||||
|
|
|
|||
|
|
@ -76,12 +76,12 @@ public class AttacksCreatureYouControlTriggeredAbility extends TriggeredAbilityI
|
|||
public String getRule() {
|
||||
String an;
|
||||
String who = filter.getMessage();
|
||||
if (who.startsWith("another")) {
|
||||
if (who.startsWith("another") || who.startsWith("a ")) {
|
||||
an = "";
|
||||
} else if (who.startsWith("a")) {
|
||||
an = "an";
|
||||
} else if (who.length() > 0 && "aeiou".contains(who.charAt(0) + "")) {
|
||||
an = "an ";
|
||||
} else {
|
||||
an = "a";
|
||||
an = "a ";
|
||||
}
|
||||
|
||||
return "When" + (once ? "" : "ever")
|
||||
|
|
|
|||
|
|
@ -45,7 +45,9 @@ public class BecomesBlockedByCreatureTriggeredAbility extends TriggeredAbilityIm
|
|||
if (!filter.match(blocker, game)) {
|
||||
return false;
|
||||
}
|
||||
this.getEffects().setTargetPointer(new FixedTarget(blocker, game));
|
||||
for (Effect effect : this.getEffects()) {
|
||||
effect.setTargetPointer(new FixedTarget(event.getSourceId()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
|
||||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author North
|
||||
*/
|
||||
public class BecomesBlockedSourceTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
public BecomesBlockedSourceTriggeredAbility(Effect effect, boolean optional) {
|
||||
super(Zone.BATTLEFIELD, effect, optional);
|
||||
}
|
||||
|
||||
public BecomesBlockedSourceTriggeredAbility(final BecomesBlockedSourceTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.CREATURE_BLOCKED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
return event.getTargetId().equals(this.getSourceId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever {this} becomes blocked, " + super.getRule();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BecomesBlockedSourceTriggeredAbility copy() {
|
||||
return new BecomesBlockedSourceTriggeredAbility(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,55 +1,55 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Styxo
|
||||
*/
|
||||
public class BecomesMonstrousTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
public BecomesMonstrousTriggeredAbility(Effect effect) {
|
||||
super(Zone.BATTLEFIELD, effect, false);
|
||||
}
|
||||
|
||||
public BecomesMonstrousTriggeredAbility(final BecomesMonstrousTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BecomesMonstrousTriggeredAbility copy() {
|
||||
return new BecomesMonstrousTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.BECOMES_MONSTROUS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
Permanent permanent = game.getPermanent(event.getTargetId());
|
||||
if (permanent != null && permanent.isCreature()
|
||||
&& (permanent.isControlledBy(getControllerId()))) {
|
||||
this.getEffects().setTargetPointer(new FixedTarget(permanent, game));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever a creature you control becomes monstrous, " + super.getRule();
|
||||
}
|
||||
}
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Styxo
|
||||
*/
|
||||
public class BecomesMonstrousTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
public BecomesMonstrousTriggeredAbility(Effect effect) {
|
||||
super(Zone.BATTLEFIELD, effect, false);
|
||||
}
|
||||
|
||||
public BecomesMonstrousTriggeredAbility(final BecomesMonstrousTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BecomesMonstrousTriggeredAbility copy() {
|
||||
return new BecomesMonstrousTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.BECOMES_MONSTROUS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
Permanent permanent = game.getPermanent(event.getTargetId());
|
||||
if (permanent != null && permanent.isCreature()
|
||||
&& (permanent.isControlledBy(getControllerId()))) {
|
||||
this.getEffects().setTargetPointer(new FixedTarget(permanent, game));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever a creature you control becomes monstrous, " + super.getRule();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,11 @@ public class BecomesTargetTriggeredAbility extends TriggeredAbilityImpl {
|
|||
}
|
||||
|
||||
public BecomesTargetTriggeredAbility(Effect effect, FilterStackObject filter, SetTargetPointer setTargetPointer) {
|
||||
super(Zone.BATTLEFIELD, effect);
|
||||
this(effect, filter, setTargetPointer, false);
|
||||
}
|
||||
|
||||
public BecomesTargetTriggeredAbility(Effect effect, FilterStackObject filter, SetTargetPointer setTargetPointer, boolean optional) {
|
||||
super(Zone.BATTLEFIELD, effect, optional);
|
||||
this.filter = filter.copy();
|
||||
this.setTargetPointer = setTargetPointer;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -103,6 +103,7 @@ public class BeginningOfEndStepTriggeredAbility extends TriggeredAbilityImpl {
|
|||
@Override
|
||||
public String getRule() {
|
||||
StringBuilder sb = new StringBuilder(getEffects().getText(modes.getMode()));
|
||||
|
||||
if (this.optional) {
|
||||
if (sb.substring(0, 6).toLowerCase(Locale.ENGLISH).equals("target")) {
|
||||
sb.insert(0, "you may have ");
|
||||
|
|
@ -114,6 +115,7 @@ public class BeginningOfEndStepTriggeredAbility extends TriggeredAbilityImpl {
|
|||
if (abilityWord != null) {
|
||||
abilityWordRule = "<i>" + abilityWord.toString() + "</i> &mdash ";
|
||||
}
|
||||
|
||||
switch (targetController) {
|
||||
case YOU:
|
||||
return sb.insert(0, generateConditionString()).insert(0, abilityWordRule + "At the beginning of your end step, ").toString();
|
||||
|
|
@ -134,6 +136,13 @@ public class BeginningOfEndStepTriggeredAbility extends TriggeredAbilityImpl {
|
|||
private String generateConditionString() {
|
||||
if (interveningIfClauseCondition != null) {
|
||||
if (interveningIfClauseCondition.toString().startsWith("if")) {
|
||||
|
||||
//Fixes punctuation on multiple sentence if-then construction
|
||||
// see -- Colfenor's Urn
|
||||
if (interveningIfClauseCondition.toString().endsWith(".")){
|
||||
return interveningIfClauseCondition.toString() + " ";
|
||||
}
|
||||
|
||||
return interveningIfClauseCondition.toString() + ", ";
|
||||
} else {
|
||||
return "if {this} is " + interveningIfClauseCondition.toString() + ", ";
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
|
|
@ -137,7 +136,7 @@ public class BeginningOfUpkeepTriggeredAbility extends TriggeredAbilityImpl {
|
|||
case OPPONENT:
|
||||
return sb.insert(0, generateZoneString()).insert(0, "At the beginning of each opponent's upkeep, ").toString();
|
||||
case ANY:
|
||||
return sb.insert(0, generateZoneString()).insert(0, "At the beginning of each upkeep, ").toString();
|
||||
return sb.insert(0, generateZoneString()).insert(0, "At the beginning of each player's upkeep, ").toString();
|
||||
case ACTIVE:
|
||||
return sb.insert(0, generateZoneString()).insert(0, "At the beginning of each player's upkeep, ").toString();
|
||||
case CONTROLLER_ATTACHED_TO:
|
||||
|
|
|
|||
|
|
@ -15,6 +15,10 @@ public class BeginningOfYourEndStepTriggeredAbility extends TriggeredAbilityImpl
|
|||
super(Zone.BATTLEFIELD, effect, optional);
|
||||
}
|
||||
|
||||
public BeginningOfYourEndStepTriggeredAbility(Zone zone, Effect effect, boolean optional) {
|
||||
super(zone, effect, optional);
|
||||
}
|
||||
|
||||
public BeginningOfYourEndStepTriggeredAbility(final BeginningOfYourEndStepTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,91 @@
|
|||
|
||||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author North, Loki
|
||||
*/
|
||||
public class BlocksOrBecomesBlockedSourceTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
protected FilterPermanent filter;
|
||||
protected String rule;
|
||||
protected boolean setTargetPointer;
|
||||
|
||||
public BlocksOrBecomesBlockedSourceTriggeredAbility(Effect effect, boolean optional) {
|
||||
this(effect, StaticFilters.FILTER_PERMANENT_CREATURE, optional, null, true);
|
||||
}
|
||||
|
||||
public BlocksOrBecomesBlockedSourceTriggeredAbility(Effect effect, FilterPermanent filter, boolean optional) {
|
||||
this(effect, filter, optional, null, true);
|
||||
}
|
||||
|
||||
public BlocksOrBecomesBlockedSourceTriggeredAbility(Effect effect, FilterPermanent filter, boolean optional, String rule) {
|
||||
this(effect, filter, optional, rule, true);
|
||||
}
|
||||
|
||||
public BlocksOrBecomesBlockedSourceTriggeredAbility(Effect effect, FilterPermanent filter, boolean optional, String rule, boolean setTargetPointer) {
|
||||
super(Zone.BATTLEFIELD, effect, optional);
|
||||
this.filter = filter;
|
||||
this.rule = rule;
|
||||
this.setTargetPointer = setTargetPointer;
|
||||
}
|
||||
|
||||
public BlocksOrBecomesBlockedSourceTriggeredAbility(final BlocksOrBecomesBlockedSourceTriggeredAbility ability) {
|
||||
super(ability);
|
||||
this.filter = ability.filter;
|
||||
this.rule = ability.rule;
|
||||
this.setTargetPointer = ability.setTargetPointer;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.BLOCKER_DECLARED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (event.getSourceId().equals(this.getSourceId())) {
|
||||
Permanent blocked = game.getPermanent(event.getTargetId());
|
||||
if (blocked != null && filter.match(blocked, game)) {
|
||||
if (setTargetPointer) {
|
||||
this.getEffects().setTargetPointer(new FixedTarget(blocked, game));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (event.getTargetId().equals(this.getSourceId())) {
|
||||
Permanent blocker = game.getPermanent(event.getSourceId());
|
||||
if (blocker != null && filter.match(blocker, game)) {
|
||||
if (setTargetPointer) {
|
||||
this.getEffects().setTargetPointer(new FixedTarget(blocker, game));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
if (rule != null) {
|
||||
return rule;
|
||||
}
|
||||
return "Whenever {this} blocks or becomes blocked" + (setTargetPointer ? " by a " + filter.getMessage() : "") + ", " + super.getRule();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlocksOrBecomesBlockedSourceTriggeredAbility copy() {
|
||||
return new BlocksOrBecomesBlockedSourceTriggeredAbility(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
|
||||
|
||||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.StaticAbility;
|
||||
import mage.abilities.effects.common.CantBeCounteredSourceEffect;
|
||||
import mage.constants.Zone;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class CantBeCounteredSourceAbility extends StaticAbility {
|
||||
|
||||
public CantBeCounteredSourceAbility() {
|
||||
super(Zone.STACK, new CantBeCounteredSourceEffect());
|
||||
}
|
||||
|
||||
public CantBeCounteredSourceAbility(CantBeCounteredSourceAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "{this} can't be countered.";
|
||||
}
|
||||
|
||||
@Override
|
||||
public CantBeCounteredSourceAbility copy() {
|
||||
return new CantBeCounteredSourceAbility(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,104 +1,104 @@
|
|||
|
||||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.ReplacementEffectImpl;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.counters.CounterType;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author emerald000
|
||||
*/
|
||||
public class CantHaveMoreThanAmountCountersSourceAbility extends SimpleStaticAbility {
|
||||
|
||||
private final CounterType counterType;
|
||||
private final int amount;
|
||||
|
||||
public CantHaveMoreThanAmountCountersSourceAbility(CounterType counterType, int amount) {
|
||||
super(Zone.BATTLEFIELD, new CantHaveMoreThanAmountCountersSourceEffect(counterType, amount));
|
||||
this.counterType = counterType;
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
private CantHaveMoreThanAmountCountersSourceAbility(CantHaveMoreThanAmountCountersSourceAbility ability) {
|
||||
super(ability);
|
||||
this.counterType = ability.counterType;
|
||||
this.amount = ability.amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Rasputin can't have more than " + CardUtil.numberToText(this.amount) + ' ' + this.counterType.getName() + " counters on it.";
|
||||
}
|
||||
|
||||
@Override
|
||||
public CantHaveMoreThanAmountCountersSourceAbility copy() {
|
||||
return new CantHaveMoreThanAmountCountersSourceAbility(this);
|
||||
}
|
||||
|
||||
public CounterType getCounterType() {
|
||||
return this.counterType;
|
||||
}
|
||||
|
||||
public int getAmount() {
|
||||
return this.amount;
|
||||
}
|
||||
}
|
||||
|
||||
class CantHaveMoreThanAmountCountersSourceEffect extends ReplacementEffectImpl {
|
||||
|
||||
private final CounterType counterType;
|
||||
private final int amount;
|
||||
|
||||
CantHaveMoreThanAmountCountersSourceEffect(CounterType counterType, int amount) {
|
||||
super(Duration.WhileOnBattlefield, Outcome.Detriment, false);
|
||||
this.counterType = counterType;
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
CantHaveMoreThanAmountCountersSourceEffect(final CantHaveMoreThanAmountCountersSourceEffect effect) {
|
||||
super(effect);
|
||||
this.counterType = effect.counterType;
|
||||
this.amount = effect.amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == EventType.ADD_COUNTER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
Permanent permanent = game.getPermanent(event.getTargetId());
|
||||
if (permanent == null) {
|
||||
permanent = game.getPermanentEntering(event.getTargetId());
|
||||
}
|
||||
return permanent != null
|
||||
&& permanent.getId().equals(source.getSourceId())
|
||||
&& event.getData().equals(this.counterType.getName())
|
||||
&& permanent.getCounters(game).getCount(this.counterType) == this.amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CantHaveMoreThanAmountCountersSourceEffect copy() {
|
||||
return new CantHaveMoreThanAmountCountersSourceEffect(this);
|
||||
}
|
||||
}
|
||||
|
||||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.ReplacementEffectImpl;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.counters.CounterType;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author emerald000
|
||||
*/
|
||||
public class CantHaveMoreThanAmountCountersSourceAbility extends SimpleStaticAbility {
|
||||
|
||||
private final CounterType counterType;
|
||||
private final int amount;
|
||||
|
||||
public CantHaveMoreThanAmountCountersSourceAbility(CounterType counterType, int amount) {
|
||||
super(Zone.BATTLEFIELD, new CantHaveMoreThanAmountCountersSourceEffect(counterType, amount));
|
||||
this.counterType = counterType;
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
private CantHaveMoreThanAmountCountersSourceAbility(CantHaveMoreThanAmountCountersSourceAbility ability) {
|
||||
super(ability);
|
||||
this.counterType = ability.counterType;
|
||||
this.amount = ability.amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Rasputin can't have more than " + CardUtil.numberToText(this.amount) + ' ' + this.counterType.getName() + " counters on it.";
|
||||
}
|
||||
|
||||
@Override
|
||||
public CantHaveMoreThanAmountCountersSourceAbility copy() {
|
||||
return new CantHaveMoreThanAmountCountersSourceAbility(this);
|
||||
}
|
||||
|
||||
public CounterType getCounterType() {
|
||||
return this.counterType;
|
||||
}
|
||||
|
||||
public int getAmount() {
|
||||
return this.amount;
|
||||
}
|
||||
}
|
||||
|
||||
class CantHaveMoreThanAmountCountersSourceEffect extends ReplacementEffectImpl {
|
||||
|
||||
private final CounterType counterType;
|
||||
private final int amount;
|
||||
|
||||
CantHaveMoreThanAmountCountersSourceEffect(CounterType counterType, int amount) {
|
||||
super(Duration.WhileOnBattlefield, Outcome.Detriment, false);
|
||||
this.counterType = counterType;
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
CantHaveMoreThanAmountCountersSourceEffect(final CantHaveMoreThanAmountCountersSourceEffect effect) {
|
||||
super(effect);
|
||||
this.counterType = effect.counterType;
|
||||
this.amount = effect.amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == EventType.ADD_COUNTER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
Permanent permanent = game.getPermanent(event.getTargetId());
|
||||
if (permanent == null) {
|
||||
permanent = game.getPermanentEntering(event.getTargetId());
|
||||
}
|
||||
return permanent != null
|
||||
&& permanent.getId().equals(source.getSourceId())
|
||||
&& event.getData().equals(this.counterType.getName())
|
||||
&& permanent.getCounters(game).getCount(this.counterType) == this.amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CantHaveMoreThanAmountCountersSourceEffect copy() {
|
||||
return new CantHaveMoreThanAmountCountersSourceEffect(this);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import mage.constants.Zone;
|
|||
*/
|
||||
public class CastCommanderAbility extends SpellAbility {
|
||||
|
||||
private String ruleText;
|
||||
private final String ruleText;
|
||||
|
||||
public CastCommanderAbility(Card card, SpellAbility spellTemplate) {
|
||||
super(spellTemplate);
|
||||
|
|
|
|||
|
|
@ -1,49 +1,49 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
/**
|
||||
* @author jeffwadsworth
|
||||
*/
|
||||
public class ControllerPlaysLandTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
public ControllerPlaysLandTriggeredAbility(Zone zone, Effect effect, Boolean optional) {
|
||||
super(zone, effect, optional);
|
||||
}
|
||||
|
||||
public ControllerPlaysLandTriggeredAbility(ControllerPlaysLandTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == EventType.LAND_PLAYED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
Permanent land = game.getPermanent(event.getTargetId());
|
||||
return land != null && land.getControllerId().equals(controllerId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ControllerPlaysLandTriggeredAbility copy() {
|
||||
return new ControllerPlaysLandTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever you play a land, ";
|
||||
}
|
||||
}
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
/**
|
||||
* @author jeffwadsworth
|
||||
*/
|
||||
public class ControllerPlaysLandTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
public ControllerPlaysLandTriggeredAbility(Zone zone, Effect effect, Boolean optional) {
|
||||
super(zone, effect, optional);
|
||||
}
|
||||
|
||||
public ControllerPlaysLandTriggeredAbility(ControllerPlaysLandTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == EventType.LAND_PLAYED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
Permanent land = game.getPermanent(event.getTargetId());
|
||||
return land != null && land.getControllerId().equals(controllerId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ControllerPlaysLandTriggeredAbility copy() {
|
||||
return new ControllerPlaysLandTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever you play a land, ";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,63 @@
|
|||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.keyword.CyclingAbility;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.stack.StackAbility;
|
||||
import mage.game.stack.StackObject;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class CycleControllerTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
private final boolean excludeSource;
|
||||
|
||||
public CycleControllerTriggeredAbility(Effect effect) {
|
||||
this(effect, false);
|
||||
}
|
||||
|
||||
public CycleControllerTriggeredAbility(Effect effect, boolean optional) {
|
||||
this(effect, optional, false);
|
||||
}
|
||||
|
||||
public CycleControllerTriggeredAbility(Effect effect, boolean optional, boolean excludeSource) {
|
||||
super(Zone.BATTLEFIELD, effect, optional);
|
||||
this.excludeSource = excludeSource;
|
||||
}
|
||||
|
||||
private CycleControllerTriggeredAbility(final CycleControllerTriggeredAbility ability) {
|
||||
super(ability);
|
||||
this.excludeSource = ability.excludeSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.ACTIVATED_ABILITY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (game.getState().getStack().isEmpty()
|
||||
|| !event.getPlayerId().equals(this.getControllerId())
|
||||
|| (event.getSourceId().equals(this.getSourceId()) && excludeSource)) {
|
||||
return false;
|
||||
}
|
||||
StackObject item = game.getState().getStack().getFirst();
|
||||
return item instanceof StackAbility
|
||||
&& item.getStackAbility() instanceof CyclingAbility;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever you cycle " + (excludeSource ? "another" : "a") + " card, " + super.getRule();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CycleControllerTriggeredAbility copy() {
|
||||
return new CycleControllerTriggeredAbility(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
|
||||
|
||||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.effects.Effect;
|
||||
|
|
@ -10,7 +8,6 @@ import mage.game.events.GameEvent;
|
|||
import mage.game.stack.StackObject;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Plopman
|
||||
*/
|
||||
public class CycleTriggeredAbility extends ZoneChangeTriggeredAbility {
|
||||
|
|
@ -26,7 +23,7 @@ public class CycleTriggeredAbility extends ZoneChangeTriggeredAbility {
|
|||
public CycleTriggeredAbility(CycleTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.ACTIVATED_ABILITY;
|
||||
|
|
@ -34,10 +31,11 @@ public class CycleTriggeredAbility extends ZoneChangeTriggeredAbility {
|
|||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if(event.getSourceId().equals(this.getSourceId())) {
|
||||
if (event.getSourceId().equals(this.getSourceId())) {
|
||||
StackObject object = game.getStack().getStackObject(event.getSourceId());
|
||||
if(object != null && object.getStackAbility() instanceof CyclingAbility){
|
||||
return true;
|
||||
if (object != null && object.getStackAbility() instanceof CyclingAbility) {
|
||||
this.getEffects().setValue("cycleCosts", object.getStackAbility().getCosts());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -1,104 +1,104 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.SetTargetPointer;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.DamagedCreatureEvent;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class DealsDamageToACreatureAllTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
private final boolean combatDamageOnly;
|
||||
private final FilterPermanent filterPermanent;
|
||||
private final SetTargetPointer setTargetPointer;
|
||||
|
||||
/**
|
||||
* This ability works only for permanents doing damage.
|
||||
*
|
||||
* @param effect
|
||||
* @param optional
|
||||
* @param filterPermanent The filter that restricts which permanets have to
|
||||
* trigger
|
||||
* @param setTargetPointer The target to be set to target pointer of the
|
||||
* effect.<br>
|
||||
* - PLAYER = player controlling the damage source.<br>
|
||||
* - PERMANENT = source permanent.<br>
|
||||
* - PERMANENT_TARGET = damaged creature.
|
||||
* @param combatDamageOnly The flag to determine if only combat damage has
|
||||
* to trigger
|
||||
*/
|
||||
public DealsDamageToACreatureAllTriggeredAbility(Effect effect, boolean optional, FilterPermanent filterPermanent, SetTargetPointer setTargetPointer, boolean combatDamageOnly) {
|
||||
super(Zone.BATTLEFIELD, effect, optional);
|
||||
this.combatDamageOnly = combatDamageOnly;
|
||||
this.setTargetPointer = setTargetPointer;
|
||||
this.filterPermanent = filterPermanent;
|
||||
}
|
||||
|
||||
public DealsDamageToACreatureAllTriggeredAbility(final DealsDamageToACreatureAllTriggeredAbility ability) {
|
||||
super(ability);
|
||||
this.combatDamageOnly = ability.combatDamageOnly;
|
||||
this.filterPermanent = ability.filterPermanent;
|
||||
this.setTargetPointer = ability.setTargetPointer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DealsDamageToACreatureAllTriggeredAbility copy() {
|
||||
return new DealsDamageToACreatureAllTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == EventType.DAMAGED_CREATURE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (!combatDamageOnly || ((DamagedCreatureEvent) event).isCombatDamage()) {
|
||||
Permanent permanent = game.getPermanentOrLKIBattlefield(event.getSourceId());
|
||||
if (permanent != null && filterPermanent.match(permanent, getSourceId(), getControllerId(), game)) {
|
||||
for (Effect effect : this.getEffects()) {
|
||||
effect.setValue("damage", event.getAmount());
|
||||
effect.setValue("sourceId", event.getSourceId());
|
||||
switch (setTargetPointer) {
|
||||
case PLAYER:
|
||||
effect.setTargetPointer(new FixedTarget(permanent.getControllerId()));
|
||||
break;
|
||||
case PERMANENT:
|
||||
effect.setTargetPointer(new FixedTarget(permanent, game));
|
||||
break;
|
||||
case PERMANENT_TARGET:
|
||||
Permanent permanent_target = game.getPermanentOrLKIBattlefield(event.getTargetId());
|
||||
if (permanent_target != null) {
|
||||
effect.setTargetPointer(new FixedTarget(permanent_target, game));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever " + filterPermanent.getMessage() + " deals "
|
||||
+ (combatDamageOnly ? "combat " : "") + "damage to a creature, " + super.getRule();
|
||||
}
|
||||
}
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.SetTargetPointer;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.DamagedCreatureEvent;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class DealsDamageToACreatureAllTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
private final boolean combatDamageOnly;
|
||||
private final FilterPermanent filterPermanent;
|
||||
private final SetTargetPointer setTargetPointer;
|
||||
|
||||
/**
|
||||
* This ability works only for permanents doing damage.
|
||||
*
|
||||
* @param effect
|
||||
* @param optional
|
||||
* @param filterPermanent The filter that restricts which permanets have to
|
||||
* trigger
|
||||
* @param setTargetPointer The target to be set to target pointer of the
|
||||
* effect.<br>
|
||||
* - PLAYER = player controlling the damage source.<br>
|
||||
* - PERMANENT = source permanent.<br>
|
||||
* - PERMANENT_TARGET = damaged creature.
|
||||
* @param combatDamageOnly The flag to determine if only combat damage has
|
||||
* to trigger
|
||||
*/
|
||||
public DealsDamageToACreatureAllTriggeredAbility(Effect effect, boolean optional, FilterPermanent filterPermanent, SetTargetPointer setTargetPointer, boolean combatDamageOnly) {
|
||||
super(Zone.BATTLEFIELD, effect, optional);
|
||||
this.combatDamageOnly = combatDamageOnly;
|
||||
this.setTargetPointer = setTargetPointer;
|
||||
this.filterPermanent = filterPermanent;
|
||||
}
|
||||
|
||||
public DealsDamageToACreatureAllTriggeredAbility(final DealsDamageToACreatureAllTriggeredAbility ability) {
|
||||
super(ability);
|
||||
this.combatDamageOnly = ability.combatDamageOnly;
|
||||
this.filterPermanent = ability.filterPermanent;
|
||||
this.setTargetPointer = ability.setTargetPointer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DealsDamageToACreatureAllTriggeredAbility copy() {
|
||||
return new DealsDamageToACreatureAllTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == EventType.DAMAGED_CREATURE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (!combatDamageOnly || ((DamagedCreatureEvent) event).isCombatDamage()) {
|
||||
Permanent permanent = game.getPermanentOrLKIBattlefield(event.getSourceId());
|
||||
if (permanent != null && filterPermanent.match(permanent, getSourceId(), getControllerId(), game)) {
|
||||
for (Effect effect : this.getEffects()) {
|
||||
effect.setValue("damage", event.getAmount());
|
||||
effect.setValue("sourceId", event.getSourceId());
|
||||
switch (setTargetPointer) {
|
||||
case PLAYER:
|
||||
effect.setTargetPointer(new FixedTarget(permanent.getControllerId()));
|
||||
break;
|
||||
case PERMANENT:
|
||||
effect.setTargetPointer(new FixedTarget(permanent, game));
|
||||
break;
|
||||
case PERMANENT_TARGET:
|
||||
Permanent permanent_target = game.getPermanentOrLKIBattlefield(event.getTargetId());
|
||||
if (permanent_target != null) {
|
||||
effect.setTargetPointer(new FixedTarget(permanent_target, game));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever " + filterPermanent.getMessage() + " deals "
|
||||
+ (combatDamageOnly ? "combat " : "") + "damage to a creature, " + super.getRule();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.common.DestroyTargetEffect;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
public class DestroyPlaneswalkerWhenDamagedTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
private final FilterPermanent filter;
|
||||
|
||||
public DestroyPlaneswalkerWhenDamagedTriggeredAbility() {
|
||||
this((FilterPermanent) null);
|
||||
}
|
||||
|
||||
public DestroyPlaneswalkerWhenDamagedTriggeredAbility(FilterPermanent filter) {
|
||||
super(Zone.BATTLEFIELD, null);
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
private DestroyPlaneswalkerWhenDamagedTriggeredAbility(final DestroyPlaneswalkerWhenDamagedTriggeredAbility effect) {
|
||||
super(effect);
|
||||
this.filter = effect.filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DestroyPlaneswalkerWhenDamagedTriggeredAbility copy() {
|
||||
return new DestroyPlaneswalkerWhenDamagedTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.DAMAGED_PLANESWALKER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
Permanent permanent = getSourcePermanentIfItStillExists(game);
|
||||
if (permanent != null) {
|
||||
boolean applies = filter != null ?
|
||||
filter.match(permanent, game) : event.getSourceId().equals(getSourceId());
|
||||
if (applies) {
|
||||
Effect effect = new DestroyTargetEffect();
|
||||
effect.setTargetPointer(new FixedTarget(event.getTargetId(), game));
|
||||
this.getEffects().clear();
|
||||
this.addEffect(effect);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever " + (filter != null ? filter.getMessage() : "this creature") + " deals damage to a planeswalker, destroy that planeswalker.";
|
||||
}
|
||||
}
|
||||
|
|
@ -69,7 +69,7 @@ public class DiesCreatureTriggeredAbility extends TriggeredAbilityImpl {
|
|||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
|
||||
if (zEvent.isDiesEvent()) {
|
||||
if (filter.match(zEvent.getTarget(), sourceId, controllerId, game) && zEvent.getTarget().isCreature()) {
|
||||
if (filter.match(zEvent.getTarget(), sourceId, controllerId, game)) {
|
||||
if (setTargetPointer) {
|
||||
for (Effect effect : this.getEffects()) {
|
||||
effect.setTargetPointer(new FixedTarget(event.getTargetId(), game));
|
||||
|
|
|
|||
|
|
@ -0,0 +1,79 @@
|
|||
package mage.abilities.common;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.PermanentToken;
|
||||
|
||||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class DiesSourceTriggeredAbility extends ZoneChangeTriggeredAbility {
|
||||
|
||||
public DiesSourceTriggeredAbility(Effect effect, boolean optional) {
|
||||
super(Zone.BATTLEFIELD, Zone.GRAVEYARD, effect, "When {this} dies, ", optional);
|
||||
}
|
||||
|
||||
public DiesSourceTriggeredAbility(Effect effect) {
|
||||
this(effect, false);
|
||||
}
|
||||
|
||||
public DiesSourceTriggeredAbility(DiesSourceTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInUseableZone(Game game, MageObject source, GameEvent event) {
|
||||
// check it was previously on battlefield
|
||||
Permanent before = ((ZoneChangeEvent) event).getTarget();
|
||||
if (before == null) {
|
||||
return false;
|
||||
}
|
||||
if (!this.hasSourceObjectAbility(game, before, event)) { // the permanent does not have the ability so no trigger
|
||||
return false;
|
||||
}
|
||||
// check now it is in graveyard if it is no token
|
||||
if (!(before instanceof PermanentToken) && before.getZoneChangeCounter(game) + 1 == game.getState().getZoneChangeCounter(sourceId)) {
|
||||
Zone after = game.getState().getZone(sourceId);
|
||||
return after != null && Zone.GRAVEYARD.match(after);
|
||||
} else {
|
||||
// Already moved to another zone, so guess it's ok
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
if (super.checkEventType(event, game)) {
|
||||
return ((ZoneChangeEvent) event).getFromZone() == Zone.BATTLEFIELD && ((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DiesSourceTriggeredAbility copy() {
|
||||
return new DiesSourceTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (super.checkTrigger(event, game)) {
|
||||
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
|
||||
if (zEvent.getTarget().isTransformable()) {
|
||||
if (!zEvent.getTarget().getAbilities().contains(this)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (Effect effect : getEffects()) {
|
||||
effect.setValue("permanentLeftBattlefield", zEvent.getTarget());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
package mage.abilities.common;
|
||||
|
||||
import mage.MageObject;
|
||||
|
|
@ -17,6 +16,7 @@ import mage.game.permanent.Permanent;
|
|||
public class DiesThisOrAnotherCreatureTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
protected FilterCreaturePermanent filter;
|
||||
private boolean applyFilterOnSource = false;
|
||||
|
||||
public DiesThisOrAnotherCreatureTriggeredAbility(Effect effect, boolean optional) {
|
||||
this(effect, optional, new FilterCreaturePermanent());
|
||||
|
|
@ -30,6 +30,12 @@ public class DiesThisOrAnotherCreatureTriggeredAbility extends TriggeredAbilityI
|
|||
public DiesThisOrAnotherCreatureTriggeredAbility(DiesThisOrAnotherCreatureTriggeredAbility ability) {
|
||||
super(ability);
|
||||
this.filter = ability.filter;
|
||||
this.applyFilterOnSource = ability.applyFilterOnSource;
|
||||
}
|
||||
|
||||
public DiesThisOrAnotherCreatureTriggeredAbility setApplyFilterOnSource(boolean applyFilterOnSource) {
|
||||
this.applyFilterOnSource = applyFilterOnSource;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -68,7 +74,7 @@ public class DiesThisOrAnotherCreatureTriggeredAbility extends TriggeredAbilityI
|
|||
|
||||
if (zEvent.isDiesEvent()) {
|
||||
if (zEvent.getTarget() != null) {
|
||||
if (zEvent.getTarget().getId().equals(this.getSourceId())) {
|
||||
if (!applyFilterOnSource && zEvent.getTarget().getId().equals(this.getSourceId())) {
|
||||
return true;
|
||||
} else {
|
||||
if (filter.match(zEvent.getTarget(), getSourceId(), getControllerId(), game)) {
|
||||
|
|
|
|||
|
|
@ -1,54 +1,54 @@
|
|||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
import mage.game.stack.StackObject;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Styxo
|
||||
*/
|
||||
public class DiscardedByOpponentTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
public DiscardedByOpponentTriggeredAbility(Effect effect) {
|
||||
this(effect, false);
|
||||
}
|
||||
|
||||
public DiscardedByOpponentTriggeredAbility(Effect effect, boolean optional) {
|
||||
super(Zone.GRAVEYARD, effect, optional);
|
||||
}
|
||||
|
||||
public DiscardedByOpponentTriggeredAbility(final DiscardedByOpponentTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DiscardedByOpponentTriggeredAbility copy() {
|
||||
return new DiscardedByOpponentTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == EventType.DISCARDED_CARD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (getSourceId().equals(event.getTargetId())) {
|
||||
StackObject stackObject = game.getStack().getStackObject(event.getSourceId());
|
||||
if (stackObject != null) {
|
||||
return game.getOpponents(this.getControllerId()).contains(stackObject.getControllerId());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "When a spell or ability an opponent controls causes you to discard this card, " + super.getRule();
|
||||
}
|
||||
}
|
||||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
import mage.game.stack.StackObject;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Styxo
|
||||
*/
|
||||
public class DiscardedByOpponentTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
public DiscardedByOpponentTriggeredAbility(Effect effect) {
|
||||
this(effect, false);
|
||||
}
|
||||
|
||||
public DiscardedByOpponentTriggeredAbility(Effect effect, boolean optional) {
|
||||
super(Zone.GRAVEYARD, effect, optional);
|
||||
}
|
||||
|
||||
public DiscardedByOpponentTriggeredAbility(final DiscardedByOpponentTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DiscardedByOpponentTriggeredAbility copy() {
|
||||
return new DiscardedByOpponentTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == EventType.DISCARDED_CARD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (getSourceId().equals(event.getTargetId())) {
|
||||
StackObject stackObject = game.getStack().getStackObject(event.getSourceId());
|
||||
if (stackObject != null) {
|
||||
return game.getOpponents(this.getControllerId()).contains(stackObject.getControllerId());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "When a spell or ability an opponent controls causes you to discard this card, " + super.getRule();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
|
|
@ -43,7 +42,7 @@ public class EnchantedCreatureBlockedTriggeredAbility extends TriggeredAbilityIm
|
|||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever enchanted creature becomes blocked by a creature, " + super.getRule();
|
||||
return "Whenever enchanted creature becomes blocked, " + super.getRule();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
|
||||
package mage.abilities.common;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.SetTargetPointer;
|
||||
|
|
@ -12,8 +11,9 @@ import mage.game.events.GameEvent;
|
|||
import mage.game.permanent.Permanent;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class EntersBattlefieldAllTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
|
@ -22,6 +22,7 @@ public class EntersBattlefieldAllTriggeredAbility extends TriggeredAbilityImpl {
|
|||
protected String rule;
|
||||
protected boolean controlledText;
|
||||
protected SetTargetPointer setTargetPointer;
|
||||
protected final boolean thisOrAnother;
|
||||
|
||||
/**
|
||||
* zone = BATTLEFIELD optional = false
|
||||
|
|
@ -54,11 +55,16 @@ public class EntersBattlefieldAllTriggeredAbility extends TriggeredAbilityImpl {
|
|||
}
|
||||
|
||||
public EntersBattlefieldAllTriggeredAbility(Zone zone, Effect effect, FilterPermanent filter, boolean optional, SetTargetPointer setTargetPointer, String rule, boolean controlledText) {
|
||||
this(zone, effect, filter, optional, setTargetPointer, rule, controlledText, false);
|
||||
}
|
||||
|
||||
protected EntersBattlefieldAllTriggeredAbility(Zone zone, Effect effect, FilterPermanent filter, boolean optional, SetTargetPointer setTargetPointer, String rule, boolean controlledText, boolean thisOrAnother) {
|
||||
super(zone, effect, optional);
|
||||
this.filter = filter;
|
||||
this.rule = rule;
|
||||
this.controlledText = controlledText;
|
||||
this.setTargetPointer = setTargetPointer;
|
||||
this.thisOrAnother = thisOrAnother;
|
||||
}
|
||||
|
||||
public EntersBattlefieldAllTriggeredAbility(final EntersBattlefieldAllTriggeredAbility ability) {
|
||||
|
|
@ -67,6 +73,7 @@ public class EntersBattlefieldAllTriggeredAbility extends TriggeredAbilityImpl {
|
|||
this.rule = ability.rule;
|
||||
this.controlledText = ability.controlledText;
|
||||
this.setTargetPointer = ability.setTargetPointer;
|
||||
this.thisOrAnother = ability.thisOrAnother;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -105,7 +112,11 @@ public class EntersBattlefieldAllTriggeredAbility extends TriggeredAbilityImpl {
|
|||
if (rule != null && !rule.isEmpty()) {
|
||||
return rule;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder("Whenever ").append(filter.getMessage());
|
||||
StringBuilder sb = new StringBuilder("Whenever ");
|
||||
if (thisOrAnother) {
|
||||
sb.append("{this} or another ");
|
||||
}
|
||||
sb.append(filter.getMessage());
|
||||
sb.append(" enters the battlefield");
|
||||
if (controlledText) {
|
||||
sb.append(" under your control, ");
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.SetTargetPointer;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class EntersBattlefieldThisOrAnotherTriggeredAbility extends EntersBattlefieldAllTriggeredAbility {
|
||||
|
||||
private final boolean onlyControlled;
|
||||
|
||||
public EntersBattlefieldThisOrAnotherTriggeredAbility(Effect effect, FilterPermanent filter) {
|
||||
this(effect, filter, false, false);
|
||||
}
|
||||
|
||||
public EntersBattlefieldThisOrAnotherTriggeredAbility(Effect effect, FilterPermanent filter, boolean optional, boolean onlyControlled) {
|
||||
this(effect, filter, optional, SetTargetPointer.NONE, onlyControlled);
|
||||
}
|
||||
|
||||
public EntersBattlefieldThisOrAnotherTriggeredAbility(Effect effect, FilterPermanent filter, boolean optional, SetTargetPointer setTargetPointer, boolean onlyControlled) {
|
||||
this(Zone.BATTLEFIELD, effect, filter, optional, setTargetPointer, onlyControlled);
|
||||
}
|
||||
|
||||
public EntersBattlefieldThisOrAnotherTriggeredAbility(Zone zone, Effect effect, FilterPermanent filter, boolean optional, SetTargetPointer setTargetPointer, boolean onlyControlled) {
|
||||
super(zone, effect, filter, optional, setTargetPointer, null, onlyControlled, true);
|
||||
this.onlyControlled = onlyControlled;
|
||||
}
|
||||
|
||||
private EntersBattlefieldThisOrAnotherTriggeredAbility(final EntersBattlefieldThisOrAnotherTriggeredAbility ability) {
|
||||
super(ability);
|
||||
this.onlyControlled = ability.onlyControlled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (!super.checkTrigger(event, game)) {
|
||||
return false;
|
||||
}
|
||||
Permanent permanent = game.getPermanent(event.getTargetId());
|
||||
if (permanent == null) {
|
||||
return false;
|
||||
}
|
||||
if (permanent.getId().equals(getSourceId())) {
|
||||
return true;
|
||||
}
|
||||
if (onlyControlled && !permanent.isControlledBy(this.getControllerId())) {
|
||||
return false;
|
||||
}
|
||||
return filter.match(permanent, getSourceId(), getControllerId(), game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntersBattlefieldThisOrAnotherTriggeredAbility copy() {
|
||||
return new EntersBattlefieldThisOrAnotherTriggeredAbility(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.StaticAbility;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.RestrictionEffect;
|
||||
import mage.abilities.effects.common.combat.AttacksIfAbleAttachedEffect;
|
||||
import mage.constants.AttachmentType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class GoadAttachedAbility extends StaticAbility {
|
||||
|
||||
public GoadAttachedAbility(Effect... effects) {
|
||||
super(Zone.BATTLEFIELD, null);
|
||||
for (Effect effect : effects) {
|
||||
this.addEffect(effect);
|
||||
}
|
||||
this.addEffect(new AttacksIfAbleAttachedEffect(
|
||||
Duration.WhileOnBattlefield, AttachmentType.AURA
|
||||
).setText(", and is goaded. "));
|
||||
this.addEffect(new GoadAttackEffect());
|
||||
}
|
||||
|
||||
private GoadAttachedAbility(final GoadAttachedAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GoadAttachedAbility copy() {
|
||||
return new GoadAttachedAbility(this);
|
||||
}
|
||||
}
|
||||
|
||||
class GoadAttackEffect extends RestrictionEffect {
|
||||
|
||||
GoadAttackEffect() {
|
||||
super(Duration.WhileOnBattlefield);
|
||||
staticText = "<i>(It attacks each combat if able and attacks a player other than you if able.)</i>";
|
||||
}
|
||||
|
||||
private GoadAttackEffect(final GoadAttackEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GoadAttackEffect copy() {
|
||||
return new GoadAttackEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(Permanent permanent, Ability source, Game game) {
|
||||
Permanent attachment = game.getPermanent(source.getSourceId());
|
||||
return attachment != null && attachment.getAttachedTo() != null
|
||||
&& permanent.getId().equals(attachment.getAttachedTo());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) {
|
||||
if (defenderId == null) {
|
||||
return true;
|
||||
}
|
||||
return !defenderId.equals(source.getControllerId());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,88 +1,88 @@
|
|||
|
||||
package mage.abilities.common;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.SetTargetPointer;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Styxo
|
||||
*/
|
||||
public class LeavesBattlefieldAllTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
protected FilterPermanent filter;
|
||||
protected SetTargetPointer setTargetPointer;
|
||||
|
||||
public LeavesBattlefieldAllTriggeredAbility(Effect effect, FilterPermanent filter) {
|
||||
this(effect, filter, false);
|
||||
}
|
||||
|
||||
public LeavesBattlefieldAllTriggeredAbility(Effect effect, FilterPermanent filter, boolean optional) {
|
||||
this(Zone.BATTLEFIELD, effect, filter, optional);
|
||||
}
|
||||
|
||||
public LeavesBattlefieldAllTriggeredAbility(Zone zone, Effect effect, FilterPermanent filter, boolean optional) {
|
||||
this(zone, effect, filter, optional, SetTargetPointer.NONE);
|
||||
}
|
||||
|
||||
public LeavesBattlefieldAllTriggeredAbility(Zone zone, Effect effect, FilterPermanent filter, boolean optional, SetTargetPointer setTargetPointer) {
|
||||
super(zone, effect, optional);
|
||||
this.filter = filter;
|
||||
this.setTargetPointer = setTargetPointer;
|
||||
}
|
||||
|
||||
private LeavesBattlefieldAllTriggeredAbility(final LeavesBattlefieldAllTriggeredAbility ability) {
|
||||
super(ability);
|
||||
filter = ability.filter;
|
||||
setTargetPointer = ability.setTargetPointer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LeavesBattlefieldAllTriggeredAbility copy() {
|
||||
return new LeavesBattlefieldAllTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.ZONE_CHANGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
|
||||
if (zEvent.getFromZone() == Zone.BATTLEFIELD) {
|
||||
UUID targetId = event.getTargetId();
|
||||
Permanent permanent = game.getPermanentOrLKIBattlefield(targetId);
|
||||
if (permanent != null && filter.match(permanent, getSourceId(), getControllerId(), game)) {
|
||||
if (setTargetPointer != SetTargetPointer.NONE) {
|
||||
for (Effect effect : this.getEffects()) {
|
||||
switch (setTargetPointer) {
|
||||
case PERMANENT:
|
||||
effect.setTargetPointer(new FixedTarget(permanent.getId()));
|
||||
break;
|
||||
case PLAYER:
|
||||
effect.setTargetPointer(new FixedTarget(permanent.getControllerId()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever " + filter.getMessage() + " leaves the battlefield, " + super.getRule();
|
||||
}
|
||||
}
|
||||
|
||||
package mage.abilities.common;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.SetTargetPointer;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Styxo
|
||||
*/
|
||||
public class LeavesBattlefieldAllTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
protected FilterPermanent filter;
|
||||
protected SetTargetPointer setTargetPointer;
|
||||
|
||||
public LeavesBattlefieldAllTriggeredAbility(Effect effect, FilterPermanent filter) {
|
||||
this(effect, filter, false);
|
||||
}
|
||||
|
||||
public LeavesBattlefieldAllTriggeredAbility(Effect effect, FilterPermanent filter, boolean optional) {
|
||||
this(Zone.BATTLEFIELD, effect, filter, optional);
|
||||
}
|
||||
|
||||
public LeavesBattlefieldAllTriggeredAbility(Zone zone, Effect effect, FilterPermanent filter, boolean optional) {
|
||||
this(zone, effect, filter, optional, SetTargetPointer.NONE);
|
||||
}
|
||||
|
||||
public LeavesBattlefieldAllTriggeredAbility(Zone zone, Effect effect, FilterPermanent filter, boolean optional, SetTargetPointer setTargetPointer) {
|
||||
super(zone, effect, optional);
|
||||
this.filter = filter;
|
||||
this.setTargetPointer = setTargetPointer;
|
||||
}
|
||||
|
||||
protected LeavesBattlefieldAllTriggeredAbility(final LeavesBattlefieldAllTriggeredAbility ability) {
|
||||
super(ability);
|
||||
filter = ability.filter;
|
||||
setTargetPointer = ability.setTargetPointer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LeavesBattlefieldAllTriggeredAbility copy() {
|
||||
return new LeavesBattlefieldAllTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.ZONE_CHANGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
|
||||
if (zEvent.getFromZone() == Zone.BATTLEFIELD) {
|
||||
UUID targetId = event.getTargetId();
|
||||
Permanent permanent = game.getPermanentOrLKIBattlefield(targetId);
|
||||
if (permanent != null && filter.match(permanent, getSourceId(), getControllerId(), game)) {
|
||||
if (setTargetPointer != SetTargetPointer.NONE) {
|
||||
for (Effect effect : this.getEffects()) {
|
||||
switch (setTargetPointer) {
|
||||
case PERMANENT:
|
||||
effect.setTargetPointer(new FixedTarget(permanent, game));
|
||||
break;
|
||||
case PLAYER:
|
||||
effect.setTargetPointer(new FixedTarget(permanent.getControllerId()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever " + filter.getMessage() + " leaves the battlefield, " + super.getRule();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
package mage.abilities.common;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -78,7 +77,7 @@ class LicidEffect extends OneShotEffect {
|
|||
if (licid != null) {
|
||||
UUID messageId = UUID.randomUUID();
|
||||
LicidContinuousEffect effect = new LicidContinuousEffect(messageId);
|
||||
effect.setTargetPointer(new FixedTarget(licid.getId()));
|
||||
effect.setTargetPointer(new FixedTarget(licid, game));
|
||||
game.addEffect(effect, source);
|
||||
new AttachEffect(Outcome.Neutral).apply(game, source);
|
||||
SpecialAction specialAction = new LicidSpecialAction(this.specialActionCost, messageId, licid.getIdName());
|
||||
|
|
@ -130,7 +129,8 @@ class LicidContinuousEffect extends ContinuousEffectImpl {
|
|||
}
|
||||
}
|
||||
}
|
||||
licid.getAbilities(game).removeAll(toRemove);
|
||||
licid.removeAbilities(toRemove, source.getSourceId(), game);
|
||||
|
||||
Ability ability = new EnchantAbility("creature");
|
||||
ability.setRuleAtTheTop(true);
|
||||
licid.addAbility(ability, source.getSourceId(), game);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class MutatesSourceTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
public MutatesSourceTriggeredAbility(Effect effect) {
|
||||
this(effect, false);
|
||||
}
|
||||
|
||||
public MutatesSourceTriggeredAbility(Effect effect, boolean optional) {
|
||||
super(Zone.BATTLEFIELD, effect, optional);
|
||||
}
|
||||
|
||||
private MutatesSourceTriggeredAbility(final MutatesSourceTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MutatesSourceTriggeredAbility copy() {
|
||||
return new MutatesSourceTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
// TODO: implement this
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
// TODO: implement this
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever this creature mutates, " + super.getRule();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,48 +1,48 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
/**
|
||||
* @author jeffwadsworth
|
||||
*/
|
||||
public class OpponentPlaysLandTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
public OpponentPlaysLandTriggeredAbility(Zone zone, Effect effect, Boolean optional) {
|
||||
super(zone, effect, optional);
|
||||
}
|
||||
|
||||
public OpponentPlaysLandTriggeredAbility(OpponentPlaysLandTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.LAND_PLAYED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
Permanent land = game.getPermanent(event.getTargetId());
|
||||
return land != null && game.getOpponents(controllerId).contains(land.getControllerId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public OpponentPlaysLandTriggeredAbility copy() {
|
||||
return new OpponentPlaysLandTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever an opponent plays a land, ";
|
||||
}
|
||||
}
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
/**
|
||||
* @author jeffwadsworth
|
||||
*/
|
||||
public class OpponentPlaysLandTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
public OpponentPlaysLandTriggeredAbility(Zone zone, Effect effect, Boolean optional) {
|
||||
super(zone, effect, optional);
|
||||
}
|
||||
|
||||
public OpponentPlaysLandTriggeredAbility(OpponentPlaysLandTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.LAND_PLAYED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
Permanent land = game.getPermanent(event.getTargetId());
|
||||
return land != null && game.getOpponents(controllerId).contains(land.getControllerId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public OpponentPlaysLandTriggeredAbility copy() {
|
||||
return new OpponentPlaysLandTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever an opponent plays a land, ";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,13 @@
|
|||
|
||||
package mage.abilities.common;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.ActivatedAbilityImpl;
|
||||
import mage.abilities.effects.common.PassEffect;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class PassAbility extends ActivatedAbilityImpl {
|
||||
|
|
@ -29,7 +28,7 @@ public class PassAbility extends ActivatedAbilityImpl {
|
|||
|
||||
@Override
|
||||
public ActivationStatus canActivate(UUID playerId, Game game) {
|
||||
return ActivationStatus.getTrue();
|
||||
return ActivationStatus.getTrue(this, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ public class PutCardIntoGraveFromAnywhereAllTriggeredAbility extends TriggeredAb
|
|||
switch (setTargetPointer) {
|
||||
case CARD:
|
||||
for (Effect effect : getEffects()) {
|
||||
effect.setTargetPointer(new FixedTarget(card.getId(), card.getZoneChangeCounter(game)));
|
||||
effect.setTargetPointer(new FixedTarget(card, game));
|
||||
}
|
||||
break;
|
||||
case PLAYER:
|
||||
|
|
|
|||
|
|
@ -41,6 +41,9 @@ public class TapForManaAllTriggeredAbility extends TriggeredAbilityImpl {
|
|||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (game.inCheckPlayableState()) { // Ignored - see GameEvent.TAPPED_FOR_MANA
|
||||
return false;
|
||||
}
|
||||
Permanent permanent = game.getPermanentOrLKIBattlefield(event.getSourceId());
|
||||
if (permanent != null && filter.match(permanent, getSourceId(), getControllerId(), game)) {
|
||||
ManaEvent mEvent = (ManaEvent) event;
|
||||
|
|
@ -49,7 +52,7 @@ public class TapForManaAllTriggeredAbility extends TriggeredAbilityImpl {
|
|||
}
|
||||
switch(setTargetPointer) {
|
||||
case PERMANENT:
|
||||
getEffects().get(0).setTargetPointer(new FixedTarget(permanent.getId()));
|
||||
getEffects().get(0).setTargetPointer(new FixedTarget(permanent, game));
|
||||
break;
|
||||
case PLAYER:
|
||||
getEffects().get(0).setTargetPointer(new FixedTarget(permanent.getControllerId()));
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ public class TapForManaAllTriggeredManaAbility extends TriggeredManaAbility {
|
|||
effect.setValue("mana", mEvent.getMana());
|
||||
switch(setTargetPointer) {
|
||||
case PERMANENT:
|
||||
effect.setTargetPointer(new FixedTarget(permanent.getId()));
|
||||
effect.setTargetPointer(new FixedTarget(permanent, game));
|
||||
break;
|
||||
case PLAYER:
|
||||
effect.setTargetPointer(new FixedTarget(permanent.getControllerId()));
|
||||
|
|
|
|||
|
|
@ -34,6 +34,9 @@ public class TapLandForManaAllTriggeredAbility extends TriggeredAbilityImpl {
|
|||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (game.inCheckPlayableState()) { // Ignored - see GameEvent.TAPPED_FOR_MANA
|
||||
return false;
|
||||
}
|
||||
Permanent permanent = game.getPermanentOrLKIBattlefield(event.getSourceId());
|
||||
if (permanent != null && permanent.isLand()) {
|
||||
if (setTargetPointer) {
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ public class TapLandForManaAllTriggeredManaAbility extends TriggeredManaAbility
|
|||
Permanent permanent = game.getPermanentOrLKIBattlefield(event.getSourceId());
|
||||
if (permanent != null && permanent.isLand()) {
|
||||
if (setTargetPointer) {
|
||||
getEffects().get(0).setTargetPointer(new FixedTarget(permanent.getId()));
|
||||
getEffects().get(0).setTargetPointer(new FixedTarget(permanent, game));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ public class TurnFaceUpAbility extends SpecialAction {
|
|||
this.usesStack = false;
|
||||
this.abilityType = AbilityType.SPECIAL_ACTION;
|
||||
this.setRuleVisible(false); // will be made visible only to controller in CardView
|
||||
this.setWorksFaceDown(true);
|
||||
}
|
||||
|
||||
public TurnFaceUpAbility(final TurnFaceUpAbility ability) {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ public class UnattachedTriggeredAbility extends TriggeredAbilityImpl {
|
|||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (event.getSourceId().equals(this.getSourceId()) ) {
|
||||
getEffects().get(0).setTargetPointer(new FixedTarget(event.getTargetId()));
|
||||
getEffects().get(0).setTargetPointer(new FixedTarget(event.getTargetId(), game));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@ public class ZoneChangeAllTriggeredAbility extends TriggeredAbilityImpl {
|
|||
|
||||
public ZoneChangeAllTriggeredAbility(Zone zone, Zone fromZone, Zone toZone, Effect effect, FilterPermanent filter, String rule, boolean optional) {
|
||||
super(zone, effect, optional);
|
||||
if (fromZone == Zone.BATTLEFIELD) {
|
||||
setLeavesTheBattlefieldTrigger(true);
|
||||
}
|
||||
this.fromZone = fromZone;
|
||||
this.toZone = toZone;
|
||||
this.rule = rule;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
package mage.abilities.common.delayed;
|
||||
|
||||
import mage.constants.Outcome;
|
||||
|
|
@ -19,7 +18,6 @@ public class PactDelayedTriggeredAbility extends DelayedTriggeredAbility {
|
|||
super(new PactEffect(cost));
|
||||
}
|
||||
|
||||
|
||||
public PactDelayedTriggeredAbility(PactDelayedTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
|
@ -39,8 +37,6 @@ public class PactDelayedTriggeredAbility extends DelayedTriggeredAbility {
|
|||
return game.isActivePlayer(this.getControllerId());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "At the beginning of your next upkeep " + modes.getText();
|
||||
|
|
@ -49,8 +45,7 @@ public class PactDelayedTriggeredAbility extends DelayedTriggeredAbility {
|
|||
|
||||
class PactEffect extends OneShotEffect {
|
||||
|
||||
private ManaCosts cost;
|
||||
|
||||
private final ManaCosts cost;
|
||||
|
||||
public PactEffect(ManaCosts cost) {
|
||||
super(Outcome.Neutral);
|
||||
|
|
@ -60,7 +55,7 @@ class PactEffect extends OneShotEffect {
|
|||
|
||||
public PactEffect(final PactEffect effect) {
|
||||
super(effect);
|
||||
this.cost = effect.cost;
|
||||
this.cost = effect.cost.copy();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -71,10 +66,10 @@ class PactEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
if (player != null) {
|
||||
if (player.chooseUse(Outcome.Benefit, "Pay " + cost.getText() + '?', source, game)) {
|
||||
if (player != null) {
|
||||
if (player.chooseUse(Outcome.Benefit, "Pay " + cost.getText() + '?', source, game)) {
|
||||
cost.clearPaid();
|
||||
if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)){
|
||||
if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -83,7 +78,4 @@ class PactEffect extends OneShotEffect {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
package mage.abilities.common.delayed;
|
||||
|
||||
import mage.abilities.DelayedTriggeredAbility;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.Duration;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class ReflexiveTriggeredAbility extends DelayedTriggeredAbility {
|
||||
|
||||
private final String text;
|
||||
|
||||
public ReflexiveTriggeredAbility(Effect effect, boolean optional, String text) {
|
||||
super(effect, Duration.EndOfTurn, true, optional);
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
protected ReflexiveTriggeredAbility(final ReflexiveTriggeredAbility ability) {
|
||||
super(ability);
|
||||
this.text = ability.text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.OPTION_USED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
return event.getPlayerId().equals(this.getControllerId())
|
||||
&& event.getSourceId().equals(this.getSourceId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return text.substring(0, 1).toUpperCase(Locale.ENGLISH) + text.substring(1) + '.';
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReflexiveTriggeredAbility copy() {
|
||||
return new ReflexiveTriggeredAbility(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,38 +1,38 @@
|
|||
|
||||
package mage.abilities.condition;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import mage.abilities.Ability;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
* Combines conditions to one compound conditon, one condition must be
|
||||
* true to return true for the compound condtion.
|
||||
*
|
||||
* @author emerald000
|
||||
*/
|
||||
public class OrCondition implements Condition {
|
||||
|
||||
private final ArrayList<Condition> conditions = new ArrayList<>();
|
||||
private final String text;
|
||||
|
||||
public OrCondition(Condition... conditions) {
|
||||
this("", conditions);
|
||||
}
|
||||
|
||||
public OrCondition(String text, Condition... conditions) {
|
||||
this.conditions.addAll(Arrays.asList(conditions));
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return conditions.stream().anyMatch(condition -> condition.apply(game, source));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
||||
package mage.abilities.condition;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import mage.abilities.Ability;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
* Combines conditions to one compound conditon, one condition must be
|
||||
* true to return true for the compound condtion.
|
||||
*
|
||||
* @author emerald000
|
||||
*/
|
||||
public class OrCondition implements Condition {
|
||||
|
||||
private final ArrayList<Condition> conditions = new ArrayList<>();
|
||||
private final String text;
|
||||
|
||||
public OrCondition(Condition... conditions) {
|
||||
this("", conditions);
|
||||
}
|
||||
|
||||
public OrCondition(String text, Condition... conditions) {
|
||||
this.conditions.addAll(Arrays.asList(conditions));
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return conditions.stream().anyMatch(condition -> condition.apply(game, source));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return text;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
package mage.abilities.condition.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Source must be attached to permanent
|
||||
*
|
||||
* @author JayDi85
|
||||
*/
|
||||
public class AttachedToPermanentCondition implements Condition {
|
||||
|
||||
final UUID permanentId;
|
||||
|
||||
public AttachedToPermanentCondition(UUID permanentId) {
|
||||
this.permanentId = permanentId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent attachment = game.getPermanent(source.getSourceId());
|
||||
Permanent permanent = game.getPermanent(this.permanentId);
|
||||
if (attachment != null && permanent != null) {
|
||||
return permanent.getAttachments().contains(attachment.getId());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,24 +1,24 @@
|
|||
|
||||
package mage.abilities.condition.common;
|
||||
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.watchers.common.AttackedThisTurnWatcher;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public enum AttackedThisTurnSourceCondition implements Condition {
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
|
||||
AttackedThisTurnWatcher watcher = game.getState().getWatcher(AttackedThisTurnWatcher.class);
|
||||
return sourcePermanent != null && watcher.getAttackedThisTurnCreatures().contains(new MageObjectReference(sourcePermanent, game));
|
||||
}
|
||||
}
|
||||
|
||||
package mage.abilities.condition.common;
|
||||
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.watchers.common.AttackedThisTurnWatcher;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public enum AttackedThisTurnSourceCondition implements Condition {
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId());
|
||||
AttackedThisTurnWatcher watcher = game.getState().getWatcher(AttackedThisTurnWatcher.class);
|
||||
return sourcePermanent != null && watcher.getAttackedThisTurnCreatures().contains(new MageObjectReference(sourcePermanent, game));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ public enum BuybackCondition implements Condition {
|
|||
public boolean apply(Game game, Ability source) {
|
||||
Card card = game.getCard(source.getSourceId());
|
||||
if (card != null) {
|
||||
return card.getAbilities().stream()
|
||||
return card.getAbilities(game).stream()
|
||||
.filter(a -> a instanceof BuybackAbility)
|
||||
.anyMatch(a -> ((BuybackAbility) a).isBuybackActivated(game));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import mage.watchers.common.CastFromHandWatcher;
|
|||
*
|
||||
* @author Loki
|
||||
*/
|
||||
public enum CastFromHandSourceCondition implements Condition {
|
||||
public enum CastFromHandSourcePermanentCondition implements Condition {
|
||||
|
||||
instance;
|
||||
|
||||
|
|
@ -1,26 +1,26 @@
|
|||
|
||||
package mage.abilities.condition.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.designations.DesignationType;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LvelX2
|
||||
*/
|
||||
public enum CitysBlessingCondition implements Condition {
|
||||
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return game.getPlayer(source.getControllerId()).hasDesignation(DesignationType.CITYS_BLESSING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "you have the city's blessing";
|
||||
}
|
||||
}
|
||||
|
||||
package mage.abilities.condition.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.designations.DesignationType;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LvelX2
|
||||
*/
|
||||
public enum CitysBlessingCondition implements Condition {
|
||||
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return game.getPlayer(source.getControllerId()).hasDesignation(DesignationType.CITYS_BLESSING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "you have the city's blessing";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
package mage.abilities.condition.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.constants.CommanderCardType;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public enum ControlACommanderCondition implements Condition {
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return game.getPlayerList()
|
||||
.stream()
|
||||
.map(game::getPlayer)
|
||||
.filter(Objects::nonNull)
|
||||
.map(player -> game.getCommandersIds(player, CommanderCardType.COMMANDER_OR_OATHBREAKER))
|
||||
.flatMap(Collection::stream)
|
||||
.map(game::getPermanent)
|
||||
.filter(Objects::nonNull)
|
||||
.map(Permanent::getControllerId)
|
||||
.anyMatch(source.getControllerId()::equals);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "If you control a commander";
|
||||
}
|
||||
}
|
||||
|
|
@ -1,88 +1,88 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package mage.abilities.condition.common;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.constants.TargetController;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Styxo
|
||||
*/
|
||||
public class CreatureCountCondition implements Condition {
|
||||
|
||||
private FilterCreaturePermanent filter;
|
||||
private int creatureCount;
|
||||
private TargetController targetController;
|
||||
|
||||
public CreatureCountCondition(FilterCreaturePermanent filter, int creatureCount, TargetController targetController) {
|
||||
this.filter = filter;
|
||||
this.creatureCount = creatureCount;
|
||||
this.targetController = targetController;
|
||||
}
|
||||
|
||||
public CreatureCountCondition(int creatureCount, TargetController targetController) {
|
||||
this.filter = new FilterCreaturePermanent();
|
||||
this.creatureCount = creatureCount;
|
||||
this.targetController = targetController;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
switch (targetController) {
|
||||
case YOU:
|
||||
return game.getBattlefield().countAll(filter, source.getControllerId(), game) == creatureCount;
|
||||
case OPPONENT:
|
||||
for (UUID opponent : game.getOpponents(source.getControllerId())) {
|
||||
if (game.getBattlefield().countAll(filter, opponent, game) != creatureCount) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
case ANY:
|
||||
return game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) == creatureCount;
|
||||
default:
|
||||
throw new UnsupportedOperationException("Value for targetController not supported: " + targetController.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
switch (targetController) {
|
||||
case YOU:
|
||||
sb.append("you");
|
||||
break;
|
||||
case OPPONENT:
|
||||
sb.append("your opponents");
|
||||
break;
|
||||
case ANY:
|
||||
sb.append("if ");
|
||||
sb.append(creatureCount);
|
||||
sb.append(' ');
|
||||
sb.append(filter.getMessage());
|
||||
sb.append(" are on the battlefield");
|
||||
return sb.toString();
|
||||
}
|
||||
sb.append(" control");
|
||||
if (creatureCount == 0) {
|
||||
sb.append(" no ");
|
||||
} else {
|
||||
sb.append(" exactly ");
|
||||
sb.append(creatureCount);
|
||||
sb.append(' ');
|
||||
}
|
||||
sb.append(filter.getMessage());
|
||||
sb.append(creatureCount != 1 ? "s" : "");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package mage.abilities.condition.common;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.constants.TargetController;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Styxo
|
||||
*/
|
||||
public class CreatureCountCondition implements Condition {
|
||||
|
||||
private FilterCreaturePermanent filter;
|
||||
private int creatureCount;
|
||||
private TargetController targetController;
|
||||
|
||||
public CreatureCountCondition(FilterCreaturePermanent filter, int creatureCount, TargetController targetController) {
|
||||
this.filter = filter;
|
||||
this.creatureCount = creatureCount;
|
||||
this.targetController = targetController;
|
||||
}
|
||||
|
||||
public CreatureCountCondition(int creatureCount, TargetController targetController) {
|
||||
this.filter = new FilterCreaturePermanent();
|
||||
this.creatureCount = creatureCount;
|
||||
this.targetController = targetController;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
switch (targetController) {
|
||||
case YOU:
|
||||
return game.getBattlefield().countAll(filter, source.getControllerId(), game) == creatureCount;
|
||||
case OPPONENT:
|
||||
for (UUID opponent : game.getOpponents(source.getControllerId())) {
|
||||
if (game.getBattlefield().countAll(filter, opponent, game) != creatureCount) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
case ANY:
|
||||
return game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) == creatureCount;
|
||||
default:
|
||||
throw new UnsupportedOperationException("Value for targetController not supported: " + targetController.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
switch (targetController) {
|
||||
case YOU:
|
||||
sb.append("you");
|
||||
break;
|
||||
case OPPONENT:
|
||||
sb.append("your opponents");
|
||||
break;
|
||||
case ANY:
|
||||
sb.append("if ");
|
||||
sb.append(creatureCount);
|
||||
sb.append(' ');
|
||||
sb.append(filter.getMessage());
|
||||
sb.append(" are on the battlefield");
|
||||
return sb.toString();
|
||||
}
|
||||
sb.append(" control");
|
||||
if (creatureCount == 0) {
|
||||
sb.append(" no ");
|
||||
} else {
|
||||
sb.append(" exactly ");
|
||||
sb.append(creatureCount);
|
||||
sb.append(' ');
|
||||
}
|
||||
sb.append(filter.getMessage());
|
||||
sb.append(creatureCount != 1 ? "s" : "");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,9 +19,9 @@ public enum DashedCondition implements Condition {
|
|||
public boolean apply(Game game, Ability source) {
|
||||
Card card = game.getCard(source.getSourceId());
|
||||
if (card != null) {
|
||||
return card.getAbilities().stream()
|
||||
return card.getAbilities(game).stream()
|
||||
.filter(a -> a instanceof DashAbility)
|
||||
.anyMatch(d -> ((DashAbility)d).isActivated(source, game));
|
||||
.anyMatch(d -> ((DashAbility) d).isActivated(source, game));
|
||||
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ public enum EvokedCondition implements Condition {
|
|||
public boolean apply(Game game, Ability source) {
|
||||
Card card = game.getCard(source.getSourceId());
|
||||
if (card != null) {
|
||||
return card.getAbilities().stream()
|
||||
return card.getAbilities(game).stream()
|
||||
.filter(ab -> ab instanceof EvokeAbility)
|
||||
.anyMatch(evoke -> ((EvokeAbility) evoke).isActivated(source, game));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,29 +1,29 @@
|
|||
|
||||
package mage.abilities.condition.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.game.Game;
|
||||
import mage.watchers.common.LifeLossOtherFromCombatWatcher;
|
||||
|
||||
/**
|
||||
* Describes condition when an opponent has been dealt any amount of non-combat
|
||||
* damage
|
||||
*
|
||||
* @author Styxo
|
||||
*/
|
||||
public enum HateCondition implements Condition {
|
||||
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
LifeLossOtherFromCombatWatcher watcher = game.getState().getWatcher(LifeLossOtherFromCombatWatcher.class);
|
||||
return watcher != null && watcher.opponentLostLifeOtherFromCombat(source.getControllerId(), game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "if an opponent lost life from source other than combat damage this turn";
|
||||
}
|
||||
}
|
||||
|
||||
package mage.abilities.condition.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.game.Game;
|
||||
import mage.watchers.common.LifeLossOtherFromCombatWatcher;
|
||||
|
||||
/**
|
||||
* Describes condition when an opponent has been dealt any amount of non-combat
|
||||
* damage
|
||||
*
|
||||
* @author Styxo
|
||||
*/
|
||||
public enum HateCondition implements Condition {
|
||||
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
LifeLossOtherFromCombatWatcher watcher = game.getState().getWatcher(LifeLossOtherFromCombatWatcher.class);
|
||||
return watcher != null && watcher.opponentLostLifeOtherFromCombat(source.getControllerId(), game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "if an opponent lost life from source other than combat damage this turn";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,28 +1,28 @@
|
|||
|
||||
package mage.abilities.condition.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.game.Game;
|
||||
import mage.watchers.WatcherUtils;
|
||||
import mage.watchers.common.PlayerLostLifeWatcher;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX
|
||||
*/
|
||||
public enum LiveLostLastTurnCondition implements Condition {
|
||||
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
PlayerLostLifeWatcher watcher = game.getState().getWatcher(PlayerLostLifeWatcher.class);
|
||||
if (watcher != null) {
|
||||
return watcher.getLifeLostLastTurn(source.getControllerId()) > 0;
|
||||
} else {
|
||||
WatcherUtils.logMissingWatcher(game, source, PlayerLostLifeWatcher.class, this.getClass());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
package mage.abilities.condition.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.game.Game;
|
||||
import mage.watchers.WatcherUtils;
|
||||
import mage.watchers.common.PlayerLostLifeWatcher;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX
|
||||
*/
|
||||
public enum LiveLostLastTurnCondition implements Condition {
|
||||
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
PlayerLostLifeWatcher watcher = game.getState().getWatcher(PlayerLostLifeWatcher.class);
|
||||
if (watcher != null) {
|
||||
return watcher.getLifeLostLastTurn(source.getControllerId()) > 0;
|
||||
} else {
|
||||
WatcherUtils.logMissingWatcher(game, source, PlayerLostLifeWatcher.class, this.getClass());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,9 +22,9 @@ import java.util.UUID;
|
|||
*/
|
||||
public class OathbreakerOnBattlefieldCondition implements Condition {
|
||||
|
||||
private UUID playerId;
|
||||
private FilterControlledPermanent filter;
|
||||
private String compatibleNames;
|
||||
private final UUID playerId;
|
||||
private final FilterControlledPermanent filter;
|
||||
private final String compatibleNames;
|
||||
|
||||
public OathbreakerOnBattlefieldCondition(Game game, UUID playerId, UUID signatureSpellId, Set<UUID> oathbreakersToSearch) {
|
||||
this.playerId = playerId;
|
||||
|
|
@ -35,17 +35,17 @@ public class OathbreakerOnBattlefieldCondition implements Condition {
|
|||
|
||||
// spell can be casted by any compatible oathbreakers
|
||||
List<PermanentIdPredicate> compatibleList = new ArrayList<>();
|
||||
List<String> compatibleNames = new ArrayList<>();
|
||||
List<String> compatibleNamesList = new ArrayList<>();
|
||||
if (oathbreakersToSearch != null && !oathbreakersToSearch.isEmpty()) {
|
||||
for (UUID id : oathbreakersToSearch) {
|
||||
Card commander = game.getCard(id);
|
||||
if (commander != null && ManaUtil.isColorIdentityCompatible(commander.getColorIdentity(), spellColors)) {
|
||||
compatibleList.add(new PermanentIdPredicate(id));
|
||||
compatibleNames.add(commander.getName());
|
||||
compatibleNamesList.add(commander.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
this.compatibleNames = String.join("; ", compatibleNames);
|
||||
this.compatibleNames = String.join("; ", compatibleNamesList);
|
||||
|
||||
if (compatibleList.isEmpty()) {
|
||||
// random id to disable condition
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
package mage.abilities.condition.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author JayDi85
|
||||
*/
|
||||
|
||||
public enum OpponentHasNoCardsInHandCondition implements Condition {
|
||||
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
if (player != null) {
|
||||
for (UUID playerId : game.getOpponents(source.getControllerId())) {
|
||||
Player opponent = game.getPlayer(playerId);
|
||||
if (opponent != null && opponent.getHand().isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "an opponent has no cards in hand";
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +1,16 @@
|
|||
|
||||
package mage.abilities.condition.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.abilities.keyword.ProwlAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.SubType;
|
||||
import mage.game.Game;
|
||||
import mage.watchers.common.ProwlWatcher;
|
||||
|
||||
/**
|
||||
* Checks if a the spell was cast with the alternate prowl costs
|
||||
* Is it able to activate prowl cost (damage was made)
|
||||
*
|
||||
* @author LevelX2
|
||||
* @author JayDi85
|
||||
*/
|
||||
public enum ProwlCondition implements Condition {
|
||||
|
||||
|
|
@ -18,22 +18,15 @@ public enum ProwlCondition implements Condition {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
ProwlWatcher watcher = game.getState().getWatcher(ProwlWatcher.class);
|
||||
Card card = game.getCard(source.getSourceId());
|
||||
if (card != null) {
|
||||
for (Ability ability : card.getAbilities()) {
|
||||
if (ability instanceof ProwlAbility) {
|
||||
if (((ProwlAbility) ability).isActivated(source, game)) {
|
||||
return true;
|
||||
}
|
||||
if (watcher != null && card != null) {
|
||||
for (SubType subtype : card.getSubtype(game)) {
|
||||
if (watcher.hasSubtypeMadeCombatDamage(source.getControllerId(), subtype)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{source}'s prowl cost was paid";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
package mage.abilities.condition.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.abilities.keyword.ProwlAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
* Checks if a the spell was cast with the alternate prowl costs
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public enum ProwlCostWasPaidCondition implements Condition {
|
||||
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Card card = game.getCard(source.getSourceId());
|
||||
if (card != null) {
|
||||
for (Ability ability : card.getAbilities()) {
|
||||
if (ability instanceof ProwlAbility) {
|
||||
if (((ProwlAbility) ability).isActivated(source, game)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{source}'s prowl cost was paid";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -21,6 +21,6 @@ public enum RaidCondition implements Condition {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "if you attacked with a creature this turn";
|
||||
return "if you attacked this turn";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,31 +1,43 @@
|
|||
|
||||
package mage.abilities.condition.common;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.watchers.common.LostControlWatcher;
|
||||
|
||||
/**
|
||||
* This condition remembers controller on the first apply.
|
||||
* As long as this controller keeps unchanged and the source is
|
||||
* on the battlefield, the condition is true.
|
||||
* This condition checks if ever since first call of the apply method the
|
||||
* controller of the source has changed
|
||||
*
|
||||
* Monitoring the LOST_CONTROL event has the advantage that also all layered
|
||||
* effects can correctly check for controller change because comparing old and
|
||||
* new controller during their apply time does not take into account layered
|
||||
* change control effects that will be applied later.
|
||||
*
|
||||
* This condition needs the LostControlWatcher, so be sure to add it to the card
|
||||
* that uses the condition.
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class SourceOnBattlefieldControlUnchangedCondition implements Condition {
|
||||
|
||||
private UUID controllerId;
|
||||
|
||||
private Long checkingSince;
|
||||
private int startingZoneChangeCounter;
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
if (controllerId == null) {
|
||||
controllerId = source.getControllerId();
|
||||
if (checkingSince == null) {
|
||||
checkingSince = System.currentTimeMillis() - 1;
|
||||
startingZoneChangeCounter = game.getState().getZoneChangeCounter(source.getSourceId());
|
||||
}
|
||||
Permanent permanent = game.getBattlefield().getPermanent(source.getSourceId());
|
||||
return (permanent != null && Objects.equals(controllerId, source.getControllerId()));
|
||||
if (game.getState().getZoneChangeCounter(source.getSourceId()) > startingZoneChangeCounter) {
|
||||
return false;
|
||||
}
|
||||
LostControlWatcher watcher = game.getState().getWatcher(LostControlWatcher.class);
|
||||
if (watcher != null) {
|
||||
return checkingSince > watcher.getOrderOfLastLostControl(source.getSourceId());
|
||||
}
|
||||
throw new UnsupportedOperationException("LostControlWatcher not found!");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package mage.abilities.condition.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class SourceRemainsInZoneCondition implements Condition {
|
||||
|
||||
private final Zone zone;
|
||||
private int timesChangedZones = -1;
|
||||
|
||||
public SourceRemainsInZoneCondition(Zone zone) {
|
||||
this.zone = zone;
|
||||
this.timesChangedZones = -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
if (timesChangedZones == -1) { // Only changed on first execution
|
||||
timesChangedZones = game.getState().getZoneChangeCounter(source.getSourceId());
|
||||
}
|
||||
return (timesChangedZones == game.getState().getZoneChangeCounter(source.getSourceId())
|
||||
&& zone.equals(game.getState().getZone(source.getSourceId())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "for as long as {this} remains on the " + zone.toString();
|
||||
}
|
||||
}
|
||||
|
|
@ -27,10 +27,10 @@ public enum SuspendedCondition implements Condition {
|
|||
public boolean apply(Game game, Ability source) {
|
||||
Card card = game.getCard(source.getSourceId());
|
||||
if (card != null) {
|
||||
boolean found = card.getAbilities().stream().anyMatch(ability -> ability instanceof SuspendAbility);
|
||||
boolean found = card.getAbilities(game).containsClass(SuspendAbility.class);
|
||||
|
||||
if (!found) {
|
||||
found = game.getState().getAllOtherAbilities(source.getSourceId()).stream().anyMatch(ability -> ability instanceof SuspendAbility);
|
||||
found = game.getState().getAllOtherAbilities(source.getSourceId()).containsClass(SuspendAbility.class);
|
||||
|
||||
}
|
||||
if (found) {
|
||||
|
|
|
|||
|
|
@ -1,72 +1,72 @@
|
|||
|
||||
package mage.abilities.condition.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.cards.Card;
|
||||
import mage.counters.CounterType;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Styxo
|
||||
*/
|
||||
public class TargetHasCounterCondition implements Condition {
|
||||
|
||||
private final CounterType counterType;
|
||||
private int amount = 1;
|
||||
private int from = -1;
|
||||
private int to;
|
||||
|
||||
public TargetHasCounterCondition(CounterType type) {
|
||||
this.counterType = type;
|
||||
}
|
||||
|
||||
public TargetHasCounterCondition(CounterType type, int amount) {
|
||||
this.counterType = type;
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public TargetHasCounterCondition(CounterType type, int from, int to) {
|
||||
this.counterType = type;
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("null")
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Card card = null;
|
||||
Permanent permanent = game.getPermanentOrLKIBattlefield(source.getFirstTarget());
|
||||
if (permanent == null) {
|
||||
card = game.getCard(source.getFirstTarget());
|
||||
if (card == null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (from != -1) { //range compare
|
||||
int count;
|
||||
if (card != null) {
|
||||
count = card.getCounters(game).getCount(counterType);
|
||||
} else {
|
||||
count = permanent.getCounters(game).getCount(counterType);
|
||||
}
|
||||
if (to == Integer.MAX_VALUE) {
|
||||
return count >= from;
|
||||
}
|
||||
return count >= from && count <= to;
|
||||
} else { // single compare (lte)
|
||||
if (card != null) {
|
||||
return card.getCounters(game).getCount(counterType) >= amount;
|
||||
} else {
|
||||
return permanent.getCounters(game).getCount(counterType) >= amount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "if it has a " + counterType.getName() + " on it";
|
||||
}
|
||||
}
|
||||
|
||||
package mage.abilities.condition.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.cards.Card;
|
||||
import mage.counters.CounterType;
|
||||
import mage.game.Game;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Styxo
|
||||
*/
|
||||
public class TargetHasCounterCondition implements Condition {
|
||||
|
||||
private final CounterType counterType;
|
||||
private int amount = 1;
|
||||
private int from = -1;
|
||||
private int to;
|
||||
|
||||
public TargetHasCounterCondition(CounterType type) {
|
||||
this.counterType = type;
|
||||
}
|
||||
|
||||
public TargetHasCounterCondition(CounterType type, int amount) {
|
||||
this.counterType = type;
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public TargetHasCounterCondition(CounterType type, int from, int to) {
|
||||
this.counterType = type;
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("null")
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Card card = null;
|
||||
Permanent permanent = game.getPermanentOrLKIBattlefield(source.getFirstTarget());
|
||||
if (permanent == null) {
|
||||
card = game.getCard(source.getFirstTarget());
|
||||
if (card == null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (from != -1) { //range compare
|
||||
int count;
|
||||
if (card != null) {
|
||||
count = card.getCounters(game).getCount(counterType);
|
||||
} else {
|
||||
count = permanent.getCounters(game).getCount(counterType);
|
||||
}
|
||||
if (to == Integer.MAX_VALUE) {
|
||||
return count >= from;
|
||||
}
|
||||
return count >= from && count <= to;
|
||||
} else { // single compare (lte)
|
||||
if (card != null) {
|
||||
return card.getCounters(game).getCount(counterType) >= amount;
|
||||
} else {
|
||||
return permanent.getCounters(game).getCount(counterType) >= amount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "if it has a " + counterType.getName() + " on it";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
package mage.abilities.condition.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.constants.ComparisonType;
|
||||
import mage.abilities.condition.IntCompareCondition;
|
||||
import mage.constants.ComparisonType;
|
||||
import mage.game.Game;
|
||||
import mage.watchers.common.PlayerGainedLifeWatcher;
|
||||
|
||||
|
|
@ -27,6 +27,6 @@ public class YouGainedLifeCondition extends IntCompareCondition {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("if you gained %s or more life this turn ", value + 1);
|
||||
return String.format("if you gained %s or more life this turn", value + 1);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -151,11 +151,11 @@ public class AlternativeCostSourceAbility extends StaticAbility implements Alter
|
|||
for (AlternativeCost2 alternateCost : alternativeCostsToCheck) {
|
||||
alternateCost.activate();
|
||||
for (Iterator it = ((Costs) alternateCost).iterator(); it.hasNext(); ) {
|
||||
Cost costDeailed = (Cost) it.next();
|
||||
if (costDeailed instanceof ManaCost) {
|
||||
ability.getManaCostsToPay().add((ManaCost) costDeailed.copy());
|
||||
} else {
|
||||
ability.getCosts().add(costDeailed.copy());
|
||||
Cost costDetailed = (Cost) it.next();
|
||||
if (costDetailed instanceof ManaCost) {
|
||||
ability.getManaCostsToPay().add((ManaCost) costDetailed.copy());
|
||||
} else if (costDetailed != null) {
|
||||
ability.getCosts().add(costDetailed.copy());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -222,7 +222,7 @@ public class AlternativeCostSourceAbility extends StaticAbility implements Alter
|
|||
sb.append("pay ");
|
||||
}
|
||||
String text = alternativeCost.getText(true);
|
||||
sb.append(Character.toLowerCase(text.charAt(0)) + text.substring(1));
|
||||
sb.append(Character.toLowerCase(text.charAt(0))).append(text.substring(1));
|
||||
}
|
||||
++numberCosts;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,5 +8,14 @@ import mage.game.Game;
|
|||
*/
|
||||
public interface CostAdjuster {
|
||||
|
||||
/**
|
||||
* Must check playable and real cast states.
|
||||
* Example: if it need stack related info (like real targets) then must check two states (game.inCheckPlayableState):
|
||||
* 1. In playable state it must check all possible use cases (e.g. allow to reduce on any available target and modes)
|
||||
* 2. In real cast state it must check current use case (e.g. real selected targets and modes)
|
||||
*
|
||||
* @param ability
|
||||
* @param game
|
||||
*/
|
||||
void adjustCosts(Ability ability, Game game);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,58 +1,63 @@
|
|||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jeffwadsworth
|
||||
*/
|
||||
|
||||
package mage.abilities.costs.common;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.costs.CostImpl;
|
||||
import mage.cards.Card;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.players.Player;
|
||||
|
||||
public class CyclingDiscardCost extends CostImpl {
|
||||
|
||||
public CyclingDiscardCost() {
|
||||
}
|
||||
|
||||
public CyclingDiscardCost(CyclingDiscardCost cost) {
|
||||
super(cost);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) {
|
||||
return game.getPlayer(controllerId).getHand().contains(sourceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) {
|
||||
Player player = game.getPlayer(controllerId);
|
||||
if (player != null) {
|
||||
Card card = player.getHand().get(sourceId, game);
|
||||
if (card != null) {
|
||||
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.CYCLE_CARD, card.getId(), card.getId(), card.getOwnerId()));
|
||||
paid = player.discard(card, null, game);
|
||||
if (paid) {
|
||||
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.CYCLED_CARD, card.getId(), card.getId(), card.getOwnerId()));
|
||||
}
|
||||
}
|
||||
}
|
||||
return paid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText() {
|
||||
return "Discard this card";
|
||||
}
|
||||
|
||||
@Override
|
||||
public CyclingDiscardCost copy() {
|
||||
return new CyclingDiscardCost(this);
|
||||
}
|
||||
}
|
||||
package mage.abilities.costs.common;
|
||||
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.costs.CostImpl;
|
||||
import mage.cards.Card;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.players.Player;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author jeffwadsworth
|
||||
*/
|
||||
public class CyclingDiscardCost extends CostImpl {
|
||||
|
||||
private MageObjectReference cycledCard = null;
|
||||
|
||||
public CyclingDiscardCost() {
|
||||
}
|
||||
|
||||
private CyclingDiscardCost(CyclingDiscardCost cost) {
|
||||
super(cost);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) {
|
||||
return game.getPlayer(controllerId).getHand().contains(sourceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) {
|
||||
Player player = game.getPlayer(controllerId);
|
||||
if (player != null) {
|
||||
Card card = player.getHand().get(sourceId, game);
|
||||
if (card != null) {
|
||||
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.CYCLE_CARD, card.getId(), card.getId(), card.getOwnerId()));
|
||||
paid = player.discard(card, null, game);
|
||||
if (paid) {
|
||||
cycledCard = new MageObjectReference(card, game);
|
||||
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.CYCLED_CARD, card.getId(), card.getId(), card.getOwnerId()));
|
||||
}
|
||||
}
|
||||
}
|
||||
return paid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText() {
|
||||
return "Discard this card";
|
||||
}
|
||||
|
||||
@Override
|
||||
public CyclingDiscardCost copy() {
|
||||
return new CyclingDiscardCost(this);
|
||||
}
|
||||
|
||||
public MageObjectReference getCycledCard() {
|
||||
return cycledCard;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
|
||||
package mage.abilities.costs.common;
|
||||
|
||||
import mage.filter.FilterCard;
|
||||
import mage.target.common.TargetCardInHand;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author magenoxx_at_googlemail.com
|
||||
*/
|
||||
public class DiscardCardCost extends DiscardTargetCost {
|
||||
|
|
@ -15,7 +13,7 @@ public class DiscardCardCost extends DiscardTargetCost {
|
|||
}
|
||||
|
||||
public DiscardCardCost(boolean randomDiscard) {
|
||||
this(new FilterCard(randomDiscard ?"a card at random":"a card"), randomDiscard);
|
||||
this(new FilterCard(randomDiscard ? "a card at random" : "a card"), randomDiscard);
|
||||
}
|
||||
|
||||
public DiscardCardCost(FilterCard filter) {
|
||||
|
|
@ -23,7 +21,7 @@ public class DiscardCardCost extends DiscardTargetCost {
|
|||
}
|
||||
|
||||
public DiscardCardCost(FilterCard filter, boolean randomDiscard) {
|
||||
super(new TargetCardInHand(filter), randomDiscard);
|
||||
super(new TargetCardInHand(filter).withChooseHint("discard cost"), randomDiscard);
|
||||
}
|
||||
|
||||
public DiscardCardCost(final DiscardCardCost cost) {
|
||||
|
|
|
|||
|
|
@ -1,27 +1,23 @@
|
|||
|
||||
|
||||
package mage.abilities.costs.common;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.costs.CostImpl;
|
||||
import mage.cards.Card;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
|
||||
public class DiscardHandCost extends CostImpl {
|
||||
|
||||
public DiscardHandCost() {
|
||||
|
||||
}
|
||||
|
||||
public DiscardHandCost(final DiscardHandCost cost) {
|
||||
private DiscardHandCost(final DiscardHandCost cost) {
|
||||
super(cost);
|
||||
}
|
||||
|
||||
|
|
@ -38,12 +34,11 @@ public class DiscardHandCost extends CostImpl {
|
|||
@Override
|
||||
public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) {
|
||||
Player player = game.getPlayer(controllerId);
|
||||
if (player != null) {
|
||||
for (Card card : player.getHand().getCards(game)) {
|
||||
player.discard(card, ability, game);
|
||||
}
|
||||
paid = true;
|
||||
if (player == null) {
|
||||
return paid;
|
||||
}
|
||||
player.discard(player.getHand(), ability, game);
|
||||
paid = true;
|
||||
return paid;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,20 +1,21 @@
|
|||
|
||||
package mage.abilities.costs.common;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.costs.CostImpl;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.Cards;
|
||||
import mage.cards.CardsImpl;
|
||||
import mage.constants.Outcome;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.target.common.TargetCardInHand;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
public class DiscardTargetCost extends CostImpl {
|
||||
|
|
@ -50,13 +51,11 @@ public class DiscardTargetCost extends CostImpl {
|
|||
if (randomDiscard) {
|
||||
this.cards.addAll(player.discard(amount, true, ability, game).getCards(game));
|
||||
} else if (targets.choose(Outcome.Discard, controllerId, sourceId, game)) {
|
||||
for (UUID targetId : targets.get(0).getTargets()) {
|
||||
Card card = player.getHand().get(targetId, game);
|
||||
if (card == null) {
|
||||
return false;
|
||||
}
|
||||
player.discard(card, ability, game);
|
||||
this.cards.add(card);
|
||||
Cards toDiscard = new CardsImpl();
|
||||
toDiscard.addAll(targets.get(0).getTargets());
|
||||
Cards discarded = player.discard(toDiscard, ability, game);
|
||||
if (!discarded.isEmpty()) {
|
||||
cards.addAll(discarded.getCards(game));
|
||||
}
|
||||
}
|
||||
paid = cards.size() >= amount;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
package mage.abilities.costs.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
|
|
@ -10,7 +9,6 @@ import mage.players.Player;
|
|||
import mage.target.common.TargetCardInHand;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class DiscardXTargetCost extends VariableCostImpl {
|
||||
|
|
|
|||
|
|
@ -1,54 +1,54 @@
|
|||
|
||||
package mage.abilities.costs.common;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.costs.CostImpl;
|
||||
import mage.abilities.effects.ContinuousEffect;
|
||||
import mage.abilities.effects.common.DontUntapInControllersNextUntapStepTargetEffect;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author emerald000
|
||||
*/
|
||||
public class ExertSourceCost extends CostImpl {
|
||||
|
||||
public ExertSourceCost() {
|
||||
this.text = "Exert {this}";
|
||||
}
|
||||
|
||||
public ExertSourceCost(ExertSourceCost cost) {
|
||||
super(cost);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) {
|
||||
Player player = game.getPlayer(controllerId);
|
||||
Permanent permanent = game.getPermanent(sourceId);
|
||||
if (player != null && permanent != null) {
|
||||
game.fireEvent(GameEvent.getEvent(EventType.BECOMES_EXERTED, permanent.getId(), permanent.getId(), permanent.getControllerId()));
|
||||
ContinuousEffect effect = new DontUntapInControllersNextUntapStepTargetEffect("", permanent.getControllerId());
|
||||
effect.setTargetPointer(new FixedTarget(permanent, game));
|
||||
game.addEffect(effect, ability);
|
||||
paid = true;
|
||||
}
|
||||
return paid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExertSourceCost copy() {
|
||||
return new ExertSourceCost(this);
|
||||
}
|
||||
}
|
||||
|
||||
package mage.abilities.costs.common;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.costs.CostImpl;
|
||||
import mage.abilities.effects.ContinuousEffect;
|
||||
import mage.abilities.effects.common.DontUntapInControllersNextUntapStepTargetEffect;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author emerald000
|
||||
*/
|
||||
public class ExertSourceCost extends CostImpl {
|
||||
|
||||
public ExertSourceCost() {
|
||||
this.text = "Exert {this}";
|
||||
}
|
||||
|
||||
public ExertSourceCost(ExertSourceCost cost) {
|
||||
super(cost);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) {
|
||||
Player player = game.getPlayer(controllerId);
|
||||
Permanent permanent = game.getPermanent(sourceId);
|
||||
if (player != null && permanent != null) {
|
||||
game.fireEvent(GameEvent.getEvent(EventType.BECOMES_EXERTED, permanent.getId(), permanent.getId(), permanent.getControllerId()));
|
||||
ContinuousEffect effect = new DontUntapInControllersNextUntapStepTargetEffect("", permanent.getControllerId());
|
||||
effect.setTargetPointer(new FixedTarget(permanent, game));
|
||||
game.addEffect(effect, ability);
|
||||
paid = true;
|
||||
}
|
||||
return paid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExertSourceCost copy() {
|
||||
return new ExertSourceCost(this);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,9 @@ public class ExileFromGraveCost extends CostImpl {
|
|||
+ CardUtil.numberToText(target.getMaxNumberOfTargets()))
|
||||
+ ' ' + target.getTargetName();
|
||||
} else {
|
||||
this.text = "Exile " + target.getTargetName();
|
||||
this.text = "Exile "
|
||||
+ (target.getTargetName().startsWith("card ") ? "a ":"")
|
||||
+ target.getTargetName();
|
||||
}
|
||||
if (!this.text.endsWith(" from your graveyard")) {
|
||||
this.text = this.text + " from your graveyard";
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import mage.players.Player;
|
|||
public class ExileSourceFromGraveCost extends CostImpl {
|
||||
|
||||
public ExileSourceFromGraveCost() {
|
||||
this.text = "Exile this card from your graveyard";
|
||||
this.text = "Exile {this} from your graveyard";
|
||||
}
|
||||
|
||||
public ExileSourceFromGraveCost(ExileSourceFromGraveCost cost) {
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ public class PayLifeCost extends CostImpl {
|
|||
//life total; in other words, the player loses that much life. (Players can always pay 0 life.)
|
||||
int lifeToPayAmount = amount.calculate(game, ability, null);
|
||||
// Paying 0 life is not considered paying any life.
|
||||
if (lifeToPayAmount > 0 && !game.getPlayer(controllerId).canPayLifeCost()) {
|
||||
if (lifeToPayAmount > 0 && !game.getPlayer(controllerId).canPayLifeCost(ability)) {
|
||||
return false;
|
||||
}
|
||||
return game.getPlayer(controllerId).getLife() >= lifeToPayAmount || lifeToPayAmount == 0;
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ public class PayVariableLifeCost extends VariableCostImpl {
|
|||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null) {
|
||||
// Paying 0 life is not considered paying any life, so paying 0 is still allowed
|
||||
if (game.getPlayer(source.getControllerId()).canPayLifeCost()) {
|
||||
if (game.getPlayer(source.getControllerId()).canPayLifeCost(source)) {
|
||||
maxValue = controller.getLife();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,60 +1,60 @@
|
|||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package mage.abilities.costs.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.costs.CostImpl;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.target.common.TargetCardInHand;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author jeffwadsworth
|
||||
*/
|
||||
|
||||
public class PutCardFromHandOnTopOfLibraryCost extends CostImpl {
|
||||
|
||||
public PutCardFromHandOnTopOfLibraryCost() {
|
||||
this.text = "Put a card from your hand on top of your library";
|
||||
}
|
||||
|
||||
public PutCardFromHandOnTopOfLibraryCost(PutCardFromHandOnTopOfLibraryCost cost) {
|
||||
super(cost);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) {
|
||||
Player controller = game.getPlayer(controllerId);
|
||||
TargetCardInHand targetCardInHand = new TargetCardInHand();
|
||||
targetCardInHand.setRequired(false);
|
||||
Card card;
|
||||
if (targetCardInHand.canChoose(controllerId, game)
|
||||
&& controller.choose(Outcome.PreventDamage, targetCardInHand, sourceId, game)) {
|
||||
card = game.getCard(targetCardInHand.getFirstTarget());
|
||||
paid = card != null && controller.moveCardToLibraryWithInfo(card, sourceId, game, Zone.HAND, true, true);
|
||||
}
|
||||
return paid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) {
|
||||
Player controller = game.getPlayer(controllerId);
|
||||
return (controller != null
|
||||
&& !controller.getHand().isEmpty());
|
||||
}
|
||||
|
||||
@Override
|
||||
public PutCardFromHandOnTopOfLibraryCost copy() {
|
||||
return new PutCardFromHandOnTopOfLibraryCost(this);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* To change this license header, choose License Headers in Project Properties.
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package mage.abilities.costs.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.costs.CostImpl;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.target.common.TargetCardInHand;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author jeffwadsworth
|
||||
*/
|
||||
|
||||
public class PutCardFromHandOnTopOfLibraryCost extends CostImpl {
|
||||
|
||||
public PutCardFromHandOnTopOfLibraryCost() {
|
||||
this.text = "Put a card from your hand on top of your library";
|
||||
}
|
||||
|
||||
public PutCardFromHandOnTopOfLibraryCost(PutCardFromHandOnTopOfLibraryCost cost) {
|
||||
super(cost);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) {
|
||||
Player controller = game.getPlayer(controllerId);
|
||||
TargetCardInHand targetCardInHand = new TargetCardInHand();
|
||||
targetCardInHand.setRequired(false);
|
||||
Card card;
|
||||
if (targetCardInHand.canChoose(controllerId, game)
|
||||
&& controller.choose(Outcome.PreventDamage, targetCardInHand, sourceId, game)) {
|
||||
card = game.getCard(targetCardInHand.getFirstTarget());
|
||||
paid = card != null && controller.moveCardToLibraryWithInfo(card, sourceId, game, Zone.HAND, true, true);
|
||||
}
|
||||
return paid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) {
|
||||
Player controller = game.getPlayer(controllerId);
|
||||
return (controller != null
|
||||
&& !controller.getHand().isEmpty());
|
||||
}
|
||||
|
||||
@Override
|
||||
public PutCardFromHandOnTopOfLibraryCost copy() {
|
||||
return new PutCardFromHandOnTopOfLibraryCost(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,18 +1,17 @@
|
|||
|
||||
package mage.abilities.costs.common;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.costs.CostImpl;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
public class PutTopCardOfYourLibraryToGraveyardCost extends CostImpl {
|
||||
|
||||
private final int numberOfCards;
|
||||
|
|
@ -27,7 +26,7 @@ public class PutTopCardOfYourLibraryToGraveyardCost extends CostImpl {
|
|||
this.text = setText();
|
||||
}
|
||||
|
||||
public PutTopCardOfYourLibraryToGraveyardCost(PutTopCardOfYourLibraryToGraveyardCost cost) {
|
||||
private PutTopCardOfYourLibraryToGraveyardCost(final PutTopCardOfYourLibraryToGraveyardCost cost) {
|
||||
super(cost);
|
||||
this.numberOfCards = cost.numberOfCards;
|
||||
this.cardsMovedToGraveyard.addAll(cost.getCardsMovedToGraveyard());
|
||||
|
|
@ -38,8 +37,7 @@ public class PutTopCardOfYourLibraryToGraveyardCost extends CostImpl {
|
|||
Player player = game.getPlayer(controllerId);
|
||||
if (player != null && player.getLibrary().size() >= numberOfCards) {
|
||||
paid = true;
|
||||
this.cardsMovedToGraveyard.addAll(player.getLibrary().getTopCards(game, numberOfCards));
|
||||
player.moveCards(player.getLibrary().getTopCards(game, numberOfCards), Zone.GRAVEYARD, ability, game);
|
||||
this.cardsMovedToGraveyard.addAll(player.millCards(numberOfCards, ability, game).getCards(game));
|
||||
}
|
||||
return paid;
|
||||
}
|
||||
|
|
@ -60,13 +58,6 @@ public class PutTopCardOfYourLibraryToGraveyardCost extends CostImpl {
|
|||
}
|
||||
|
||||
private String setText() {
|
||||
StringBuilder sb = new StringBuilder("Put the top ");
|
||||
if (numberOfCards == 1) {
|
||||
sb.append("card");
|
||||
} else {
|
||||
sb.append(CardUtil.numberToText(numberOfCards)).append(" cards");
|
||||
}
|
||||
sb.append(" of your library into your graveyard");
|
||||
return sb.toString();
|
||||
return "mill " + (numberOfCards == 1 ? "a card" : CardUtil.numberToText(numberOfCards) + " cards");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,10 +23,10 @@ import java.util.UUID;
|
|||
*/
|
||||
public class RemoveCounterCost extends CostImpl {
|
||||
|
||||
private TargetPermanent target;
|
||||
protected TargetPermanent target;
|
||||
private String name;
|
||||
private CounterType counterTypeToRemove;
|
||||
private int countersToRemove;
|
||||
protected int countersToRemove;
|
||||
|
||||
public RemoveCounterCost(TargetPermanent target) {
|
||||
this(target, null);
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ public class ReturnToHandChosenControlledPermanentCost extends CostImpl {
|
|||
target.setNotTarget(true);
|
||||
this.addTarget(target);
|
||||
if (target.getMaxNumberOfTargets() > 1 && target.getMaxNumberOfTargets() == target.getNumberOfTargets()) {
|
||||
this.text = "return " + CardUtil.numberToText(target.getMaxNumberOfTargets()) + ' '
|
||||
this.text = "Return " + CardUtil.numberToText(target.getMaxNumberOfTargets()) + ' '
|
||||
+ target.getTargetName()
|
||||
+ (target.getTargetName().endsWith(" you control") ? "" : " you control")
|
||||
+ " to their owner's hand";
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
package mage.abilities.costs.mana;
|
||||
|
||||
/**
|
||||
* Some special AlternateManaPaymentAbility must be restricted to pay before or after mana abilities.
|
||||
* Game logic: if you use special mana ability then normal mana abilities must be restricted and vice versa,
|
||||
* see Convoke for more info and rules
|
||||
*
|
||||
* @author JayDi85
|
||||
*/
|
||||
|
||||
public enum ActivationManaAbilityStep {
|
||||
BEFORE(0), // assist
|
||||
NORMAL(1), // all activated mana abilities
|
||||
AFTER(2); // convoke, delve, improvise
|
||||
|
||||
private final int stepOrder;
|
||||
|
||||
ActivationManaAbilityStep(int stepOrder) {
|
||||
this.stepOrder = stepOrder;
|
||||
}
|
||||
|
||||
public int getStepOrder() {
|
||||
return stepOrder;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +1,17 @@
|
|||
|
||||
package mage.abilities.costs.mana;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.mana.ManaOptions;
|
||||
import mage.game.Game;
|
||||
|
||||
/**
|
||||
* Interface for abilities that allow the player to pay mana costs of a spell in alternate ways.
|
||||
* For the payment SpecialActions are used.
|
||||
*
|
||||
* <p>
|
||||
* Example of such an alternate payment ability: {@link mage.abilities.keyword.DelveAbility}
|
||||
*
|
||||
* @author LevelX2
|
||||
* @author LevelX2, JayDi85
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface AlternateManaPaymentAbility {
|
||||
/**
|
||||
* Adds the special action to the state, that allows the user to do the alternate mana payment
|
||||
|
|
@ -22,4 +21,21 @@ public interface AlternateManaPaymentAbility {
|
|||
* @param unpaid unapaid mana costs of the spell
|
||||
*/
|
||||
void addSpecialAction(Ability source, Game game, ManaCost unpaid);
|
||||
|
||||
/**
|
||||
* All possible mana payments that can make that ability (uses to find playable abilities)
|
||||
*
|
||||
* @param source
|
||||
* @param game
|
||||
* @param unpaid
|
||||
* @return
|
||||
*/
|
||||
ManaOptions getManaOptions(Ability source, Game game, ManaCost unpaid);
|
||||
|
||||
/**
|
||||
* Mana payment step where you can use it
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
ActivationManaAbilityStep useOnActivationManaAbilityStep();
|
||||
}
|
||||
|
|
@ -120,7 +120,7 @@ public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> implements M
|
|||
}
|
||||
|
||||
Player player = game.getPlayer(controllerId);
|
||||
handleKrrikPhyrexianManaCosts(controllerId, ability, game);
|
||||
handleLikePhyrexianManaCosts(controllerId, ability, game); // e.g. K'rrik, Son of Yawgmoth
|
||||
if (!player.getManaPool().isForcedToPay()) {
|
||||
assignPayment(game, ability, player.getManaPool(), this);
|
||||
}
|
||||
|
|
@ -150,13 +150,16 @@ public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> implements M
|
|||
*/
|
||||
@Override
|
||||
public boolean payOrRollback(Ability ability, Game game, UUID sourceId, UUID payingPlayerId) {
|
||||
int bookmark = game.bookmarkState();
|
||||
handlePhyrexianManaCosts(payingPlayerId, ability, game);
|
||||
if (pay(ability, game, sourceId, payingPlayerId, false, null)) {
|
||||
game.removeBookmark(bookmark);
|
||||
return true;
|
||||
Player player = game.getPlayer(payingPlayerId);
|
||||
if (player != null) {
|
||||
int bookmark = game.bookmarkState();
|
||||
handlePhyrexianManaCosts(payingPlayerId, ability, game);
|
||||
if (pay(ability, game, sourceId, payingPlayerId, false, null)) {
|
||||
game.removeBookmark(bookmark);
|
||||
return true;
|
||||
}
|
||||
player.restoreState(bookmark, ability.getRule(), game);
|
||||
}
|
||||
game.restoreState(bookmark, ability.getRule());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -170,11 +173,6 @@ public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> implements M
|
|||
|
||||
while (manaCostIterator.hasNext()) {
|
||||
ManaCost manaCost = manaCostIterator.next();
|
||||
PhyrexianManaCost tempPhyrexianCost = null;
|
||||
Mana mana = manaCost.getMana();
|
||||
|
||||
FilterMana phyrexianColors = player.getPhyrexianColors();
|
||||
|
||||
if (manaCost instanceof PhyrexianManaCost) {
|
||||
PhyrexianManaCost phyrexianManaCost = (PhyrexianManaCost) manaCost;
|
||||
PayLifeCost payLifeCost = new PayLifeCost(2);
|
||||
|
|
@ -189,7 +187,7 @@ public class ManaCostsImpl<T extends ManaCost> extends ArrayList<T> implements M
|
|||
tempCosts.pay(source, game, source.getSourceId(), player.getId(), false, null);
|
||||
}
|
||||
|
||||
private void handleKrrikPhyrexianManaCosts(UUID payingPlayerId, Ability source, Game game) {
|
||||
private void handleLikePhyrexianManaCosts(UUID payingPlayerId, Ability source, Game game) {
|
||||
Player player = game.getPlayer(payingPlayerId);
|
||||
if (this == null || player == null) {
|
||||
return; // nothing to be done without any mana costs. prevents NRE from occurring here
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue