mirror of
https://github.com/correl/mage.git
synced 2024-12-25 03:00:15 +00:00
Some changes/fixes to conspire ability.
This commit is contained in:
parent
8e50c18d8c
commit
7b68604471
14 changed files with 234 additions and 128 deletions
|
@ -58,7 +58,7 @@ public class AEthertow extends CardImpl {
|
||||||
this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter));
|
this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter));
|
||||||
|
|
||||||
// Conspire
|
// Conspire
|
||||||
this.addAbility(new ConspireAbility(this));
|
this.addAbility(new ConspireAbility(getId(), ConspireAbility.ConspireTargets.ONE));
|
||||||
}
|
}
|
||||||
|
|
||||||
public AEthertow(final AEthertow card) {
|
public AEthertow(final AEthertow card) {
|
||||||
|
|
|
@ -51,7 +51,7 @@ public class BarkshellBlessing extends CardImpl {
|
||||||
this.getSpellAbility().addEffect(new BoostTargetEffect(2, 2, Duration.EndOfTurn));
|
this.getSpellAbility().addEffect(new BoostTargetEffect(2, 2, Duration.EndOfTurn));
|
||||||
|
|
||||||
// Conspire
|
// Conspire
|
||||||
this.addAbility(new ConspireAbility(this));
|
this.addAbility(new ConspireAbility(getId(), ConspireAbility.ConspireTargets.ONE));
|
||||||
}
|
}
|
||||||
|
|
||||||
public BarkshellBlessing(final BarkshellBlessing card) {
|
public BarkshellBlessing(final BarkshellBlessing card) {
|
||||||
|
|
|
@ -50,7 +50,7 @@ public class BurnTrail extends CardImpl {
|
||||||
this.getSpellAbility().addTarget(new TargetCreatureOrPlayer());
|
this.getSpellAbility().addTarget(new TargetCreatureOrPlayer());
|
||||||
|
|
||||||
// Conspire
|
// Conspire
|
||||||
this.addAbility(new ConspireAbility(this));
|
this.addAbility(new ConspireAbility(getId(), ConspireAbility.ConspireTargets.ONE));
|
||||||
}
|
}
|
||||||
|
|
||||||
public BurnTrail(final BurnTrail card) {
|
public BurnTrail(final BurnTrail card) {
|
||||||
|
|
|
@ -51,7 +51,7 @@ public class DisturbingPlot extends CardImpl {
|
||||||
this.getSpellAbility().addTarget(new TargetCardInGraveyard(new FilterCreatureCard("creature card in a graveyard")));
|
this.getSpellAbility().addTarget(new TargetCardInGraveyard(new FilterCreatureCard("creature card in a graveyard")));
|
||||||
|
|
||||||
// Conspire
|
// Conspire
|
||||||
this.addAbility(new ConspireAbility(this));
|
this.addAbility(new ConspireAbility(getId(), ConspireAbility.ConspireTargets.ONE));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ public class GhastlyDiscovery extends CardImpl {
|
||||||
this.getSpellAbility().addEffect(new GhastlyDiscoveryEffect());
|
this.getSpellAbility().addEffect(new GhastlyDiscoveryEffect());
|
||||||
|
|
||||||
// Conspire
|
// Conspire
|
||||||
this.addAbility(new ConspireAbility(this));
|
this.addAbility(new ConspireAbility(getId(), ConspireAbility.ConspireTargets.NONE));
|
||||||
}
|
}
|
||||||
|
|
||||||
public GhastlyDiscovery(final GhastlyDiscovery card) {
|
public GhastlyDiscovery(final GhastlyDiscovery card) {
|
||||||
|
|
|
@ -58,7 +58,7 @@ public class Giantbaiting extends CardImpl {
|
||||||
this.getSpellAbility().addEffect(new GiantbaitingEffect());
|
this.getSpellAbility().addEffect(new GiantbaitingEffect());
|
||||||
|
|
||||||
// Conspire
|
// Conspire
|
||||||
this.addAbility(new ConspireAbility(this));
|
this.addAbility(new ConspireAbility(getId(), ConspireAbility.ConspireTargets.NONE));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,7 @@ public class GleefulSabotage extends CardImpl {
|
||||||
this.getSpellAbility().addTarget(new TargetPermanent(new FilterArtifactOrEnchantmentPermanent()));
|
this.getSpellAbility().addTarget(new TargetPermanent(new FilterArtifactOrEnchantmentPermanent()));
|
||||||
|
|
||||||
// Conspire
|
// Conspire
|
||||||
this.addAbility(new ConspireAbility(this));
|
this.addAbility(new ConspireAbility(getId(), ConspireAbility.ConspireTargets.ONE));
|
||||||
}
|
}
|
||||||
|
|
||||||
public GleefulSabotage(final GleefulSabotage card) {
|
public GleefulSabotage(final GleefulSabotage card) {
|
||||||
|
|
|
@ -50,7 +50,7 @@ public class MemorySluice extends CardImpl {
|
||||||
this.getSpellAbility().addTarget(new TargetPlayer());
|
this.getSpellAbility().addTarget(new TargetPlayer());
|
||||||
|
|
||||||
// Conspire
|
// Conspire
|
||||||
this.addAbility(new ConspireAbility(this));
|
this.addAbility(new ConspireAbility(getId(), ConspireAbility.ConspireTargets.ONE));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ public class MineExcavation extends CardImpl {
|
||||||
this.getSpellAbility().addTarget(new TargetCardInGraveyard(filter));
|
this.getSpellAbility().addTarget(new TargetCardInGraveyard(filter));
|
||||||
|
|
||||||
// Conspire
|
// Conspire
|
||||||
this.addAbility(new ConspireAbility(this));
|
this.addAbility(new ConspireAbility(getId(), ConspireAbility.ConspireTargets.ONE));
|
||||||
}
|
}
|
||||||
|
|
||||||
public MineExcavation(final MineExcavation card) {
|
public MineExcavation(final MineExcavation card) {
|
||||||
|
|
|
@ -64,7 +64,7 @@ public class TraitorsRoar extends CardImpl {
|
||||||
this.getSpellAbility().addEffect(new TraitorsRoarEffect());
|
this.getSpellAbility().addEffect(new TraitorsRoarEffect());
|
||||||
|
|
||||||
// Conspire
|
// Conspire
|
||||||
this.addAbility(new ConspireAbility(this));
|
this.addAbility(new ConspireAbility(getId(), ConspireAbility.ConspireTargets.ONE));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,6 @@
|
||||||
* authors and should not be interpreted as representing official policies, either expressed
|
* authors and should not be interpreted as representing official policies, either expressed
|
||||||
* or implied, of BetaSteward_at_googlemail.com.
|
* or implied, of BetaSteward_at_googlemail.com.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.mage.test.cards.abilities.keywords;
|
package org.mage.test.cards.abilities.keywords;
|
||||||
|
|
||||||
import mage.constants.PhaseStep;
|
import mage.constants.PhaseStep;
|
||||||
|
@ -40,31 +39,31 @@ import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
public class ConspireTest extends CardTestPlayerBase {
|
public class ConspireTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 702.77. Conspire
|
* 702.77. Conspire 702.77a Conspire is a keyword that represents two
|
||||||
* 702.77a Conspire is a keyword that represents two abilities. The first is a static ability that functions
|
* abilities. The first is a static ability that functions while the spell
|
||||||
* while the spell with conspire is on the stack. The second is a triggered ability that functions
|
* with conspire is on the stack. The second is a triggered ability that
|
||||||
* while the spell with conspire is on the stack. “Conspire” means “As an additional cost to cast
|
* functions while the spell with conspire is on the stack. “Conspire” means
|
||||||
* this spell, you may tap two untapped creatures you control that each share a color with it” and
|
* “As an additional cost to cast this spell, you may tap two untapped
|
||||||
* “When you cast this spell, if its conspire cost was paid, copy it. If the spell has any targets, you
|
* creatures you control that each share a color with it” and “When you cast
|
||||||
* may choose new targets for the copy.” Paying a spell’s conspire cost follows the rules for
|
* this spell, if its conspire cost was paid, copy it. If the spell has any
|
||||||
* paying additional costs in rules 601.2b and 601.2e–g.
|
* targets, you may choose new targets for the copy.” Paying a spell’s
|
||||||
|
* conspire cost follows the rules for paying additional costs in rules
|
||||||
|
* 601.2b and 601.2e–g.
|
||||||
*
|
*
|
||||||
* 702.77b If a spell has multiple instances of conspire, each is paid separately and triggers based on
|
* 702.77b If a spell has multiple instances of conspire, each is paid
|
||||||
* its own payment, not any other instance of conspire
|
* separately and triggers based on its own payment, not any other instance
|
||||||
|
* of conspire
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Burn Trail
|
* Burn Trail Sorcery, 3R (4) Burn Trail deals 3 damage to target creature
|
||||||
* Sorcery, 3R (4)
|
* or player.
|
||||||
* Burn Trail deals 3 damage to target creature or player.
|
|
||||||
*
|
*
|
||||||
* Conspire (As you cast this spell, you may tap two untapped creatures you
|
* Conspire (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
|
* control that share a color with it. When you do, copy it and you may
|
||||||
* choose a new target for the copy.)
|
* choose a new target for the copy.)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testConspire() {
|
public void testConspire() {
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4);
|
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4);
|
||||||
|
@ -72,7 +71,6 @@ public class ConspireTest extends CardTestPlayerBase {
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Raging Goblin");
|
addCard(Zone.BATTLEFIELD, playerA, "Raging Goblin");
|
||||||
addCard(Zone.HAND, playerA, "Burn Trail");
|
addCard(Zone.HAND, playerA, "Burn Trail");
|
||||||
|
|
||||||
|
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Burn Trail", playerB);
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Burn Trail", playerB);
|
||||||
setChoice(playerA, "Yes");
|
setChoice(playerA, "Yes");
|
||||||
|
|
||||||
|
@ -93,7 +91,6 @@ public class ConspireTest extends CardTestPlayerBase {
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Raging Goblin");
|
addCard(Zone.BATTLEFIELD, playerA, "Raging Goblin");
|
||||||
addCard(Zone.HAND, playerA, "Burn Trail");
|
addCard(Zone.HAND, playerA, "Burn Trail");
|
||||||
|
|
||||||
|
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Burn Trail", playerB);
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Burn Trail", playerB);
|
||||||
setChoice(playerA, "No");
|
setChoice(playerA, "No");
|
||||||
|
|
||||||
|
@ -107,4 +104,50 @@ public class ConspireTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWortTheRaidmother() {
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 7);
|
||||||
|
// When Wort, the Raidmother enters the battlefield, put two 1/1 red and green Goblin Warrior creature tokens onto the battlefield.
|
||||||
|
// 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.)
|
||||||
|
addCard(Zone.HAND, playerA, "Wort, the Raidmother");
|
||||||
|
addCard(Zone.HAND, playerA, "Lightning Bolt");
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Wort, the Raidmother");// {4}{R/G}{R/G}
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", playerB);
|
||||||
|
setChoice(playerA, "Yes");
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
assertPermanentCount(playerA, "Wort, the Raidmother", 1);
|
||||||
|
assertGraveyardCount(playerA, "Lightning Bolt", 1);
|
||||||
|
assertLife(playerB, 14);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWortTheRaidmotherWithConspireSpell() {
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 10);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Raging Goblin", 2);
|
||||||
|
// When Wort, the Raidmother enters the battlefield, put two 1/1 red and green Goblin Warrior creature tokens onto the battlefield.
|
||||||
|
// 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.)
|
||||||
|
addCard(Zone.HAND, playerA, "Wort, the Raidmother");
|
||||||
|
addCard(Zone.HAND, playerA, "Burn Trail");
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Wort, the Raidmother"); // {4}{R/G}{R/G}
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Burn Trail", playerB);
|
||||||
|
setChoice(playerA, "Yes"); // use Conspire from Burn Trail itself
|
||||||
|
setChoice(playerA, "Yes"); // use Conspire gained from Wort, the Raidmother
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
assertPermanentCount(playerA, "Wort, the Raidmother", 1);
|
||||||
|
assertLife(playerB, 11);
|
||||||
|
assertLife(playerA, 20);
|
||||||
|
assertGraveyardCount(playerA, "Burn Trail", 1);
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -445,20 +445,28 @@ public abstract class AbilityImpl implements Ability {
|
||||||
public boolean activateAlternateOrAdditionalCosts(MageObject sourceObject, boolean noMana, Player controller, Game game) {
|
public boolean activateAlternateOrAdditionalCosts(MageObject sourceObject, boolean noMana, Player controller, Game game) {
|
||||||
boolean alternativeCostisUsed = false;
|
boolean alternativeCostisUsed = false;
|
||||||
if (sourceObject != null && !(sourceObject instanceof Permanent) && !(this instanceof FlashbackAbility)) {
|
if (sourceObject != null && !(sourceObject instanceof Permanent) && !(this instanceof FlashbackAbility)) {
|
||||||
for (Ability ability : sourceObject.getAbilities()) {
|
Abilities<Ability> abilities = null;
|
||||||
// if cast for noMana no Alternative costs are allowed
|
if (sourceObject instanceof Card) {
|
||||||
if (!noMana && ability instanceof AlternativeSourceCosts) {
|
abilities = ((Card) sourceObject).getAbilities(game);
|
||||||
AlternativeSourceCosts alternativeSpellCosts = (AlternativeSourceCosts) ability;
|
} else {
|
||||||
if (alternativeSpellCosts.isAvailable(this, game)) {
|
sourceObject.getAbilities();
|
||||||
if (alternativeSpellCosts.askToActivateAlternativeCosts(this, game)) {
|
}
|
||||||
// only one alternative costs may be activated
|
if (abilities != null) {
|
||||||
alternativeCostisUsed = true;
|
for (Ability ability : abilities) {
|
||||||
break;
|
// if cast for noMana no Alternative costs are allowed
|
||||||
|
if (!noMana && ability instanceof AlternativeSourceCosts) {
|
||||||
|
AlternativeSourceCosts alternativeSpellCosts = (AlternativeSourceCosts) ability;
|
||||||
|
if (alternativeSpellCosts.isAvailable(this, game)) {
|
||||||
|
if (alternativeSpellCosts.askToActivateAlternativeCosts(this, game)) {
|
||||||
|
// only one alternative costs may be activated
|
||||||
|
alternativeCostisUsed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if (ability instanceof OptionalAdditionalSourceCosts) {
|
||||||
if (ability instanceof OptionalAdditionalSourceCosts) {
|
((OptionalAdditionalSourceCosts) ability).addOptionalAdditionalCosts(this, game);
|
||||||
((OptionalAdditionalSourceCosts) ability).addOptionalAdditionalCosts(this, game);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// controller specific alternate spell costs
|
// controller specific alternate spell costs
|
||||||
|
|
|
@ -27,14 +27,16 @@
|
||||||
*/
|
*/
|
||||||
package mage.abilities.keyword;
|
package mage.abilities.keyword;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.SpellAbility;
|
import mage.abilities.SpellAbility;
|
||||||
import mage.abilities.StaticAbility;
|
import mage.abilities.StaticAbility;
|
||||||
import mage.abilities.TriggeredAbilityImpl;
|
import mage.abilities.TriggeredAbilityImpl;
|
||||||
import mage.abilities.costs.Cost;
|
import mage.abilities.costs.Cost;
|
||||||
import mage.abilities.costs.Costs;
|
import mage.abilities.costs.Costs;
|
||||||
import mage.abilities.costs.OptionalAdditionalCost;
|
|
||||||
import mage.abilities.costs.OptionalAdditionalCostImpl;
|
import mage.abilities.costs.OptionalAdditionalCostImpl;
|
||||||
import mage.abilities.costs.OptionalAdditionalSourceCosts;
|
import mage.abilities.costs.OptionalAdditionalSourceCosts;
|
||||||
import mage.abilities.costs.common.TapTargetCost;
|
import mage.abilities.costs.common.TapTargetCost;
|
||||||
|
@ -50,48 +52,77 @@ import mage.filter.predicate.permanent.TappedPredicate;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.events.GameEvent;
|
import mage.game.events.GameEvent;
|
||||||
import mage.game.stack.Spell;
|
import mage.game.stack.Spell;
|
||||||
import mage.game.stack.StackObject;
|
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
import mage.target.common.TargetControlledPermanent;
|
import mage.target.common.TargetControlledPermanent;
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* 702.77. Conspire 702.77a Conspire is a keyword that represents two abilities.
|
* 702.77. Conspire
|
||||||
* The first is a static ability that functions while the spell with conspire is
|
* 702.77a Conspire is a keyword that represents two abilities.
|
||||||
* on the stack. The second is a triggered ability that functions while the
|
* The first is a static ability that functions while the spell with conspire is on the stack.
|
||||||
* spell with conspire is on the stack. "Conspire" means "As an additional cost
|
* The second is a triggered ability that functions while the spell with conspire is on the stack.
|
||||||
* to cast this spell, you may tap two untapped creatures you control that each
|
* "Conspire" means "As an additional cost to cast this spell,
|
||||||
* share a color with it" and "When you cast this spell, if its conspire cost
|
* you may tap two untapped creatures you control that each share a color with it"
|
||||||
* was paid, copy it. If the spell has any targets, you may choose new targets
|
* and "When you cast this spell, if its conspire cost was paid, copy it.
|
||||||
* for the copy." Paying a spell’s conspire cost follows the rules for paying
|
* If the spell has any targets, you may choose new targets for the copy."
|
||||||
* additional costs in rules 601.2b and 601.2e–g. 702.77b If a spell has
|
* Paying a spell’s conspire cost follows the rules for paying additional costs in rules 601.2b and 601.2e–g.
|
||||||
* multiple instances of conspire, each is paid separately and triggers based on
|
* 702.77b If a spell has multiple instances of conspire, each is paid separately and triggers
|
||||||
* its own payment, not any other instance of conspire. *
|
* based on its own payment, not any other instance of conspire. *
|
||||||
*
|
*
|
||||||
* @author jeffwadsworth heavily based off the replicate keyword by LevelX
|
* @author jeffwadsworth heavily based off the replicate keyword by LevelX
|
||||||
*/
|
*/
|
||||||
public class ConspireAbility extends StaticAbility implements OptionalAdditionalSourceCosts {
|
public class ConspireAbility extends StaticAbility implements OptionalAdditionalSourceCosts {
|
||||||
|
|
||||||
private static final String keywordText = "Conspire";
|
private static final String keywordText = "Conspire";
|
||||||
private static final String reminderTextCost = "<i>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.)</i>";
|
private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creatures you control that share a color with it");
|
||||||
private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("two untapped creatures you control that share a color with it");
|
protected static final String CONSPIRE_ACTIVATION_KEY = "ConspireActivation";
|
||||||
|
|
||||||
static {
|
static {
|
||||||
filter.add(Predicates.not(new TappedPredicate()));
|
filter.add(Predicates.not(new TappedPredicate()));
|
||||||
filter.add(new SharesColorWithSourcePredicate());
|
filter.add(new SharesColorWithSourcePredicate());
|
||||||
}
|
}
|
||||||
|
|
||||||
Cost costConspire = new TapTargetCost(new TargetControlledPermanent(2, 2, filter, true));
|
public enum ConspireTargets {
|
||||||
OptionalAdditionalCost conspireCost = new OptionalAdditionalCostImpl(keywordText, "-", reminderTextCost, costConspire);
|
|
||||||
|
|
||||||
public ConspireAbility(Card card) {
|
NONE,
|
||||||
|
ONE,
|
||||||
|
MORE
|
||||||
|
}
|
||||||
|
|
||||||
|
private UUID conspireId;
|
||||||
|
private String reminderText;
|
||||||
|
private OptionalAdditionalCostImpl 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) {
|
||||||
super(Zone.STACK, null);
|
super(Zone.STACK, null);
|
||||||
setRuleAtTheTop(false);
|
this.conspireId = conspireId;
|
||||||
addSubAbility(new ConspireTriggeredAbility());
|
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 a new targets for the copy.)";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
conspireCost = new OptionalAdditionalCostImpl(keywordText, "-", reminderText,
|
||||||
|
new TapTargetCost(new TargetControlledPermanent(2, 2, filter, true)));
|
||||||
|
addSubAbility(new ConspireTriggeredAbility(conspireId));
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConspireAbility(final ConspireAbility ability) {
|
public ConspireAbility(final ConspireAbility ability) {
|
||||||
super(ability);
|
super(ability);
|
||||||
conspireCost = ability.conspireCost;
|
this.conspireId = ability.conspireId;
|
||||||
|
this.conspireCost = ability.conspireCost.copy();
|
||||||
|
this.reminderText = ability.reminderText;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -106,18 +137,21 @@ public class ConspireAbility extends StaticAbility implements OptionalAdditional
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public UUID getConspireId() {
|
||||||
public boolean isActivated() {
|
return conspireId;
|
||||||
if (conspireCost != null) {
|
|
||||||
return conspireCost.isActivated();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resetConspire() {
|
@Override
|
||||||
if (conspireCost != null) {
|
public boolean isActivated() {
|
||||||
conspireCost.reset();
|
throw new UnsupportedOperationException("Use ConspireAbility.isActivated(Ability ability, Game game) method instead!");
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isActivated(Ability ability, Game game) {
|
||||||
|
Set<UUID> activations = (Set<UUID>) game.getState().getValue(CONSPIRE_ACTIVATION_KEY + ability.getId());
|
||||||
|
if (activations != null) {
|
||||||
|
return activations.contains(getConspireId());
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -125,9 +159,9 @@ public class ConspireAbility extends StaticAbility implements OptionalAdditional
|
||||||
if (ability instanceof SpellAbility) {
|
if (ability instanceof SpellAbility) {
|
||||||
Player player = game.getPlayer(controllerId);
|
Player player = game.getPlayer(controllerId);
|
||||||
if (player != null) {
|
if (player != null) {
|
||||||
this.resetConspire();
|
resetConspire(ability, game);
|
||||||
if (player.chooseUse(Outcome.Benefit, new StringBuilder("Pay ").append(conspireCost.getText(false)).append(" ?").toString(), ability, game)) {
|
if (player.chooseUse(Outcome.Benefit, "Pay " + conspireCost.getText(false) + " ?", ability, game)) {
|
||||||
conspireCost.activate();
|
activateConspire(ability, game);
|
||||||
for (Iterator it = ((Costs) conspireCost).iterator(); it.hasNext();) {
|
for (Iterator it = ((Costs) conspireCost).iterator(); it.hasNext();) {
|
||||||
Cost cost = (Cost) it.next();
|
Cost cost = (Cost) it.next();
|
||||||
ability.getCosts().add(cost.copy());
|
ability.getCosts().add(cost.copy());
|
||||||
|
@ -137,6 +171,22 @@ public class ConspireAbility extends StaticAbility implements OptionalAdditional
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void activateConspire(Ability ability, Game game) {
|
||||||
|
Set<UUID> activations = (Set<UUID>) 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<UUID> activations = (Set<UUID>) game.getState().getValue(CONSPIRE_ACTIVATION_KEY + ability.getId());
|
||||||
|
if (activations != null) {
|
||||||
|
activations.remove(getConspireId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getRule() {
|
public String getRule() {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
|
@ -167,13 +217,17 @@ public class ConspireAbility extends StaticAbility implements OptionalAdditional
|
||||||
|
|
||||||
class ConspireTriggeredAbility extends TriggeredAbilityImpl {
|
class ConspireTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
public ConspireTriggeredAbility() {
|
private UUID conspireId;
|
||||||
|
|
||||||
|
public ConspireTriggeredAbility(UUID conspireId) {
|
||||||
super(Zone.STACK, new ConspireEffect());
|
super(Zone.STACK, new ConspireEffect());
|
||||||
|
this.conspireId = conspireId;
|
||||||
this.setRuleVisible(false);
|
this.setRuleVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ConspireTriggeredAbility(final ConspireTriggeredAbility ability) {
|
private ConspireTriggeredAbility(final ConspireTriggeredAbility ability) {
|
||||||
super(ability);
|
super(ability);
|
||||||
|
this.conspireId = ability.conspireId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -188,20 +242,18 @@ class ConspireTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean checkTrigger(GameEvent event, Game game) {
|
public boolean checkTrigger(GameEvent event, Game game) {
|
||||||
if (event.getSourceId().equals(this.sourceId)) {
|
if (event.getSourceId().equals(getSourceId())) {
|
||||||
StackObject spell = game.getStack().getStackObject(this.sourceId);
|
Spell spell = game.getStack().getSpell(event.getSourceId());
|
||||||
if (spell instanceof Spell) {
|
for (Ability ability : spell.getAbilities(game)) {
|
||||||
Card card = game.getCard(spell.getSourceId());
|
if (ability instanceof ConspireAbility
|
||||||
if (card != null) {
|
&& ((ConspireAbility) ability).getConspireId().equals(getConspireId())) {
|
||||||
for (Ability ability : card.getAbilities()) {
|
if (((ConspireAbility) ability).isActivated(spell.getSpellAbility(), game)) {
|
||||||
if (ability instanceof ConspireAbility) {
|
for (Effect effect : this.getEffects()) {
|
||||||
if (((ConspireAbility) ability).isActivated()) {
|
if (effect instanceof ConspireEffect) {
|
||||||
for (Effect effect : this.getEffects()) {
|
((ConspireEffect) effect).setConspiredSpell(spell);
|
||||||
effect.setValue("ConspireSpell", spell);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -209,52 +261,53 @@ class ConspireTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public UUID getConspireId() {
|
||||||
|
return conspireId;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getRule() {
|
public String getRule() {
|
||||||
return "Conspire: <i>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.)</i>";
|
return "When you pay the conspire costs, copy it and you may choose a new target for the copy.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ConspireEffect extends OneShotEffect {
|
class ConspireEffect extends OneShotEffect {
|
||||||
|
|
||||||
|
private Spell conspiredSpell;
|
||||||
|
|
||||||
public ConspireEffect() {
|
public ConspireEffect() {
|
||||||
super(Outcome.Copy);
|
super(Outcome.Copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConspireEffect(final ConspireEffect effect) {
|
public ConspireEffect(final ConspireEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
|
this.conspiredSpell = effect.conspiredSpell;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Player controller = game.getPlayer(source.getControllerId());
|
Player controller = game.getPlayer(source.getControllerId());
|
||||||
if (controller != null) {
|
if (controller != null && conspiredSpell != null) {
|
||||||
Spell spell = (Spell) this.getValue("ConspireSpell");
|
Card card = game.getCard(conspiredSpell.getSourceId());
|
||||||
if (spell != null) {
|
if (card != null) {
|
||||||
Card card = game.getCard(spell.getSourceId());
|
Spell copy = conspiredSpell.copySpell();
|
||||||
if (card != null) {
|
copy.setControllerId(source.getControllerId());
|
||||||
for (Ability ability : card.getAbilities()) {
|
copy.setCopiedSpell(true);
|
||||||
if (ability instanceof ConspireAbility) {
|
game.getStack().push(copy);
|
||||||
if (((ConspireAbility) ability).isActivated()) {
|
copy.chooseNewTargets(game, source.getControllerId());
|
||||||
((ConspireAbility) ability).resetConspire();
|
if (!game.isSimulation()) {
|
||||||
}
|
game.informPlayers(controller.getLogName() + copy.getActivatedMessage(game));
|
||||||
}
|
|
||||||
}
|
|
||||||
Spell copy = spell.copySpell();
|
|
||||||
copy.setControllerId(source.getControllerId());
|
|
||||||
copy.setCopiedSpell(true);
|
|
||||||
game.getStack().push(copy);
|
|
||||||
copy.chooseNewTargets(game, source.getControllerId());
|
|
||||||
if (!game.isSimulation()) {
|
|
||||||
game.informPlayers(new StringBuilder(controller.getLogName()).append(copy.getActivatedMessage(game)).toString());
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setConspiredSpell(Spell conspiredSpell) {
|
||||||
|
this.conspiredSpell = conspiredSpell;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ConspireEffect copy() {
|
public ConspireEffect copy() {
|
||||||
return new ConspireEffect(this);
|
return new ConspireEffect(this);
|
||||||
|
|
|
@ -106,6 +106,7 @@ public abstract class StackObjImpl implements StackObject {
|
||||||
public boolean chooseNewTargets(Game game, UUID targetControllerId, boolean forceChange, boolean onlyOneTarget, FilterPermanent filterNewTarget) {
|
public boolean chooseNewTargets(Game game, UUID targetControllerId, boolean forceChange, boolean onlyOneTarget, FilterPermanent filterNewTarget) {
|
||||||
Player targetController = game.getPlayer(targetControllerId);
|
Player targetController = game.getPlayer(targetControllerId);
|
||||||
if (targetController != null) {
|
if (targetController != null) {
|
||||||
|
StringBuilder oldTargetDescription = new StringBuilder();
|
||||||
StringBuilder newTargetDescription = new StringBuilder();
|
StringBuilder newTargetDescription = new StringBuilder();
|
||||||
// Fused split spells or spells where "Splice on Arcane" was used can have more than one ability
|
// Fused split spells or spells where "Splice on Arcane" was used can have more than one ability
|
||||||
Abilities<Ability> objectAbilities = new AbilitiesImpl<>();
|
Abilities<Ability> objectAbilities = new AbilitiesImpl<>();
|
||||||
|
@ -118,6 +119,7 @@ public abstract class StackObjImpl implements StackObject {
|
||||||
// Some spells can have more than one mode
|
// Some spells can have more than one mode
|
||||||
for (UUID modeId : ability.getModes().getSelectedModes()) {
|
for (UUID modeId : ability.getModes().getSelectedModes()) {
|
||||||
Mode mode = ability.getModes().get(modeId);
|
Mode mode = ability.getModes().get(modeId);
|
||||||
|
oldTargetDescription.append(ability.getTargetDescription(mode.getTargets(), game));
|
||||||
for (Target target : mode.getTargets()) {
|
for (Target target : mode.getTargets()) {
|
||||||
Target newTarget = chooseNewTarget(targetController, ability, mode, target, forceChange, filterNewTarget, game);
|
Target newTarget = chooseNewTarget(targetController, ability, mode, target, forceChange, filterNewTarget, game);
|
||||||
// clear the old target and copy all targets from new target
|
// clear the old target and copy all targets from new target
|
||||||
|
@ -131,7 +133,7 @@ public abstract class StackObjImpl implements StackObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if (newTargetDescription.length() > 0 && !game.isSimulation()) {
|
if (!newTargetDescription.toString().equals(oldTargetDescription.toString()) && !game.isSimulation()) {
|
||||||
game.informPlayers(this.getLogName() + " is now " + newTargetDescription.toString());
|
game.informPlayers(this.getLogName() + " is now " + newTargetDescription.toString());
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
Loading…
Reference in a new issue