Implemented Crystalline Resonance

This commit is contained in:
Evan Kranzler 2020-04-07 20:52:03 -04:00
parent 357d1873db
commit 2d11f69d0e
6 changed files with 186 additions and 88 deletions

View file

@ -0,0 +1,76 @@
package mage.cards.c;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.CycleControllerTriggeredAbility;
import mage.abilities.effects.common.CopyPermanentEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
import mage.filter.predicate.permanent.AnotherPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.TargetPermanent;
import mage.util.functions.ApplyToPermanent;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class CrystallineResonance extends CardImpl {
private static final FilterPermanent filter = new FilterPermanent("another permanent");
static {
filter.add(AnotherPredicate.instance);
}
public CrystallineResonance(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}");
// Whenever you cycle a card, you may have Crystalline Resonance become a copy of another target permanent until your next turn, except it has this ability.
this.addAbility(this.createAbility());
}
private CrystallineResonance(final CrystallineResonance card) {
super(card);
}
@Override
public CrystallineResonance copy() {
return new CrystallineResonance(this);
}
static Ability createAbility() {
Ability ability = new CycleControllerTriggeredAbility(
new CopyPermanentEffect(
StaticFilters.FILTER_PERMANENT_CREATURE,
new CrystallineResonanceApplier(), true
).setDuration(Duration.UntilYourNextTurn).setText(
"have {this} become a copy of another target permanent until your next turn, " +
"except it has this ability"
), true
);
ability.addTarget(new TargetPermanent(filter));
return ability;
}
}
class CrystallineResonanceApplier extends ApplyToPermanent {
@Override
public boolean apply(Game game, Permanent permanent, Ability source, UUID copyToObjectId) {
permanent.getAbilities().add(CrystallineResonance.createAbility());
return true;
}
@Override
public boolean apply(Game game, MageObject mageObject, Ability source, UUID copyToObjectId) {
mageObject.getAbilities().add(CrystallineResonance.createAbility());
return true;
}
}

View file

@ -28,7 +28,7 @@ public final class DrannithStinger extends CardImpl {
// Whenever you cycle another card, Drannith Stinger deals 1 damage to each opponent. // Whenever you cycle another card, Drannith Stinger deals 1 damage to each opponent.
this.addAbility(new CycleControllerTriggeredAbility( this.addAbility(new CycleControllerTriggeredAbility(
new DamagePlayersEffect(1, TargetController.OPPONENT) new DamagePlayersEffect(1, TargetController.OPPONENT), false, true
)); ));
// Cycling {1} // Cycling {1}

View file

@ -27,7 +27,7 @@ public final class FlourishingFox extends CardImpl {
// Whenever you cycle another card, put a +1/+1 counter on Flourishing Fox. // Whenever you cycle another card, put a +1/+1 counter on Flourishing Fox.
this.addAbility(new CycleControllerTriggeredAbility( this.addAbility(new CycleControllerTriggeredAbility(
new AddCountersSourceEffect(CounterType.P1P1.createInstance()) new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false, true
)); ));
// Cycling {1} // Cycling {1}

View file

@ -71,6 +71,7 @@ public final class Commander2020Edition extends ExpansionSet {
cards.add(new SetCardInfo("Commander's Sphere", 240, Rarity.COMMON, mage.cards.c.CommandersSphere.class)); cards.add(new SetCardInfo("Commander's Sphere", 240, Rarity.COMMON, mage.cards.c.CommandersSphere.class));
cards.add(new SetCardInfo("Crop Rotation", 169, Rarity.COMMON, mage.cards.c.CropRotation.class)); cards.add(new SetCardInfo("Crop Rotation", 169, Rarity.COMMON, mage.cards.c.CropRotation.class));
cards.add(new SetCardInfo("Cryptic Trilobite", 21, Rarity.RARE, mage.cards.c.CrypticTrilobite.class)); cards.add(new SetCardInfo("Cryptic Trilobite", 21, Rarity.RARE, mage.cards.c.CrypticTrilobite.class));
cards.add(new SetCardInfo("Crystalline Resonance", 31, Rarity.RARE, mage.cards.c.CrystallineResonance.class));
cards.add(new SetCardInfo("Curious Herd", 59, Rarity.RARE, mage.cards.c.CuriousHerd.class)); cards.add(new SetCardInfo("Curious Herd", 59, Rarity.RARE, mage.cards.c.CuriousHerd.class));
cards.add(new SetCardInfo("Daring Fiendbonder", 41, Rarity.RARE, mage.cards.d.DaringFiendbonder.class)); cards.add(new SetCardInfo("Daring Fiendbonder", 41, Rarity.RARE, mage.cards.d.DaringFiendbonder.class));
cards.add(new SetCardInfo("Deadly Tempest", 131, Rarity.RARE, mage.cards.d.DeadlyTempest.class)); cards.add(new SetCardInfo("Deadly Tempest", 131, Rarity.RARE, mage.cards.d.DeadlyTempest.class));

View file

@ -14,16 +14,24 @@ import mage.game.stack.StackObject;
*/ */
public class CycleControllerTriggeredAbility extends TriggeredAbilityImpl { public class CycleControllerTriggeredAbility extends TriggeredAbilityImpl {
private final boolean excludeSource;
public CycleControllerTriggeredAbility(Effect effect) { public CycleControllerTriggeredAbility(Effect effect) {
this(effect, false); this(effect, false);
} }
public CycleControllerTriggeredAbility(Effect effect, boolean optional) { public CycleControllerTriggeredAbility(Effect effect, boolean optional) {
this(effect, optional, false);
}
public CycleControllerTriggeredAbility(Effect effect, boolean optional, boolean excludeSource) {
super(Zone.BATTLEFIELD, effect, optional); super(Zone.BATTLEFIELD, effect, optional);
this.excludeSource = excludeSource;
} }
private CycleControllerTriggeredAbility(final CycleControllerTriggeredAbility ability) { private CycleControllerTriggeredAbility(final CycleControllerTriggeredAbility ability) {
super(ability); super(ability);
this.excludeSource = ability.excludeSource;
} }
@Override @Override
@ -35,7 +43,7 @@ public class CycleControllerTriggeredAbility extends TriggeredAbilityImpl {
public boolean checkTrigger(GameEvent event, Game game) { public boolean checkTrigger(GameEvent event, Game game) {
if (game.getState().getStack().isEmpty() if (game.getState().getStack().isEmpty()
|| !event.getPlayerId().equals(this.getControllerId()) || !event.getPlayerId().equals(this.getControllerId())
|| event.getSourceId().equals(this.getSourceId())) { || (event.getSourceId().equals(this.getSourceId()) && excludeSource)) {
return false; return false;
} }
StackObject item = game.getState().getStack().getFirst(); StackObject item = game.getState().getStack().getFirst();
@ -45,7 +53,7 @@ public class CycleControllerTriggeredAbility extends TriggeredAbilityImpl {
@Override @Override
public String getRule() { public String getRule() {
return "Whenever you cycle another card, " + super.getRule(); return "Whenever you cycle " + (excludeSource ? "another" : "a") + " card, " + super.getRule();
} }
@Override @Override

View file

@ -6,11 +6,11 @@ import mage.abilities.SpellAbility;
import mage.abilities.effects.Effect; import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.keyword.EnchantAbility; import mage.abilities.keyword.EnchantAbility;
import mage.constants.Duration;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SubType; import mage.constants.SubType;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.filter.common.FilterCreaturePermanent;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
@ -26,13 +26,14 @@ import java.util.UUID;
*/ */
public class CopyPermanentEffect extends OneShotEffect { public class CopyPermanentEffect extends OneShotEffect {
private FilterPermanent filter; private final FilterPermanent filter;
private ApplyToPermanent applier; private final ApplyToPermanent applier;
private final boolean useTargetOfAbility;
private Permanent bluePrintPermanent; private Permanent bluePrintPermanent;
private boolean useTargetOfAbility; private Duration duration = Duration.Custom;
public CopyPermanentEffect() { public CopyPermanentEffect() {
this(new FilterCreaturePermanent()); this(StaticFilters.FILTER_PERMANENT_CREATURE);
} }
public CopyPermanentEffect(ApplyToPermanent applier) { public CopyPermanentEffect(ApplyToPermanent applier) {
@ -72,88 +73,95 @@ public class CopyPermanentEffect extends OneShotEffect {
if (sourcePermanent == null) { if (sourcePermanent == null) {
sourcePermanent = game.getObject(source.getSourceId()); sourcePermanent = game.getObject(source.getSourceId());
} }
if (controller != null && sourcePermanent != null) { if (controller == null || sourcePermanent == null) {
Permanent copyFromPermanent = null; return false;
if (useTargetOfAbility) { }
copyFromPermanent = game.getPermanent(getTargetPointer().getFirst(game, source)); Permanent copyFromPermanent = null;
} else { if (useTargetOfAbility) {
Target target = new TargetPermanent(filter); copyFromPermanent = game.getPermanent(getTargetPointer().getFirst(game, source));
target.setNotTarget(true); } else {
if (target.canChoose(source.getSourceId(), controller.getId(), game)) { Target target = new TargetPermanent(filter);
controller.choose(Outcome.Copy, target, source.getSourceId(), game); target.setNotTarget(true);
copyFromPermanent = game.getPermanent(target.getFirstTarget()); if (target.canChoose(source.getSourceId(), controller.getId(), game)) {
} controller.choose(Outcome.Copy, target, source.getSourceId(), game);
} copyFromPermanent = game.getPermanent(target.getFirstTarget());
if (copyFromPermanent != null) {
bluePrintPermanent = game.copyPermanent(copyFromPermanent, sourcePermanent.getId(), source, applier);
if (bluePrintPermanent == null) {
return false;
}
// if object is a copy of an aura, it needs to attach again for new target
if (bluePrintPermanent.hasSubtype(SubType.AURA, game)) {
//copied from mage.cards.c.CopyEnchantment.java
// permanent can be attached (Estrid's Mask) or enchant (Utopia Sprawl)
// TODO: fix Animate Dead -- it's can't be copied (can't retarget)
Outcome auraOutcome = Outcome.BoostCreature;
Target auraTarget = null;
// attach - search effect in spell ability (example: cast Utopia Sprawl, cast Estrid's Invocation on it)
for (Ability ability : bluePrintPermanent.getAbilities()) {
if (ability instanceof SpellAbility) {
auraOutcome = ability.getEffects().getOutcome(ability);
for (Effect effect : ability.getEffects()) {
if (effect instanceof AttachEffect) {
if (bluePrintPermanent.getSpellAbility().getTargets().size() > 0) {
auraTarget = bluePrintPermanent.getSpellAbility().getTargets().get(0);
}
}
}
}
}
// enchant - search in all abilities (example: cast Estrid's Invocation on enchanted creature by Estrid, the Masked second ability, cast Estrid's Invocation on it)
if (auraTarget == null) {
for (Ability ability : bluePrintPermanent.getAbilities()) {
if (ability instanceof EnchantAbility) {
auraOutcome = ability.getEffects().getOutcome(ability);
if (ability.getTargets().size() > 0) { // Animate Dead don't have targets
auraTarget = ability.getTargets().get(0);
}
}
}
}
/* if this is a copy of a copy, the copy's target has been
* copied and needs to be cleared
*/
if (auraTarget != null) {
// clear selected target
if (auraTarget.getFirstTarget() != null) {
auraTarget.remove(auraTarget.getFirstTarget());
}
// select new target
auraTarget.setNotTarget(true);
if (controller.choose(auraOutcome, auraTarget, source.getSourceId(), game)) {
UUID targetId = auraTarget.getFirstTarget();
Permanent targetPermanent = game.getPermanent(targetId);
Player targetPlayer = game.getPlayer(targetId);
if (targetPermanent != null) {
targetPermanent.addAttachment(sourcePermanent.getId(), game);
} else if (targetPlayer != null) {
targetPlayer.addAttachment(sourcePermanent.getId(), game);
} else {
return false;
}
}
}
}
} }
}
if (copyFromPermanent == null) {
return true; return true;
} }
return false; bluePrintPermanent = game.copyPermanent(duration, copyFromPermanent, sourcePermanent.getId(), source, applier);
if (bluePrintPermanent == null) {
return false;
}
// if object is a copy of an aura, it needs to attach again for new target
if (!bluePrintPermanent.hasSubtype(SubType.AURA, game)) {
return true;
}
//copied from mage.cards.c.CopyEnchantment.java
// permanent can be attached (Estrid's Mask) or enchant (Utopia Sprawl)
// TODO: fix Animate Dead -- it's can't be copied (can't retarget)
Outcome auraOutcome = Outcome.BoostCreature;
Target auraTarget = null;
// attach - search effect in spell ability (example: cast Utopia Sprawl, cast Estrid's Invocation on it)
for (Ability ability : bluePrintPermanent.getAbilities()) {
if (!(ability instanceof SpellAbility)) {
continue;
}
auraOutcome = ability.getEffects().getOutcome(ability);
for (Effect effect : ability.getEffects()) {
if (!(effect instanceof AttachEffect)) {
continue;
}
if (bluePrintPermanent.getSpellAbility().getTargets().size() > 0) {
auraTarget = bluePrintPermanent.getSpellAbility().getTargets().get(0);
}
}
}
// enchant - search in all abilities (example: cast Estrid's Invocation on enchanted creature by Estrid, the Masked second ability, cast Estrid's Invocation on it)
if (auraTarget == null) {
for (Ability ability : bluePrintPermanent.getAbilities()) {
if (!(ability instanceof EnchantAbility)) {
continue;
}
auraOutcome = ability.getEffects().getOutcome(ability);
if (ability.getTargets().size() > 0) { // Animate Dead don't have targets
auraTarget = ability.getTargets().get(0);
}
}
}
/* if this is a copy of a copy, the copy's target has been
* copied and needs to be cleared
*/
if (auraTarget == null) {
return true;
}
// clear selected target
if (auraTarget.getFirstTarget() != null) {
auraTarget.remove(auraTarget.getFirstTarget());
}
// select new target
auraTarget.setNotTarget(true);
if (!controller.choose(auraOutcome, auraTarget, source.getSourceId(), game)) {
return true;
}
UUID targetId = auraTarget.getFirstTarget();
Permanent targetPermanent = game.getPermanent(targetId);
Player targetPlayer = game.getPlayer(targetId);
if (targetPermanent != null) {
targetPermanent.addAttachment(sourcePermanent.getId(), game);
} else if (targetPlayer != null) {
targetPlayer.addAttachment(sourcePermanent.getId(), game);
} else {
return false;
}
return true;
} }
public Permanent getBluePrintPermanent() { public Permanent getBluePrintPermanent() {
@ -164,4 +172,9 @@ public class CopyPermanentEffect extends OneShotEffect {
public CopyPermanentEffect copy() { public CopyPermanentEffect copy() {
return new CopyPermanentEffect(this); return new CopyPermanentEffect(this);
} }
public CopyPermanentEffect setDuration(Duration duration) {
this.duration = duration;
return this;
}
} }