diff --git a/Mage.Sets/src/mage/cards/c/CaptainAmericaFirstAvenger.java b/Mage.Sets/src/mage/cards/c/CaptainAmericaFirstAvenger.java new file mode 100644 index 00000000000..86ada3c4358 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CaptainAmericaFirstAvenger.java @@ -0,0 +1,215 @@ +package mage.cards.c; + +import java.util.UUID; +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfCombatTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.EarlyTargetCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageMultiEffect; +import mage.constants.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.common.FilterEquipmentPermanent; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.filter.predicate.permanent.AttachedToPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.Target; +import mage.target.TargetPermanent; +import mage.target.common.TargetAnyTargetAmount; + +/** + * + * @author Grath + */ +public final class CaptainAmericaFirstAvenger extends CardImpl { + + private static final FilterPermanent filter = new FilterEquipmentPermanent("Equipment you control"); + + static { + filter.add(TargetController.YOU.getControllerPredicate()); + } + + public CaptainAmericaFirstAvenger(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}{W}{U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.subtype.add(SubType.HERO); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Throw ... — {3}, Unattach an Equipment from Captain America: He deals damage equal to that Equipment’s mana value divided as you choose among one, two, or three targets. + Ability ability = new SimpleActivatedAbility( + new DamageMultiEffect(CaptainAmericaFirstAvengerValue.instance).setText( + "he deals damage equal to that Equipment's mana value divided as you choose among one, two, or three targets."), + new GenericManaCost(3)); + ability.addCost(new CaptainAmericaFirstAvengerUnattachCost()); + ability.addTarget(new TargetAnyTargetAmount(CaptainAmericaFirstAvengerValue.instance, 3)); + this.addAbility(ability.withFlavorWord("Throw ...")); + + // ... Catch — At the beginning of combat on your turn, attach up to one target Equipment you control to Captain America. + ability = new BeginningOfCombatTriggeredAbility( + new CaptainAmericaFirstAvengerCatchEffect(), TargetController.YOU, false + ); + ability.addTarget(new TargetPermanent(0, 1, filter)); + this.addAbility(ability.withFlavorWord("... Catch")); + } + + private CaptainAmericaFirstAvenger(final CaptainAmericaFirstAvenger card) { + super(card); + } + + @Override + public CaptainAmericaFirstAvenger copy() { + return new CaptainAmericaFirstAvenger(this); + } +} + +enum CaptainAmericaPredicate implements ObjectSourcePlayerPredicate { + instance; + + // Functional negation of AnotherPredicate. + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + if (!input.getObject().getId().equals(input.getSourceId())) { + return false; + } + int zcc = input.getSource().getSourceObjectZoneChangeCounter(); + return zcc == input.getObject().getZoneChangeCounter(game); + } + + @Override + public String toString() { + return "{this}"; + } +} + +enum CaptainAmericaFirstAvengerValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + int amount = 0; + for (Cost cost : sourceAbility.getCosts()) { + if (cost instanceof CaptainAmericaFirstAvengerUnattachCost && !cost.getTargets().isEmpty()) { + Permanent equipment = game.getPermanentOrLKIBattlefield(cost.getTargets().getFirstTarget()); + if (equipment != null) { + amount = equipment.getManaValue(); + } + } + } + return amount; + } + + @Override + public DynamicValue copy() { + return instance; + } + + @Override + public String toString() { + return "X"; + } + + @Override + public String getMessage() { + return "that Equipment's mana value"; + } +} + +class CaptainAmericaFirstAvengerUnattachCost extends EarlyTargetCost { + + private static final FilterPermanent filter = new FilterEquipmentPermanent("equipment attached to this creature"); + private static final FilterPermanent subfilter = new FilterControlledPermanent("{this}"); + + static { + subfilter.add(CaptainAmericaPredicate.instance); + filter.add(new AttachedToPredicate(subfilter)); + } + + CaptainAmericaFirstAvengerUnattachCost() { + super(); + } + + protected CaptainAmericaFirstAvengerUnattachCost(final CaptainAmericaFirstAvengerUnattachCost cost) { + super(cost); + } + + @Override + public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { + Permanent permanent = game.getPermanent(source.getSourceId()); + return permanent != null + && !permanent.getAttachments().isEmpty(); + } + + @Override + public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { + Player player = game.getPlayer(source.getControllerId()); + Permanent permanent = game.getPermanent(source.getSourceId()); + if (permanent == null || player == null) { + return paid; + } + Permanent equipment = game.getPermanentOrLKIBattlefield(getTargets().getFirstTarget()); + if (equipment == null || !permanent.getAttachments().contains(equipment.getId()) || + !player.chooseUse(Outcome.Benefit, "Unattach " + equipment.getIdName() + "?", source, game)) { + return false; + } + paid = permanent.removeAttachment(equipment.getId(), source, game); + + return paid; + } + + @Override + public CaptainAmericaFirstAvengerUnattachCost copy() { + return new CaptainAmericaFirstAvengerUnattachCost(this); + } + + @Override + public void chooseTarget(Game game, Ability source, Player controller) { + Target chosenEquipment = new TargetPermanent(1, 1, filter, true); + controller.choose(Outcome.Benefit, chosenEquipment, source, game); + addTarget(chosenEquipment); + } + + @Override + public String getText() { + return "Unattach an Equipment from {this}"; + } +} + +class CaptainAmericaFirstAvengerCatchEffect extends OneShotEffect { + + CaptainAmericaFirstAvengerCatchEffect() { + super(Outcome.Benefit); + staticText = "attach target Equipment you control to {this}"; + } + + private CaptainAmericaFirstAvengerCatchEffect(final CaptainAmericaFirstAvengerCatchEffect effect) { + super(effect); + } + + @Override + public CaptainAmericaFirstAvengerCatchEffect copy() { + return new CaptainAmericaFirstAvengerCatchEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent equipment = game.getPermanent(this.getTargetPointer().getFirst(game, source)); + Permanent creature = source.getSourcePermanentIfItStillExists(game); + return equipment != null && creature != null && creature.addAttachment(equipment.getId(), source, game); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/SecretLairDrop.java b/Mage.Sets/src/mage/sets/SecretLairDrop.java index 6dfdbe190e4..0d42e161001 100644 --- a/Mage.Sets/src/mage/sets/SecretLairDrop.java +++ b/Mage.Sets/src/mage/sets/SecretLairDrop.java @@ -1380,6 +1380,7 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Mayhem Devil", 1715, Rarity.RARE, mage.cards.m.MayhemDevil.class)); cards.add(new SetCardInfo("Moldervine Reclamation", 1716, Rarity.RARE, mage.cards.m.MoldervineReclamation.class)); cards.add(new SetCardInfo("Prossh, Skyraider of Kher", 1717, Rarity.MYTHIC, mage.cards.p.ProsshSkyraiderOfKher.class)); + cards.add(new SetCardInfo("Captain America, First Avenger", 1726, Rarity.MYTHIC, mage.cards.c.CaptainAmericaFirstAvenger.class)); cards.add(new SetCardInfo("Iron Man, Titan of Innovation", 1731, Rarity.MYTHIC, mage.cards.i.IronManTitanOfInnovation.class)); cards.add(new SetCardInfo("Wolverine, Best There Is", 1737, Rarity.MYTHIC, mage.cards.w.WolverineBestThereIs.class)); cards.add(new SetCardInfo("Jace, the Mind Sculptor", 8001, Rarity.MYTHIC, mage.cards.j.JaceTheMindSculptor.class)); diff --git a/Mage/src/main/java/mage/abilities/AbilityImpl.java b/Mage/src/main/java/mage/abilities/AbilityImpl.java index 6da0269961c..3acf3dcff25 100644 --- a/Mage/src/main/java/mage/abilities/AbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/AbilityImpl.java @@ -6,6 +6,7 @@ import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.condition.Condition; import mage.abilities.costs.*; import mage.abilities.costs.common.PayLifeCost; +import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCosts; import mage.abilities.costs.mana.ManaCostsImpl; @@ -330,6 +331,10 @@ public abstract class AbilityImpl implements Ability { handlePhyrexianManaCosts(game, controller); + // 20241022 - 601.2b + // Not yet included in 601.2b but this is where it will be + handleChooseCostTargets(game, controller); + /* 20130201 - 601.2b * If the spell is modal the player announces the mode choice (see rule 700.2). */ @@ -649,6 +654,17 @@ public abstract class AbilityImpl implements Ability { } } + /** + * 601.2b Choose targets for costs that have to be chosen early. + */ + private void handleChooseCostTargets(Game game, Player controller) { + for (Cost cost : getCosts()) { + if (cost instanceof EarlyTargetCost && cost.getTargets().isEmpty()) { + ((EarlyTargetCost) cost).chooseTarget(game, this, controller); + } + } + } + /** * Handles X mana costs and sets manaCostsToPay. * diff --git a/Mage/src/main/java/mage/abilities/costs/EarlyTargetCost.java b/Mage/src/main/java/mage/abilities/costs/EarlyTargetCost.java new file mode 100644 index 00000000000..359188f7fdc --- /dev/null +++ b/Mage/src/main/java/mage/abilities/costs/EarlyTargetCost.java @@ -0,0 +1,25 @@ +package mage.abilities.costs; + +import mage.abilities.Ability; +import mage.game.Game; +import mage.players.Player; + +/** + * @author Grath + * Costs which extend this class need to have targets chosen, and those targets must be chosen during 601.2b step. + */ +public abstract class EarlyTargetCost extends CostImpl { + + protected EarlyTargetCost() { + super(); + } + + protected EarlyTargetCost(final EarlyTargetCost cost) { + super(cost); + } + + @Override + public abstract EarlyTargetCost copy(); + + public abstract void chooseTarget(Game game, Ability source, Player controller); +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/DamageMultiEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DamageMultiEffect.java index 57cb0c4dc13..653be78f3e7 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DamageMultiEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DamageMultiEffect.java @@ -28,7 +28,11 @@ public class DamageMultiEffect extends OneShotEffect { } public DamageMultiEffect(int amount, String whoDealDamageName) { - this(StaticValue.get(amount)); + this(StaticValue.get(amount), whoDealDamageName); + } + + public DamageMultiEffect(DynamicValue amount, String whoDealDamageName) { + this(amount); this.sourceName = whoDealDamageName; }