diff --git a/Mage.Sets/src/mage/cards/t/ThrastaTempestsRoar.java b/Mage.Sets/src/mage/cards/t/ThrastaTempestsRoar.java
new file mode 100644
index 0000000000..240f941352
--- /dev/null
+++ b/Mage.Sets/src/mage/cards/t/ThrastaTempestsRoar.java
@@ -0,0 +1,87 @@
+package mage.cards.t;
+
+import java.util.UUID;
+
+import mage.MageInt;
+import mage.abilities.Ability;
+import mage.abilities.common.AsEntersBattlefieldAbility;
+import mage.abilities.common.SimpleStaticAbility;
+import mage.abilities.dynamicvalue.DynamicValue;
+import mage.abilities.effects.Effect;
+import mage.abilities.effects.common.continuous.GainAbilitySourceEffect;
+import mage.abilities.effects.common.cost.SpellCostReductionForEachSourceEffect;
+import mage.abilities.hint.ValueHint;
+import mage.abilities.keyword.HasteAbility;
+import mage.abilities.keyword.HexproofAbility;
+import mage.abilities.keyword.TrampleAbility;
+import mage.abilities.keyword.TrampleOverPlaneswalkersAbility;
+import mage.cards.CardImpl;
+import mage.cards.CardSetInfo;
+import mage.constants.*;
+import mage.game.Game;
+import mage.watchers.common.CastSpellLastTurnWatcher;
+
+/**
+ * @author Fubs
+ */
+public final class ThrastaTempestsRoar extends CardImpl {
+
+ public ThrastaTempestsRoar(UUID ownerId, CardSetInfo setInfo) {
+ super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{10}{G}{G}");
+ addSuperType(SuperType.LEGENDARY);
+ this.subtype.add(SubType.DINOSAUR);
+ this.power = new MageInt(7);
+ this.toughness = new MageInt(7);
+
+ //This spell costs 3 less to cast for each other spell cast this turn
+ ThrastaDynamicValue spellCastCount = new ThrastaDynamicValue();
+ //spellCastCount does not need -1 because cast count increases only after current spell cast/reduction.
+ this.addAbility(new SimpleStaticAbility(Zone.ALL, new SpellCostReductionForEachSourceEffect(3, spellCastCount))
+ .addHint(new ValueHint("spell cast", spellCastCount))
+ );
+
+ //Trample, Haste, and Trample over planeswalkers
+ this.addAbility(TrampleAbility.getInstance());
+ this.addAbility(HasteAbility.getInstance());
+ this.addAbility(TrampleOverPlaneswalkersAbility.getInstance());
+
+ //Thrasta has hexproof as long as it entered the battlefield this turn.
+ this.addAbility(new AsEntersBattlefieldAbility(new GainAbilitySourceEffect(HexproofAbility.getInstance(), Duration.EndOfTurn)));
+ }
+
+ private ThrastaTempestsRoar(final mage.cards.t.ThrastaTempestsRoar card) {
+ super(card);
+ }
+
+ @Override
+ public ThrastaTempestsRoar copy() {
+ return new mage.cards.t.ThrastaTempestsRoar(this);
+ }
+}
+
+class ThrastaDynamicValue implements DynamicValue {
+ @Override
+ public int calculate(Game game, Ability sourceAbility, Effect effect) {
+ CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class);
+ if (watcher != null) {
+ return watcher.getAmountOfSpellsAllPlayersCastOnCurrentTurn();
+ }
+ return 0;
+ }
+
+ @Override
+ public ThrastaDynamicValue copy() {
+ return new ThrastaDynamicValue();
+ }
+
+ @Override
+ public String toString() {
+ return "1";
+ }
+
+ @Override
+ public String getMessage() {
+ return "spells cast this turn";
+ }
+
+}
diff --git a/Mage.Sets/src/mage/sets/ModernHorizons2.java b/Mage.Sets/src/mage/sets/ModernHorizons2.java
index 79042d8b79..c7d6052719 100644
--- a/Mage.Sets/src/mage/sets/ModernHorizons2.java
+++ b/Mage.Sets/src/mage/sets/ModernHorizons2.java
@@ -46,5 +46,6 @@ public final class ModernHorizons2 extends ExpansionSet {
cards.add(new SetCardInfo("Urza's Saga", 259, Rarity.RARE, mage.cards.u.UrzasSaga.class));
cards.add(new SetCardInfo("Verdant Catacombs", 260, Rarity.RARE, mage.cards.v.VerdantCatacombs.class));
cards.add(new SetCardInfo("Yusri, Fortune's Flame", 218, Rarity.RARE, mage.cards.y.YusriFortunesFlame.class));
+ cards.add(new SetCardInfo("Thrasta, Tempest's Roar", 178, Rarity.MYTHIC, mage.cards.t.ThrastaTempestsRoar.class));
}
}
diff --git a/Mage/src/main/java/mage/abilities/keyword/TrampleOverPlaneswalkersAbility.java b/Mage/src/main/java/mage/abilities/keyword/TrampleOverPlaneswalkersAbility.java
new file mode 100644
index 0000000000..bdeddea1ec
--- /dev/null
+++ b/Mage/src/main/java/mage/abilities/keyword/TrampleOverPlaneswalkersAbility.java
@@ -0,0 +1,43 @@
+package mage.abilities.keyword;
+
+import mage.abilities.MageSingleton;
+import mage.abilities.StaticAbility;
+import mage.abilities.icon.abilities.TrampleAbilityIcon;
+import mage.constants.Zone;
+
+import java.io.ObjectStreamException;
+
+/**
+ * @author Fubs
+ */
+public class TrampleOverPlaneswalkersAbility extends StaticAbility implements MageSingleton {
+
+ private static final TrampleOverPlaneswalkersAbility instance;
+
+ static {
+ instance = new TrampleOverPlaneswalkersAbility();
+ }
+
+ private Object readResolve() throws ObjectStreamException {
+ return instance;
+ }
+
+ public static TrampleOverPlaneswalkersAbility getInstance() {
+ return instance;
+ }
+
+ private TrampleOverPlaneswalkersAbility() {
+ super(Zone.BATTLEFIELD, null);
+ }
+
+ @Override
+ public String getRule() {
+ return "Trample over planeswalkers (This creature can deal excess combat damage to the controller of the planeswalker it's attacking.)";
+ }
+
+ @Override
+ public TrampleOverPlaneswalkersAbility copy() {
+ return instance;
+ }
+
+}
diff --git a/Mage/src/main/java/mage/game/combat/CombatGroup.java b/Mage/src/main/java/mage/game/combat/CombatGroup.java
index 831e2544d8..2e9cb57088 100644
--- a/Mage/src/main/java/mage/game/combat/CombatGroup.java
+++ b/Mage/src/main/java/mage/game/combat/CombatGroup.java
@@ -102,6 +102,10 @@ public class CombatGroup implements Serializable, Copyable {
return perm.getAbilities().containsKey(TrampleAbility.getInstance().getId());
}
+ private boolean hasTrampleOverPlaneswalkers(Permanent perm) {
+ return perm.getAbilities().containsKey(TrampleOverPlaneswalkersAbility.getInstance().getId());
+ }
+
private boolean hasBanding(Permanent perm) {
return perm.getAbilities().containsKey(BandingAbility.getInstance().getId());
}
@@ -256,7 +260,7 @@ public class CombatGroup implements Serializable, Copyable {
if (canDamage(attacker, first)) {
//20091005 - 510.1c, 702.17c
if (!blocked || hasTrample(attacker)) {
- defenderDamage(attacker, getDamageValueFromPermanent(attacker, game), game);
+ defenderDamage(attacker, getDamageValueFromPermanent(attacker, game), game, false);
}
}
}
@@ -278,7 +282,7 @@ public class CombatGroup implements Serializable, Copyable {
blocker.markDamage(damageAssigned, attacker.getId(), null, game, true, true);
damage -= damageAssigned;
if (damage > 0) {
- defenderDamage(attacker, damage, game);
+ defenderDamage(attacker, damage, game, false);
}
}
} else {
@@ -343,7 +347,7 @@ public class CombatGroup implements Serializable, Copyable {
}
}
if (damage > 0 && hasTrample(attacker) && excessDamageToDefender) {
- defenderDamage(attacker, damage, game);
+ defenderDamage(attacker, damage, game, false);
} else if (!blockerOrder.isEmpty()) {
// Assign the damage left to first blocker
assigned.put(blockerOrder.get(0), assigned.get(blockerOrder.get(0)) == null ? 0 : assigned.get(blockerOrder.get(0)) + damage);
@@ -541,19 +545,47 @@ public class CombatGroup implements Serializable, Copyable {
}
}
}
+ /**
+ * Do damage to attacked player or planeswalker
+ * @param attacker
+ * @param amount
+ * @param game
+ * @param damageToDefenderController excess damage to defender's controller (example: trample over planeswalker)
+ */
+ private void defenderDamage(Permanent attacker, int amount, Game game, boolean damageToDefenderController) {
+ UUID affectedDefenderId = this.defenderId;
+ if (damageToDefenderController) {
+ affectedDefenderId = game.getControllerId(this.defenderId);
+ }
- private void defenderDamage(Permanent attacker, int amount, Game game) {
- if (this.defenderIsPlaneswalker) {
- Permanent defender = game.getPermanent(defenderId);
- if (defender != null) {
- defender.markDamage(amount, attacker.getId(), null, game, true, true);
- }
- } else {
- Player defender = game.getPlayer(defenderId);
- if (defender != null) {
- defender.damage(amount, attacker.getId(), null, game, true, true);
+ // on planeswalker
+ Permanent planeswalker = game.getPermanent(affectedDefenderId);
+ if (planeswalker != null) {
+ // apply excess damage from "trample over planeswaslkers" ability (example: Thrasta, Tempest's Roar)
+ if (hasTrampleOverPlaneswalkers(attacker)) {
+ int lethalDamage = planeswalker.getLethalDamage(attacker.getId(), game);
+ if (lethalDamage >= amount) {
+ // normal damage
+ planeswalker.markDamage(amount, attacker.getId(), null, game, true, true);
+ } else {
+ // damage with excess (additional damage to planeswalker's controller)
+ planeswalker.markDamage(lethalDamage, attacker.getId(), null, game, true, true);
+ amount -= lethalDamage;
+ if (amount > 0) {
+ defenderDamage(attacker, amount, game, true);
+ }
+ }
+ } else {
+ // normal damage
+ planeswalker.markDamage(amount, attacker.getId(), null, game, true, true);
}
}
+
+ // on player
+ Player defender = game.getPlayer(affectedDefenderId);
+ if (defender != null) {
+ defender.damage(amount, attacker.getId(), null, game, true, true);
+ }
}
public boolean canBlock(Permanent blocker, Game game) {