From bbe9098d2bf7505f64a55b878c85dd358dbb27b9 Mon Sep 17 00:00:00 2001 From: Zzooouhh Date: Sat, 13 Jan 2018 13:59:37 +0000 Subject: [PATCH 1/3] Implemented Sword of the Ages --- .../src/mage/cards/s/SwordOfTheAges.java | 141 ++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/s/SwordOfTheAges.java diff --git a/Mage.Sets/src/mage/cards/s/SwordOfTheAges.java b/Mage.Sets/src/mage/cards/s/SwordOfTheAges.java new file mode 100644 index 00000000000..9e7acafb154 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SwordOfTheAges.java @@ -0,0 +1,141 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.cards.s; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTappedAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetCreatureOrPlayer; + +/** + * + * @author L_J + */ +public class SwordOfTheAges extends CardImpl { + + public SwordOfTheAges(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{6}"); + + // Sword of the Ages enters the battlefield tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + + // {T}, Sacrifice Sword of the Ages and any number of creatures you control: Sword of the Ages deals X damage to target creature or player, where X is the total power of the creatures sacrificed this way, then exile Sword of the Ages and those creature cards. + Cost cost = new SacrificeSourceCost(); + cost.setText("Sacrifice {this} and any number of creatures you control"); + Cost cost2 = new SacrificeTargetCost(new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE, new FilterControlledCreaturePermanent(), true)); + cost2.setText(""); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new SwordOfTheAgesEffect(), new TapSourceCost()); + ability.addCost(cost); + ability.addCost(cost2); + ability.addTarget(new TargetCreatureOrPlayer()); + this.addAbility(ability); + } + + public SwordOfTheAges(final SwordOfTheAges card) { + super(card); + } + + @Override + public SwordOfTheAges copy() { + return new SwordOfTheAges(this); + } +} + +class SwordOfTheAgesEffect extends OneShotEffect { + + public SwordOfTheAgesEffect() { + super(Outcome.Damage); + this.staticText = "{this} deals X damage to target creature or player, where X is the total power of the creatures sacrificed this way, then exile {this} and those creature cards"; + } + + public SwordOfTheAgesEffect(final SwordOfTheAgesEffect effect) { + super(effect); + } + + @Override + public SwordOfTheAgesEffect copy() { + return new SwordOfTheAgesEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Set cardsToExile = new HashSet<>(); + if (controller != null) { + int totalPower = 0; + Card card = game.getCard(source.getSourceId()); + if (card != null) { + cardsToExile.add(card); // consulted this on mtgjudges - regardless of what zone they end up in after sac, the creature cards and Sword will be moved to exile (unless there's another replacement effect for exiling them) + } + for (Cost cost : source.getCosts()) { + // Sword of the Ages doesn't count itself for total damage if it's a creature: http://www.mtgsalvation.com/forums/the-game/commander-edh/202963-sword-of-the-ages + if (cost instanceof SacrificeTargetCost) { + for (Permanent permanent : ((SacrificeTargetCost) cost).getPermanents()) { + totalPower += permanent.getPower().getValue(); + Card permanentCard = game.getCard(permanent.getId()); + if (permanentCard != null) { + cardsToExile.add(permanentCard); + } + } + } + } + if (totalPower > 0) { + Player player = game.getPlayer(this.getTargetPointer().getFirst(game, source)); + if (player != null) { + player.damage(totalPower, source.getSourceId(), game, false, true); + } else { + Permanent creature = game.getPermanent(this.getTargetPointer().getFirst(game, source)); + if (creature != null) { + creature.damage(totalPower, source.getSourceId(), game, false, true); + } + } + } + return controller.moveCards(cardsToExile, Zone.EXILED, source, game); + } + return false; + } +} From f10bbdf6a02bb50ddd54b29d360701376df01063 Mon Sep 17 00:00:00 2001 From: Zzooouhh Date: Sat, 13 Jan 2018 14:01:16 +0000 Subject: [PATCH 2/3] Implemented Sword of the Ages --- Mage.Sets/src/mage/sets/Legends.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Mage.Sets/src/mage/sets/Legends.java b/Mage.Sets/src/mage/sets/Legends.java index 144d0db8944..c062375e17e 100644 --- a/Mage.Sets/src/mage/sets/Legends.java +++ b/Mage.Sets/src/mage/sets/Legends.java @@ -252,6 +252,7 @@ public class Legends extends ExpansionSet { cards.add(new SetCardInfo("Storm Seeker", 119, Rarity.UNCOMMON, mage.cards.s.StormSeeker.class)); cards.add(new SetCardInfo("Storm World", 162, Rarity.RARE, mage.cards.s.StormWorld.class)); cards.add(new SetCardInfo("Sunastian Falconer", 301, Rarity.UNCOMMON, mage.cards.s.SunastianFalconer.class)); + cards.add(new SetCardInfo("Sword of the Ages", 241, Rarity.RARE, mage.cards.s.SwordOfTheAges.class)); cards.add(new SetCardInfo("Sylvan Library", 121, Rarity.UNCOMMON, mage.cards.s.SylvanLibrary.class)); cards.add(new SetCardInfo("Sylvan Paradise", 122, Rarity.UNCOMMON, mage.cards.s.SylvanParadise.class)); cards.add(new SetCardInfo("Syphon Soul", 32, Rarity.COMMON, mage.cards.s.SyphonSoul.class)); From b3d1454055df000c63f0a6efcbf1981cf8fd7f61 Mon Sep 17 00:00:00 2001 From: igoudt Date: Fri, 12 Jan 2018 17:07:06 +0100 Subject: [PATCH 3/3] rewrite raging river with streams --- Mage.Sets/src/mage/cards/r/RagingRiver.java | 49 +++++++-------------- 1 file changed, 17 insertions(+), 32 deletions(-) diff --git a/Mage.Sets/src/mage/cards/r/RagingRiver.java b/Mage.Sets/src/mage/cards/r/RagingRiver.java index fa4ef5f1dbb..17383e43aec 100644 --- a/Mage.Sets/src/mage/cards/r/RagingRiver.java +++ b/Mage.Sets/src/mage/cards/r/RagingRiver.java @@ -27,9 +27,7 @@ */ package mage.cards.r; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.AttacksWithCreaturesTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -54,6 +52,11 @@ import mage.target.Target; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.targetpointer.FixedTarget; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + /** * * @author L_J @@ -124,25 +127,13 @@ class RagingRiverEffect extends OneShotEffect { // it could be nice to invoke some graphic indicator of which creature is Left or Right in this spot StringBuilder sb = new StringBuilder("Left pile of ").append(defender.getLogName()).append(": "); - int i = 0; - for (Permanent permanent : leftLog) { - i++; - sb.append(permanent.getLogName()); - if (i < leftLog.size()) { - sb.append(", "); - } - } + sb.append(leftLog.stream().map(MageObject::getLogName).collect(Collectors.joining(", "))); + game.informPlayers(sb.toString()); sb = new StringBuilder("Right pile of ").append(defender.getLogName()).append(": "); - i = 0; - for (Permanent permanent : rightLog) { - i++; - sb.append(permanent.getLogName()); - if (i < rightLog.size()) { - sb.append(", "); - } - } + sb.append(rightLog.stream().map(MageObject::getLogName).collect(Collectors.joining(", "))); + game.informPlayers(sb.toString()); } } @@ -160,19 +151,13 @@ class RagingRiverEffect extends OneShotEffect { // shortcut in case of no labeled blockers available filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); } else { - List leftLog = new ArrayList<>(); - List rightLog = new ArrayList<>(); - - for (Permanent permanent : left) { - if (permanent.getControllerId() == defender.getId()) { - leftLog.add(permanent); - } - } - for (Permanent permanent : right) { - if (permanent.getControllerId() == defender.getId()) { - rightLog.add(permanent); - } - } + List leftLog = left.stream() + .filter(permanent -> permanent.getControllerId().equals(defender.getId())) + .collect(Collectors.toList()); + List rightLog = right.stream() + .filter(permanent -> permanent.getControllerId().equals(defender.getId())) + .collect(Collectors.toList()); + if (controller.choosePile(outcome, attacker.getName() + ": attacking " + defender.getName(), leftLog, rightLog, game)) { filter.add(Predicates.not(Predicates.or(new AbilityPredicate(FlyingAbility.class), new PermanentInListPredicate(left))));