diff --git a/Mage.Sets/src/mage/cards/o/OptimusPrimeAutobotLeader.java b/Mage.Sets/src/mage/cards/o/OptimusPrimeAutobotLeader.java
new file mode 100644
index 00000000000..a3d53cfe4dc
--- /dev/null
+++ b/Mage.Sets/src/mage/cards/o/OptimusPrimeAutobotLeader.java
@@ -0,0 +1,130 @@
+package mage.cards.o;
+
+import mage.MageInt;
+import mage.MageObjectReference;
+import mage.abilities.Ability;
+import mage.abilities.DelayedTriggeredAbility;
+import mage.abilities.common.AttacksWithCreaturesTriggeredAbility;
+import mage.abilities.effects.OneShotEffect;
+import mage.abilities.effects.common.TransformSourceEffect;
+import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
+import mage.abilities.effects.keyword.BolsterEffect;
+import mage.abilities.keyword.LivingMetalAbility;
+import mage.abilities.keyword.TrampleAbility;
+import mage.abilities.keyword.TransformAbility;
+import mage.cards.CardImpl;
+import mage.cards.CardSetInfo;
+import mage.constants.*;
+import mage.game.Game;
+import mage.game.events.DamagedPlayerEvent;
+import mage.game.events.GameEvent;
+import mage.game.permanent.Permanent;
+
+import java.util.UUID;
+
+/**
+ * @author xenohedron
+ */
+public final class OptimusPrimeAutobotLeader extends CardImpl {
+
+ public OptimusPrimeAutobotLeader(UUID ownerId, CardSetInfo setInfo) {
+ super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "");
+
+ this.addSuperType(SuperType.LEGENDARY);
+ this.subtype.add(SubType.VEHICLE);
+ this.power = new MageInt(6);
+ this.toughness = new MageInt(8);
+ this.color.setWhite(true);
+ this.color.setBlue(true);
+ this.color.setRed(true);
+ this.nightCard = true;
+
+ // Living metal
+ this.addAbility(new LivingMetalAbility());
+
+ // Trample
+ this.addAbility(TrampleAbility.getInstance());
+
+ // Whenever you attack, bolster 2. The chosen creature gains trample until end of turn. When that creature deals combat damage to a player this turn, convert Optimus Prime.
+ this.addAbility(new AttacksWithCreaturesTriggeredAbility(new BolsterEffect(2)
+ .withAdditionalEffect(new GainAbilityTargetEffect(TrampleAbility.getInstance()))
+ .withAdditionalEffect(new OptimusPrimeAutobotLeaderEffect())
+ .setText("bolster 2. The chosen creature gains trample until end of turn. When that creature deals combat damage to a player this turn, convert {this}"),
+ 1));
+
+ // Transform Ability
+ this.addAbility(new TransformAbility());
+ }
+
+ private OptimusPrimeAutobotLeader(final OptimusPrimeAutobotLeader card) {
+ super(card);
+ }
+
+ @Override
+ public OptimusPrimeAutobotLeader copy() {
+ return new OptimusPrimeAutobotLeader(this);
+ }
+}
+
+class OptimusPrimeAutobotLeaderEffect extends OneShotEffect {
+
+ OptimusPrimeAutobotLeaderEffect() {
+ super(Outcome.Transform);
+ }
+
+ private OptimusPrimeAutobotLeaderEffect(final OptimusPrimeAutobotLeaderEffect effect) {
+ super(effect);
+ }
+
+ @Override
+ public OptimusPrimeAutobotLeaderEffect copy() {
+ return new OptimusPrimeAutobotLeaderEffect(this);
+ }
+
+ @Override
+ public boolean apply(Game game, Ability source) {
+ Permanent creature = game.getPermanent(getTargetPointer().getFirst(game, source));
+ if (creature == null) {
+ return false;
+ }
+ game.addDelayedTriggeredAbility(new OptimusPrimeAutobotLeaderDelayedTriggeredAbility(new MageObjectReference(creature, game)), source);
+ return true;
+ }
+
+}
+
+class OptimusPrimeAutobotLeaderDelayedTriggeredAbility extends DelayedTriggeredAbility {
+
+ private final MageObjectReference mor;
+
+ OptimusPrimeAutobotLeaderDelayedTriggeredAbility(MageObjectReference mor) {
+ super(new TransformSourceEffect().setText("convert {this}"), Duration.EndOfTurn);
+ this.mor = mor;
+ setTriggerPhrase("When that creature deals combat damage to a player this turn, ");
+ }
+
+ private OptimusPrimeAutobotLeaderDelayedTriggeredAbility(final OptimusPrimeAutobotLeaderDelayedTriggeredAbility ability) {
+ super(ability);
+ this.mor = ability.mor;
+ }
+
+ @Override
+ public OptimusPrimeAutobotLeaderDelayedTriggeredAbility copy() {
+ return new OptimusPrimeAutobotLeaderDelayedTriggeredAbility(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 permanent = game.getPermanent(event.getSourceId());
+ return mor.refersTo(permanent, game);
+ }
+ return false;
+ }
+
+}
diff --git a/Mage.Sets/src/mage/cards/o/OptimusPrimeHero.java b/Mage.Sets/src/mage/cards/o/OptimusPrimeHero.java
new file mode 100644
index 00000000000..0bb61678675
--- /dev/null
+++ b/Mage.Sets/src/mage/cards/o/OptimusPrimeHero.java
@@ -0,0 +1,80 @@
+package mage.cards.o;
+
+import mage.MageInt;
+import mage.abilities.Ability;
+import mage.abilities.common.BeginningOfEndStepTriggeredAbility;
+import mage.abilities.common.DiesSourceTriggeredAbility;
+import mage.abilities.effects.OneShotEffect;
+import mage.abilities.effects.keyword.BolsterEffect;
+import mage.abilities.keyword.MoreThanMeetsTheEyeAbility;
+import mage.abilities.keyword.TransformAbility;
+import mage.cards.Card;
+import mage.cards.CardImpl;
+import mage.cards.CardSetInfo;
+import mage.constants.*;
+import mage.game.Game;
+import mage.players.Player;
+
+import java.util.UUID;
+
+/**
+ * @author jbureau88
+ */
+public final class OptimusPrimeHero extends CardImpl {
+
+ public OptimusPrimeHero(UUID ownerId, CardSetInfo setInfo) {
+ super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}{U}{R}{W}");
+
+ this.addSuperType(SuperType.LEGENDARY);
+ this.subtype.add(SubType.ROBOT);
+ this.power = new MageInt(4);
+ this.toughness = new MageInt(8);
+ this.secondSideCardClazz = mage.cards.o.OptimusPrimeAutobotLeader.class;
+
+ // More Than Meets the Eye {2}{U}{R}{W}
+ this.addAbility(new MoreThanMeetsTheEyeAbility(this, "{2}{U}{R}{W}"));
+
+ // At the beginning of each end step, bolster 1.
+ this.addAbility(new BeginningOfEndStepTriggeredAbility(new BolsterEffect(1), TargetController.ANY, false));
+
+ // When Optimus Prime dies, return it to the battlefield converted under its owner’s control.
+ this.addAbility(new DiesSourceTriggeredAbility(new OptimusPrimeHeroEffect()));
+ }
+
+ private OptimusPrimeHero(final OptimusPrimeHero card) {
+ super(card);
+ }
+
+ @Override
+ public OptimusPrimeHero copy() {
+ return new OptimusPrimeHero(this);
+ }
+}
+
+class OptimusPrimeHeroEffect extends OneShotEffect {
+
+ OptimusPrimeHeroEffect() {
+ super(Outcome.Benefit);
+ staticText = "return it to the battlefield converted under its owner's control.";
+ }
+
+ private OptimusPrimeHeroEffect(final OptimusPrimeHeroEffect effect) {
+ super(effect);
+ }
+
+ @Override
+ public OptimusPrimeHeroEffect copy() {
+ return new OptimusPrimeHeroEffect(this);
+ }
+
+ @Override
+ public boolean apply(Game game, Ability source) {
+ Player controller = game.getPlayer(source.getControllerId());
+ Card card = game.getCard(source.getSourceId());
+ if (card == null || controller == null) {
+ return false;
+ }
+ game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + source.getSourceId(), Boolean.TRUE);
+ return controller.moveCards(card, Zone.BATTLEFIELD, source, game);
+ }
+}
diff --git a/Mage.Sets/src/mage/sets/Transformers.java b/Mage.Sets/src/mage/sets/Transformers.java
index 7194803d830..152d9f65331 100644
--- a/Mage.Sets/src/mage/sets/Transformers.java
+++ b/Mage.Sets/src/mage/sets/Transformers.java
@@ -31,6 +31,10 @@ public final class Transformers extends ExpansionSet {
cards.add(new SetCardInfo("Jetfire, Ingenious Scientist", 3, Rarity.MYTHIC, mage.cards.j.JetfireIngeniousScientist.class));
cards.add(new SetCardInfo("Megatron, Destructive Force", 12, Rarity.MYTHIC, mage.cards.m.MegatronDestructiveForce.class));
cards.add(new SetCardInfo("Megatron, Tyrant", 12, Rarity.MYTHIC, mage.cards.m.MegatronTyrant.class));
+ cards.add(new SetCardInfo("Optimus Prime, Autobot Leader", 13, Rarity.MYTHIC, mage.cards.o.OptimusPrimeAutobotLeader.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Optimus Prime, Hero", 13, Rarity.MYTHIC, mage.cards.o.OptimusPrimeHero.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Optimus Prime, Autobot Leader", 27, Rarity.MYTHIC, mage.cards.o.OptimusPrimeAutobotLeader.class, NON_FULL_USE_VARIOUS));
+ cards.add(new SetCardInfo("Optimus Prime, Hero", 27, Rarity.MYTHIC, mage.cards.o.OptimusPrimeHero.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Ratchet, Field Medic", 2, Rarity.MYTHIC, mage.cards.r.RatchetFieldMedic.class));
cards.add(new SetCardInfo("Ratchet, Rescue Racer", 2, Rarity.MYTHIC, mage.cards.r.RatchetRescueRacer.class));
cards.add(new SetCardInfo("Starscream, Power Hungry", 5, Rarity.MYTHIC, mage.cards.s.StarscreamPowerHungry.class));
diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/bot/OptimusPrimeTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/bot/OptimusPrimeTest.java
new file mode 100644
index 00000000000..516732177cc
--- /dev/null
+++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/bot/OptimusPrimeTest.java
@@ -0,0 +1,70 @@
+package org.mage.test.cards.single.bot;
+
+import mage.abilities.keyword.TrampleAbility;
+import mage.constants.PhaseStep;
+import mage.constants.Zone;
+import org.junit.Test;
+import org.mage.test.serverside.base.CardTestPlayerBase;
+
+/**
+ * @author xenohedron
+ */
+public class OptimusPrimeTest extends CardTestPlayerBase {
+
+ private static final String optimus = "Optimus Prime, Hero";
+ /*
+ * Optimus Prime, Hero {3}{U}{R}{W}
+ * Legendary Artifact Creature — Robot
+ *
+ * More Than Meets the Eye {2}{U}{R}{W} (You may cast this card converted for {2}{U}{R}{W}.)
+ * At the beginning of each end step, bolster 1. (Choose a creature with the least toughness among creatures you control and put a +1/+1 counter on it.)
+ * When Optimus Prime dies, return it to the battlefield converted under its owner’s control.
+ * 4/8
+ *
+ * Optimus Prime, Autobot Leader
+ * Legendary Artifact — Vehicle
+ *
+ * Living metal (As long as it’s your turn, this Vehicle is also a creature.)
+ * Trample
+ * Whenever you attack, bolster 2. The chosen creature gains trample until end of turn.
+ * When that creature deals combat damage to a player this turn, convert Optimus Prime.
+ * 6/8
+ */
+ private static final String ghoul = "Gutless Ghoul"; // 2/2 "{1}, Sacrifice a creature: You gain 2 life."
+ private static final String myr = "Omega Myr"; // 1/2
+ private static final String centaur = "Centaur Courser"; // 3/3
+
+ @Test
+ public void testOptimusPrime() {
+ addCard(Zone.BATTLEFIELD, playerA, optimus);
+ addCard(Zone.BATTLEFIELD, playerA, ghoul);
+ addCard(Zone.BATTLEFIELD, playerA, myr);
+ addCard(Zone.BATTLEFIELD, playerA, "Wastes");
+ addCard(Zone.BATTLEFIELD, playerB, centaur);
+
+ activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}, Sacrifice"); // gain 2 life
+ setChoice(playerA, optimus); // sac, returns transformed
+
+ attack(1, playerA, ghoul, playerB);
+ addTarget(playerA, ghoul); // choice for bolster, becomes a 4/4 with trample
+ block(1, playerB, centaur, ghoul);
+ setChoice(playerA, "X=3"); // assign 3 damage to centaur, 1 damage tramples over
+ // optimus triggers and transforms
+ // at end step, bolster 1, only target is myr
+
+ setStopAt(2, PhaseStep.UPKEEP);
+ setStrictChooseMode(true);
+ execute();
+
+ assertLife(playerA, 20 + 2);
+ assertLife(playerB, 20 - 1);
+ assertGraveyardCount(playerB, centaur, 1);
+ assertGraveyardCount(playerA, optimus, 0);
+ assertPowerToughness(playerA, optimus, 4, 8);
+ assertPowerToughness(playerA, ghoul, 4, 4);
+ assertPowerToughness(playerA, myr, 2, 3);
+ assertAbility(playerA, ghoul, TrampleAbility.getInstance(), false);
+
+ }
+
+}
diff --git a/Mage/src/main/java/mage/abilities/AbilityImpl.java b/Mage/src/main/java/mage/abilities/AbilityImpl.java
index 2f62c532bf6..f7a29b182d7 100644
--- a/Mage/src/main/java/mage/abilities/AbilityImpl.java
+++ b/Mage/src/main/java/mage/abilities/AbilityImpl.java
@@ -430,7 +430,6 @@ public abstract class AbilityImpl implements Ability {
if (this instanceof SpellAbility) {
// A player can't apply two alternative methods of casting or two alternative costs to a single spell.
switch (((SpellAbility) this).getSpellAbilityCastMode()) {
-
case FLASHBACK:
case MADNESS:
case TRANSFORMED:
diff --git a/Mage/src/main/java/mage/abilities/effects/keyword/BolsterEffect.java b/Mage/src/main/java/mage/abilities/effects/keyword/BolsterEffect.java
index eb670149f4a..008f9393378 100644
--- a/Mage/src/main/java/mage/abilities/effects/keyword/BolsterEffect.java
+++ b/Mage/src/main/java/mage/abilities/effects/keyword/BolsterEffect.java
@@ -3,7 +3,9 @@ package mage.abilities.effects.keyword;
import mage.abilities.Ability;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.StaticValue;
+import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.Effect;
+import mage.abilities.effects.Effects;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.counter.AddCountersTargetEffect;
import mage.constants.ComparisonType;
@@ -19,6 +21,7 @@ import mage.players.Player;
import mage.target.Target;
import mage.target.TargetPermanent;
import mage.target.targetpointer.FixedTarget;
+import mage.util.CardUtil;
/**
* @author LevelX2
@@ -27,6 +30,8 @@ public class BolsterEffect extends OneShotEffect {
private final DynamicValue amount;
+ private Effects additionalEffects = new Effects();
+
public BolsterEffect(int amount) {
this(StaticValue.get(amount));
}
@@ -40,6 +45,7 @@ public class BolsterEffect extends OneShotEffect {
protected BolsterEffect(final BolsterEffect effect) {
super(effect);
this.amount = effect.amount;
+ this.additionalEffects = effect.additionalEffects.copy();
}
@Override
@@ -47,55 +53,72 @@ public class BolsterEffect extends OneShotEffect {
return new BolsterEffect(this);
}
+ // Text must be set manually
+ public BolsterEffect withAdditionalEffect(Effect effect) {
+ additionalEffects.add(effect);
+ return this;
+ }
+
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
- if (controller != null) {
- if (amount.calculate(game, source, this) <= 0) {
- return true;
- }
- int leastToughness = Integer.MAX_VALUE;
- Permanent selectedCreature = null;
- for (Permanent permanent : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, controller.getId(), game)) {
- if (leastToughness > permanent.getToughness().getValue()) {
- leastToughness = permanent.getToughness().getValue();
- selectedCreature = permanent;
- } else if (leastToughness == permanent.getToughness().getValue()) {
- leastToughness = permanent.getToughness().getValue();
- selectedCreature = null;
- }
- }
- if (leastToughness != Integer.MAX_VALUE) {
- if (selectedCreature == null) {
- FilterPermanent filter = new FilterControlledCreaturePermanent("creature you control with toughness " + leastToughness);
- filter.add(new ToughnessPredicate(ComparisonType.EQUAL_TO, leastToughness));
- Target target = new TargetPermanent(1, 1, filter, true);
- if (controller.chooseTarget(outcome, target, source, game)) {
- selectedCreature = game.getPermanent(target.getFirstTarget());
- }
- }
- if (selectedCreature != null) {
- Effect effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance(amount.calculate(game, source, this)));
- effect.setTargetPointer(new FixedTarget(selectedCreature, game));
- return effect.apply(game, source);
- }
- }
+ if (controller == null) {
+ return false;
+ }
+ if (amount.calculate(game, source, this) <= 0) {
return true;
}
- return false;
+ int leastToughness = Integer.MAX_VALUE;
+ Permanent selectedCreature = null;
+ for (Permanent permanent : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, controller.getId(), game)) {
+ if (leastToughness > permanent.getToughness().getValue()) {
+ leastToughness = permanent.getToughness().getValue();
+ selectedCreature = permanent; // automatically select if only one
+ } else if (leastToughness == permanent.getToughness().getValue()) {
+ leastToughness = permanent.getToughness().getValue();
+ selectedCreature = null; // more than one so need to manually select
+ }
+ }
+ if (leastToughness == Integer.MAX_VALUE) {
+ return false; // no creature found
+ }
+ if (selectedCreature == null) {
+ FilterPermanent filter = new FilterControlledCreaturePermanent("creature you control with toughness " + leastToughness);
+ filter.add(new ToughnessPredicate(ComparisonType.EQUAL_TO, leastToughness));
+ Target target = new TargetPermanent(1, 1, filter, true);
+ if (controller.chooseTarget(outcome, target, source, game)) {
+ selectedCreature = game.getPermanent(target.getFirstTarget());
+ }
+ }
+ if (selectedCreature == null) {
+ return false;
+ }
+ Effect effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance(amount.calculate(game, source, this)));
+ FixedTarget fixedTarget = new FixedTarget(selectedCreature, game);
+ effect.setTargetPointer(fixedTarget);
+ effect.apply(game, source);
+ if (!additionalEffects.isEmpty()) {
+ for (Effect additionalEffect : additionalEffects) {
+ additionalEffect.setTargetPointer(fixedTarget);
+ if (additionalEffect instanceof OneShotEffect) {
+ additionalEffect.apply(game, source);
+ } else {
+ game.addEffect((ContinuousEffect) additionalEffect, source);
+ }
+ }
+ }
+ return true;
}
private String setText() {
- StringBuilder sb = new StringBuilder("bolster ");
if (amount instanceof StaticValue) {
- sb.append(amount);
- sb.append(". (Choose a creature with the least toughness or tied with the least toughness among creatures you control. Put ");
- sb.append(amount).append(" +1/+1 counters on it.)");
+ int number = ((StaticValue) amount).getValue();
+ return "bolster " + number
+ +". (Choose a creature with the least toughness among creatures you control and put "
+ + CardUtil.numberToText(number, "a") + " +1/+1 counter" + (number == 1 ? "" : "s") + " on it.)";
} else {
- sb.append("X, where X is the number of ");
- sb.append(amount.getMessage());
- sb.append(". (Choose a creature with the least toughness among creatures you control and put X +1/+1 counters on it.)");
+ return "bolster X, where X is the number of " + amount.getMessage()
+ + ". (Choose a creature with the least toughness among creatures you control and put X +1/+1 counters on it.)";
}
- return sb.toString();
}
}