diff --git a/Mage.Sets/src/mage/cards/a/Aethertow.java b/Mage.Sets/src/mage/cards/a/Aethertow.java
index f126ce78317..f9af151c47c 100644
--- a/Mage.Sets/src/mage/cards/a/Aethertow.java
+++ b/Mage.Sets/src/mage/cards/a/Aethertow.java
@@ -31,7 +31,7 @@ public final class Aethertow extends CardImpl {
this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter));
// Conspire
- this.addAbility(new ConspireAbility(getId(), ConspireAbility.ConspireTargets.ONE));
+ this.addAbility(new ConspireAbility(ConspireAbility.ConspireTargets.ONE));
}
private Aethertow(final Aethertow card) {
diff --git a/Mage.Sets/src/mage/cards/b/BarkshellBlessing.java b/Mage.Sets/src/mage/cards/b/BarkshellBlessing.java
index 15a587256d3..86c46bfb2bd 100644
--- a/Mage.Sets/src/mage/cards/b/BarkshellBlessing.java
+++ b/Mage.Sets/src/mage/cards/b/BarkshellBlessing.java
@@ -24,7 +24,7 @@ public final class BarkshellBlessing extends CardImpl {
this.getSpellAbility().addEffect(new BoostTargetEffect(2, 2, Duration.EndOfTurn));
// Conspire
- this.addAbility(new ConspireAbility(getId(), ConspireAbility.ConspireTargets.ONE));
+ this.addAbility(new ConspireAbility(ConspireAbility.ConspireTargets.ONE));
}
private BarkshellBlessing(final BarkshellBlessing card) {
diff --git a/Mage.Sets/src/mage/cards/b/BurnTrail.java b/Mage.Sets/src/mage/cards/b/BurnTrail.java
index f2620442ca4..9c070b730ae 100644
--- a/Mage.Sets/src/mage/cards/b/BurnTrail.java
+++ b/Mage.Sets/src/mage/cards/b/BurnTrail.java
@@ -23,7 +23,7 @@ public final class BurnTrail extends CardImpl {
this.getSpellAbility().addTarget(new TargetAnyTarget());
// Conspire
- this.addAbility(new ConspireAbility(getId(), ConspireAbility.ConspireTargets.ONE));
+ this.addAbility(new ConspireAbility(ConspireAbility.ConspireTargets.ONE));
}
private BurnTrail(final BurnTrail card) {
diff --git a/Mage.Sets/src/mage/cards/d/DisturbingPlot.java b/Mage.Sets/src/mage/cards/d/DisturbingPlot.java
index e9ced3a80ce..f8b24e66d33 100644
--- a/Mage.Sets/src/mage/cards/d/DisturbingPlot.java
+++ b/Mage.Sets/src/mage/cards/d/DisturbingPlot.java
@@ -24,7 +24,7 @@ public final class DisturbingPlot extends CardImpl {
this.getSpellAbility().addTarget(new TargetCardInGraveyard(new FilterCreatureCard("creature card in a graveyard")));
// Conspire
- this.addAbility(new ConspireAbility(getId(), ConspireAbility.ConspireTargets.ONE));
+ this.addAbility(new ConspireAbility(ConspireAbility.ConspireTargets.ONE));
}
diff --git a/Mage.Sets/src/mage/cards/d/DreamHalls.java b/Mage.Sets/src/mage/cards/d/DreamHalls.java
index 19928b062e8..51b608af534 100644
--- a/Mage.Sets/src/mage/cards/d/DreamHalls.java
+++ b/Mage.Sets/src/mage/cards/d/DreamHalls.java
@@ -46,7 +46,7 @@ class DreamHallsEffect extends ContinuousEffectImpl {
static {
filter.add(new AnotherCardPredicate());
- filter.add(new SharesColorWithSourcePredicate());
+ filter.add(SharesColorWithSourcePredicate.instance);
}
private final AlternativeCostSourceAbility alternativeCastingCostAbility = new AlternativeCostSourceAbility(new DiscardCardCost(filter), SourceIsSpellCondition.instance);
diff --git a/Mage.Sets/src/mage/cards/g/GhastlyDiscovery.java b/Mage.Sets/src/mage/cards/g/GhastlyDiscovery.java
index 6243e09fe49..aed7f17c206 100644
--- a/Mage.Sets/src/mage/cards/g/GhastlyDiscovery.java
+++ b/Mage.Sets/src/mage/cards/g/GhastlyDiscovery.java
@@ -25,7 +25,7 @@ public final class GhastlyDiscovery extends CardImpl {
this.getSpellAbility().addEffect(new GhastlyDiscoveryEffect());
// Conspire
- this.addAbility(new ConspireAbility(getId(), ConspireAbility.ConspireTargets.NONE));
+ this.addAbility(new ConspireAbility(ConspireAbility.ConspireTargets.NONE));
}
private GhastlyDiscovery(final GhastlyDiscovery card) {
diff --git a/Mage.Sets/src/mage/cards/g/Giantbaiting.java b/Mage.Sets/src/mage/cards/g/Giantbaiting.java
index 4f688b34145..112ce1272ee 100644
--- a/Mage.Sets/src/mage/cards/g/Giantbaiting.java
+++ b/Mage.Sets/src/mage/cards/g/Giantbaiting.java
@@ -26,7 +26,7 @@ public final class Giantbaiting extends CardImpl {
this.getSpellAbility().addEffect(new GiantbaitingEffect());
// Conspire
- this.addAbility(new ConspireAbility(getId(), ConspireAbility.ConspireTargets.NONE));
+ this.addAbility(new ConspireAbility(ConspireAbility.ConspireTargets.NONE));
}
diff --git a/Mage.Sets/src/mage/cards/g/GleefulSabotage.java b/Mage.Sets/src/mage/cards/g/GleefulSabotage.java
index b8740eb911d..86b8463fb5b 100644
--- a/Mage.Sets/src/mage/cards/g/GleefulSabotage.java
+++ b/Mage.Sets/src/mage/cards/g/GleefulSabotage.java
@@ -25,7 +25,7 @@ public final class GleefulSabotage extends CardImpl {
this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT));
// Conspire
- this.addAbility(new ConspireAbility(getId(), ConspireAbility.ConspireTargets.ONE));
+ this.addAbility(new ConspireAbility(ConspireAbility.ConspireTargets.ONE));
}
private GleefulSabotage(final GleefulSabotage card) {
diff --git a/Mage.Sets/src/mage/cards/m/MemorySluice.java b/Mage.Sets/src/mage/cards/m/MemorySluice.java
index a911e031f89..13ee4e0952f 100644
--- a/Mage.Sets/src/mage/cards/m/MemorySluice.java
+++ b/Mage.Sets/src/mage/cards/m/MemorySluice.java
@@ -23,7 +23,7 @@ public final class MemorySluice extends CardImpl {
this.getSpellAbility().addTarget(new TargetPlayer());
// Conspire
- this.addAbility(new ConspireAbility(getId(), ConspireAbility.ConspireTargets.ONE));
+ this.addAbility(new ConspireAbility(ConspireAbility.ConspireTargets.ONE));
}
diff --git a/Mage.Sets/src/mage/cards/m/MineExcavation.java b/Mage.Sets/src/mage/cards/m/MineExcavation.java
index 815f33043ef..6c533d70803 100644
--- a/Mage.Sets/src/mage/cards/m/MineExcavation.java
+++ b/Mage.Sets/src/mage/cards/m/MineExcavation.java
@@ -32,7 +32,7 @@ public final class MineExcavation extends CardImpl {
this.getSpellAbility().addTarget(new TargetCardInGraveyard(filter));
// Conspire
- this.addAbility(new ConspireAbility(getId(), ConspireAbility.ConspireTargets.ONE));
+ this.addAbility(new ConspireAbility(ConspireAbility.ConspireTargets.ONE));
}
private MineExcavation(final MineExcavation card) {
diff --git a/Mage.Sets/src/mage/cards/t/TraitorsRoar.java b/Mage.Sets/src/mage/cards/t/TraitorsRoar.java
index 387646e7765..d789661e71b 100644
--- a/Mage.Sets/src/mage/cards/t/TraitorsRoar.java
+++ b/Mage.Sets/src/mage/cards/t/TraitorsRoar.java
@@ -35,7 +35,7 @@ public final class TraitorsRoar extends CardImpl {
this.getSpellAbility().addEffect(new TraitorsRoarEffect());
// Conspire
- this.addAbility(new ConspireAbility(getId(), ConspireAbility.ConspireTargets.ONE));
+ this.addAbility(new ConspireAbility(ConspireAbility.ConspireTargets.ONE));
}
diff --git a/Mage.Sets/src/mage/cards/w/WortTheRaidmother.java b/Mage.Sets/src/mage/cards/w/WortTheRaidmother.java
index f8bc5b1c0cd..5cdfdad7600 100644
--- a/Mage.Sets/src/mage/cards/w/WortTheRaidmother.java
+++ b/Mage.Sets/src/mage/cards/w/WortTheRaidmother.java
@@ -59,17 +59,13 @@ class WortGainConspireEffect extends ContinuousEffectImpl {
filter.add(Predicates.or(new ColorPredicate(ObjectColor.RED), new ColorPredicate(ObjectColor.GREEN)));
}
- private final ConspireAbility conspireAbility;
-
public WortGainConspireEffect() {
super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility);
staticText = "Each red or green instant or sorcery spell you cast has conspire. (As you cast the spell, you may tap two untapped creatures you control that share a color with it. When you do, copy it and you may choose new targets for the copy.)";
- conspireAbility = new ConspireAbility(getId(), ConspireAbility.ConspireTargets.MORE);
}
public WortGainConspireEffect(final WortGainConspireEffect effect) {
super(effect);
- this.conspireAbility = new ConspireAbility(getId(), ConspireAbility.ConspireTargets.MORE);
}
@Override
@@ -81,11 +77,13 @@ class WortGainConspireEffect extends ContinuousEffectImpl {
public boolean apply(Game game, Ability source) {
for (StackObject stackObject : game.getStack()) {
// only spells cast, so no copies of spells
- if ((stackObject instanceof Spell) && !stackObject.isCopy() && stackObject.isControlledBy(source.getControllerId())) {
- Spell spell = (Spell) stackObject;
- if (filter.match(stackObject, game)) {
- game.getState().addOtherAbility(spell.getCard(), conspireAbility);
- }
+ if ((!(stackObject instanceof Spell)) || stackObject.isCopy()
+ || !stackObject.isControlledBy(source.getControllerId())) {
+ continue;
+ }
+ Spell spell = (Spell) stackObject;
+ if (filter.match(stackObject, game)) {
+ game.getState().addOtherAbility(spell.getCard(), new ConspireAbility(ConspireAbility.ConspireTargets.MORE));
}
}
return true;
diff --git a/Mage/src/main/java/mage/abilities/keyword/ConspireAbility.java b/Mage/src/main/java/mage/abilities/keyword/ConspireAbility.java
index 43332eb8b5a..32de82ddf5b 100644
--- a/Mage/src/main/java/mage/abilities/keyword/ConspireAbility.java
+++ b/Mage/src/main/java/mage/abilities/keyword/ConspireAbility.java
@@ -3,13 +3,11 @@ package mage.abilities.keyword;
import mage.abilities.Ability;
import mage.abilities.SpellAbility;
import mage.abilities.StaticAbility;
-import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.costs.*;
import mage.abilities.costs.common.TapTargetCost;
import mage.abilities.costs.mana.ManaCostsImpl;
-import mage.abilities.effects.Effect;
-import mage.abilities.effects.OneShotEffect;
-import mage.cards.Card;
+import mage.abilities.effects.common.CastSourceTriggeredAbility;
+import mage.abilities.effects.common.CopySourceSpellEffect;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Zone;
@@ -18,14 +16,15 @@ import mage.filter.predicate.mageobject.SharesColorWithSourcePredicate;
import mage.filter.predicate.permanent.TappedPredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
+import mage.game.permanent.Permanent;
import mage.game.stack.Spell;
import mage.players.Player;
import mage.target.common.TargetControlledPermanent;
-import java.util.HashSet;
+import java.util.Collection;
import java.util.Iterator;
-import java.util.Set;
-import java.util.UUID;
+import java.util.List;
+import java.util.Objects;
/*
* 702.77. Conspire
@@ -45,62 +44,54 @@ import java.util.UUID;
public class ConspireAbility extends StaticAbility implements OptionalAdditionalSourceCosts {
private static final String keywordText = "Conspire";
- private static final FilterControlledPermanent filter = new FilterControlledPermanent("untapped creatures you control that share a color with it");
protected static final String CONSPIRE_ACTIVATION_KEY = "ConspireActivation";
+ private static final FilterControlledPermanent filter
+ = new FilterControlledPermanent("untapped creatures you control that share a color with it");
static {
filter.add(TappedPredicate.UNTAPPED);
- filter.add(new SharesColorWithSourcePredicate());
+ filter.add(SharesColorWithSourcePredicate.instance);
filter.add(CardType.CREATURE.getPredicate());
}
public enum ConspireTargets {
- NONE,
- ONE,
- MORE
+ NONE(""),
+ ONE(" and you may choose a new target for the copy"),
+ MORE(" and you may choose new targets for the copy");
+ private final String message;
+
+ ConspireTargets(String message) {
+ this.message = message;
+ }
+
+ public String getReminder() {
+ return "as you cast this spell, you may tap two untapped creatures you control " +
+ "that share a color with it. When you do, copy it" + message;
+ }
}
- private final UUID conspireId;
- private String reminderText;
- private OptionalAdditionalCost conspireCost;
+ private final String reminderText;
+ private final OptionalAdditionalCost conspireCost;
/**
* Unique Id for a ConspireAbility but may not change while a continuous
* effect gives Conspire
*
- * @param conspireId
* @param conspireTargets controls the content of the reminder text
*/
- public ConspireAbility(UUID conspireId, ConspireTargets conspireTargets) {
+ public ConspireAbility(ConspireTargets conspireTargets) {
super(Zone.STACK, null);
- this.conspireId = conspireId;
- switch (conspireTargets) {
- case NONE:
- reminderText = "As you cast this spell, you may tap two untapped creatures you control that share a color with it. When you do, copy it.";
- break;
- case ONE:
- reminderText = "As you cast this spell, you may tap two untapped creatures you control that share a color with it. When you do, copy it and you may choose a new target for the copy.";
- break;
- case MORE:
- reminderText = "As you cast this spell, you may tap two untapped creatures you control that share a color with it. When you do, copy it and you may choose new targets for the copy.";
- break;
- }
-
- Cost cost = new TapTargetCost(new TargetControlledPermanent(2, 2, filter, true));
- cost.setText("");
- addConspireCostAndSetup(new OptionalAdditionalCostImpl(keywordText, " ", reminderText, cost));
-
- addSubAbility(new ConspireTriggeredAbility(conspireId));
- }
-
- private void addConspireCostAndSetup(OptionalAdditionalCost newCost) {
- this.conspireCost = newCost;
+ reminderText = conspireTargets.getReminder();
+ this.conspireCost = new OptionalAdditionalCostImpl(
+ keywordText, " ", reminderText,
+ new TapTargetCost(new TargetControlledPermanent(2, filter))
+ );
this.conspireCost.setCostType(VariableCostType.ADDITIONAL);
+ addSubAbility(new ConspireTriggeredAbility());
}
public ConspireAbility(final ConspireAbility ability) {
super(ability);
- this.conspireId = ability.conspireId;
this.conspireCost = ability.conspireCost.copy();
this.reminderText = ability.reminderText;
}
@@ -113,66 +104,39 @@ public class ConspireAbility extends StaticAbility implements OptionalAdditional
@Override
public void addCost(Cost cost) {
if (conspireCost != null) {
- ((Costs) conspireCost).add(cost);
+ ((Costs) conspireCost).add(cost);
}
}
- public UUID getConspireId() {
- return conspireId;
- }
-
@Override
public boolean isActivated() {
throw new UnsupportedOperationException("Use ConspireAbility.isActivated(Ability ability, Game game) method instead!");
}
- public boolean isActivated(Ability ability, Game game) {
- Set activations = (Set) game.getState().getValue(CONSPIRE_ACTIVATION_KEY + ability.getId());
- if (activations != null) {
- return activations.contains(getConspireId());
- }
- return false;
- }
-
@Override
public void addOptionalAdditionalCosts(Ability ability, Game game) {
- if (ability instanceof SpellAbility) {
- Player player = game.getPlayer(getControllerId());
- if (player != null) {
- resetConspire(ability, game);
- // AI supports conspire
- if (conspireCost.canPay(ability, this, getControllerId(), game)
- && player.chooseUse(Outcome.Benefit, "Pay " + conspireCost.getText(false) + " ?", ability, game)) {
- activateConspire(ability, game);
- for (Iterator it = ((Costs) conspireCost).iterator(); it.hasNext(); ) {
- Cost cost = (Cost) it.next();
- if (cost instanceof ManaCostsImpl) {
- ability.getManaCostsToPay().add((ManaCostsImpl) cost.copy());
- } else {
- ability.getCosts().add(cost.copy());
- }
- }
- }
+ if (!(ability instanceof SpellAbility)) {
+ return;
+ }
+ Player player = game.getPlayer(getControllerId());
+ if (player == null) {
+ return;
+ }
+ // AI supports conspire
+ if (!conspireCost.canPay(ability, this, getControllerId(), game)
+ || !player.chooseUse(Outcome.Benefit, "Pay " + conspireCost.getText(false) + " ?", ability, game)) {
+ return;
+ }
+ for (Iterator it = ((Costs) conspireCost).iterator(); it.hasNext(); ) {
+ Cost cost = (Cost) it.next();
+ if (cost instanceof ManaCostsImpl) {
+ ability.getManaCostsToPay().add((ManaCostsImpl>) cost.copy());
+ } else {
+ ability.getCosts().add(cost.copy());
}
}
}
- private void activateConspire(Ability ability, Game game) {
- Set activations = (Set) game.getState().getValue(CONSPIRE_ACTIVATION_KEY + ability.getId());
- if (activations == null) {
- activations = new HashSet<>();
- game.getState().setValue(CONSPIRE_ACTIVATION_KEY + ability.getId(), activations);
- }
- activations.add(getConspireId());
- }
-
- private void resetConspire(Ability ability, Game game) {
- Set activations = (Set) game.getState().getValue(CONSPIRE_ACTIVATION_KEY + ability.getId());
- if (activations != null) {
- activations.remove(getConspireId());
- }
- }
-
@Override
public String getRule() {
StringBuilder sb = new StringBuilder();
@@ -185,35 +149,19 @@ public class ConspireAbility extends StaticAbility implements OptionalAdditional
@Override
public String getCastMessageSuffix() {
- if (conspireCost != null) {
- return conspireCost.getCastSuffixMessage(0);
- } else {
- return "";
- }
- }
-
- public String getReminderText() {
- if (conspireCost != null) {
- return conspireCost.getReminderText();
- } else {
- return "";
- }
+ return conspireCost != null ? conspireCost.getCastSuffixMessage(0) : "";
}
}
-class ConspireTriggeredAbility extends TriggeredAbilityImpl {
+class ConspireTriggeredAbility extends CastSourceTriggeredAbility {
- private final UUID conspireId;
-
- public ConspireTriggeredAbility(UUID conspireId) {
- super(Zone.STACK, new ConspireEffect());
- this.conspireId = conspireId;
+ public ConspireTriggeredAbility() {
+ super(new CopySourceSpellEffect(), false);
this.setRuleVisible(false);
}
private ConspireTriggeredAbility(final ConspireTriggeredAbility ability) {
super(ability);
- this.conspireId = ability.conspireId;
}
@Override
@@ -221,34 +169,21 @@ class ConspireTriggeredAbility extends TriggeredAbilityImpl {
return new ConspireTriggeredAbility(this);
}
- @Override
- public boolean checkEventType(GameEvent event, Game game) {
- return event.getType() == GameEvent.EventType.SPELL_CAST;
- }
-
@Override
public boolean checkTrigger(GameEvent event, Game game) {
- if (event.getSourceId().equals(getSourceId())) {
- Spell spell = game.getStack().getSpell(event.getSourceId());
- for (Ability ability : spell.getAbilities(game)) {
- if (ability instanceof ConspireAbility
- && ((ConspireAbility) ability).getConspireId().equals(getConspireId())) {
- if (((ConspireAbility) ability).isActivated(spell.getSpellAbility(), game)) {
- for (Effect effect : this.getEffects()) {
- if (effect instanceof ConspireEffect) {
- ((ConspireEffect) effect).setConspiredSpell(spell);
- }
- }
- return true;
- }
- }
- }
+ if (!super.checkTrigger(event, game)) {
+ return false;
}
- return false;
- }
-
- public UUID getConspireId() {
- return conspireId;
+ Spell spell = game.getStack().getSpell(event.getSourceId());
+ return spell != null && spell
+ .getSpellAbility()
+ .getEffects()
+ .stream()
+ .map(effect -> effect.getValue("tappedPermanents"))
+ .filter(Objects::nonNull)
+ .map(x -> (List) x)
+ .flatMap(Collection::stream)
+ .count() >= 2;
}
@Override
@@ -256,39 +191,3 @@ class ConspireTriggeredAbility extends TriggeredAbilityImpl {
return "When you pay the conspire costs, copy it and you may choose a new target for the copy.";
}
}
-
-class ConspireEffect extends OneShotEffect {
-
- private Spell conspiredSpell;
-
- public ConspireEffect() {
- super(Outcome.Copy);
- }
-
- public ConspireEffect(final ConspireEffect effect) {
- super(effect);
- this.conspiredSpell = effect.conspiredSpell;
- }
-
- @Override
- public boolean apply(Game game, Ability source) {
- Player controller = game.getPlayer(source.getControllerId());
- if (controller != null && conspiredSpell != null) {
- Card card = game.getCard(conspiredSpell.getSourceId());
- if (card != null) {
- conspiredSpell.createCopyOnStack(game, source, source.getControllerId(), true);
- return true;
- }
- }
- return false;
- }
-
- public void setConspiredSpell(Spell conspiredSpell) {
- this.conspiredSpell = conspiredSpell;
- }
-
- @Override
- public ConspireEffect copy() {
- return new ConspireEffect(this);
- }
-}
diff --git a/Mage/src/main/java/mage/filter/predicate/mageobject/SharesColorWithSourcePredicate.java b/Mage/src/main/java/mage/filter/predicate/mageobject/SharesColorWithSourcePredicate.java
index 3beae46614e..bd76f122ecc 100644
--- a/Mage/src/main/java/mage/filter/predicate/mageobject/SharesColorWithSourcePredicate.java
+++ b/Mage/src/main/java/mage/filter/predicate/mageobject/SharesColorWithSourcePredicate.java
@@ -6,11 +6,11 @@ import mage.filter.predicate.ObjectSourcePlayerPredicate;
import mage.game.Game;
/**
- *
* @author LevelX2
*/
-public class SharesColorWithSourcePredicate implements ObjectSourcePlayerPredicate {
+public enum SharesColorWithSourcePredicate implements ObjectSourcePlayerPredicate {
+ instance;
@Override
public boolean apply(ObjectSourcePlayer input, Game game) {
@@ -26,4 +26,4 @@ public class SharesColorWithSourcePredicate implements ObjectSourcePlayerPredica
public String toString() {
return "shares a color";
}
-}
\ No newline at end of file
+}