[LCI] Implement Tishana's Tidebinder

This commit is contained in:
theelk801 2023-11-05 12:59:24 -05:00
parent 651ed39837
commit 86389b81d9
4 changed files with 152 additions and 85 deletions

View file

@ -0,0 +1,90 @@
package mage.cards.t;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.continuous.LoseAllAbilitiesTargetEffect;
import mage.abilities.keyword.FlashAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.game.stack.StackObject;
import mage.target.common.TargetActivatedOrTriggeredAbility;
import mage.target.targetpointer.FixedTarget;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class TishanasTidebinder extends CardImpl {
public TishanasTidebinder(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}");
this.subtype.add(SubType.MERFOLK);
this.subtype.add(SubType.WIZARD);
this.power = new MageInt(3);
this.toughness = new MageInt(2);
// Flash
this.addAbility(FlashAbility.getInstance());
// When Tishana's Tidebinder enters the battlefield, counter up to one target activated or triggered ability. If an ability of an artifact, creature, or planeswalker is countered this way, that permanent loses all abilities for as long as Tishana's Tidebinder remains on the battlefield.
Ability ability = new EntersBattlefieldTriggeredAbility(new TishanasTidebinderEffect());
ability.addTarget(new TargetActivatedOrTriggeredAbility(0, 1));
this.addAbility(ability);
}
private TishanasTidebinder(final TishanasTidebinder card) {
super(card);
}
@Override
public TishanasTidebinder copy() {
return new TishanasTidebinder(this);
}
}
class TishanasTidebinderEffect extends OneShotEffect {
TishanasTidebinderEffect() {
super(Outcome.Benefit);
staticText = "counter up to one target activated or triggered ability. If an ability of an " +
"artifact, creature, or planeswalker is countered this way, that permanent loses " +
"all abilities for as long as {this} remains on the battlefield";
}
private TishanasTidebinderEffect(final TishanasTidebinderEffect effect) {
super(effect);
}
@Override
public TishanasTidebinderEffect copy() {
return new TishanasTidebinderEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
StackObject stackObject = game.getStack().getStackObject(getTargetPointer().getFirst(game, source));
if (stackObject == null) {
return false;
}
Permanent permanent = game.getPermanent(stackObject.getSourceId());
game.getStack().counter(stackObject.getId(), source, game);
Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game);
if (permanent == null || sourcePermanent == null
|| !permanent.isArtifact(game) && !permanent.isCreature(game) && !permanent.isPlaneswalker(game)) {
return true;
}
game.addEffect(new LoseAllAbilitiesTargetEffect(Duration.UntilSourceLeavesBattlefield)
.setTargetPointer(new FixedTarget(permanent, game)), source);
return true;
}
}

View file

@ -323,6 +323,7 @@ public final class TheLostCavernsOfIxalan extends ExpansionSet {
cards.add(new SetCardInfo("Threefold Thunderhulk", 265, Rarity.RARE, mage.cards.t.ThreefoldThunderhulk.class));
cards.add(new SetCardInfo("Throne of the Grim Captain", 266, Rarity.RARE, mage.cards.t.ThroneOfTheGrimCaptain.class));
cards.add(new SetCardInfo("Tinker's Tote", 40, Rarity.COMMON, mage.cards.t.TinkersTote.class));
cards.add(new SetCardInfo("Tishana's Tidebinder", 81, Rarity.RARE, mage.cards.t.TishanasTidebinder.class));
cards.add(new SetCardInfo("Tithing Blade", 128, Rarity.COMMON, mage.cards.t.TithingBlade.class));
cards.add(new SetCardInfo("Treasure Cove", 267, Rarity.RARE, mage.cards.t.TreasureCove.class));
cards.add(new SetCardInfo("Treasure Map", 267, Rarity.RARE, mage.cards.t.TreasureMap.class));

View file

@ -0,0 +1,47 @@
package mage.filter.common;
import mage.abilities.Ability;
import mage.constants.AbilityType;
import mage.filter.FilterStackObject;
import mage.game.Game;
import mage.game.stack.StackObject;
import java.util.UUID;
/**
* @author TheElk801
*/
public class FilterActivatedOrTriggeredAbility extends FilterStackObject {
public FilterActivatedOrTriggeredAbility() {
this("activated or triggered ability");
}
public FilterActivatedOrTriggeredAbility(String name) {
super(name);
}
protected FilterActivatedOrTriggeredAbility(final FilterActivatedOrTriggeredAbility filter) {
super(filter);
}
@Override
public boolean match(StackObject stackObject, UUID playerId, Ability source, Game game) {
if (!super.match(stackObject, playerId, source, game) || !(stackObject instanceof Ability)) {
return false;
}
Ability ability = (Ability) stackObject;
return ability.getAbilityType() == AbilityType.TRIGGERED
|| ability.getAbilityType() == AbilityType.ACTIVATED;
}
@Override
public boolean match(StackObject stackObject, Game game) {
if (!super.match(stackObject, game) || !(stackObject instanceof Ability)) {
return false;
}
Ability ability = (Ability) stackObject;
return ability.getAbilityType() == AbilityType.TRIGGERED
|| ability.getAbilityType() == AbilityType.ACTIVATED;
}
}

View file

@ -1,101 +1,30 @@
package mage.target.common;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import mage.abilities.Ability;
import mage.constants.AbilityType;
import mage.constants.Zone;
import mage.filter.Filter;
import mage.filter.FilterStackObject;
import mage.game.Game;
import mage.game.stack.StackObject;
import mage.target.TargetObject;
import mage.filter.common.FilterActivatedOrTriggeredAbility;
import mage.target.TargetStackObject;
public class TargetActivatedOrTriggeredAbility extends TargetObject {
public class TargetActivatedOrTriggeredAbility extends TargetStackObject {
protected final FilterStackObject filter;
private static final FilterStackObject defaultFilter = new FilterActivatedOrTriggeredAbility();
public TargetActivatedOrTriggeredAbility() {
this(new FilterStackObject("activated or triggered ability"));
this(1, 1);
}
public TargetActivatedOrTriggeredAbility(FilterStackObject filter) {
this.minNumberOfTargets = 1;
this.maxNumberOfTargets = 1;
this.zone = Zone.STACK;
this.targetName = filter.getMessage();
this.filter = filter;
this(1, 1, filter);
}
public TargetActivatedOrTriggeredAbility(int minNumTargets, int maxNumTargets) {
this(minNumTargets, maxNumTargets, defaultFilter);
}
public TargetActivatedOrTriggeredAbility(int minNumTargets, int maxNumTargets, FilterStackObject filter) {
super(minNumTargets, maxNumTargets, filter);
}
protected TargetActivatedOrTriggeredAbility(final TargetActivatedOrTriggeredAbility target) {
super(target);
this.filter = target.filter.copy();
}
@Override
public boolean canTarget(UUID id, Ability source, Game game) {
// rule 114.4. A spell or ability on the stack is an illegal target for itself.
if (source != null && source.getId().equals(id)) {
return false;
}
StackObject stackObject = game.getStack().getStackObject(id);
return isActivatedOrTriggeredAbility(stackObject) && source != null && filter.match(stackObject, source.getControllerId(), source, game);
}
@Override
public boolean canChoose(UUID sourceControllerId, Ability source, Game game) {
for (StackObject stackObject : game.getStack()) {
if (isActivatedOrTriggeredAbility(stackObject)
&& filter.match(stackObject, sourceControllerId, source, game)) {
return true;
}
}
return false;
}
@Override
public boolean canChoose(UUID sourceControllerId, Game game) {
return game.getStack()
.stream()
.anyMatch(TargetActivatedOrTriggeredAbility::isActivatedOrTriggeredAbility);
}
@Override
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
return possibleTargets(sourceControllerId, game);
}
@Override
public Set<UUID> possibleTargets(UUID sourceControllerId, Game game) {
return game.getStack().stream()
.filter(TargetActivatedOrTriggeredAbility::isActivatedOrTriggeredAbility)
.map(stackObject -> stackObject.getStackAbility().getId())
.collect(Collectors.toSet());
}
@Override
public TargetActivatedOrTriggeredAbility copy() {
return new TargetActivatedOrTriggeredAbility(this);
}
@Override
public Filter getFilter() {
return filter;
}
static boolean isActivatedOrTriggeredAbility(StackObject stackObject) {
if (stackObject == null) {
return false;
}
if (stackObject instanceof Ability) {
Ability ability = (Ability) stackObject;
return ability.getAbilityType() == AbilityType.TRIGGERED
|| ability.getAbilityType() == AbilityType.ACTIVATED;
}
return false;
}
}