From 52bb2c5d7152579ff8eb765d030d1f2e13deeb8f Mon Sep 17 00:00:00 2001 From: ssk97 Date: Sat, 4 Nov 2023 03:19:21 -0700 Subject: [PATCH] [WHO] added Ace's Baseball Bat, consolidate related code (#11387) * TalruumPiper use MustBeBlockedByAllSourceEffect * Both of Bident Of Thassa's abilities can be made generic * Goblin Diplomats use generic class (with custom text) * create MustBeBlockedByAtLeastOneAttachedEffect common effect * Add Ace's Baseball Bat --- .../src/mage/cards/a/AcesBaseballBat.java | 86 +++++++++++++++ .../src/mage/cards/b/BidentOfThassa.java | 92 ++-------------- .../src/mage/cards/g/GoblinDiplomats.java | 46 ++------ .../src/mage/cards/p/PredatoryImpetus.java | 56 +--------- .../src/mage/cards/s/SlayersCleaver.java | 65 ++--------- Mage.Sets/src/mage/cards/t/TalruumPiper.java | 57 ++-------- Mage.Sets/src/mage/sets/DoctorWho.java | 1 + .../common/AttachedToTappedCondition.java | 1 - ...stBeBlockedByAtLeastOneAttachedEffect.java | 101 ++++++++++++++++++ 9 files changed, 225 insertions(+), 280 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/a/AcesBaseballBat.java create mode 100644 Mage/src/main/java/mage/abilities/effects/common/combat/MustBeBlockedByAtLeastOneAttachedEffect.java diff --git a/Mage.Sets/src/mage/cards/a/AcesBaseballBat.java b/Mage.Sets/src/mage/cards/a/AcesBaseballBat.java new file mode 100644 index 000000000000..708ec10be131 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AcesBaseballBat.java @@ -0,0 +1,86 @@ +package mage.cards.a; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.combat.MustBeBlockedByAtLeastOneAttachedEffect; +import mage.abilities.effects.common.continuous.BoostEquippedEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EquipAbility; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author notgreat + */ +public final class AcesBaseballBat extends CardImpl { + + private static final FilterControlledCreaturePermanent filterLegendary + = new FilterControlledCreaturePermanent("legendary creature"); + static { + filterLegendary.add(SuperType.LEGENDARY.getPredicate()); + } + + private static final FilterControlledCreaturePermanent filterDalek + = new FilterControlledCreaturePermanent("a Dalek"); + static { + filterDalek.add(SubType.DALEK.getPredicate()); + } + + public AcesBaseballBat(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.EQUIPMENT); + + // Equipped creature gets +3/+0 + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(3, 0))); + + // As long as equipped creature is attacking, it has first strike and must be blocked by a Dalek if able. + Ability ability = new SimpleStaticAbility(new ConditionalContinuousEffect( + new GainAbilityAttachedEffect(FirstStrikeAbility.getInstance(), AttachmentType.EQUIPMENT), + AttachedToAttackingCondition.instance, "As long as equipped creature is attacking, it has first strike")); + ability.addEffect(new MustBeBlockedByAtLeastOneAttachedEffect(filterDalek).concatBy("and")); + this.addAbility(ability); + + // Equip legendary creature (1) + this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(1), new TargetControlledCreaturePermanent(filterLegendary), false)); + + // Equip {3} + this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(3), false)); + } + + private AcesBaseballBat(final AcesBaseballBat card) { + super(card); + } + + @Override + public AcesBaseballBat copy() { + return new AcesBaseballBat(this); + } +} +enum AttachedToAttackingCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + Permanent attachment = game.getPermanent(source.getSourceId()); + if (attachment == null || attachment.getAttachedTo() == null) { + return false; + } + Permanent attachedTo = game.getPermanent(attachment.getAttachedTo()); + if (attachedTo == null) { + return false; + } + return attachedTo.isAttacking(); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BidentOfThassa.java b/Mage.Sets/src/mage/cards/b/BidentOfThassa.java index b8c0ef6a4b5d..b9fcb3a2c101 100644 --- a/Mage.Sets/src/mage/cards/b/BidentOfThassa.java +++ b/Mage.Sets/src/mage/cards/b/BidentOfThassa.java @@ -3,23 +3,20 @@ import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.DealsDamageToAPlayerAllTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.RequirementEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.combat.AttacksIfAbleAllEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SuperType; import mage.constants.Zone; -import mage.game.Game; -import mage.game.events.DamagedPlayerEvent; -import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; -import mage.game.permanent.Permanent; +import mage.constants.SetTargetPointer; +import mage.filter.StaticFilters; /** * @@ -33,9 +30,13 @@ public BidentOfThassa(UUID ownerId, CardSetInfo setInfo) { // Whenever a creature you control deals combat damage to a player, you may draw a card. - this.addAbility(new BidentOfThassaTriggeredAbility()); + this.addAbility(new DealsDamageToAPlayerAllTriggeredAbility( + new DrawCardSourceControllerEffect(1), + StaticFilters.FILTER_CONTROLLED_A_CREATURE, + true, SetTargetPointer.NONE, true + )); // {1}{U}, {T}: Creatures your opponents control attack this turn if able. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BidentOfThassaMustAttackEffect(), new ManaCostsImpl<>("{1}{U}")); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AttacksIfAbleAllEffect(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES,Duration.EndOfTurn), new ManaCostsImpl<>("{1}{U}")); ability.addCost(new TapSourceCost()); this.addAbility(ability); } @@ -49,76 +50,3 @@ public BidentOfThassa copy() { return new BidentOfThassa(this); } } - -class BidentOfThassaTriggeredAbility extends TriggeredAbilityImpl { - - public BidentOfThassaTriggeredAbility() { - super(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), true); - } - - private BidentOfThassaTriggeredAbility(final BidentOfThassaTriggeredAbility ability) { - super(ability); - } - - @Override - public BidentOfThassaTriggeredAbility copy() { - return new BidentOfThassaTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DAMAGED_PLAYER; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (((DamagedPlayerEvent) event).isCombatDamage()) { - Permanent creature = game.getPermanent(event.getSourceId()); - if (creature != null && creature.isControlledBy(controllerId)) { - return true; - } - } - return false; - } - - @Override - public String getRule() { - return " Whenever a creature you control deals combat damage to a player, you may draw a card."; - } -} - -class BidentOfThassaMustAttackEffect extends RequirementEffect { - - public BidentOfThassaMustAttackEffect() { - super(Duration.EndOfTurn); - staticText = "Creatures your opponents control attack this turn if able"; - } - - private BidentOfThassaMustAttackEffect(final BidentOfThassaMustAttackEffect effect) { - super(effect); - } - - @Override - public BidentOfThassaMustAttackEffect copy() { - return new BidentOfThassaMustAttackEffect(this); - } - - @Override - public boolean applies(Permanent permanent, Ability source, Game game) { - if (game.getOpponents(source.getControllerId()).contains(permanent.getControllerId())) { - return true; - } - return false; - } - - @Override - public boolean mustAttack(Game game) { - return true; - } - - @Override - public boolean mustBlock(Game game) { - return false; - } - -} diff --git a/Mage.Sets/src/mage/cards/g/GoblinDiplomats.java b/Mage.Sets/src/mage/cards/g/GoblinDiplomats.java index 8fd95aac9184..767bb70d7a3f 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinDiplomats.java +++ b/Mage.Sets/src/mage/cards/g/GoblinDiplomats.java @@ -3,18 +3,16 @@ import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.effects.RequirementEffect; +import mage.abilities.effects.common.combat.AttacksIfAbleAllEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Duration; import mage.constants.Zone; -import mage.game.Game; -import mage.game.permanent.Permanent; +import mage.filter.StaticFilters; /** * @@ -30,7 +28,10 @@ public GoblinDiplomats(UUID ownerId, CardSetInfo setInfo) { this.toughness = new MageInt(1); // {T}: Each creature attacks this turn if able. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new GoblinDiplomatsEffect(), new TapSourceCost())); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, + new AttacksIfAbleAllEffect(StaticFilters.FILTER_PERMANENT_ALL_CREATURES, Duration.EndOfTurn) + .setText("Each creature attacks this turn if able"), + new TapSourceCost())); } @@ -43,38 +44,3 @@ public GoblinDiplomats copy() { return new GoblinDiplomats(this); } } - -class GoblinDiplomatsEffect extends RequirementEffect { - - public GoblinDiplomatsEffect() { - super(Duration.EndOfTurn); - this.staticText = "Each creature attacks this turn if able"; - } - - private GoblinDiplomatsEffect(final GoblinDiplomatsEffect effect) { - super(effect); - } - - @Override - public GoblinDiplomatsEffect copy() { - return new GoblinDiplomatsEffect(this); - } - - @Override - public boolean applies(Permanent permanent, Ability source, Game game) { - if (permanent != null) { - return true; - } - return false; - } - - @Override - public boolean mustAttack(Game game) { - return true; - } - - @Override - public boolean mustBlock(Game game) { - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/p/PredatoryImpetus.java b/Mage.Sets/src/mage/cards/p/PredatoryImpetus.java index c76544243586..a951531bcbe3 100644 --- a/Mage.Sets/src/mage/cards/p/PredatoryImpetus.java +++ b/Mage.Sets/src/mage/cards/p/PredatoryImpetus.java @@ -2,19 +2,16 @@ import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.RequirementEffect; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.combat.GoadAttachedEffect; +import mage.abilities.effects.common.combat.MustBeBlockedByAtLeastOneAttachedEffect; import mage.abilities.effects.common.continuous.BoostEnchantedEffect; import mage.abilities.keyword.EnchantAbility; 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.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; @@ -39,7 +36,7 @@ public PredatoryImpetus(UUID ownerId, CardSetInfo setInfo) { // Enchanted creature gets +3/+3, must be blocked if able, and is goaded. ability = new SimpleStaticAbility(new BoostEnchantedEffect(3, 3)); - ability.addEffect(new PredatoryImpetusEffect()); + ability.addEffect(new MustBeBlockedByAtLeastOneAttachedEffect().concatBy(",")); ability.addEffect(new GoadAttachedEffect().concatBy(",")); this.addAbility(ability); } @@ -53,52 +50,3 @@ public PredatoryImpetus copy() { return new PredatoryImpetus(this); } } - -class PredatoryImpetusEffect extends RequirementEffect { - - PredatoryImpetusEffect() { - super(Duration.WhileOnBattlefield); - staticText = ", must be blocked if able"; - } - - private PredatoryImpetusEffect(final PredatoryImpetusEffect effect) { - super(effect); - } - - @Override - public boolean applies(Permanent permanent, Ability source, Game game) { - Permanent attachment = game.getPermanent(source.getSourceId()); - if (attachment == null || attachment.getAttachedTo() == null) { - return false; - } - Permanent attachedCreature = game.getPermanent(attachment.getAttachedTo()); - return attachedCreature != null && attachedCreature.isAttacking() - && permanent.canBlock(attachment.getAttachedTo(), game); - } - - @Override - public boolean mustAttack(Game game) { - return false; - } - - @Override - public boolean mustBlock(Game game) { - return false; - } - - @Override - public UUID mustBlockAttackerIfElseUnblocked(Ability source, Game game) { - Permanent attachment = game.getPermanent(source.getSourceId()); - return attachment == null ? null : attachment.getAttachedTo(); - } - - @Override - public int getMinNumberOfBlockers() { - return 1; - } - - @Override - public PredatoryImpetusEffect copy() { - return new PredatoryImpetusEffect(this); - } -} diff --git a/Mage.Sets/src/mage/cards/s/SlayersCleaver.java b/Mage.Sets/src/mage/cards/s/SlayersCleaver.java index 15b88afd281f..cc6707d1ac55 100644 --- a/Mage.Sets/src/mage/cards/s/SlayersCleaver.java +++ b/Mage.Sets/src/mage/cards/s/SlayersCleaver.java @@ -5,14 +5,13 @@ import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.RequirementEffect; +import mage.abilities.effects.common.combat.MustBeBlockedByAtLeastOneAttachedEffect; import mage.abilities.effects.common.continuous.BoostEquippedEffect; import mage.abilities.keyword.EquipAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.game.Game; -import mage.game.permanent.Permanent; +import mage.filter.common.FilterCreaturePermanent; /** * @@ -20,13 +19,19 @@ */ public final class SlayersCleaver extends CardImpl { + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("an Eldrazi"); + + static { + filter.add(SubType.ELDRAZI.getPredicate()); + } public SlayersCleaver(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{3}"); this.subtype.add(SubType.EQUIPMENT); // Equipped creature gets +3/+1 and must be blocked by an Eldrazi if able. Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(3, 1)); - ability.addEffect(new SlayersCleaverEffect()); + ability.addEffect(new MustBeBlockedByAtLeastOneAttachedEffect(filter).concatBy("and")); this.addAbility(ability); // Equip {4} @@ -42,55 +47,3 @@ public SlayersCleaver copy() { return new SlayersCleaver(this); } } - -class SlayersCleaverEffect extends RequirementEffect { - - public SlayersCleaverEffect() { - this(Duration.WhileOnBattlefield); - } - - public SlayersCleaverEffect(Duration duration) { - super(duration); - staticText = "and must be blocked by an Eldrazi if able"; - } - - private SlayersCleaverEffect(final SlayersCleaverEffect effect) { - super(effect); - } - - @Override - public boolean applies(Permanent permanent, Ability source, Game game) { - Permanent equipment = game.getPermanent(source.getSourceId()); - if (equipment == null || equipment.getAttachedTo() == null) { - return false; - } - Permanent attachedCreature = game.getPermanent(equipment.getAttachedTo()); - return attachedCreature != null && attachedCreature.isAttacking() - && permanent.canBlock(equipment.getAttachedTo(), game) && permanent.hasSubtype(SubType.ELDRAZI, game); - } - - @Override - public boolean mustAttack(Game game) { - return false; - } - - @Override - public boolean mustBlock(Game game) { - return false; - } - - @Override - public UUID mustBlockAttackerIfElseUnblocked(Ability source, Game game) { - Permanent equipment = game.getPermanent(source.getSourceId()); - if (equipment != null) { - return equipment.getAttachedTo(); - } - return null; - } - - @Override - public SlayersCleaverEffect copy() { - return new SlayersCleaverEffect(this); - } - -} diff --git a/Mage.Sets/src/mage/cards/t/TalruumPiper.java b/Mage.Sets/src/mage/cards/t/TalruumPiper.java index a582f9a196d5..12d833523d4a 100644 --- a/Mage.Sets/src/mage/cards/t/TalruumPiper.java +++ b/Mage.Sets/src/mage/cards/t/TalruumPiper.java @@ -3,9 +3,8 @@ import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.RequirementEffect; +import mage.abilities.effects.common.combat.MustBeBlockedByAllSourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -13,8 +12,8 @@ import mage.constants.SubType; import mage.constants.Duration; import mage.constants.Zone; -import mage.game.Game; -import mage.game.permanent.Permanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AbilityPredicate; /** * @@ -22,6 +21,12 @@ */ public final class TalruumPiper extends CardImpl { + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures with flying"); + + static { + filter.add(new AbilityPredicate(FlyingAbility.class)); + } + public TalruumPiper(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{R}"); this.subtype.add(SubType.MINOTAUR); @@ -29,7 +34,7 @@ public TalruumPiper(UUID ownerId, CardSetInfo setInfo) { this.toughness = new MageInt(3); // All creatures with flying able to block Talruum Piper do so. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new TalruumPiperEffect())); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new MustBeBlockedByAllSourceEffect(Duration.WhileOnBattlefield, filter))); } private TalruumPiper(final TalruumPiper card) { @@ -41,45 +46,3 @@ public TalruumPiper copy() { return new TalruumPiper(this); } } - -class TalruumPiperEffect extends RequirementEffect { - - public TalruumPiperEffect() { - super(Duration.WhileOnBattlefield); - staticText = "All creatures with flying able to block {this} do so"; - } - - private TalruumPiperEffect(final TalruumPiperEffect effect) { - super(effect); - } - - @Override - public boolean applies(Permanent permanent, Ability source, Game game) { - Permanent sourceCreature = game.getPermanent(source.getSourceId()); - if (sourceCreature != null && sourceCreature.isAttacking()) { - return permanent.getAbilities().contains(FlyingAbility.getInstance()) - && permanent.canBlock(source.getSourceId(), game); - } - return false; - } - - @Override - public boolean mustAttack(Game game) { - return false; - } - - @Override - public boolean mustBlock(Game game) { - return true; - } - - @Override - public UUID mustBlockAttacker(Ability source, Game game) { - return source.getSourceId(); - } - - @Override - public TalruumPiperEffect copy() { - return new TalruumPiperEffect(this); - } -} diff --git a/Mage.Sets/src/mage/sets/DoctorWho.java b/Mage.Sets/src/mage/sets/DoctorWho.java index 3f59ee878ce6..d448dae20df6 100644 --- a/Mage.Sets/src/mage/sets/DoctorWho.java +++ b/Mage.Sets/src/mage/sets/DoctorWho.java @@ -19,6 +19,7 @@ private DoctorWho() { super("Doctor Who", "WHO", ExpansionSet.buildDate(2023, 10, 13), SetType.SUPPLEMENTAL); cards.add(new SetCardInfo("Ace, Fearless Rebel", 98, Rarity.RARE, mage.cards.a.AceFearlessRebel.class)); + cards.add(new SetCardInfo("Ace's Baseball Bat", 170, Rarity.RARE, mage.cards.a.AcesBaseballBat.class)); cards.add(new SetCardInfo("Adric, Mathematical Genius", 33, Rarity.RARE, mage.cards.a.AdricMathematicalGenius.class)); cards.add(new SetCardInfo("Alistair, the Brigadier", 112, Rarity.RARE, mage.cards.a.AlistairTheBrigadier.class)); cards.add(new SetCardInfo("All of History, All at Once", 34, Rarity.RARE, mage.cards.a.AllOfHistoryAllAtOnce.class)); diff --git a/Mage/src/main/java/mage/abilities/condition/common/AttachedToTappedCondition.java b/Mage/src/main/java/mage/abilities/condition/common/AttachedToTappedCondition.java index 32ec82352d33..a10269b844c2 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/AttachedToTappedCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/AttachedToTappedCondition.java @@ -13,7 +13,6 @@ public enum AttachedToTappedCondition implements Condition { instance; - @Override public boolean apply(Game game, Ability source) { Permanent attachment = game.getPermanent(source.getSourceId()); diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/MustBeBlockedByAtLeastOneAttachedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/MustBeBlockedByAtLeastOneAttachedEffect.java new file mode 100644 index 000000000000..73416c0b045e --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/MustBeBlockedByAtLeastOneAttachedEffect.java @@ -0,0 +1,101 @@ + +package mage.abilities.effects.common.combat; + +import mage.abilities.Ability; +import mage.abilities.effects.RequirementEffect; +import mage.constants.Duration; +import mage.filter.FilterPermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; + +import java.util.UUID; + +/** + *

+ *

+ * http://tappedout.net/mtg-questions/must-be-blocked-if-able-effect-makes-other-attacking-creatures-essentially-unblockable/ + *

+ * When you Declare Blockers, you choose an arrangement for your blockers, then + * check to see if there are any restrictions or requirements. + *

+ * If any restrictions are violated, the block is illegal. (For example, trying + * to block with Sightless Ghoul) If any requirements are violated, the least + * possible number of requirements must be violated, otherwise the block is + * illegal. (For example, your opponent control two creatures that he has cast + * Deadly Allure on, but you control only one creature. Blocking either one will + * violate a requirement, "This creature must be blocked this turn if able", but + * it will also violate the least possible number of requirements, thus it is + * legal.) If the block is illegal, the game state backs up and you declare + * blockers again. (Note that while you can, in some cases, circumvent + * requirements such as "This creature must be blocked" or "This creature must + * block any attacking creature" you can never circumvent restrictions: "This + * creature can't block" or "Only one creature may block this turn.") Because + * you declare ALL your blockers at once, THEN check for + * restrictions/requirements, you may block Deadly Allure'd creatures with only + * one creature, if you choose. This still works with Lure: This card sets up a + * requirement that ALL creatures must block it if able. Any block that violates + * more than the minimum number of requirements is still illegal. + * + * @author notgreat + */ +public class MustBeBlockedByAtLeastOneAttachedEffect extends RequirementEffect { + + private final FilterPermanent filter; + + public MustBeBlockedByAtLeastOneAttachedEffect() { + this((FilterPermanent)null); + } + public MustBeBlockedByAtLeastOneAttachedEffect(FilterPermanent filter) { + super(Duration.WhileOnBattlefield); + this.filter = filter; + if (filter == null) { + staticText = "must be blocked if able"; + } else { + staticText = "must be blocked by "+(filter.getMessage())+" if able"; + } + } + + protected MustBeBlockedByAtLeastOneAttachedEffect(final MustBeBlockedByAtLeastOneAttachedEffect effect) { + super(effect); + filter = effect.filter; + } + + @Override + public boolean applies(Permanent permanent, Ability source, Game game) { + Permanent attachment = game.getPermanent(source.getSourceId()); + if (attachment == null || attachment.getAttachedTo() == null) { + return false; + } + Permanent attachedCreature = game.getPermanent(attachment.getAttachedTo()); + if (attachedCreature != null && attachedCreature.isAttacking() + && permanent.canBlock(attachment.getAttachedTo(), game)){ + return (filter == null || filter.match(permanent, attachment.getControllerId(), source, game)); + } + return false; + } + @Override + public boolean mustAttack(Game game) { + return false; + } + + @Override + public boolean mustBlock(Game game) { + return false; + } + + @Override + public UUID mustBlockAttackerIfElseUnblocked(Ability source, Game game) { + Permanent attachment = game.getPermanent(source.getSourceId()); + return attachment == null ? null : attachment.getAttachedTo(); + } + + @Override + public int getMinNumberOfBlockers() { + return filter == null ? 1 : 0; + } + + @Override + public MustBeBlockedByAtLeastOneAttachedEffect copy() { + return new MustBeBlockedByAtLeastOneAttachedEffect(this); + } +}