mirror of
https://github.com/magefree/mage.git
synced 2025-12-25 21:12:04 -08:00
Merge branch 'master' into fix_hints_equip
# Conflicts: # Mage.Sets/src/mage/cards/b/BehemothSledge.java # Mage.Sets/src/mage/cards/d/DivinersWand.java # Mage.Sets/src/mage/cards/u/UmbralMantle.java # Mage.Sets/src/mage/cards/u/UnscytheKillerOfKings.java # Mage.Sets/src/mage/cards/w/WandOfOrcus.java # Mage/src/main/java/mage/abilities/keyword/EquipAbility.java
This commit is contained in:
commit
b3bf42389b
5304 changed files with 66289 additions and 32481 deletions
|
|
@ -14,6 +14,7 @@ public enum MageIdentifier {
|
|||
KessDissidentMageWatcher,
|
||||
LurrusOfTheDreamDenWatcher,
|
||||
MuldrothaTheGravetideWatcher,
|
||||
ShareTheSpoilsWatcher,
|
||||
WishWatcher,
|
||||
GlimpseTheCosmosWatcher
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import mage.abilities.Abilities;
|
|||
import mage.abilities.Ability;
|
||||
import mage.abilities.costs.mana.ManaCost;
|
||||
import mage.abilities.costs.mana.ManaCosts;
|
||||
import mage.abilities.text.TextPart;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.FrameStyle;
|
||||
import mage.constants.CardType;
|
||||
|
|
@ -117,25 +116,6 @@ public interface MageObject extends MageItem, Serializable, Copyable<MageObject>
|
|||
|
||||
void setStartingLoyalty(int startingLoyalty);
|
||||
|
||||
/**
|
||||
* Dynamic cost modification for card (process only OWN abilities).
|
||||
* <p>
|
||||
* Usage example: if it need stack related info (like real targets) then must check two
|
||||
* states (game.inCheckPlayableState):
|
||||
* <p>
|
||||
* 1. In playable state it must check all possible use cases (e.g. allow to
|
||||
* reduce on any available target and modes)
|
||||
* <p>
|
||||
* 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);
|
||||
|
||||
void adjustTargets(Ability ability, Game game);
|
||||
|
||||
// memory object copy (not mtg)
|
||||
@Override
|
||||
MageObject copy();
|
||||
|
|
@ -508,13 +488,5 @@ public interface MageObject extends MageItem, Serializable, Copyable<MageObject>
|
|||
*/
|
||||
void setIsAllCreatureTypes(Game game, boolean value);
|
||||
|
||||
List<TextPart> getTextParts();
|
||||
|
||||
TextPart addTextPart(TextPart textPart);
|
||||
|
||||
void removePTCDA();
|
||||
|
||||
default void changeSubType(SubType fromSubType, SubType toSubType) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,16 +3,12 @@ package mage;
|
|||
import mage.abilities.Abilities;
|
||||
import mage.abilities.AbilitiesImpl;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility;
|
||||
import mage.abilities.costs.mana.ManaCost;
|
||||
import mage.abilities.costs.mana.ManaCosts;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.ContinuousEffect;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.keyword.ChangelingAbility;
|
||||
import mage.abilities.mana.ActivatedManaAbilityImpl;
|
||||
import mage.abilities.text.TextPart;
|
||||
import mage.abilities.text.TextPartSubType;
|
||||
import mage.cards.FrameStyle;
|
||||
import mage.cards.mock.MockCard;
|
||||
import mage.constants.*;
|
||||
|
|
@ -43,9 +39,9 @@ public abstract class MageObjectImpl implements MageObject {
|
|||
protected String text;
|
||||
protected MageInt power;
|
||||
protected MageInt toughness;
|
||||
protected int startingLoyalty = -1; // -2 means X, -1 means none, 0 and up is normal
|
||||
protected boolean copy;
|
||||
protected MageObject copyFrom; // copied card INFO (used to call original adjusters)
|
||||
protected List<TextPart> textParts;
|
||||
|
||||
public MageObjectImpl() {
|
||||
this(UUID.randomUUID());
|
||||
|
|
@ -60,7 +56,6 @@ public abstract class MageObjectImpl implements MageObject {
|
|||
frameStyle = FrameStyle.M15_NORMAL;
|
||||
manaCost = new ManaCostsImpl<>();
|
||||
abilities = new AbilitiesImpl<>();
|
||||
textParts = new ArrayList<>();
|
||||
}
|
||||
|
||||
public MageObjectImpl(final MageObjectImpl object) {
|
||||
|
|
@ -73,14 +68,13 @@ public abstract class MageObjectImpl implements MageObject {
|
|||
frameStyle = object.frameStyle;
|
||||
power = object.power.copy();
|
||||
toughness = object.toughness.copy();
|
||||
startingLoyalty = object.startingLoyalty;
|
||||
abilities = object.abilities.copy();
|
||||
this.cardType.addAll(object.cardType);
|
||||
this.subtype.copyFrom(object.subtype);
|
||||
supertype.addAll(object.supertype);
|
||||
this.copy = object.copy;
|
||||
this.copyFrom = (object.copyFrom != null ? object.copyFrom.copy() : null);
|
||||
textParts = new ArrayList<>();
|
||||
textParts.addAll(object.textParts);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -174,21 +168,12 @@ public abstract class MageObjectImpl implements MageObject {
|
|||
|
||||
@Override
|
||||
public int getStartingLoyalty() {
|
||||
for (Ability ab : getAbilities()) {
|
||||
if (ab instanceof PlaneswalkerEntersWithLoyaltyCountersAbility) {
|
||||
return ((PlaneswalkerEntersWithLoyaltyCountersAbility) ab).getStartingLoyalty();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return startingLoyalty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStartingLoyalty(int startingLoyalty) {
|
||||
for (Ability ab : getAbilities()) {
|
||||
if (ab instanceof PlaneswalkerEntersWithLoyaltyCountersAbility) {
|
||||
((PlaneswalkerEntersWithLoyaltyCountersAbility) ab).setStartingLoyalty(startingLoyalty);
|
||||
}
|
||||
}
|
||||
this.startingLoyalty = startingLoyalty;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -249,16 +234,6 @@ public abstract class MageObjectImpl implements MageObject {
|
|||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void adjustCosts(Ability ability, Game game) {
|
||||
ability.adjustCosts(game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void adjustTargets(Ability ability, Game game) {
|
||||
ability.adjustTargets(game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSubtype(SubType value, Game game) {
|
||||
if (value == null) {
|
||||
|
|
@ -316,26 +291,6 @@ public abstract class MageObjectImpl implements MageObject {
|
|||
this.getSubtype(game).setIsAllCreatureTypes(value && (this.isTribal(game) || this.isCreature(game)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TextPart> getTextParts() {
|
||||
return textParts;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextPart addTextPart(TextPart textPart) {
|
||||
textParts.add(textPart);
|
||||
return textPart;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void changeSubType(SubType fromSubType, SubType toSubType) {
|
||||
for (TextPart textPart : textParts) {
|
||||
if (textPart instanceof TextPartSubType && textPart.getCurrentValue().equals(fromSubType)) {
|
||||
textPart.replaceWith(toSubType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove power/toughness character defining abilities
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -138,13 +138,25 @@ public class MageObjectReference implements Comparable<MageObjectReference>, Ser
|
|||
}
|
||||
|
||||
public boolean refersTo(MageObject mageObject, Game game) {
|
||||
if (mageObject != null) {
|
||||
if (mageObject instanceof Spell) {
|
||||
return Objects.equals(((Spell) mageObject).getSourceId(), this.sourceId) && this.zoneChangeCounter == mageObject.getZoneChangeCounter(game);
|
||||
}
|
||||
return mageObject.getId().equals(sourceId) && this.zoneChangeCounter == mageObject.getZoneChangeCounter(game);
|
||||
return refersTo(mageObject, game, 0);
|
||||
}
|
||||
|
||||
public boolean refersTo(MageObject mageObject, Game game, int offset) {
|
||||
if (mageObject == null) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
if (mageObject instanceof Spell) {
|
||||
return Objects.equals(((Spell) mageObject).getSourceId(), this.sourceId) && this.zoneChangeCounter + offset == mageObject.getZoneChangeCounter(game);
|
||||
}
|
||||
return mageObject.getId().equals(sourceId) && this.zoneChangeCounter + offset == mageObject.getZoneChangeCounter(game);
|
||||
}
|
||||
|
||||
public boolean refersTo(Ability source, Game game) {
|
||||
if (source == null || !source.getSourceId().equals(sourceId)) {
|
||||
return false;
|
||||
}
|
||||
return zoneChangeCounter * source.getSourceObjectZoneChangeCounter() == 0
|
||||
|| zoneChangeCounter == source.getSourceObjectZoneChangeCounter();
|
||||
}
|
||||
|
||||
public Permanent getPermanent(Game game) {
|
||||
|
|
|
|||
|
|
@ -83,6 +83,16 @@ public enum ManaSymbol {
|
|||
PHYREXIAN_R("{R/P}", R, Type.PHYREXIAN, Type.COLORED, Type.MONOCOLORED),
|
||||
PHYREXIAN_B("{B/P}", B, Type.PHYREXIAN, Type.COLORED, Type.MONOCOLORED),
|
||||
PHYREXIAN_U("{U/P}", U, Type.PHYREXIAN, Type.COLORED, Type.MONOCOLORED),
|
||||
PHYREXIAN_HYBRID_WU("{W/U/P}", W, U, Type.PHYREXIAN, Type.HYBRID, Type.COLORED),
|
||||
PHYREXIAN_HYBRID_WB("{W/B/P}", W, B, Type.PHYREXIAN, Type.HYBRID, Type.COLORED),
|
||||
PHYREXIAN_HYBRID_UB("{U/B/P}", U, B, Type.PHYREXIAN, Type.HYBRID, Type.COLORED),
|
||||
PHYREXIAN_HYBRID_UR("{U/R/P}", U, R, Type.PHYREXIAN, Type.HYBRID, Type.COLORED),
|
||||
PHYREXIAN_HYBRID_BR("{B/R/P}", B, R, Type.PHYREXIAN, Type.HYBRID, Type.COLORED),
|
||||
PHYREXIAN_HYBRID_BG("{B/G/P}", B, G, Type.PHYREXIAN, Type.HYBRID, Type.COLORED),
|
||||
PHYREXIAN_HYBRID_RG("{R/G/P}", R, G, Type.PHYREXIAN, Type.HYBRID, Type.COLORED),
|
||||
PHYREXIAN_HYBRID_RW("{R/W/P}", R, W, Type.PHYREXIAN, Type.HYBRID, Type.COLORED),
|
||||
PHYREXIAN_HYBRID_GW("{G/W/P}", G, W, Type.PHYREXIAN, Type.HYBRID, Type.COLORED),
|
||||
PHYREXIAN_HYBRID_GU("{G/U/P}", G, U, Type.PHYREXIAN, Type.HYBRID, Type.COLORED),
|
||||
SNOW("{S}", Type.SNOW);
|
||||
|
||||
private enum Type {
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
|
||||
package mage;
|
||||
|
||||
import mage.constants.ColoredManaSymbol;
|
||||
import mage.util.Copyable;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import mage.constants.ColoredManaSymbol;
|
||||
import mage.util.Copyable;
|
||||
|
||||
public class ObjectColor implements Serializable, Copyable<ObjectColor>, Comparable<ObjectColor> {
|
||||
|
||||
public static final ObjectColor WHITE = new ObjectColor("W");
|
||||
|
|
@ -182,13 +182,13 @@ public class ObjectColor implements Serializable, Copyable<ObjectColor>, Compara
|
|||
}
|
||||
|
||||
public void setColor(ObjectColor color) {
|
||||
this.setBlack(color.isBlack());
|
||||
this.setBlue(color.isBlue());
|
||||
this.setGreen(color.isGreen());
|
||||
this.setRed(color.isRed());
|
||||
this.setWhite(color.isWhite());
|
||||
this.setBlack(color != null && color.isBlack());
|
||||
this.setBlue(color != null && color.isBlue());
|
||||
this.setGreen(color != null && color.isGreen());
|
||||
this.setRed(color != null && color.isRed());
|
||||
this.setWhite(color != null && color.isWhite());
|
||||
|
||||
this.setGold(color.isGold());
|
||||
this.setGold(color != null && color.isGold());
|
||||
}
|
||||
|
||||
public void addColor(ObjectColor color) {
|
||||
|
|
|
|||
|
|
@ -541,7 +541,7 @@ public interface Ability extends Controllable, Serializable {
|
|||
|
||||
boolean canFizzle();
|
||||
|
||||
void setTargetAdjuster(TargetAdjuster targetAdjuster);
|
||||
Ability setTargetAdjuster(TargetAdjuster targetAdjuster);
|
||||
|
||||
TargetAdjuster getTargetAdjuster();
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,10 @@ import mage.MageIdentifier;
|
|||
import mage.MageObject;
|
||||
import mage.abilities.costs.*;
|
||||
import mage.abilities.costs.common.PayLifeCost;
|
||||
import mage.abilities.costs.mana.*;
|
||||
import mage.abilities.costs.mana.ManaCost;
|
||||
import mage.abilities.costs.mana.ManaCosts;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.costs.mana.VariableManaCost;
|
||||
import mage.abilities.effects.ContinuousEffect;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.Effects;
|
||||
|
|
@ -357,8 +360,8 @@ public abstract class AbilityImpl implements Ability {
|
|||
// and/or zones become the target of a spell trigger at this point; they'll wait to be put on
|
||||
// the stack until the spell has finished being cast.)
|
||||
|
||||
if (sourceObject != null && this.getAbilityType() != AbilityType.TRIGGERED) { // triggered abilities check this already in playerImpl.triggerAbility
|
||||
sourceObject.adjustTargets(this, game);
|
||||
if (this.getAbilityType() != AbilityType.TRIGGERED) { // triggered abilities check this already in playerImpl.triggerAbility
|
||||
adjustTargets(game);
|
||||
}
|
||||
|
||||
if (!getTargets().isEmpty()) {
|
||||
|
|
@ -384,8 +387,8 @@ public abstract class AbilityImpl implements Ability {
|
|||
boolean needCostModification = !CardUtil.isFusedPartAbility(this, game);
|
||||
|
||||
//20101001 - 601.2e
|
||||
if (needCostModification && sourceObject != null) {
|
||||
sourceObject.adjustCosts(this, game); // still needed for CostAdjuster objects (to handle some types of dynamic costs)
|
||||
if (needCostModification) {
|
||||
adjustCosts(game); // still needed for CostAdjuster objects (to handle some types of dynamic costs)
|
||||
game.getContinuousEffects().costModification(this, game);
|
||||
}
|
||||
|
||||
|
|
@ -536,14 +539,15 @@ public abstract class AbilityImpl implements Ability {
|
|||
while (costIterator.hasNext()) {
|
||||
ManaCost cost = costIterator.next();
|
||||
|
||||
if (cost instanceof PhyrexianManaCost) {
|
||||
PhyrexianManaCost phyrexianManaCost = (PhyrexianManaCost) cost;
|
||||
PayLifeCost payLifeCost = new PayLifeCost(2);
|
||||
if (payLifeCost.canPay(this, this, controller.getId(), game)
|
||||
&& controller.chooseUse(Outcome.LoseLife, "Pay 2 life instead of " + phyrexianManaCost.getBaseText() + '?', this, game)) {
|
||||
costIterator.remove();
|
||||
costs.add(payLifeCost);
|
||||
}
|
||||
if (!cost.isPhyrexian()) {
|
||||
continue;
|
||||
}
|
||||
PayLifeCost payLifeCost = new PayLifeCost(2);
|
||||
if (payLifeCost.canPay(this, this, controller.getId(), game)
|
||||
&& controller.chooseUse(Outcome.LoseLife, "Pay 2 life instead of " + cost.getText().replace("/P", "") + '?', this, game)) {
|
||||
costIterator.remove();
|
||||
costs.add(payLifeCost);
|
||||
manaCostsToPay.incrPhyrexianPaid();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -962,7 +966,7 @@ public abstract class AbilityImpl implements Ability {
|
|||
if (target.getTargetController() != null) {
|
||||
abilityControllerId = target.getTargetController();
|
||||
}
|
||||
if (!target.canChoose(ability.getSourceId(), abilityControllerId, game)) {
|
||||
if (!target.canChoose(abilityControllerId, ability, game)) {
|
||||
validTargets = false;
|
||||
break;
|
||||
}
|
||||
|
|
@ -1325,8 +1329,9 @@ public abstract class AbilityImpl implements Ability {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void setTargetAdjuster(TargetAdjuster targetAdjuster) {
|
||||
public AbilityImpl setTargetAdjuster(TargetAdjuster targetAdjuster) {
|
||||
this.targetAdjuster = targetAdjuster;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -6,10 +6,8 @@ import mage.abilities.condition.Condition;
|
|||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.costs.Costs;
|
||||
import mage.abilities.costs.mana.ManaCosts;
|
||||
import mage.abilities.costs.mana.PhyrexianManaCost;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.Effects;
|
||||
import mage.abilities.keyword.FlashAbility;
|
||||
import mage.abilities.mana.ManaOptions;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.*;
|
||||
|
|
@ -61,19 +59,13 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa
|
|||
|
||||
public ActivatedAbilityImpl(Zone zone, Effect effect) {
|
||||
super(AbilityType.ACTIVATED, zone);
|
||||
if (effect != null) {
|
||||
this.addEffect(effect);
|
||||
}
|
||||
this.addEffect(effect);
|
||||
}
|
||||
|
||||
public ActivatedAbilityImpl(Zone zone, Effect effect, ManaCosts cost) {
|
||||
super(AbilityType.ACTIVATED, zone);
|
||||
if (effect != null) {
|
||||
this.addEffect(effect);
|
||||
}
|
||||
if (cost != null) {
|
||||
this.addManaCost(cost);
|
||||
}
|
||||
this.addEffect(effect);
|
||||
this.addManaCost(cost);
|
||||
}
|
||||
|
||||
public ActivatedAbilityImpl(Zone zone, Effects effects, ManaCosts cost) {
|
||||
|
|
@ -83,30 +75,18 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa
|
|||
this.addEffect(effect);
|
||||
}
|
||||
}
|
||||
if (cost != null) {
|
||||
this.addManaCost(cost);
|
||||
}
|
||||
this.addManaCost(cost);
|
||||
}
|
||||
|
||||
public ActivatedAbilityImpl(Zone zone, Effect effect, Cost cost) {
|
||||
super(AbilityType.ACTIVATED, zone);
|
||||
if (effect != null) {
|
||||
this.addEffect(effect);
|
||||
}
|
||||
if (cost != null) {
|
||||
if (cost instanceof PhyrexianManaCost) {
|
||||
this.addManaCost((PhyrexianManaCost) cost);
|
||||
} else {
|
||||
this.addCost(cost);
|
||||
}
|
||||
}
|
||||
this.addEffect(effect);
|
||||
this.addCost(cost);
|
||||
}
|
||||
|
||||
public ActivatedAbilityImpl(Zone zone, Effect effect, Costs<Cost> costs) {
|
||||
super(AbilityType.ACTIVATED, zone);
|
||||
if (effect != null) {
|
||||
this.addEffect(effect);
|
||||
}
|
||||
this.addEffect(effect);
|
||||
if (costs != null) {
|
||||
for (Cost cost : costs) {
|
||||
this.addCost(cost);
|
||||
|
|
@ -121,15 +101,13 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa
|
|||
this.addEffect(effect);
|
||||
}
|
||||
}
|
||||
if (cost != null) {
|
||||
this.addCost(cost);
|
||||
}
|
||||
this.addCost(cost);
|
||||
}
|
||||
|
||||
public ActivatedAbilityImpl(Zone zone, Effects effects, Costs<Cost> costs) {
|
||||
super(AbilityType.ACTIVATED, zone);
|
||||
for (Effect effect : effects) {
|
||||
if (effect != null) {
|
||||
if (effects != null) {
|
||||
for (Effect effect : effects) {
|
||||
this.addEffect(effect);
|
||||
}
|
||||
}
|
||||
|
|
@ -205,11 +183,6 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa
|
|||
game);
|
||||
asInstant = approvingObject != null;
|
||||
asInstant |= (timing == TimingRule.INSTANT);
|
||||
Card card = game.getCard(getSourceId());
|
||||
if (card != null) {
|
||||
asInstant |= card.isInstant(game);
|
||||
asInstant |= card.hasAbility(FlashAbility.getInstance(), game);
|
||||
}
|
||||
if (!asInstant && !game.canPlaySorcery(playerId)) {
|
||||
return ActivationStatus.getFalse();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,10 +18,6 @@ public class Mode implements Serializable {
|
|||
protected final Effects effects;
|
||||
protected String flavorWord;
|
||||
|
||||
public Mode() {
|
||||
this((Effect) null);
|
||||
}
|
||||
|
||||
public Mode(Effect effect) {
|
||||
this.id = UUID.randomUUID();
|
||||
this.targets = new Targets();
|
||||
|
|
@ -54,23 +50,25 @@ public class Mode implements Serializable {
|
|||
return targets;
|
||||
}
|
||||
|
||||
public void addTarget(Target target) {
|
||||
this.addTarget(target, false);
|
||||
public Mode addTarget(Target target) {
|
||||
return this.addTarget(target, false);
|
||||
}
|
||||
|
||||
public void addTarget(Target target, Boolean addChooseHintFromEffect) {
|
||||
public Mode addTarget(Target target, Boolean addChooseHintFromEffect) {
|
||||
targets.add(target);
|
||||
if (addChooseHintFromEffect) {
|
||||
target.withChooseHint(this.getEffects().getText(this));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Effects getEffects() {
|
||||
return effects;
|
||||
}
|
||||
|
||||
public void addEffect(Effect effect) {
|
||||
public Mode addEffect(Effect effect) {
|
||||
effects.add(effect);
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getFlavorWord() {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package mage.abilities;
|
|||
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.abilities.costs.OptionalAdditionalModeSourceCosts;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.TargetController;
|
||||
|
|
@ -42,7 +43,7 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
|||
private boolean mayChooseNone = false;
|
||||
|
||||
public Modes() {
|
||||
this.currentMode = new Mode();
|
||||
this.currentMode = new Mode((Effect) null);
|
||||
this.put(currentMode.getId(), currentMode);
|
||||
this.minModes = 1;
|
||||
this.maxModes = 1;
|
||||
|
|
@ -209,7 +210,7 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
|||
|
||||
// use case: make all modes chooseable
|
||||
if (moreCondition != null && moreCondition.apply(game, source)) {
|
||||
realMaxModes = Integer.MAX_VALUE;
|
||||
realMaxModes = this.size();
|
||||
}
|
||||
|
||||
// use case: limit max modes by opponents (wtf?!)
|
||||
|
|
@ -218,7 +219,7 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
|||
realMaxModes = 0;
|
||||
for (UUID targetPlayerId : game.getState().getPlayersInRange(source.getControllerId(), game)) {
|
||||
Player targetPlayer = game.getPlayer(targetPlayerId);
|
||||
if (((FilterPlayer) this.maxModesFilter).match(targetPlayer, source.getSourceId(), source.getControllerId(), game)) {
|
||||
if (((FilterPlayer) this.maxModesFilter).match(targetPlayer, source.getControllerId(), source, game)) {
|
||||
realMaxModes++;
|
||||
}
|
||||
}
|
||||
|
|
@ -291,7 +292,7 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
|||
}
|
||||
for (Mode mode : this.values()) {
|
||||
if ((!isEachModeOnlyOnce() || onceSelectedModes == null || !onceSelectedModes.contains(mode.getId()))
|
||||
&& mode.getTargets().canChoose(source.getSourceId(), source.getControllerId(), game)) {
|
||||
&& mode.getTargets().canChoose(source.getControllerId(), source, game)) {
|
||||
this.addSelectedMode(mode.getId());
|
||||
}
|
||||
}
|
||||
|
|
@ -305,19 +306,18 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
|||
// Some spells and abilities specify that a player other than their controller chooses a mode for it.
|
||||
// In that case, the other player does so when the spell or ability's controller normally would do so.
|
||||
// If there is more than one other player who could make such a choice, the spell or ability's controller decides which of those players will make the choice.
|
||||
UUID playerId = null;
|
||||
UUID playerId;
|
||||
if (modeChooser == TargetController.OPPONENT) {
|
||||
TargetOpponent targetOpponent = new TargetOpponent();
|
||||
if (targetOpponent.choose(Outcome.Benefit, source.getControllerId(), source.getSourceId(), game)) {
|
||||
playerId = targetOpponent.getFirstTarget();
|
||||
}
|
||||
targetOpponent.choose(Outcome.Benefit, source.getControllerId(), source.getSourceId(), source, game);
|
||||
playerId = targetOpponent.getFirstTarget();
|
||||
} else {
|
||||
playerId = source.getControllerId();
|
||||
}
|
||||
if (playerId == null) {
|
||||
Player player = game.getPlayer(playerId);
|
||||
if (player == null) {
|
||||
return false;
|
||||
}
|
||||
Player player = game.getPlayer(playerId);
|
||||
|
||||
// player chooses modes manually
|
||||
this.currentMode = null;
|
||||
|
|
@ -340,7 +340,13 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
|||
if (isEachModeOnlyOnce()) {
|
||||
setAlreadySelectedModes(source, game);
|
||||
}
|
||||
return true;
|
||||
if (modeChooser == TargetController.OPPONENT) {
|
||||
selectedModes
|
||||
.stream()
|
||||
.map(this::get)
|
||||
.map(Mode::getEffects)
|
||||
.forEach(effects -> effects.setValue("choosingPlayer", playerId));
|
||||
}
|
||||
} else {
|
||||
// only one mode available
|
||||
if (currentMode == null) {
|
||||
|
|
@ -349,8 +355,8 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
|||
this.addSelectedMode(mode.getId());
|
||||
this.setActiveMode(mode);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -467,23 +473,30 @@ public class Modes extends LinkedHashMap<UUID, Mode> {
|
|||
if (mayChooseNone) {
|
||||
sb.append("you may ");
|
||||
}
|
||||
if (this.chooseText != null) {
|
||||
sb.append(chooseText);
|
||||
} else if (this.getMinModes() == 0 && this.getMaxModes(null, null) == 1) {
|
||||
sb.append("choose up to one");
|
||||
} else if (this.getMinModes() == 0 && this.getMaxModes(null, null) > 2) {
|
||||
sb.append("choose any number");
|
||||
} else if (this.getMinModes() == 1 && this.getMaxModes(null, null) == 2) {
|
||||
sb.append("choose one or both");
|
||||
} else if (this.getMinModes() == 1 && this.getMaxModes(null, null) > 2) {
|
||||
sb.append("choose one or more");
|
||||
} else if (this.getMinModes() == this.getMaxModes(null, null)) {
|
||||
sb.append("choose " + CardUtil.numberToText(this.getMinModes()));
|
||||
if (this.chooseText == null) {
|
||||
if (modeChooser == TargetController.OPPONENT) {
|
||||
sb.append("an opponent chooses ");
|
||||
} else {
|
||||
sb.append("choose ");
|
||||
}
|
||||
if (this.getMinModes() == 0 && this.getMaxModes(null, null) == 1) {
|
||||
sb.append("up to one");
|
||||
} else if (this.getMinModes() == 0 && this.getMaxModes(null, null) > 2) {
|
||||
sb.append("any number");
|
||||
} else if (this.getMinModes() == 1 && this.getMaxModes(null, null) == 2) {
|
||||
sb.append("one or both");
|
||||
} else if (this.getMinModes() == 1 && this.getMaxModes(null, null) > 2) {
|
||||
sb.append("one or more");
|
||||
} else if (this.getMinModes() == this.getMaxModes(null, null)) {
|
||||
sb.append(CardUtil.numberToText(this.getMinModes()));
|
||||
} else {
|
||||
throw new UnsupportedOperationException("no text available for this selection of min and max modes");
|
||||
}
|
||||
} else {
|
||||
throw new UnsupportedOperationException("no text available for this selection of min and max modes");
|
||||
sb.append(chooseText);
|
||||
}
|
||||
|
||||
if (isEachModeOnlyOnce()) {
|
||||
if (isEachModeOnlyOnce() && this.getMaxModesFilter() == null) {
|
||||
sb.append(" that hasn't been chosen");
|
||||
}
|
||||
if (isResetEachTurn()) {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import mage.abilities.costs.VariableCost;
|
|||
import mage.abilities.costs.mana.ManaCost;
|
||||
import mage.abilities.costs.mana.VariableManaCost;
|
||||
import mage.abilities.keyword.FlashAbility;
|
||||
import mage.cards.AdventureCardSpell;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.SplitCard;
|
||||
import mage.constants.*;
|
||||
|
|
@ -69,7 +70,7 @@ public class SpellAbility extends ActivatedAbilityImpl {
|
|||
// forced to cast (can be part id or main id)
|
||||
Set<UUID> idsToCheck = new HashSet<>();
|
||||
idsToCheck.add(object.getId());
|
||||
if (object instanceof Card) {
|
||||
if (object instanceof Card && !(object instanceof AdventureCardSpell)) {
|
||||
idsToCheck.add(((Card) object).getMainCard().getId());
|
||||
}
|
||||
for (UUID idToCheck : idsToCheck) {
|
||||
|
|
|
|||
|
|
@ -91,8 +91,11 @@ public class TriggeredAbilities extends ConcurrentHashMap<String, TriggeredAbili
|
|||
}
|
||||
}
|
||||
|
||||
if (ability.checkTrigger(event, game) && ability.checkTriggeredAlready(game)) {
|
||||
if (ability.checkTrigger(event, game) && ability.checkTriggeredAlready(game) && ability.checkUsedAlready(game)) {
|
||||
NumberOfTriggersEvent numberOfTriggersEvent = new NumberOfTriggersEvent(ability, event);
|
||||
// store the event that led to the triggered event (Strict Proctor)
|
||||
// numberOfTriggerers event is only checked in replacement effects
|
||||
game.getState().setValue("triggeringEvent" + ability.getSourceId(), event);
|
||||
if (!game.replaceEvent(numberOfTriggersEvent)) {
|
||||
for (int i = 0; i < numberOfTriggersEvent.getAmount(); i++) {
|
||||
ability.trigger(game, ability.getControllerId(), event);
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@ public interface TriggeredAbility extends Ability {
|
|||
|
||||
boolean checkTriggeredAlready(Game game);
|
||||
|
||||
boolean checkUsedAlready(Game game);
|
||||
|
||||
TriggeredAbility setTriggersOnce(boolean triggersOnce);
|
||||
|
||||
boolean checkInterveningIfClause(Game game);
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
|
|||
protected boolean optional;
|
||||
protected boolean leavesTheBattlefieldTrigger;
|
||||
private boolean triggersOnce = false;
|
||||
private boolean doOnlyOnce = false;
|
||||
private GameEvent triggerEvent = null;
|
||||
private String triggerPhrase = null;
|
||||
|
||||
|
|
@ -52,6 +53,7 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
|
|||
this.optional = ability.optional;
|
||||
this.leavesTheBattlefieldTrigger = ability.leavesTheBattlefieldTrigger;
|
||||
this.triggersOnce = ability.triggersOnce;
|
||||
this.doOnlyOnce = ability.doOnlyOnce;
|
||||
this.triggerPhrase = ability.triggerPhrase;
|
||||
}
|
||||
|
||||
|
|
@ -105,6 +107,23 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkUsedAlready(Game game) {
|
||||
if (!doOnlyOnce) {
|
||||
return true;
|
||||
}
|
||||
Integer lastTurnUsed = (Integer) game.getState().getValue(
|
||||
CardUtil.getCardZoneString("lastTurnUsed" + originalId, sourceId, game)
|
||||
);
|
||||
return lastTurnUsed == null || lastTurnUsed != game.getTurnNum();
|
||||
}
|
||||
|
||||
public TriggeredAbility setDoOnlyOnce(boolean doOnlyOnce) {
|
||||
this.optional = true;
|
||||
this.doOnlyOnce = doOnlyOnce;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkInterveningIfClause(Game game) {
|
||||
return true;
|
||||
|
|
@ -112,22 +131,30 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
|
|||
|
||||
@Override
|
||||
public boolean resolve(Game game) {
|
||||
if (!checkInterveningIfClause(game)) {
|
||||
return false;
|
||||
}
|
||||
if (isOptional()) {
|
||||
MageObject object = game.getObject(getSourceId());
|
||||
Player player = game.getPlayer(this.getControllerId());
|
||||
if (player != null && object != null) {
|
||||
if (!player.chooseUse(getEffects().getOutcome(this), this.getRule(object.getLogName()), this, game)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (player == null || object == null
|
||||
|| !player.chooseUse(
|
||||
getEffects().getOutcome(this),
|
||||
this.getRule(object.getLogName()), this, game
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//20091005 - 603.4
|
||||
if (checkInterveningIfClause(game)) {
|
||||
return super.resolve(game);
|
||||
if (!super.resolve(game)) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
if (doOnlyOnce) {
|
||||
game.getState().setValue(CardUtil.getCardZoneString(
|
||||
"lastTurnUsed" + originalId, sourceId, game
|
||||
), game.getTurnNum());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -160,16 +187,18 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
|
|||
superRule = newRule.toString();
|
||||
}
|
||||
} else if (this.getTargets().isEmpty()
|
||||
|| ruleLow.startsWith("exile")
|
||||
|| ruleLow.startsWith("attach")
|
||||
|| ruleLow.startsWith("counter")
|
||||
|| ruleLow.startsWith("destroy")
|
||||
|| ruleLow.startsWith("return")
|
||||
|| ruleLow.startsWith("tap")
|
||||
|| ruleLow.startsWith("untap")
|
||||
|| ruleLow.startsWith("exchange")
|
||||
|| ruleLow.startsWith("exile")
|
||||
|| ruleLow.startsWith("gain")
|
||||
|| ruleLow.startsWith("goad")
|
||||
|| ruleLow.startsWith("put")
|
||||
|| ruleLow.startsWith("remove")
|
||||
|| ruleLow.startsWith("counter")
|
||||
|| ruleLow.startsWith("exchange")
|
||||
|| ruleLow.startsWith("goad")) {
|
||||
|| ruleLow.startsWith("return")
|
||||
|| ruleLow.startsWith("tap")
|
||||
|| ruleLow.startsWith("untap")) {
|
||||
sb.append("you may ");
|
||||
} else if (!ruleLow.startsWith("its controller may")) {
|
||||
sb.append("you may have ");
|
||||
|
|
@ -180,6 +209,9 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
|
|||
if (triggersOnce) {
|
||||
sb.append(" This ability triggers only once each turn.");
|
||||
}
|
||||
if (doOnlyOnce) {
|
||||
sb.append(" Do this only once each turn.");
|
||||
}
|
||||
}
|
||||
String prefix;
|
||||
if (abilityWord != null) {
|
||||
|
|
@ -329,7 +361,7 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge
|
|||
}
|
||||
}
|
||||
if (sourceObject == null) { // source is no permanent
|
||||
sourceObject = game.getObject(source.getSourceId());
|
||||
sourceObject = game.getObject(source);
|
||||
if (sourceObject == null || sourceObject.isPermanent(game)) {
|
||||
return false; // No source object found => ability is not valid
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import mage.abilities.effects.Effect;
|
|||
import mage.constants.AbilityWord;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.predicate.mageobject.AnotherCardPredicate;
|
||||
import mage.filter.predicate.mageobject.AnotherPredicate;
|
||||
import mage.filter.predicate.mageobject.NamePredicate;
|
||||
import mage.target.common.TargetCardInHand;
|
||||
|
||||
|
|
@ -26,7 +26,7 @@ public class GrandeurAbility extends ActivatedAbilityImpl {
|
|||
|
||||
FilterCard filter = new FilterCard("another card named " + cardName);
|
||||
filter.add(new NamePredicate(cardName));
|
||||
filter.add(new AnotherCardPredicate());
|
||||
filter.add(AnotherPredicate.instance);
|
||||
this.addCost(new DiscardTargetCost(new TargetCardInHand(filter)));
|
||||
setAbilityWord(AbilityWord.GRANDEUR);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,6 @@ public class ActivateOnlyByOpponentActivatedAbility extends ActivatedAbilityImpl
|
|||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return super.getRule() + " Only any opponent may activate this ability.";
|
||||
return super.getRule() + " Only your opponents may activate this ability.";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.AbilityWord;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.StaticFilters;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class AllianceAbility extends EntersBattlefieldControlledTriggeredAbility {
|
||||
|
||||
public AllianceAbility(Effect effect) {
|
||||
super(Zone.BATTLEFIELD, effect, StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE, false);
|
||||
this.setAbilityWord(AbilityWord.ALLIANCE);
|
||||
}
|
||||
|
||||
private AllianceAbility(final AllianceAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AllianceAbility copy() {
|
||||
return new AllianceAbility(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
package mage.abilities.common;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.SetTargetPointer;
|
||||
|
|
@ -11,9 +10,11 @@ import mage.game.Game;
|
|||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class AttacksAllTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
|
@ -59,7 +60,7 @@ public class AttacksAllTriggeredAbility extends TriggeredAbilityImpl {
|
|||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
Permanent permanent = game.getPermanent(event.getSourceId());
|
||||
if (filter.match(permanent, getSourceId(), getControllerId(), game)) {
|
||||
if (filter.match(permanent, getControllerId(), this, game)) {
|
||||
if (attacksYouOrYourPlaneswalker) {
|
||||
boolean check = false;
|
||||
if (event.getTargetId().equals(getControllerId())) {
|
||||
|
|
@ -74,18 +75,15 @@ public class AttacksAllTriggeredAbility extends TriggeredAbilityImpl {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
getEffects().setValue("attacker", permanent);
|
||||
switch (setTargetPointer) {
|
||||
case PERMANENT:
|
||||
for (Effect effect : getEffects()) {
|
||||
effect.setTargetPointer(new FixedTarget(permanent, game));
|
||||
}
|
||||
getEffects().setTargetPointer(new FixedTarget(permanent, game));
|
||||
break;
|
||||
case PLAYER:
|
||||
UUID playerId = controller ? permanent.getControllerId() : game.getCombat().getDefendingPlayerId(permanent.getId(), game);
|
||||
if (playerId != null) {
|
||||
for (Effect effect : getEffects()) {
|
||||
effect.setTargetPointer(new FixedTarget(playerId));
|
||||
}
|
||||
getEffects().setTargetPointer(new FixedTarget(playerId));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -101,10 +99,8 @@ public class AttacksAllTriggeredAbility extends TriggeredAbilityImpl {
|
|||
|
||||
@Override
|
||||
public String getTriggerPhrase() {
|
||||
return "Whenever " + (filter.getMessage().startsWith("an") ? "" : "a ")
|
||||
+ filter.getMessage() + " attacks"
|
||||
+ (attacksYouOrYourPlaneswalker ? " you or a planeswalker you control" : "")
|
||||
+ ", " ;
|
||||
return "Whenever " + CardUtil.addArticle(filter.getMessage()) + " attacks"
|
||||
+ (attacksYouOrYourPlaneswalker ? " you or a planeswalker you control" : "") + ", ";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ public class AttacksAloneControlledTriggeredAbility extends TriggeredAbilityImpl
|
|||
return false;
|
||||
}
|
||||
Permanent permanent = game.getPermanent(game.getCombat().getAttackers().get(0));
|
||||
if (permanent == null || !filter.match(permanent, getSourceId(), getControllerId(), game)) {
|
||||
if (permanent == null || !filter.match(permanent, getControllerId(), this, game)) {
|
||||
return false;
|
||||
}
|
||||
if (setTargetPointer) {
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ public class AttacksCreatureYouControlTriggeredAbility extends TriggeredAbilityI
|
|||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
Permanent sourcePermanent = game.getPermanent(event.getSourceId());
|
||||
if (filter.match(sourcePermanent, sourceId, controllerId, game)) {
|
||||
if (filter.match(sourcePermanent, controllerId, this, game)) {
|
||||
if (setTargetPointer) {
|
||||
this.getEffects().setTargetPointer(new FixedTarget(event.getSourceId(), game));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ public class AttacksWithCreaturesTriggeredAbility extends TriggeredAbilityImpl {
|
|||
.getAttackers()
|
||||
.stream()
|
||||
.map(game::getPermanent)
|
||||
.filter(permanent -> filter.match(permanent, sourceId, controllerId, game))
|
||||
.filter(permanent -> filter.match(permanent, controllerId, this, game))
|
||||
.mapToInt(x -> 1)
|
||||
.sum();
|
||||
if (attackers < minAttackers) {
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ public class BecomesBlockedAllTriggeredAbility extends TriggeredAbilityImpl {
|
|||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
Permanent permanent = game.getPermanent(event.getTargetId());
|
||||
if (filter.match(permanent, getSourceId(), getControllerId(), game)) {
|
||||
if (filter.match(permanent, getControllerId(), this, game)) {
|
||||
if (setTargetPointer) {
|
||||
this.getEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,8 +7,8 @@ import mage.filter.StaticFilters;
|
|||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
/**
|
||||
* @author North
|
||||
|
|
@ -41,21 +41,16 @@ public class BecomesBlockedByCreatureTriggeredAbility extends TriggeredAbilityIm
|
|||
if (!event.getTargetId().equals(this.getSourceId())) {
|
||||
return false;
|
||||
}
|
||||
Permanent blocker = game.getPermanent(event.getSourceId());
|
||||
if (!filter.match(blocker, game)) {
|
||||
if (!filter.match(game.getPermanent(event.getSourceId()), getControllerId(), this, game)) {
|
||||
return false;
|
||||
}
|
||||
for (Effect effect : this.getEffects()) {
|
||||
effect.setTargetPointer(new FixedTarget(event.getSourceId(), game));
|
||||
}
|
||||
getEffects().setTargetPointer(new FixedTarget(event.getSourceId(), game));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTriggerPhrase() {
|
||||
return "Whenever {this} becomes blocked by "
|
||||
+ (filter.getMessage().startsWith("an ") ? "" : "a ")
|
||||
+ filter.getMessage() + ", " ;
|
||||
return "Whenever {this} becomes blocked by " + CardUtil.addArticle(filter.getMessage()) + ", ";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -1,20 +1,17 @@
|
|||
/*
|
||||
* To change this template, 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.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;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jeffwadsworth
|
||||
*/
|
||||
public class BecomesTappedTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
|
@ -23,7 +20,7 @@ public class BecomesTappedTriggeredAbility extends TriggeredAbilityImpl {
|
|||
protected boolean setTargetPointer;
|
||||
|
||||
public BecomesTappedTriggeredAbility(Effect effect, boolean optional) {
|
||||
this(effect, optional, new FilterPermanent("a permanent"));
|
||||
this(effect, optional, StaticFilters.FILTER_PERMANENT_A);
|
||||
}
|
||||
|
||||
public BecomesTappedTriggeredAbility(Effect effect, boolean optional, FilterPermanent filter) {
|
||||
|
|
@ -31,7 +28,11 @@ public class BecomesTappedTriggeredAbility extends TriggeredAbilityImpl {
|
|||
}
|
||||
|
||||
public BecomesTappedTriggeredAbility(Effect effect, boolean optional, FilterPermanent filter, boolean setTargetPointer) {
|
||||
super(Zone.BATTLEFIELD, effect, optional);
|
||||
this(Zone.BATTLEFIELD, effect, optional, filter, setTargetPointer);
|
||||
}
|
||||
|
||||
public BecomesTappedTriggeredAbility(Zone zone, Effect effect, boolean optional, FilterPermanent filter, boolean setTargetPointer) {
|
||||
super(zone, effect, optional);
|
||||
this.filter = filter;
|
||||
this.setTargetPointer = setTargetPointer;
|
||||
}
|
||||
|
|
@ -55,17 +56,17 @@ public class BecomesTappedTriggeredAbility extends TriggeredAbilityImpl {
|
|||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
Permanent permanent = game.getPermanent(event.getTargetId());
|
||||
if (filter.match(permanent, getSourceId(), getControllerId(), game)) {
|
||||
if (setTargetPointer) {
|
||||
this.getEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game));
|
||||
}
|
||||
return true;
|
||||
if (!filter.match(permanent, getControllerId(), this, game)) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
if (setTargetPointer) {
|
||||
this.getEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTriggerPhrase() {
|
||||
return "Whenever " + filter.getMessage() + " becomes tapped, " ;
|
||||
return "Whenever " + CardUtil.addArticle(filter.getMessage()) + " becomes tapped, ";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import mage.constants.Zone;
|
|||
import mage.filter.FilterStackObject;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.stack.StackObject;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
|
@ -56,7 +55,7 @@ public class BecomesTargetAttachedTriggeredAbility extends TriggeredAbilityImpl
|
|||
StackObject sourceObject = game.getStack().getStackObject(event.getSourceId());
|
||||
if (enchantment != null && enchantment.getAttachedTo() != null) {
|
||||
if (event.getTargetId().equals(enchantment.getAttachedTo())
|
||||
&& filter.match(sourceObject, getSourceId(), getControllerId(), game)) {
|
||||
&& filter.match(sourceObject, getControllerId(), this, game)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ public class BecomesTargetTriggeredAbility extends TriggeredAbilityImpl {
|
|||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
StackObject sourceObject = game.getStack().getStackObject(event.getSourceId());
|
||||
if (!event.getTargetId().equals(getSourceId())
|
||||
|| !filter.match(sourceObject, getSourceId(), getControllerId(), game)) {
|
||||
|| !filter.match(sourceObject, getControllerId(), this, game)) {
|
||||
return false;
|
||||
}
|
||||
switch (setTargetPointer) {
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ import mage.target.targetpointer.FixedTarget;
|
|||
|
||||
public class BeginningOfCombatTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
private TargetController targetController;
|
||||
private boolean setTargetPointer;
|
||||
private final TargetController targetController;
|
||||
private final boolean setTargetPointer;
|
||||
|
||||
public BeginningOfCombatTriggeredAbility(Effect effect, TargetController targetController, boolean isOptional) {
|
||||
this(Zone.BATTLEFIELD, effect, targetController, isOptional, false);
|
||||
|
|
@ -62,6 +62,7 @@ public class BeginningOfCombatTriggeredAbility extends TriggeredAbilityImpl {
|
|||
return true;
|
||||
}
|
||||
break;
|
||||
case EACH_PLAYER:
|
||||
case ANY:
|
||||
if (setTargetPointer) {
|
||||
this.getEffects().forEach(effect -> {
|
||||
|
|
@ -80,6 +81,8 @@ public class BeginningOfCombatTriggeredAbility extends TriggeredAbilityImpl {
|
|||
return "At the beginning of combat on your turn, " + generateZoneString();
|
||||
case OPPONENT:
|
||||
return "At the beginning of each opponent's combat step, " + generateZoneString();
|
||||
case EACH_PLAYER:
|
||||
return "At the beginning of combat on each player's turn, " + generateZoneString();
|
||||
case ANY:
|
||||
return "At the beginning of each combat, " + generateZoneString();
|
||||
}
|
||||
|
|
@ -87,9 +90,8 @@ public class BeginningOfCombatTriggeredAbility extends TriggeredAbilityImpl {
|
|||
}
|
||||
|
||||
private String generateZoneString() {
|
||||
switch (getZone()) {
|
||||
case GRAVEYARD:
|
||||
return "if {this} is in your graveyard, ";
|
||||
if (getZone() == Zone.GRAVEYARD) {
|
||||
return "if {this} is in your graveyard, ";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,64 @@
|
|||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
/**
|
||||
* @author Hiddevb
|
||||
*/
|
||||
public class BlocksCreatureTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
private final FilterCreaturePermanent filter;
|
||||
|
||||
public BlocksCreatureTriggeredAbility(Effect effect) {
|
||||
this(effect, false);
|
||||
}
|
||||
|
||||
public BlocksCreatureTriggeredAbility(Effect effect, boolean optional) {
|
||||
this(effect, StaticFilters.FILTER_PERMANENT_CREATURE, optional);
|
||||
}
|
||||
|
||||
public BlocksCreatureTriggeredAbility(Effect effect, FilterCreaturePermanent filter, boolean optional) {
|
||||
super(Zone.BATTLEFIELD, effect, optional);
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
public BlocksCreatureTriggeredAbility(final BlocksCreatureTriggeredAbility ability) {
|
||||
super(ability);
|
||||
this.filter = ability.filter;
|
||||
}
|
||||
|
||||
@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())) {
|
||||
return false;
|
||||
}
|
||||
if (!filter.match(game.getPermanent(event.getTargetId()), getControllerId(), this, game)) {
|
||||
return false;
|
||||
}
|
||||
getEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTriggerPhrase() {
|
||||
return "Whenever {this} blocks " + CardUtil.addArticle(filter.getMessage()) + ", ";
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlocksCreatureTriggeredAbility copy() {
|
||||
return new BlocksCreatureTriggeredAbility(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -21,7 +21,11 @@ public class BlocksOrBecomesBlockedSourceTriggeredAbility extends TriggeredAbili
|
|||
protected boolean setTargetPointer;
|
||||
|
||||
public BlocksOrBecomesBlockedSourceTriggeredAbility(Effect effect, boolean optional) {
|
||||
this(effect, StaticFilters.FILTER_PERMANENT_CREATURE, optional, null, true);
|
||||
this(effect, optional, true);
|
||||
}
|
||||
|
||||
public BlocksOrBecomesBlockedSourceTriggeredAbility(Effect effect, boolean optional, boolean setTargetPointer) {
|
||||
this(effect, StaticFilters.FILTER_PERMANENT_CREATURE, optional, null, setTargetPointer);
|
||||
}
|
||||
|
||||
public BlocksOrBecomesBlockedSourceTriggeredAbility(Effect effect, FilterPermanent filter, boolean optional) {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
package mage.abilities.common;
|
||||
|
||||
import mage.constants.Zone;
|
||||
|
|
@ -6,7 +5,7 @@ import mage.abilities.TriggeredAbilityImpl;
|
|||
import mage.abilities.effects.Effect;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -14,50 +13,32 @@ import mage.target.targetpointer.FixedTarget;
|
|||
*/
|
||||
public class BlocksSourceTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
private boolean setTargetPointer;
|
||||
private boolean once = false;
|
||||
public BlocksSourceTriggeredAbility(Effect effect) {
|
||||
this(effect, false);
|
||||
}
|
||||
|
||||
public BlocksSourceTriggeredAbility(Effect effect, boolean optional) {
|
||||
this(effect, optional, false);
|
||||
}
|
||||
|
||||
public BlocksSourceTriggeredAbility(Effect effect, boolean optional, boolean setTargetPointer) {
|
||||
this(effect, optional, setTargetPointer, false);
|
||||
}
|
||||
|
||||
public BlocksSourceTriggeredAbility(Effect effect, boolean optional, boolean setTargetPointer, boolean once) {
|
||||
super(Zone.BATTLEFIELD, effect, optional);
|
||||
this.setTargetPointer = setTargetPointer;
|
||||
this.once = once;
|
||||
}
|
||||
|
||||
public BlocksSourceTriggeredAbility(final BlocksSourceTriggeredAbility ability) {
|
||||
super(ability);
|
||||
this.setTargetPointer = ability.setTargetPointer;
|
||||
this.once = ability.once;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.BLOCKER_DECLARED;
|
||||
return event.getType() == GameEvent.EventType.DECLARED_BLOCKERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (event.getSourceId().equals(this.getSourceId())) {
|
||||
if (setTargetPointer) {
|
||||
for (Effect effect : this.getEffects()) {
|
||||
effect.setTargetPointer(new FixedTarget(event.getTargetId()));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
Permanent permanent = game.getPermanent(getSourceId());
|
||||
return permanent != null && permanent.getBlocking() > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTriggerPhrase() {
|
||||
return "When" + (once ? "" : "ever") + " {this} blocks" + (setTargetPointer ? " a creature, " : ", ") ;
|
||||
return "Whenever {this} blocks, ";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import mage.abilities.dynamicvalue.DynamicValue;
|
|||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.hint.Hint;
|
||||
import mage.abilities.hint.ValueHint;
|
||||
import mage.constants.TargetController;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
|
|
@ -17,19 +18,28 @@ import mage.watchers.common.CastSpellLastTurnWatcher;
|
|||
public class CastSecondSpellTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
private static final Hint hint = new ValueHint("Spells you cast this turn", SpellCastValue.instance);
|
||||
private final TargetController targetController;
|
||||
|
||||
public CastSecondSpellTriggeredAbility(Effect effect) {
|
||||
this(Zone.BATTLEFIELD, effect, false);
|
||||
this(effect, TargetController.YOU);
|
||||
}
|
||||
|
||||
public CastSecondSpellTriggeredAbility(Zone zone, Effect effect, boolean optional) {
|
||||
public CastSecondSpellTriggeredAbility(Effect effect, TargetController targetController) {
|
||||
this(Zone.BATTLEFIELD, effect, targetController, false);
|
||||
}
|
||||
|
||||
public CastSecondSpellTriggeredAbility(Zone zone, Effect effect, TargetController targetController, boolean optional) {
|
||||
super(zone, effect, optional);
|
||||
this.addWatcher(new CastSpellLastTurnWatcher());
|
||||
this.addHint(hint);
|
||||
if (targetController == TargetController.YOU) {
|
||||
this.addHint(hint);
|
||||
}
|
||||
this.targetController = targetController;
|
||||
}
|
||||
|
||||
private CastSecondSpellTriggeredAbility(final CastSecondSpellTriggeredAbility ability) {
|
||||
super(ability);
|
||||
this.targetController = ability.targetController;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -39,8 +49,21 @@ public class CastSecondSpellTriggeredAbility extends TriggeredAbilityImpl {
|
|||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (!isControlledBy(event.getPlayerId())) {
|
||||
return false;
|
||||
switch (targetController) {
|
||||
case YOU:
|
||||
if (!isControlledBy(event.getPlayerId())) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case OPPONENT:
|
||||
if (!game.getOpponents(getControllerId()).contains(event.getPlayerId())) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case ANY:
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("TargetController " + targetController + " not supported");
|
||||
}
|
||||
CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class);
|
||||
return watcher != null && watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(event.getPlayerId()) == 2;
|
||||
|
|
@ -48,7 +71,16 @@ public class CastSecondSpellTriggeredAbility extends TriggeredAbilityImpl {
|
|||
|
||||
@Override
|
||||
public String getTriggerPhrase() {
|
||||
return "Whenever you cast your second spell each turn, " ;
|
||||
switch (targetController) {
|
||||
case YOU:
|
||||
return "Whenever you cast your second spell each turn, ";
|
||||
case OPPONENT:
|
||||
return "Whenever an opponent casts their second spell each turn, ";
|
||||
case ANY:
|
||||
return "Whenever a player casts their second spell each turn, ";
|
||||
default:
|
||||
throw new IllegalArgumentException("TargetController " + targetController + " not supported");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.StaticAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.Zone;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class CommanderChooseColorAbility extends StaticAbility {
|
||||
|
||||
public CommanderChooseColorAbility() {
|
||||
super(Zone.ALL, null);
|
||||
}
|
||||
|
||||
private CommanderChooseColorAbility(final CommanderChooseColorAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommanderChooseColorAbility copy() {
|
||||
return new CommanderChooseColorAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "If {this} is your commander, choose a color before the game begins. {this} is the chosen color.";
|
||||
}
|
||||
|
||||
public static boolean checkCard(Card card) {
|
||||
return card.getAbilities().stream().anyMatch(CommanderChooseColorAbility.class::isInstance);
|
||||
}
|
||||
}
|
||||
|
|
@ -17,39 +17,39 @@ import java.util.UUID;
|
|||
/**
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class ControlledCreaturesDealCombatDamagePlayerTriggeredAbility extends TriggeredAbilityImpl {
|
||||
public class DealCombatDamageControlledTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
private final Set<UUID> damagedPlayerIds = new HashSet<>();
|
||||
private final boolean setTargetPointer;
|
||||
private final boolean onlyOpponents;
|
||||
|
||||
public ControlledCreaturesDealCombatDamagePlayerTriggeredAbility(Effect effect) {
|
||||
public DealCombatDamageControlledTriggeredAbility(Effect effect) {
|
||||
this(Zone.BATTLEFIELD, effect);
|
||||
}
|
||||
|
||||
public ControlledCreaturesDealCombatDamagePlayerTriggeredAbility(Zone zone, Effect effect) {
|
||||
public DealCombatDamageControlledTriggeredAbility(Zone zone, Effect effect) {
|
||||
this(zone, effect, false);
|
||||
}
|
||||
|
||||
public ControlledCreaturesDealCombatDamagePlayerTriggeredAbility(Zone zone, Effect effect, boolean setTargetPointer) {
|
||||
public DealCombatDamageControlledTriggeredAbility(Zone zone, Effect effect, boolean setTargetPointer) {
|
||||
this(zone, effect, setTargetPointer, false);
|
||||
}
|
||||
|
||||
public ControlledCreaturesDealCombatDamagePlayerTriggeredAbility(Zone zone, Effect effect, boolean setTargetPointer, boolean onlyOpponents) {
|
||||
public DealCombatDamageControlledTriggeredAbility(Zone zone, Effect effect, boolean setTargetPointer, boolean onlyOpponents) {
|
||||
super(zone, effect, false);
|
||||
this.setTargetPointer = setTargetPointer;
|
||||
this.onlyOpponents = onlyOpponents;
|
||||
}
|
||||
|
||||
public ControlledCreaturesDealCombatDamagePlayerTriggeredAbility(final ControlledCreaturesDealCombatDamagePlayerTriggeredAbility ability) {
|
||||
public DealCombatDamageControlledTriggeredAbility(final DealCombatDamageControlledTriggeredAbility ability) {
|
||||
super(ability);
|
||||
this.setTargetPointer = ability.setTargetPointer;
|
||||
this.onlyOpponents = ability.onlyOpponents;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ControlledCreaturesDealCombatDamagePlayerTriggeredAbility copy() {
|
||||
return new ControlledCreaturesDealCombatDamagePlayerTriggeredAbility(this);
|
||||
public DealCombatDamageControlledTriggeredAbility copy() {
|
||||
return new DealCombatDamageControlledTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -83,9 +83,9 @@ public class DealsCombatDamageToAPlayerTriggeredAbility extends TriggeredAbility
|
|||
return false;
|
||||
}
|
||||
}
|
||||
getAllEffects().setValue("damage", event.getAmount());
|
||||
if (setTargetPointer) {
|
||||
getAllEffects().setTargetPointer(new FixedTarget(event.getPlayerId()));
|
||||
getAllEffects().setValue("damage", event.getAmount());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
|
||||
|
||||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
|
|
@ -26,13 +24,13 @@ public class DealsCombatDamageTriggeredAbility extends TriggeredAbilityImpl {
|
|||
}
|
||||
|
||||
public DealsCombatDamageTriggeredAbility(final DealsCombatDamageTriggeredAbility ability) {
|
||||
super(ability);
|
||||
this.usedInPhase = ability.usedInPhase;
|
||||
super(ability);
|
||||
this.usedInPhase = ability.usedInPhase;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DealsCombatDamageTriggeredAbility copy() {
|
||||
return new DealsCombatDamageTriggeredAbility(this);
|
||||
return new DealsCombatDamageTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -47,10 +45,10 @@ public class DealsCombatDamageTriggeredAbility extends TriggeredAbilityImpl {
|
|||
&& event.getSourceId().equals(this.sourceId)
|
||||
&& ((DamagedEvent) event).isCombatDamage()) {
|
||||
usedInPhase = true;
|
||||
getEffects().setValue("damage", event.getAmount());
|
||||
return true;
|
||||
|
||||
}
|
||||
if (event.getType()== GameEvent.EventType.COMBAT_DAMAGE_STEP_PRE) {
|
||||
if (event.getType() == GameEvent.EventType.COMBAT_DAMAGE_STEP_PRE) {
|
||||
usedInPhase = false;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -58,7 +56,6 @@ public class DealsCombatDamageTriggeredAbility extends TriggeredAbilityImpl {
|
|||
|
||||
@Override
|
||||
public String getTriggerPhrase() {
|
||||
return "Whenever {this} deals combat damage, " ;
|
||||
return "Whenever {this} deals combat damage, ";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,12 @@
|
|||
|
||||
|
||||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.dynamicvalue.common.SavedDamageValue;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.constants.Outcome;
|
||||
import mage.abilities.effects.common.GainLifeEffect;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.players.Player;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -20,7 +16,7 @@ import mage.players.Player;
|
|||
public class DealsDamageGainLifeSourceTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
public DealsDamageGainLifeSourceTriggeredAbility() {
|
||||
super(Zone.BATTLEFIELD, new GainThatMuchLifeEffect(), false);
|
||||
super(Zone.BATTLEFIELD, new GainLifeEffect(SavedDamageValue.MUCH), false);
|
||||
}
|
||||
|
||||
public DealsDamageGainLifeSourceTriggeredAbility(final DealsDamageGainLifeSourceTriggeredAbility ability) {
|
||||
|
|
@ -53,34 +49,3 @@ public class DealsDamageGainLifeSourceTriggeredAbility extends TriggeredAbilityI
|
|||
return "Whenever {this} deals damage, " ;
|
||||
}
|
||||
}
|
||||
|
||||
class GainThatMuchLifeEffect extends OneShotEffect {
|
||||
|
||||
public GainThatMuchLifeEffect() {
|
||||
super(Outcome.GainLife);
|
||||
this.staticText = "you gain that much life";
|
||||
}
|
||||
|
||||
public GainThatMuchLifeEffect(final GainThatMuchLifeEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GainThatMuchLifeEffect copy() {
|
||||
return new GainThatMuchLifeEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null) {
|
||||
int amount = (Integer) getValue("damage");
|
||||
if (amount > 0) {
|
||||
controller.gainLife(amount, game, source);
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,27 +69,24 @@ public class DealsDamageToACreatureAllTriggeredAbility extends TriggeredAbilityI
|
|||
return false;
|
||||
}
|
||||
permanent = game.getPermanentOrLKIBattlefield(event.getSourceId());
|
||||
if (!filterPermanent.match(permanent, getSourceId(), getControllerId(), game)) {
|
||||
if (!filterPermanent.match(permanent, getControllerId(), this, game)) {
|
||||
return false;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
this.getEffects().setValue("damage", event.getAmount());
|
||||
this.getEffects().setValue("sourceId", event.getSourceId());
|
||||
switch (setTargetPointer) {
|
||||
case PLAYER:
|
||||
this.getEffects().setTargetPointer(new FixedTarget(permanent.getControllerId()));
|
||||
break;
|
||||
case PERMANENT:
|
||||
this.getEffects().setTargetPointer(new FixedTarget(permanent, game));
|
||||
break;
|
||||
case PERMANENT_TARGET:
|
||||
Permanent permanent_target = game.getPermanentOrLKIBattlefield(event.getTargetId());
|
||||
if (permanent_target != null) {
|
||||
this.getEffects().setTargetPointer(new FixedTarget(permanent_target, game));
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -97,6 +94,6 @@ public class DealsDamageToACreatureAllTriggeredAbility extends TriggeredAbilityI
|
|||
@Override
|
||||
public String getTriggerPhrase() {
|
||||
return "Whenever " + filterPermanent.getMessage() + " deals "
|
||||
+ (combatDamageOnly ? "combat " : "") + "damage to a creature, " ;
|
||||
+ (combatDamageOnly ? "combat " : "") + "damage to a creature, ";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
|
||||
package mage.abilities.common;
|
||||
|
||||
import mage.constants.Zone;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.common.FilterCreaturePermanent;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.DamagedEvent;
|
||||
|
|
@ -12,7 +12,6 @@ import mage.game.permanent.Permanent;
|
|||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX
|
||||
*/
|
||||
public class DealsDamageToACreatureTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
|
@ -43,7 +42,7 @@ public class DealsDamageToACreatureTriggeredAbility extends TriggeredAbilityImpl
|
|||
public DealsDamageToACreatureTriggeredAbility copy() {
|
||||
return new DealsDamageToACreatureTriggeredAbility(this);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.DAMAGED_PERMANENT;
|
||||
|
|
@ -55,15 +54,13 @@ public class DealsDamageToACreatureTriggeredAbility extends TriggeredAbilityImpl
|
|||
&& (!combatOnly || ((DamagedEvent) event).isCombatDamage())) {
|
||||
if (filter != null) {
|
||||
Permanent creature = game.getPermanentOrLKIBattlefield(event.getTargetId());
|
||||
if (!filter.match(creature, getSourceId(), getControllerId(), game)) {
|
||||
if (!filter.match(creature, getControllerId(), this, game)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (setTargetPointer) {
|
||||
for (Effect effect : this.getEffects()) {
|
||||
effect.setTargetPointer(new FixedTarget(event.getTargetId(), game));
|
||||
effect.setValue("damage", event.getAmount());
|
||||
}
|
||||
this.getEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game));
|
||||
this.getEffects().setValue("damage", event.getAmount());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ public class DealsDamageToAPlayerAllTriggeredAbility extends TriggeredAbilityImp
|
|||
return false;
|
||||
}
|
||||
Permanent permanent = game.getPermanent(event.getSourceId());
|
||||
if (!filter.match(permanent, getSourceId(), getControllerId(), game)) {
|
||||
if (!filter.match(permanent, getControllerId(), this, game)) {
|
||||
return false;
|
||||
}
|
||||
this.getEffects().setValue("damage", event.getAmount());
|
||||
|
|
|
|||
|
|
@ -77,8 +77,8 @@ public class DealsDamageToAPlayerAttachedTriggeredAbility extends TriggeredAbili
|
|||
|| p == null || !p.getAttachments().contains(this.getSourceId())) {
|
||||
return false;
|
||||
}
|
||||
getEffects().setValue("damage", event.getAmount());
|
||||
if (setFixedTargetPointer) {
|
||||
getEffects().setValue("damage", event.getAmount());
|
||||
getEffects().setTargetPointer(new FixedTarget(event.getPlayerId()));
|
||||
}
|
||||
return true;
|
||||
|
|
@ -86,7 +86,11 @@ public class DealsDamageToAPlayerAttachedTriggeredAbility extends TriggeredAbili
|
|||
|
||||
@Override
|
||||
public String getTriggerPhrase() {
|
||||
StringBuilder sb = new StringBuilder("Whenever ").append(attachedDescription);
|
||||
StringBuilder sb = new StringBuilder("Whenever ");
|
||||
sb.append(attachedDescription);
|
||||
if (!attachedDescription.endsWith("creature")) {
|
||||
sb.append(" creature");
|
||||
}
|
||||
sb.append(" deals");
|
||||
if (onlyCombat) {
|
||||
sb.append(" combat");
|
||||
|
|
|
|||
|
|
@ -110,6 +110,19 @@ public class DiesAttachedTriggeredAbility extends TriggeredAbilityImpl {
|
|||
}
|
||||
}
|
||||
}
|
||||
// set targetpointer to the creature that died
|
||||
if (setTargetPointer == SetTargetPointer.CARD
|
||||
|| setTargetPointer == SetTargetPointer.PERMANENT) {
|
||||
Permanent attachment = game.getPermanentOrLKIBattlefield(getSourceId());
|
||||
if (attachment != null
|
||||
&& attachment.getAttachedTo() != null) {
|
||||
Permanent attachedTo = (Permanent) game.getLastKnownInformation(attachment.getAttachedTo(),
|
||||
Zone.BATTLEFIELD, attachment.getAttachedToZoneChangeCounter());
|
||||
if (attachedTo != null) {
|
||||
getEffects().setTargetPointer(new FixedTarget(attachedTo.getId()));
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -125,7 +138,7 @@ public class DiesAttachedTriggeredAbility extends TriggeredAbilityImpl {
|
|||
if (diesRuleText) {
|
||||
sb.append(" dies, ");
|
||||
} else {
|
||||
sb.append(" is put into graveyard, ");
|
||||
sb.append(" is put into a graveyard, ");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ public class DiesCreatureTriggeredAbility extends TriggeredAbilityImpl {
|
|||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
|
||||
if (!zEvent.isDiesEvent() || !filter.match(zEvent.getTarget(), sourceId, controllerId, game)) {
|
||||
if (!zEvent.isDiesEvent() || !filter.match(zEvent.getTarget(), controllerId, this, game)) {
|
||||
return false;
|
||||
}
|
||||
getEffects().setValue("creatureDied", zEvent.getTarget());
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ public class DiesThisOrAnotherCreatureOrPlaneswalkerTriggeredAbility extends Tri
|
|||
if (zEvent.getTarget().getId().equals(this.getSourceId())) {
|
||||
return true;
|
||||
} else {
|
||||
if (filter.match(zEvent.getTarget(), getSourceId(), getControllerId(), game)) {
|
||||
if (filter.match(zEvent.getTarget(), getControllerId(), this, game)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ public class DiesThisOrAnotherCreatureTriggeredAbility extends TriggeredAbilityI
|
|||
if (!applyFilterOnSource && zEvent.getTarget().getId().equals(this.getSourceId())) {
|
||||
return true;
|
||||
} else {
|
||||
if (filter.match(zEvent.getTarget(), getSourceId(), getControllerId(), game)) {
|
||||
if (filter.match(zEvent.getTarget(), getControllerId(), this, game)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,52 +0,0 @@
|
|||
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 L_J
|
||||
*/
|
||||
public class EnchantedCreatureBlockedTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
public EnchantedCreatureBlockedTriggeredAbility(Effect effect, boolean optional) {
|
||||
super(Zone.BATTLEFIELD, effect, optional);
|
||||
}
|
||||
|
||||
public EnchantedCreatureBlockedTriggeredAbility(final EnchantedCreatureBlockedTriggeredAbility 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) {
|
||||
Permanent equipment = game.getPermanent(sourceId);
|
||||
if (equipment != null && equipment.getAttachedTo() != null) {
|
||||
Permanent equipped = game.getPermanent(equipment.getAttachedTo());
|
||||
if (equipped.getId().equals(event.getTargetId())) {
|
||||
getEffects().get(1).setTargetPointer(new FixedTarget(equipped, game));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTriggerPhrase() {
|
||||
return "Whenever enchanted creature becomes blocked, " ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnchantedCreatureBlockedTriggeredAbility copy() {
|
||||
return new EnchantedCreatureBlockedTriggeredAbility(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -84,7 +84,7 @@ public class EntersBattlefieldAllTriggeredAbility extends TriggeredAbilityImpl {
|
|||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
UUID targetId = event.getTargetId();
|
||||
Permanent permanent = game.getPermanent(targetId);
|
||||
if (!filter.match(permanent, getSourceId(), getControllerId(), game)) {
|
||||
if (!filter.match(permanent, getControllerId(), this, game)) {
|
||||
return false;
|
||||
}
|
||||
this.getEffects().setValue("permanentEnteringBattlefield", permanent);
|
||||
|
|
|
|||
|
|
@ -51,11 +51,11 @@ public class EntersBattlefieldControlledTriggeredAbility extends EntersBattlefie
|
|||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (super.checkTrigger(event, game)) {
|
||||
Permanent permanent = game.getPermanent(event.getTargetId());
|
||||
return permanent != null && permanent.isControlledBy(this.getControllerId());
|
||||
Permanent permanent = game.getPermanent(event.getTargetId());
|
||||
if (permanent == null || !permanent.isControlledBy(getControllerId())) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
return super.checkTrigger(event, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ public class EntersBattlefieldOrAttacksAllTriggeredAbility extends TriggeredAbil
|
|||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
Permanent permanent = game.getPermanent(event.getTargetId());
|
||||
if (event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD
|
||||
&& filter.match(permanent, getSourceId(), getControllerId(), game)) {
|
||||
&& filter.match(permanent, getControllerId(), this, game)) {
|
||||
if (setTargetPointer != SetTargetPointer.NONE) {
|
||||
for (Effect effect : this.getEffects()) {
|
||||
switch (setTargetPointer) {
|
||||
|
|
@ -98,7 +98,7 @@ public class EntersBattlefieldOrAttacksAllTriggeredAbility extends TriggeredAbil
|
|||
|
||||
Permanent attacker = game.getPermanent(event.getSourceId());
|
||||
if (event.getType() == GameEvent.EventType.ATTACKER_DECLARED
|
||||
&& filter.match(attacker, getSourceId(), getControllerId(), game)) {
|
||||
&& filter.match(attacker, getControllerId(), this, game)) {
|
||||
if (setTargetPointer != SetTargetPointer.NONE) {
|
||||
for (Effect effect : this.getEffects()) {
|
||||
switch (setTargetPointer) {
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ public class EntersBattlefieldThisOrAnotherTriggeredAbility extends EntersBattle
|
|||
if (onlyControlled && !permanent.isControlledBy(this.getControllerId())) {
|
||||
return false;
|
||||
}
|
||||
return filter.match(permanent, getSourceId(), getControllerId(), game);
|
||||
return filter.match(permanent, getControllerId(), this, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package mage.abilities.common;
|
|||
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.keyword.ForetellAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
|
|
@ -24,27 +23,21 @@ public class ForetellSourceControllerTriggeredAbility extends TriggeredAbilityIm
|
|||
|
||||
@Override
|
||||
public boolean checkEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.TAKEN_SPECIAL_ACTION;
|
||||
return event.getType() == GameEvent.EventType.FORETELL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
Card card = game.getCard(event.getSourceId());
|
||||
Card card = game.getCard(event.getTargetId());
|
||||
Player player = game.getPlayer(event.getPlayerId());
|
||||
if (card == null || player == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isControlledBy(player.getId())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return card.getAbilities(game).containsClass(ForetellAbility.class);
|
||||
return (card != null
|
||||
&& player != null
|
||||
&& isControlledBy(player.getId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTriggerPhrase() {
|
||||
return "Whenever you foretell a card, " ;
|
||||
return "Whenever you foretell a card, ";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -46,10 +46,8 @@ public class GainLifeControllerTriggeredAbility extends TriggeredAbilityImpl {
|
|||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (event.getPlayerId().equals(this.getControllerId())) {
|
||||
if (setTargetPointer) {
|
||||
for (Effect effect : this.getEffects()) {
|
||||
effect.setTargetPointer(new FixedTarget(event.getPlayerId()));
|
||||
effect.setValue("gainedLife", event.getAmount());
|
||||
}
|
||||
this.getEffects().setTargetPointer(new FixedTarget(event.getPlayerId()));
|
||||
this.getEffects().setValue("gainedLife", event.getAmount());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -58,6 +56,6 @@ public class GainLifeControllerTriggeredAbility extends TriggeredAbilityImpl {
|
|||
|
||||
@Override
|
||||
public String getTriggerPhrase() {
|
||||
return "Whenever you gain life, " ;
|
||||
return "Whenever you gain life, ";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,171 @@
|
|||
package mage.abilities.common;
|
||||
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.ActivatedAbilityImpl;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.costs.common.ExileSourceFromHandCost;
|
||||
import mage.abilities.costs.mana.GenericManaCost;
|
||||
import mage.abilities.effects.ContinuousEffectImpl;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.mana.*;
|
||||
import mage.constants.*;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.stack.Spell;
|
||||
import mage.target.common.TargetLandPermanent;
|
||||
import mage.util.CardUtil;
|
||||
import mage.watchers.Watcher;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public class GiveManaAbilityAndCastSourceAbility extends ActivatedAbilityImpl {
|
||||
|
||||
// TODO: write automated tests for this (it works in manual testing)
|
||||
public GiveManaAbilityAndCastSourceAbility(String colors) {
|
||||
super(Zone.HAND, new GainManaAbilitiesWhileExiledEffect(colors), new GenericManaCost(2));
|
||||
this.addCost(new ExileSourceFromHandCost());
|
||||
this.addEffect(new CastExiledFromHandCardEffect());
|
||||
this.addTarget(new TargetLandPermanent());
|
||||
this.addWatcher(new WasCastFromExileWatcher());
|
||||
}
|
||||
|
||||
private GiveManaAbilityAndCastSourceAbility(final GiveManaAbilityAndCastSourceAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GiveManaAbilityAndCastSourceAbility copy() {
|
||||
return new GiveManaAbilityAndCastSourceAbility(this);
|
||||
}
|
||||
}
|
||||
|
||||
class CastExiledFromHandCardEffect extends OneShotEffect {
|
||||
|
||||
CastExiledFromHandCardEffect() {
|
||||
super(Outcome.Benefit);
|
||||
staticText = "You may cast {this} for as long as it remains exiled";
|
||||
}
|
||||
|
||||
private CastExiledFromHandCardEffect(final CastExiledFromHandCardEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CastExiledFromHandCardEffect copy() {
|
||||
return new CastExiledFromHandCardEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Optional.of(getValue("exiledHandCardRef"))
|
||||
.filter(Objects::nonNull)
|
||||
.map(MageObjectReference.class::cast)
|
||||
.map(mor -> mor.getCard(game))
|
||||
.ifPresent(card -> CardUtil.makeCardPlayable(
|
||||
game, source, card, Duration.Custom, false
|
||||
));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class GainManaAbilitiesWhileExiledEffect extends ContinuousEffectImpl {
|
||||
|
||||
private final String colors;
|
||||
|
||||
GainManaAbilitiesWhileExiledEffect(String colors) {
|
||||
super(Duration.Custom, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility);
|
||||
this.colors = colors;
|
||||
}
|
||||
|
||||
private GainManaAbilitiesWhileExiledEffect(final GainManaAbilitiesWhileExiledEffect effect) {
|
||||
super(effect);
|
||||
this.colors = effect.colors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GainManaAbilitiesWhileExiledEffect copy() {
|
||||
return new GainManaAbilitiesWhileExiledEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
if (WasCastFromExileWatcher.check((MageObjectReference) getValue("exiledHandCardRef"), game)) {
|
||||
discard();
|
||||
return false;
|
||||
}
|
||||
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
|
||||
if (permanent == null) {
|
||||
discard();
|
||||
return false;
|
||||
}
|
||||
for (char c : colors.toCharArray()) {
|
||||
Ability ability;
|
||||
switch (c) {
|
||||
case 'W':
|
||||
ability = new WhiteManaAbility();
|
||||
break;
|
||||
case 'U':
|
||||
ability = new BlueManaAbility();
|
||||
break;
|
||||
case 'B':
|
||||
ability = new BlackManaAbility();
|
||||
break;
|
||||
case 'R':
|
||||
ability = new RedManaAbility();
|
||||
break;
|
||||
case 'G':
|
||||
ability = new GreenManaAbility();
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
permanent.addAbility(ability, source.getSourceId(), game);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(Mode mode) {
|
||||
return "target land gains \"{T}: Add " +
|
||||
CardUtil.concatWithOr(
|
||||
Arrays.stream(colors.split(""))
|
||||
.map(s -> '{' + s + '}')
|
||||
.collect(Collectors.toList())
|
||||
) +
|
||||
"\" until {this} is cast from exile";
|
||||
}
|
||||
}
|
||||
|
||||
class WasCastFromExileWatcher extends Watcher {
|
||||
|
||||
private final Set<MageObjectReference> morSet = new HashSet<>();
|
||||
|
||||
WasCastFromExileWatcher() {
|
||||
super(WatcherScope.GAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void watch(GameEvent event, Game game) {
|
||||
if (event.getType() != GameEvent.EventType.SPELL_CAST || !Zone.EXILED.match(event.getZone())) {
|
||||
return;
|
||||
}
|
||||
Spell spell = game.getSpell(event.getSourceId());
|
||||
if (spell != null) {
|
||||
morSet.add(new MageObjectReference(spell.getMainCard(), game, -1));
|
||||
}
|
||||
}
|
||||
|
||||
static boolean check(MageObjectReference mor, Game game) {
|
||||
return game
|
||||
.getState()
|
||||
.getWatcher(WasCastFromExileWatcher.class)
|
||||
.morSet
|
||||
.contains(mor);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
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((getEffects().size() > 1 ? ", " : " ") + "and is goaded. <i>(It attacks each combat if able"));
|
||||
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 = "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
|
||||
|| game.getState().getPlayersInRange(attacker.getControllerId(), game).size() == 2) { // just 2 players left, so it may attack you
|
||||
return true;
|
||||
}
|
||||
// A planeswalker controlled by the controller is the defender
|
||||
if (game.getPermanent(defenderId) != null) {
|
||||
return !game.getPermanent(defenderId).getControllerId().equals(source.getControllerId());
|
||||
}
|
||||
// The controller is the defender
|
||||
return !defenderId.equals(source.getControllerId());
|
||||
}
|
||||
}
|
||||
|
|
@ -62,7 +62,7 @@ public class LeavesBattlefieldAllTriggeredAbility extends TriggeredAbilityImpl {
|
|||
if (zEvent.getFromZone() == Zone.BATTLEFIELD) {
|
||||
UUID targetId = event.getTargetId();
|
||||
Permanent permanent = game.getPermanentOrLKIBattlefield(targetId);
|
||||
if (filter.match(permanent, getSourceId(), getControllerId(), game)) {
|
||||
if (filter.match(permanent, getControllerId(), this, game)) {
|
||||
if (setTargetPointer != SetTargetPointer.NONE) {
|
||||
for (Effect effect : this.getEffects()) {
|
||||
switch (setTargetPointer) {
|
||||
|
|
|
|||
|
|
@ -1,39 +0,0 @@
|
|||
package mage.abilities.common;
|
||||
|
||||
import mage.abilities.effects.EntersBattlefieldEffect;
|
||||
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
|
||||
import mage.counters.CounterType;
|
||||
|
||||
/**
|
||||
* @author LevelX2
|
||||
*/
|
||||
public class PlaneswalkerEntersWithLoyaltyCountersAbility extends EntersBattlefieldAbility {
|
||||
|
||||
private int startingLoyalty;
|
||||
|
||||
public PlaneswalkerEntersWithLoyaltyCountersAbility(int loyalty) {
|
||||
super(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(loyalty)));
|
||||
startingLoyalty = loyalty;
|
||||
setRuleVisible(false);
|
||||
}
|
||||
|
||||
public PlaneswalkerEntersWithLoyaltyCountersAbility(final PlaneswalkerEntersWithLoyaltyCountersAbility ability) {
|
||||
super(ability);
|
||||
startingLoyalty = ability.startingLoyalty;
|
||||
}
|
||||
|
||||
public int getStartingLoyalty() {
|
||||
return startingLoyalty;
|
||||
}
|
||||
|
||||
public void setStartingLoyalty(int startingLoyalty) {
|
||||
this.startingLoyalty = startingLoyalty;
|
||||
this.getEffects().clear();
|
||||
this.addEffect(new EntersBattlefieldEffect(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(startingLoyalty))));
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlaneswalkerEntersWithLoyaltyCountersAbility copy() {
|
||||
return new PlaneswalkerEntersWithLoyaltyCountersAbility(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -77,11 +77,12 @@ public class PutCardIntoGraveFromAnywhereAllTriggeredAbility extends TriggeredAb
|
|||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (((ZoneChangeEvent) event).getToZone() != Zone.GRAVEYARD) {
|
||||
if (((ZoneChangeEvent) event).getToZone() != Zone.GRAVEYARD
|
||||
|| !zone.match(game.getState().getZone(getSourceId()))) {
|
||||
return false;
|
||||
}
|
||||
Card card = game.getCard(event.getTargetId());
|
||||
if (card == null || card.isCopy() || !filter.match(card, getSourceId(), getControllerId(), game)) {
|
||||
if (card == null || card.isCopy() || !filter.match(card, getControllerId(), this, game)) {
|
||||
return false;
|
||||
}
|
||||
switch (setTargetPointer) {
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ class PutIntoGraveFromAnywhereEffect extends ReplacementEffectImpl {
|
|||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
if (optional) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
MageObject object = game.getObject(source.getSourceId());
|
||||
MageObject object = game.getObject(source);
|
||||
if (controller == null || object == null) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import mage.constants.Zone;
|
|||
import mage.filter.FilterPermanent;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
|
|
@ -49,7 +48,7 @@ public class PutIntoGraveFromBattlefieldAllTriggeredAbility extends TriggeredAbi
|
|||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
|
||||
if (zEvent.isDiesEvent()) {
|
||||
if (filter.match(zEvent.getTarget(), this.getSourceId(), this.getControllerId(), game)) {
|
||||
if (filter.match(zEvent.getTarget(), this.getControllerId(), this, game)) {
|
||||
if (onlyToControllerGraveyard && !this.isControlledBy(game.getOwnerId(zEvent.getTargetId()))) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import mage.game.permanent.Permanent;
|
|||
*/
|
||||
public class PutIntoGraveFromBattlefieldSourceTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
private boolean onlyToControllerGraveyard;
|
||||
private final boolean onlyToControllerGraveyard;
|
||||
|
||||
public PutIntoGraveFromBattlefieldSourceTriggeredAbility(Effect effect) {
|
||||
this(effect, false, false);
|
||||
|
|
@ -42,19 +42,21 @@ public class PutIntoGraveFromBattlefieldSourceTriggeredAbility extends Triggered
|
|||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (event.getTargetId().equals(getSourceId())) {
|
||||
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
|
||||
Permanent permanent = zEvent.getTarget();
|
||||
if (permanent != null
|
||||
&& zEvent.isDiesEvent()) {
|
||||
return !onlyToControllerGraveyard || this.isControlledBy(game.getOwnerId(zEvent.getTargetId()));
|
||||
}
|
||||
if (!event.getTargetId().equals(getSourceId())) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
|
||||
Permanent permanent = zEvent.getTarget();
|
||||
if (permanent == null || !zEvent.isDiesEvent()
|
||||
|| (onlyToControllerGraveyard && !this.isControlledBy(game.getOwnerId(zEvent.getTargetId())))) {
|
||||
return false;
|
||||
}
|
||||
this.getEffects().setValue("permanentWasCreature", permanent.isCreature(game));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTriggerPhrase() {
|
||||
return "When {this} is put into " + (onlyToControllerGraveyard ? "your" : "a") + " graveyard from the battlefield, " ;
|
||||
return "When {this} is put into " + (onlyToControllerGraveyard ? "your" : "a") + " graveyard from the battlefield, ";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ public class SacrificeAllTriggeredAbility extends TriggeredAbilityImpl {
|
|||
break;
|
||||
}
|
||||
Permanent sacrificedPermanent = game.getPermanentOrLKIBattlefield(event.getTargetId());
|
||||
return sacrificed && filter.match(sacrificedPermanent, getSourceId(), getControllerId(), game);
|
||||
return sacrificed && filter.match(sacrificedPermanent, getControllerId(), this, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ public class SacrificePermanentTriggeredAbility extends TriggeredAbilityImpl {
|
|||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
Permanent permanent = game.getPermanentOrLKIBattlefield(event.getTargetId());
|
||||
if (!isControlledBy(event.getPlayerId()) || permanent == null
|
||||
|| !filter.match(permanent, getSourceId(), getControllerId(), game)) {
|
||||
|| !filter.match(permanent, getControllerId(), this, game)) {
|
||||
return false;
|
||||
}
|
||||
this.getEffects().setValue("sacrificedPermanent", permanent);
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ public class SpellCastAllTriggeredAbility extends TriggeredAbilityImpl {
|
|||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
Spell spell = game.getStack().getSpell(event.getTargetId());
|
||||
if (!filter.match(spell, getSourceId(), getControllerId(), game)) {
|
||||
if (!filter.match(spell, getControllerId(), this, game)) {
|
||||
return false;
|
||||
}
|
||||
getEffects().setValue("spellCast", spell);
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ public class SpellCastControllerTriggeredAbility extends TriggeredAbilityImpl {
|
|||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (event.getPlayerId().equals(this.getControllerId())) {
|
||||
Spell spell = game.getStack().getSpell(event.getTargetId());
|
||||
if (filter.match(spell, getSourceId(), getControllerId(), game)) {
|
||||
if (filter.match(spell, getControllerId(), this, game)) {
|
||||
this.getEffects().setValue("spellCast", spell);
|
||||
if (rememberSource) {
|
||||
if (rememberSourceAsCard) {
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ public class SpellCastOpponentTriggeredAbility extends TriggeredAbilityImpl {
|
|||
return false;
|
||||
}
|
||||
Spell spell = game.getStack().getSpell(event.getTargetId());
|
||||
if (!filter.match(spell, getSourceId(), getControllerId(), game)) {
|
||||
if (!filter.match(spell, getControllerId(), this, game)) {
|
||||
return false;
|
||||
}
|
||||
getEffects().setValue("spellCast", spell);
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ public class TapForManaAllTriggeredAbility extends TriggeredAbilityImpl {
|
|||
}
|
||||
TappedForManaEvent manaEvent = ((TappedForManaEvent) event);
|
||||
Permanent permanent = manaEvent.getPermanent();
|
||||
if (permanent == null || !filter.match(permanent, getSourceId(), getControllerId(), game)) {
|
||||
if (permanent == null || !filter.match(permanent, getControllerId(), this, game)) {
|
||||
return false;
|
||||
}
|
||||
getEffects().setValue("mana", manaEvent.getMana());
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ public class TapForManaAllTriggeredManaAbility extends TriggeredManaAbility {
|
|||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
TappedForManaEvent manaEvent = ((TappedForManaEvent) event);
|
||||
Permanent permanent = manaEvent.getPermanent();
|
||||
if (permanent == null || !filter.match(permanent, getSourceId(), getControllerId(), game)) {
|
||||
if (permanent == null || !filter.match(permanent, getControllerId(), this, game)) {
|
||||
return false;
|
||||
}
|
||||
getEffects().setValue("mana", manaEvent.getMana());
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ public class TurnedFaceUpAllTriggeredAbility extends TriggeredAbilityImpl {
|
|||
}
|
||||
}
|
||||
Permanent permanent = game.getPermanent(event.getTargetId());
|
||||
if (filter.match(permanent, getSourceId(), getControllerId(), game)) {
|
||||
if (filter.match(permanent, getControllerId(), this, game)) {
|
||||
if (setTargetPointer) {
|
||||
for (Effect effect : getEffects()) {
|
||||
effect.setTargetPointer(new FixedTarget(event.getTargetId(), game));
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ public class ZoneChangeAllTriggeredAbility extends TriggeredAbilityImpl {
|
|||
} else {
|
||||
perm = game.getPermanent(event.getTargetId()); // LevelX2: maybe this part is not neccessary
|
||||
}
|
||||
if (filter.match(perm, sourceId, controllerId, game)) {
|
||||
if (filter.match(perm, controllerId, this, game)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,12 +20,18 @@ public class AtTheBeginOfMainPhaseDelayedTriggeredAbility extends DelayedTrigger
|
|||
NEXT_PRECOMBAT_MAIN("next precombat main phase"),
|
||||
NEXT_POSTCOMAT_MAIN("next postcombat main phase"),
|
||||
NEXT_MAIN("next main phase"),
|
||||
NEXT_MAIN_THIS_TURN("next main phase this turn");
|
||||
NEXT_MAIN_THIS_TURN("next main phase this turn", Duration.EndOfTurn);
|
||||
|
||||
private final String text;
|
||||
private final Duration duration;
|
||||
|
||||
PhaseSelection(String text) {
|
||||
this(text, Duration.EndOfGame);
|
||||
}
|
||||
|
||||
PhaseSelection(String text, Duration duration) {
|
||||
this.text = text;
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -38,7 +44,7 @@ public class AtTheBeginOfMainPhaseDelayedTriggeredAbility extends DelayedTrigger
|
|||
private final PhaseSelection phaseSelection;
|
||||
|
||||
public AtTheBeginOfMainPhaseDelayedTriggeredAbility(Effect effect, boolean optional, TargetController targetController, PhaseSelection phaseSelection) {
|
||||
super(effect, Duration.EndOfGame, true, optional);
|
||||
super(effect, phaseSelection.duration, true, optional);
|
||||
this.targetController = targetController;
|
||||
this.phaseSelection = phaseSelection;
|
||||
|
||||
|
|
@ -101,7 +107,7 @@ public class AtTheBeginOfMainPhaseDelayedTriggeredAbility extends DelayedTrigger
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
public String getTriggerPhrase() {
|
||||
switch (targetController) {
|
||||
case YOU:
|
||||
return "At the beginning of your " + phaseSelection + ", ";
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
package mage.abilities.common.delayed;
|
||||
|
||||
import mage.abilities.DelayedTriggeredAbility;
|
||||
|
|
@ -6,34 +5,32 @@ import mage.abilities.condition.Condition;
|
|||
import mage.abilities.effects.Effect;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.TargetController;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author North
|
||||
*/
|
||||
public class AtTheBeginOfNextEndStepDelayedTriggeredAbility extends DelayedTriggeredAbility {
|
||||
|
||||
private TargetController targetController;
|
||||
private Condition condition;
|
||||
private final TargetController targetController;
|
||||
private final Condition condition;
|
||||
|
||||
public AtTheBeginOfNextEndStepDelayedTriggeredAbility(Effect effect) {
|
||||
this(effect, TargetController.ANY);
|
||||
}
|
||||
|
||||
public AtTheBeginOfNextEndStepDelayedTriggeredAbility(Effect effect, TargetController targetController) {
|
||||
this(Zone.ALL, effect, targetController);
|
||||
this(effect, targetController, null);
|
||||
}
|
||||
|
||||
public AtTheBeginOfNextEndStepDelayedTriggeredAbility(Zone zone, Effect effect, TargetController targetController) {
|
||||
this(zone, effect, targetController, null);
|
||||
public AtTheBeginOfNextEndStepDelayedTriggeredAbility(Effect effect, TargetController targetController, Condition condition) {
|
||||
this(effect, targetController, condition, false);
|
||||
}
|
||||
|
||||
public AtTheBeginOfNextEndStepDelayedTriggeredAbility(Zone zone, Effect effect, TargetController targetController, Condition condition) {
|
||||
super(effect, Duration.Custom);
|
||||
public AtTheBeginOfNextEndStepDelayedTriggeredAbility(Effect effect, TargetController targetController, Condition condition, boolean optional) {
|
||||
super(effect, Duration.Custom, true, optional);
|
||||
this.zone = zone;
|
||||
this.targetController = targetController;
|
||||
this.condition = condition;
|
||||
|
|
@ -52,32 +49,33 @@ public class AtTheBeginOfNextEndStepDelayedTriggeredAbility extends DelayedTrigg
|
|||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
boolean correctEndPhase = false;
|
||||
switch (targetController) {
|
||||
case ANY:
|
||||
correctEndPhase = true;
|
||||
break;
|
||||
case YOU:
|
||||
correctEndPhase = event.getPlayerId().equals(this.controllerId);
|
||||
if (!isControlledBy(event.getPlayerId())) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case OPPONENT:
|
||||
if (game.getPlayer(this.getControllerId()).hasOpponent(event.getPlayerId(), game)) {
|
||||
correctEndPhase = true;
|
||||
if (!game.getOpponents(this.getControllerId()).contains(event.getPlayerId())) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case CONTROLLER_ATTACHED_TO:
|
||||
Permanent attachment = game.getPermanent(sourceId);
|
||||
if (attachment != null && attachment.getAttachedTo() != null) {
|
||||
Permanent attachedTo = game.getPermanent(attachment.getAttachedTo());
|
||||
if (attachedTo != null && attachedTo.isControlledBy(event.getPlayerId())) {
|
||||
correctEndPhase = true;
|
||||
}
|
||||
Permanent attachment = game.getPermanent(getSourceId());
|
||||
if (attachment == null || attachment.getAttachedTo() == null) {
|
||||
return false;
|
||||
}
|
||||
Permanent attachedTo = game.getPermanent(attachment.getAttachedTo());
|
||||
if (attachedTo == null || !attachedTo.isControlledBy(event.getPlayerId())) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException("TargetController not supported");
|
||||
}
|
||||
if (correctEndPhase) {
|
||||
return !(condition != null && !condition.apply(game, this));
|
||||
}
|
||||
return false;
|
||||
return condition == null || condition.apply(game, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -86,23 +84,17 @@ public class AtTheBeginOfNextEndStepDelayedTriggeredAbility extends DelayedTrigg
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
public String getTriggerPhrase() {
|
||||
switch (targetController) {
|
||||
case YOU:
|
||||
sb.append("At the beginning of your next end step, ");
|
||||
break;
|
||||
return "At the beginning of your next end step, ";
|
||||
case OPPONENT:
|
||||
sb.append("At the beginning of an opponent's next end step, ");
|
||||
break;
|
||||
return "At the beginning of an opponent's next end step, ";
|
||||
case ANY:
|
||||
sb.append("At the beginning of the next end step, ");
|
||||
break;
|
||||
return "At the beginning of the next end step, ";
|
||||
case CONTROLLER_ATTACHED_TO:
|
||||
sb.append("At the beginning of the next end step of enchanted creature's controller, ");
|
||||
break;
|
||||
return "At the beginning of the next end step of enchanted creature's controller, ";
|
||||
}
|
||||
sb.append(getEffects().getText(modes.getMode()));
|
||||
return sb.toString();
|
||||
throw new UnsupportedOperationException("TargetController not supported");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,6 @@ public class AnyPlayerControlsCondition implements Condition {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) > 0;
|
||||
return game.getBattlefield().count(filter, source.getControllerId(), source, game) > 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ public class AttachedToMatchesFilterCondition implements Condition {
|
|||
if (attachedTo == null) {
|
||||
attachedTo = (Permanent) game.getLastKnownInformation(permanent.getAttachedTo(), Zone.BATTLEFIELD);
|
||||
}
|
||||
if (filter.match(attachedTo, attachedTo.getId(), attachedTo.getControllerId(), game)) {
|
||||
if (filter.match(attachedTo, attachedTo.getControllerId(), source, game)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
package mage.abilities.condition.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.abilities.keyword.BlitzAbility;
|
||||
import mage.game.Game;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public enum BlitzedCondition implements Condition {
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
List<Integer> blitzActivations = (List<Integer>) game.getState().getValue(BlitzAbility.BLITZ_ACTIVATION_VALUE_KEY + source.getSourceId());
|
||||
return blitzActivations != null && blitzActivations.contains(game.getState().getZoneChangeCounter(source.getSourceId()));
|
||||
}
|
||||
}
|
||||
|
|
@ -18,7 +18,7 @@ public enum BuybackCondition implements Condition {
|
|||
Card card = game.getCard(source.getSourceId());
|
||||
if (card != null) {
|
||||
return card.getAbilities(game).stream()
|
||||
.filter(a -> a instanceof BuybackAbility)
|
||||
.filter(BuybackAbility.class::isInstance)
|
||||
.anyMatch(a -> ((BuybackAbility) a).isBuybackActivated(game));
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ public class CardsInControllerGraveyardCondition implements Condition {
|
|||
public boolean apply(Game game, Ability source) {
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
if (filter != null) {
|
||||
return player != null && player.getGraveyard().count(filter, source.getSourceId(), source.getControllerId(), game) >= value;
|
||||
return player != null && player.getGraveyard().count(filter, source.getControllerId(), source, game) >= value;
|
||||
}
|
||||
return player != null && player.getGraveyard().size() >= value;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ public enum ControlledModifiedCreatureAsSpellCastCondition implements Condition
|
|||
if (sourceObject == null || watcher == null) {
|
||||
return false;
|
||||
}
|
||||
return watcher.checkModifiedCondition(new MageObjectReference(sourceObject, game));
|
||||
return watcher.getModifiedCreatureCount(new MageObjectReference(sourceObject, game)) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ public enum ControlsCreatureGreatestPowerCondition implements Condition {
|
|||
Set<UUID> controllers = new HashSet<>();
|
||||
Integer maxPower = null;
|
||||
|
||||
List<Permanent> permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game);
|
||||
List<Permanent> permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game);
|
||||
for (Permanent permanent : permanents) {
|
||||
if (permanent == null) {
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ public enum ControlsCreatureGreatestToughnessCondition implements Condition {
|
|||
Set<UUID> controllers = new HashSet<>();
|
||||
Integer maxToughness = null;
|
||||
|
||||
List<Permanent> permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game);
|
||||
List<Permanent> permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game);
|
||||
for (Permanent permanent : permanents) {
|
||||
if (permanent == null) {
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ public class ControlsPermanentGreatestCMCCondition implements Condition {
|
|||
Set<UUID> controllers = new HashSet<>();
|
||||
Integer maxCMC = null;
|
||||
|
||||
List<Permanent> permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game);
|
||||
List<Permanent> permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game);
|
||||
for (Permanent permanent : permanents) {
|
||||
int cmc = permanent.getManaCost().manaValue();
|
||||
if (maxCMC == null || cmc > maxCMC) {
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ public enum CovenCondition implements Condition {
|
|||
.getBattlefield()
|
||||
.getActivePermanents(
|
||||
StaticFilters.FILTER_CONTROLLED_CREATURE,
|
||||
source.getControllerId(), source.getSourceId(), game
|
||||
source.getControllerId(), source, game
|
||||
)
|
||||
.stream()
|
||||
.filter(Objects::nonNull)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
package mage.abilities.condition.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.abilities.hint.ConditionHint;
|
||||
import mage.abilities.hint.Hint;
|
||||
import mage.game.Game;
|
||||
import mage.watchers.common.CreatedTokenWatcher;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public enum CreatedTokenThisTurnCondition implements Condition {
|
||||
instance;
|
||||
private static final Hint hint = new ConditionHint(instance, "You created a token this turn");
|
||||
|
||||
public static Hint getHint() {
|
||||
return hint;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return CreatedTokenWatcher.checkPlayer(source.getControllerId(), game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "if you created a token this turn";
|
||||
}
|
||||
}
|
||||
|
|
@ -43,7 +43,7 @@ public class CreatureCountCondition implements Condition {
|
|||
}
|
||||
return true;
|
||||
case ANY:
|
||||
return game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) == creatureCount;
|
||||
return game.getBattlefield().count(filter, source.getControllerId(), source, game) == creatureCount;
|
||||
default:
|
||||
throw new UnsupportedOperationException("Value for targetController not supported: " + targetController.toString());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
package mage.abilities.condition.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
|
|
@ -6,24 +5,21 @@ import mage.abilities.condition.Condition;
|
|||
import mage.abilities.keyword.DashAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.game.Game;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
/**
|
||||
* @author LevelX2
|
||||
*/
|
||||
|
||||
public enum DashedCondition implements Condition {
|
||||
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Card card = game.getCard(source.getSourceId());
|
||||
if (card != null) {
|
||||
return card.getAbilities(game).stream()
|
||||
.filter(a -> a instanceof DashAbility)
|
||||
.anyMatch(d -> ((DashAbility) d).isActivated(source, game));
|
||||
|
||||
}
|
||||
return false;
|
||||
return card != null
|
||||
&& CardUtil.castStream(card
|
||||
.getAbilities(game)
|
||||
.stream(), DashAbility.class)
|
||||
.anyMatch(ability -> ability.isActivated(source, game));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ public enum DeliriumCondition implements Condition {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "if there are four or more card types among cards in your graveyard";
|
||||
return "there are four or more card types among cards in your graveyard";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,68 @@
|
|||
package mage.abilities.condition.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.abilities.hint.Hint;
|
||||
import mage.constants.SubType;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.filter.common.FilterControlledPermanent;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public enum DesertControlledOrGraveyardCondition implements Condition {
|
||||
instance;
|
||||
|
||||
private static final FilterPermanent filter = new FilterControlledPermanent(SubType.DESERT);
|
||||
private static final FilterCard filter2 = new FilterCard();
|
||||
|
||||
static {
|
||||
filter2.add(SubType.DESERT.getPredicate());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
if (game.getBattlefield().contains(filter, source, game, 1)) {
|
||||
return true;
|
||||
}
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
return player != null && player.getGraveyard().count(filter2, game) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "you control a Desert or there is a Desert card in your graveyard";
|
||||
}
|
||||
|
||||
public static Hint getHint() {
|
||||
return DesertControlledOrGraveyardHint.instance;
|
||||
}
|
||||
|
||||
enum DesertControlledOrGraveyardHint implements Hint {
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public String getText(Game game, Ability ability) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (game.getBattlefield().contains(filter, ability, game, 1)) {
|
||||
sb.append("You control a Desert");
|
||||
}
|
||||
Player player = game.getPlayer(ability.getControllerId());
|
||||
if (player != null && player.getGraveyard().count(filter2, game) > 0) {
|
||||
if (sb.length() > 0) {
|
||||
sb.append("<br>");
|
||||
}
|
||||
sb.append("You have a Desert card in your graveyard");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Hint copy() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
package mage.abilities.condition.common;
|
||||
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.condition.Condition;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
*/
|
||||
public enum DifferentManaValuesInGraveCondition implements Condition {
|
||||
FIVE(5);
|
||||
private final int amount;
|
||||
|
||||
DifferentManaValuesInGraveCondition(int amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
return player != null
|
||||
&& player
|
||||
.getGraveyard()
|
||||
.getCards(game)
|
||||
.stream()
|
||||
.mapToInt(MageObject::getManaValue)
|
||||
.distinct()
|
||||
.count() >= amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "there are " + CardUtil.numberToText(amount) + " or more mana values among cards in your graveyard";
|
||||
}
|
||||
}
|
||||
|
|
@ -30,7 +30,7 @@ public class EnchantedCreatureColorCondition implements Condition {
|
|||
Permanent enchantment = game.getPermanent(source.getSourceId());
|
||||
if (enchantment != null) {
|
||||
Permanent creature = game.getPermanent(enchantment.getAttachedTo());
|
||||
if(filter.match(creature, source.getSourceId(), enchantment.getControllerId(), game)){
|
||||
if(filter.match(creature, enchantment.getControllerId(), source, game)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ public class EnchantedCreatureSubtypeCondition implements Condition {
|
|||
Permanent enchantment = game.getPermanent(source.getSourceId());
|
||||
if (enchantment != null) {
|
||||
Permanent creature = game.getPermanent(enchantment.getAttachedTo());
|
||||
if (filter.match(creature, source.getSourceId(), enchantment.getControllerId(), game)) {
|
||||
if (filter.match(creature, enchantment.getControllerId(), source, game)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ public enum EvokedCondition implements Condition {
|
|||
Card card = game.getCard(source.getSourceId());
|
||||
if (card != null) {
|
||||
return card.getAbilities(game).stream()
|
||||
.filter(ab -> ab instanceof EvokeAbility)
|
||||
.filter(EvokeAbility.class::isInstance)
|
||||
.anyMatch(evoke -> ((EvokeAbility) evoke).isActivated(source, game));
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ public enum FaceDownSourceCondition implements Condition {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
MageObject mageObject = game.getObject(source.getSourceId());
|
||||
MageObject mageObject = game.getObject(source);
|
||||
if (mageObject != null) {
|
||||
if (mageObject instanceof Permanent) {
|
||||
return ((Permanent)mageObject).isFaceDown(game);
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ public class MeldCondition implements Condition {
|
|||
FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent();
|
||||
filter.add(new NamePredicate(this.meldWithName));
|
||||
filter.add(new OwnerIdPredicate(source.getControllerId()));
|
||||
return game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) > 0;
|
||||
return game.getBattlefield().count(filter, source.getControllerId(), source, game) > 0;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ public class MostCommonColorCondition implements Condition {
|
|||
i = 0;
|
||||
for (ObjectColor color : ObjectColor.getAllColors()) {
|
||||
colorFilters[i].add(new ColorPredicate(color));
|
||||
colorCounts[i] = game.getBattlefield().count(colorFilters[i], source.getId(), source.getControllerId(), game);
|
||||
colorCounts[i] = game.getBattlefield().count(colorFilters[i], source.getControllerId(), source, game);
|
||||
i++;
|
||||
}
|
||||
int max = 0;
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ public class OathbreakerOnBattlefieldCondition implements Condition {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
// source.getSourceId() is null for commander's effects
|
||||
int permanentsOnBattlefield = game.getBattlefield().count(this.filter, source.getSourceId(), playerId, game);
|
||||
int permanentsOnBattlefield = game.getBattlefield().count(this.filter, playerId, source, game);
|
||||
return permanentsOnBattlefield > 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ public enum OneOpponentCondition implements Condition {
|
|||
.stream()
|
||||
.map(game::getPlayer)
|
||||
.filter(Objects::nonNull)
|
||||
.filter(player -> !player.hasLost())
|
||||
.count() <= 1;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ public class OpponentControlsPermanentCondition implements Condition {
|
|||
for (UUID opponentId : game.getOpponents(source.getControllerId())) {
|
||||
FilterPermanent localFilter = filter.copy();
|
||||
localFilter.add(new ControllerIdPredicate(opponentId));
|
||||
if (ComparisonType.compare(game.getBattlefield().count(localFilter, source.getSourceId(), source.getControllerId(), game), type, this.count)) {
|
||||
if (ComparisonType.compare(game.getBattlefield().count(localFilter, source.getControllerId(), source, game), type, this.count)) {
|
||||
conditionApplies = true;
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ public class PermanentsOnTheBattlefieldCondition implements Condition {
|
|||
localFilter = filter;
|
||||
}
|
||||
return ComparisonType.compare(game.getBattlefield().count(
|
||||
localFilter, source.getSourceId(), source.getControllerId(), game
|
||||
localFilter, source.getControllerId(), source, game
|
||||
), type, count);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ public enum ProwlCostWasPaidCondition implements Condition {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "{this}'s prowl cost was paid";
|
||||
return "this spell's prowl cost was paid";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ instance;
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
MageObject object = game.getObject(source.getSourceId());
|
||||
MageObject object = game.getObject(source);
|
||||
return object != null && !object.isLand(game);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ public class SourceMatchesFilterCondition implements Condition {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Permanent permanent = game.getBattlefield().getPermanent(source.getSourceId());
|
||||
if (FILTER.match(permanent, permanent.getId(), permanent.getControllerId(), game)) {
|
||||
if (FILTER.match(permanent, permanent.getControllerId(), source, game)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
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