implement [LTC] Call for Aid (#11727)

* [LTC] Implementing "Call for Aid" (#10259)

* [LTC] Call for Aid: Correcting permanent selection filter and "can't attack target this turn" effect

* [LTC] Call for Aid: Making "You can't attack target opponent" a global effect.

* address PR comments

* fix duration

---------

Co-authored-by: xenohedron <xenohedron@users.noreply.github.com>
This commit is contained in:
Lukas Spillner 2024-02-03 22:46:03 +01:00 committed by GitHub
parent 7945c6e3e4
commit d8a199047d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 166 additions and 0 deletions

View file

@ -0,0 +1,165 @@
package mage.cards.c;
import mage.abilities.Ability;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.RestrictionEffect;
import mage.abilities.effects.common.UntapAllEffect;
import mage.abilities.effects.common.continuous.GainAbilityAllEffect;
import mage.abilities.effects.common.continuous.GainControlAllEffect;
import mage.abilities.keyword.HasteAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.permanent.ControllerIdPredicate;
import mage.filter.predicate.permanent.PermanentReferenceInCollectionPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetOpponent;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
/**
* @author spillnerdev, xenohedron
*/
public final class CallForAid extends CardImpl {
public CallForAid(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{R}");
// Gain control of all creatures target opponent controls until end of turn. Untap those creatures. They gain haste until end of turn. You can't attack that player this turn. You can't sacrifice those creatures this turn.
getSpellAbility().addTarget(new TargetOpponent());
getSpellAbility().addEffect(new CallForAidEffect());
}
private CallForAid(final CallForAid card) {
super(card);
}
@Override
public CallForAid copy() {
return new CallForAid(this);
}
}
class CallForAidEffect extends OneShotEffect {
CallForAidEffect() {
super(Outcome.Benefit);
this.staticText = "Gain control of all creatures target opponent controls until end of turn. " +
"Untap those creatures. They gain haste until end of turn. " +
"You can't attack that player this turn. You can't sacrifice those creatures this turn.";
}
private CallForAidEffect(CallForAidEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Player opponent = game.getPlayer(getTargetPointer().getFirst(game, source));
if (opponent == null) {
return false;
}
FilterPermanent filter = new FilterCreaturePermanent();
filter.add(new ControllerIdPredicate(opponent.getId()));
List<Permanent> opponentCreatures = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game);
filter = new FilterPermanent();
filter.add(new PermanentReferenceInCollectionPredicate(opponentCreatures, game));
//"Gain control of all creatures target opponent controls until end of turn"
new GainControlAllEffect(Duration.EndOfTurn, filter).apply(game, source);
game.getState().processAction(game);
//"Untap those creatures".
new UntapAllEffect(filter).apply(game, source);
//"They gain haste until end of turn"
game.addEffect(new GainAbilityAllEffect(HasteAbility.getInstance(), Duration.EndOfTurn, filter), source);
//"You can't attack that player this turn"
game.addEffect(new CallForAidCantAttackThatPlayerEffect().setTargetPointer(this.getTargetPointer().copy()), source);
//"You can't sacrifice those creatures this turn"
game.addEffect(new CallForAidYouCantSacrificeEffect(source.getControllerId(), filter), source);
return true;
}
@Override
public CallForAidEffect copy() {
return new CallForAidEffect(this);
}
}
class CallForAidCantAttackThatPlayerEffect extends RestrictionEffect {
CallForAidCantAttackThatPlayerEffect() {
super(Duration.EndOfTurn, Outcome.Detriment);
}
private CallForAidCantAttackThatPlayerEffect(final CallForAidCantAttackThatPlayerEffect effect) {
super(effect);
}
@Override
public CallForAidCantAttackThatPlayerEffect copy() {
return new CallForAidCantAttackThatPlayerEffect(this);
}
@Override
public boolean applies(Permanent permanent, Ability source, Game game) {
// Effect applies to all permanents (most likely creatures) controlled by the caster of "Call for Aid"
return Objects.equals(source.getControllerId(), permanent.getControllerId());
}
@Override
public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) {
if (defenderId == null || attacker == null) {
return true;
}
// Should be only a single target in case of "Call for Aid"
return !this.getTargetPointer().getTargets(game,source).contains(defenderId);
}
}
class CallForAidYouCantSacrificeEffect extends ContinuousEffectImpl {
private final UUID playerId; // controller who is prevented from sacrificing
private final FilterPermanent filter; // filter containing permanents that can't be sacrificed
CallForAidYouCantSacrificeEffect(UUID playerId, FilterPermanent filter) {
super(Duration.EndOfTurn, Layer.RulesEffects, SubLayer.NA, Outcome.Benefit);
this.playerId = playerId;
this.filter = filter;
}
private CallForAidYouCantSacrificeEffect(final CallForAidYouCantSacrificeEffect effect) {
super(effect);
this.playerId = effect.playerId;
this.filter = effect.filter;
}
@Override
public CallForAidYouCantSacrificeEffect copy() {
return new CallForAidYouCantSacrificeEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) {
if (permanent.getControllerId().equals(playerId)) {
permanent.setCanBeSacrificed(false);
}
}
return true;
}
}

View file

@ -50,6 +50,7 @@ public final class TalesOfMiddleEarthCommander extends ExpansionSet {
cards.add(new SetCardInfo("Brushland", 297, Rarity.RARE, mage.cards.b.Brushland.class));
cards.add(new SetCardInfo("Cabal Coffers", 360, Rarity.MYTHIC, mage.cards.c.CabalCoffers.class));
cards.add(new SetCardInfo("Call Forth the Tempest", 509, Rarity.RARE, mage.cards.c.CallForthTheTempest.class));
cards.add(new SetCardInfo("Call for Aid", 30, Rarity.RARE, mage.cards.c.CallForAid.class));
cards.add(new SetCardInfo("Call for Unity", 163, Rarity.RARE, mage.cards.c.CallForUnity.class));
cards.add(new SetCardInfo("Canopy Vista", 298, Rarity.RARE, mage.cards.c.CanopyVista.class));
cards.add(new SetCardInfo("Castle Ardenvale", 361, Rarity.MYTHIC, mage.cards.c.CastleArdenvale.class));