From a9951b0584018a14a5f5088dbb0b08cbd32213c7 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 14 Feb 2018 08:33:24 +0100 Subject: [PATCH 1/9] * Drain Life - Fixed tool tip text. --- Mage.Sets/src/mage/cards/d/DrainLife.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Mage.Sets/src/mage/cards/d/DrainLife.java b/Mage.Sets/src/mage/cards/d/DrainLife.java index 8ace809f01..f517c7252b 100644 --- a/Mage.Sets/src/mage/cards/d/DrainLife.java +++ b/Mage.Sets/src/mage/cards/d/DrainLife.java @@ -45,7 +45,7 @@ import mage.target.common.TargetCreatureOrPlayer; /** * * @author KholdFuzion - + * */ public class DrainLife extends CardImpl { @@ -55,10 +55,8 @@ public class DrainLife extends CardImpl { filterBlack.setBlack(true); } - public DrainLife(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{1}{B}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{1}{B}"); // Spend only black mana on X. // Drain Life deals X damage to target creature or player. You gain life equal to the damage dealt, but not more life than the player's life total before Drain Life dealt damage or the creature's toughness. @@ -84,7 +82,7 @@ class DrainLifeEffect extends OneShotEffect { public DrainLifeEffect() { super(Outcome.Damage); - staticText = "Drain Life deals X damage to target creature or player. You gain life equal to the damage dealt, but not more life than the player's life total before Drain Life dealt damage or the creature's toughness."; + staticText = "Spend only black mana on X.
{this} deals X damage to target creature or player. You gain life equal to the damage dealt, but not more life than the player's life total before Drain Life dealt damage or the creature's toughness"; } public DrainLifeEffect(final DrainLifeEffect effect) { @@ -97,7 +95,7 @@ class DrainLifeEffect extends OneShotEffect { int lifetogain = amount; if (amount > 0) { Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (permanent != null ) { + if (permanent != null) { if (permanent.getToughness().getValue() < amount) { lifetogain = permanent.getToughness().getValue(); } From 949897632def04cbcb83b8d0455dd528c07787d1 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 14 Feb 2018 08:45:40 +0100 Subject: [PATCH 2/9] * Lunge - Fixed that damage was dealt twice to targets. --- Mage.Sets/src/mage/cards/l/Lunge.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Mage.Sets/src/mage/cards/l/Lunge.java b/Mage.Sets/src/mage/cards/l/Lunge.java index 8316d5c970..f602f212be 100644 --- a/Mage.Sets/src/mage/cards/l/Lunge.java +++ b/Mage.Sets/src/mage/cards/l/Lunge.java @@ -44,14 +44,13 @@ import mage.target.targetpointer.SecondTargetPointer; public class Lunge extends CardImpl { public Lunge(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{R}"); - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R}"); // Lunge deals 2 damage to target creature and 2 damage to target player. - this.getSpellAbility().addEffect(new DamageTargetEffect(2)); + this.getSpellAbility().addEffect(new DamageTargetEffect(2).setUseOnlyTargetPointer(true)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - Effect effect = new DamageTargetEffect(2); + Effect effect = new DamageTargetEffect(2).setUseOnlyTargetPointer(true); effect.setTargetPointer(new SecondTargetPointer()); effect.setText("and 2 damage to target player"); this.getSpellAbility().addEffect(effect); From 014c93e05e6076c14b015acbbd982847ca91bfa2 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 14 Feb 2018 11:48:22 +0100 Subject: [PATCH 3/9] * Eye of the Storm - Fixed possible endless loop if player quits game. --- Mage.Sets/src/mage/cards/e/EyeOfTheStorm.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Mage.Sets/src/mage/cards/e/EyeOfTheStorm.java b/Mage.Sets/src/mage/cards/e/EyeOfTheStorm.java index 2724ef2b86..53d282810c 100644 --- a/Mage.Sets/src/mage/cards/e/EyeOfTheStorm.java +++ b/Mage.Sets/src/mage/cards/e/EyeOfTheStorm.java @@ -147,8 +147,8 @@ class EyeOfTheStormEffect1 extends OneShotEffect { if (spell != null && eyeOfTheStorm != null) { Player spellController = game.getPlayer(spell.getControllerId()); Card card = spell.getCard(); - if (spellController == null - || card == null + if (spellController == null + || card == null || !instantOrSorceryfilter.match(card, game)) { return false; } @@ -159,14 +159,14 @@ class EyeOfTheStormEffect1 extends OneShotEffect { eyeOfTheStorm.imprint(card.getId(), game);// technically, using the imprint functionality here is not correct. - if (eyeOfTheStorm.getImprinted() != null + if (eyeOfTheStorm.getImprinted() != null && !eyeOfTheStorm.getImprinted().isEmpty()) { CardsImpl copiedCards = new CardsImpl(); for (UUID uuid : eyeOfTheStorm.getImprinted()) { card = game.getCard(uuid); // Check if owner of card is still in game - if (card != null + if (card != null && game.getPlayer(card.getOwnerId()) != null) { if (card.isSplitCard()) { copiedCards.add(((SplitCard) card).getLeftHalfCard()); @@ -178,7 +178,7 @@ class EyeOfTheStormEffect1 extends OneShotEffect { } boolean continueCasting = true; - while (continueCasting) { + while (spellController.isInGame() && continueCasting) { continueCasting = copiedCards.size() > 1 && spellController.chooseUse(outcome, "Cast one of the copied cards without paying its mana cost?", source, game); Card cardToCopy; From 3b19304f64f42a0989336c7d6a43ad4a5fb49bae Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 14 Feb 2018 12:41:44 +0100 Subject: [PATCH 4/9] * Fixed that soulbond arrow to paired card was not shown and improved soulbond text on permanent. --- .../src/main/java/mage/client/util/gui/GuiDisplayUtil.java | 6 ------ Mage.Common/src/main/java/mage/view/CardView.java | 7 +++---- .../main/java/mage/abilities/keyword/SoulbondAbility.java | 4 +++- Mage/src/main/java/mage/game/permanent/PermanentImpl.java | 4 ++++ 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/Mage.Client/src/main/java/mage/client/util/gui/GuiDisplayUtil.java b/Mage.Client/src/main/java/mage/client/util/gui/GuiDisplayUtil.java index 293231595b..6a5dd6c453 100644 --- a/Mage.Client/src/main/java/mage/client/util/gui/GuiDisplayUtil.java +++ b/Mage.Client/src/main/java/mage/client/util/gui/GuiDisplayUtil.java @@ -134,12 +134,6 @@ public final class GuiDisplayUtil { for (String rule : card.getRules()) { textLines.basicTextLength += rule.length(); } - if (card.getMageObjectType() == MageObjectType.PERMANENT) { - if (card.getPairedCard() != null) { - textLines.lines.add("Paired with another creature"); - textLines.basicTextLength += 30; - } - } if (card.getMageObjectType().canHaveCounters()) { ArrayList counters = new ArrayList<>(); if (card instanceof PermanentView) { diff --git a/Mage.Common/src/main/java/mage/view/CardView.java b/Mage.Common/src/main/java/mage/view/CardView.java index 3d56ae7d26..b5d1f205a3 100644 --- a/Mage.Common/src/main/java/mage/view/CardView.java +++ b/Mage.Common/src/main/java/mage/view/CardView.java @@ -27,6 +27,8 @@ */ package mage.view; +import java.util.*; +import java.util.stream.Collectors; import mage.MageObject; import mage.ObjectColor; import mage.abilities.Abilities; @@ -51,9 +53,6 @@ import mage.target.Target; import mage.target.Targets; import mage.util.SubTypeList; -import java.util.*; -import java.util.stream.Collectors; - /** * @author BetaSteward_at_googlemail.com */ @@ -352,12 +351,12 @@ public class CardView extends SimpleCardView { if (game != null) { if (permanent.getCounters(game) != null && !permanent.getCounters(game).isEmpty()) { this.loyalty = Integer.toString(permanent.getCounters(game).getCount(CounterType.LOYALTY)); - this.pairedCard = permanent.getPairedCard() != null ? permanent.getPairedCard().getSourceId() : null; counters = new ArrayList<>(); for (Counter counter : permanent.getCounters(game).values()) { counters.add(new CounterView(counter)); } } + this.pairedCard = permanent.getPairedCard() != null ? permanent.getPairedCard().getSourceId() : null; if (!permanent.getControllerId().equals(permanent.getOwnerId())) { controlledByOwner = false; } diff --git a/Mage/src/main/java/mage/abilities/keyword/SoulbondAbility.java b/Mage/src/main/java/mage/abilities/keyword/SoulbondAbility.java index 26226c8ac0..b4b1aa1bff 100644 --- a/Mage/src/main/java/mage/abilities/keyword/SoulbondAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/SoulbondAbility.java @@ -32,7 +32,6 @@ import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.OneShotEffect; -import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SetTargetPointer; import mage.constants.TargetController; @@ -47,6 +46,7 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetControlledPermanent; +import mage.util.GameLog; /** * 702.94. Soulbond @@ -168,7 +168,9 @@ class SoulboundEntersSelfEffect extends OneShotEffect { Permanent chosen = game.getPermanent(target.getFirstTarget()); if (chosen != null) { chosen.setPairedCard(new MageObjectReference(permanent, game)); + chosen.addInfo("soulbond", "Soulbond to " + GameLog.getColoredObjectIdNameForTooltip(permanent), game); permanent.setPairedCard(new MageObjectReference(chosen, game)); + permanent.addInfo("soulbond", "Soulbond to " + GameLog.getColoredObjectIdNameForTooltip(chosen), game); if (!game.isSimulation()) { game.informPlayers(controller.getLogName() + " soulbonds " + permanent.getLogName() + " with " + chosen.getLogName()); } diff --git a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java index c68a8be15d..e66e9cb442 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java @@ -1319,6 +1319,10 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { @Override public void setPairedCard(MageObjectReference pairedCard) { this.pairedPermanent = pairedCard; + if (pairedCard == null) { + // remove existing soulbond info text + this.addInfo("soulbond", null, null); + } } @Override From e77b457414712c32b89b58b19de727036c047a78 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 14 Feb 2018 17:33:59 +0100 Subject: [PATCH 5/9] * Madness ability - reworked madness ability design. --- .../java/mage/abilities/SpellAbility.java | 37 +++++++++++--- .../abilities/keyword/MadnessAbility.java | 50 ++++++------------- .../mage/constants/SpellAbilityCastMode.java | 48 ++++++++++++++++++ 3 files changed, 92 insertions(+), 43 deletions(-) create mode 100644 Mage/src/main/java/mage/constants/SpellAbilityCastMode.java diff --git a/Mage/src/main/java/mage/abilities/SpellAbility.java b/Mage/src/main/java/mage/abilities/SpellAbility.java index f09f246b7f..2cd291a957 100644 --- a/Mage/src/main/java/mage/abilities/SpellAbility.java +++ b/Mage/src/main/java/mage/abilities/SpellAbility.java @@ -38,6 +38,7 @@ import mage.cards.Card; import mage.cards.SplitCard; import mage.constants.AbilityType; import mage.constants.AsThoughEffectType; +import mage.constants.SpellAbilityCastMode; import mage.constants.SpellAbilityType; import mage.constants.TimingRule; import mage.constants.Zone; @@ -51,6 +52,7 @@ import mage.players.Player; public class SpellAbility extends ActivatedAbilityImpl { protected SpellAbilityType spellAbilityType; + protected SpellAbilityCastMode spellAbilityCastMode; protected String cardName; public SpellAbility(ManaCost cost, String cardName) { @@ -62,23 +64,22 @@ public class SpellAbility extends ActivatedAbilityImpl { } public SpellAbility(ManaCost cost, String cardName, Zone zone, SpellAbilityType spellAbilityType) { + this(cost, cardName, zone, spellAbilityType, SpellAbilityCastMode.NORMAL); + } + + public SpellAbility(ManaCost cost, String cardName, Zone zone, SpellAbilityType spellAbilityType, SpellAbilityCastMode spellAbilityCastMode) { super(AbilityType.SPELL, zone); this.cardName = cardName; this.spellAbilityType = spellAbilityType; + this.spellAbilityCastMode = spellAbilityCastMode; this.addManaCost(cost); - switch (spellAbilityType) { - case SPLIT_FUSED: - this.name = "Cast fused " + cardName; - break; - default: - this.name = "Cast " + cardName; - } - + setSpellName(); } public SpellAbility(final SpellAbility ability) { super(ability); this.spellAbilityType = ability.spellAbilityType; + this.spellAbilityCastMode = ability.spellAbilityCastMode; this.cardName = ability.cardName; } @@ -209,4 +210,24 @@ public class SpellAbility extends ActivatedAbilityImpl { } return amount * xMultiplier; } + + private void setSpellName() { + switch (spellAbilityType) { + case SPLIT_FUSED: + this.name = "Cast fused " + cardName; + break; + default: + this.name = "Cast " + cardName + (this.spellAbilityCastMode != SpellAbilityCastMode.NORMAL ? " by " + spellAbilityCastMode.toString() : ""); + } + } + + public SpellAbilityCastMode getSpellAbilityCastMode() { + return spellAbilityCastMode; + } + + public void setSpellAbilityCastMode(SpellAbilityCastMode spellAbilityCastMode) { + this.spellAbilityCastMode = spellAbilityCastMode; + setSpellName(); + } + } diff --git a/Mage/src/main/java/mage/abilities/keyword/MadnessAbility.java b/Mage/src/main/java/mage/abilities/keyword/MadnessAbility.java index aa24ffb848..b8a74f8711 100644 --- a/Mage/src/main/java/mage/abilities/keyword/MadnessAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/MadnessAbility.java @@ -1,8 +1,9 @@ package mage.abilities.keyword; -import java.util.ArrayList; import java.util.UUID; +import mage.MageObject; import mage.abilities.Ability; +import mage.abilities.SpellAbility; import mage.abilities.StaticAbility; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.condition.Condition; @@ -13,10 +14,13 @@ import mage.abilities.effects.ReplacementEffectImpl; import mage.cards.Card; import mage.constants.Duration; import mage.constants.Outcome; +import mage.constants.SpellAbilityCastMode; +import mage.constants.SpellAbilityType; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; +import mage.game.stack.Spell; import mage.players.Player; /** @@ -133,8 +137,6 @@ class MadnessReplacementEffect extends ReplacementEffectImpl { */ class MadnessTriggeredAbility extends TriggeredAbilityImpl { - //This array holds the Id's of all of the cards that activated madness - private static ArrayList activatedIds = new ArrayList<>(); private final UUID madnessOriginalId; MadnessTriggeredAbility(ManaCosts madnessCost, UUID madnessOriginalId) { @@ -176,25 +178,9 @@ class MadnessTriggeredAbility extends TriggeredAbilityImpl { } return false; } - activatedIds.add(getSourceId()); return true; } - @Override - public boolean isActivated() { - //Look through the list of activated Ids and see if the current source's Id is one of them - for (UUID currentId : activatedIds) { - if (currentId.equals(getSourceId())) { - //Remove the current source from the list, so if the card is somehow recast without - //paying the madness cost, this will return false - activatedIds.remove(currentId); - return true; - } - } - //If the current source's Id was not found, return false - return false; - } - @Override public String getRule() { return "When this card is exiled this way, " + super.getRule(); @@ -225,17 +211,15 @@ class MadnessCastEffect extends OneShotEffect { } if (owner != null && card != null && owner.chooseUse(outcome, "Cast " + card.getLogName() + " by madness?", source, game)) { - ManaCosts costRef = card.getSpellAbility().getManaCostsToPay(); + // replace with the new cost + SpellAbility castByMadness = card.getSpellAbility().copy(); + ManaCosts costRef = castByMadness.getManaCostsToPay(); + castByMadness.setSpellAbilityType(SpellAbilityType.BASE_ALTERNATE); + castByMadness.setSpellAbilityCastMode(SpellAbilityCastMode.MADNESS); costRef.clear(); costRef.add(madnessCost); - boolean result = owner.cast(card.getSpellAbility(), game, false); - // Reset the casting costs (in case the player cancels cast and plays the card later) - // TODO: Check if this is neccessary - costRef.clear(); - for (ManaCost manaCost : card.getSpellAbility().getManaCosts()) { - costRef.add(manaCost); - } + boolean result = owner.cast(castByMadness, game, false); return result; } @@ -254,14 +238,10 @@ enum MadnessCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - Card card = game.getCard(source.getSourceId()); - if (card != null) { - for (Ability ability : card.getAbilities()) { - if (ability instanceof MadnessTriggeredAbility) { - if (ability.isActivated()) { - return true; - } - } + MageObject madnessSpell = game.getLastKnownInformation(source.getSourceId(), Zone.STACK, source.getSourceObjectZoneChangeCounter() - 1); + if (madnessSpell instanceof Spell) { + if (((Spell) madnessSpell).getSpellAbility() != null) { + return ((Spell) madnessSpell).getSpellAbility().getSpellAbilityCastMode() == SpellAbilityCastMode.MADNESS; } } return false; diff --git a/Mage/src/main/java/mage/constants/SpellAbilityCastMode.java b/Mage/src/main/java/mage/constants/SpellAbilityCastMode.java new file mode 100644 index 0000000000..663c8c8f1b --- /dev/null +++ b/Mage/src/main/java/mage/constants/SpellAbilityCastMode.java @@ -0,0 +1,48 @@ +/* + * 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.constants; + +/** + * + * @author LevelX2 + */ +public enum SpellAbilityCastMode { + NORMAL("Normal"), + MADNESS("Madness"); + + private final String text; + + SpellAbilityCastMode(String text) { + this.text = text; + } + + @Override + public String toString() { + return text; + } +} From 00dd941260e8f1fa79857d673ac38e4bc861c331 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 14 Feb 2018 17:35:47 +0100 Subject: [PATCH 6/9] * Grave Scrabbler - Fixed that it was also possible to return a card from graveyard even if not cast by madness. --- .../src/mage/cards/g/GraveScrabbler.java | 23 +------------------ 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/Mage.Sets/src/mage/cards/g/GraveScrabbler.java b/Mage.Sets/src/mage/cards/g/GraveScrabbler.java index ccb3b459e7..f86199a122 100644 --- a/Mage.Sets/src/mage/cards/g/GraveScrabbler.java +++ b/Mage.Sets/src/mage/cards/g/GraveScrabbler.java @@ -2,10 +2,8 @@ package mage.cards.g; import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.TriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.condition.Condition; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.decorator.ConditionalTriggeredAbility; import mage.abilities.effects.common.ReturnToHandTargetEffect; @@ -16,7 +14,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.common.FilterCreatureCard; -import mage.game.Game; import mage.target.common.TargetCardInGraveyard; public class GraveScrabbler extends CardImpl { @@ -35,7 +32,7 @@ public class GraveScrabbler extends CardImpl { //you may return target creature card from a graveyard to its owner's hand. TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), true); ability.addTarget(new TargetCardInGraveyard(new FilterCreatureCard("creature card in a graveyard"))); - this.addAbility(new ConditionalTriggeredAbility(ability, MadnessPaidCondition.instance, + this.addAbility(new ConditionalTriggeredAbility(ability, MadnessAbility.GetCondition(), "When {this} enters the battlefield, if its madness cost was paid, you may return target creature card from a graveyard to its owner's hand.")); } @@ -49,21 +46,3 @@ public class GraveScrabbler extends CardImpl { } } - -enum MadnessPaidCondition implements Condition { - instance; - - @Override - public boolean apply(Game game, Ability source) { - Card card = game.getCard(source.getSourceId()); - if (card != null) { - for (Ability ability : card.getAbilities()) { - if (ability instanceof MadnessAbility) { - return ((MadnessAbility) ability).getCosts().isPaid(); - } - } - } - return false; - } - -} From d10d6361ac9a6c56e8f49f11f4e42aa883115f27 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 14 Feb 2018 22:57:57 +0100 Subject: [PATCH 7/9] * Some minor chnages. --- .../src/mage/cards/c/ContestedWarZone.java | 20 ++++----- .../abilities/keywords/FlashbackTest.java | 42 +++++++++++++++++++ .../common/AddManaOfAnyColorEffect.java | 3 ++ .../PlayLandsFromGraveyardEffect.java | 9 ++-- .../main/java/mage/game/draft/DraftCube.java | 2 - 5 files changed, 58 insertions(+), 18 deletions(-) diff --git a/Mage.Sets/src/mage/cards/c/ContestedWarZone.java b/Mage.Sets/src/mage/cards/c/ContestedWarZone.java index 998d9b874b..e73b686425 100644 --- a/Mage.Sets/src/mage/cards/c/ContestedWarZone.java +++ b/Mage.Sets/src/mage/cards/c/ContestedWarZone.java @@ -1,16 +1,16 @@ /* * Copyright 2011 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 @@ -20,7 +20,7 @@ * 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. @@ -55,14 +55,14 @@ public class ContestedWarZone extends CardImpl { private static final FilterAttackingCreature filter = new FilterAttackingCreature("Attacking creatures"); public ContestedWarZone(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.LAND},null); + super(ownerId, setInfo, new CardType[]{CardType.LAND}, null); // Whenever a creature deals combat damage to you, that creature's controller gains control of Contested War Zone. this.addAbility(new ContestedWarZoneAbility()); // {T}: Add {C} to your mana pool. this.addAbility(new ColorlessManaAbility()); - + // {1}, {T}: Attacking creatures get +1/+0 until end of turn. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostAllEffect(1, 0, Duration.EndOfTurn, filter, false), new ManaCostsImpl("{1}")); ability.addCost(new TapSourceCost()); @@ -84,7 +84,7 @@ class ContestedWarZoneAbility extends TriggeredAbilityImpl { public ContestedWarZoneAbility() { super(Zone.BATTLEFIELD, new ContestedWarZoneEffect()); - } + } public ContestedWarZoneAbility(final ContestedWarZoneAbility ability) { super(ability); @@ -102,7 +102,7 @@ class ContestedWarZoneAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - DamagedPlayerEvent damageEvent = (DamagedPlayerEvent)event; + DamagedPlayerEvent damageEvent = (DamagedPlayerEvent) event; if (damageEvent.isCombatDamage()) { Permanent permanent = game.getPermanent(event.getSourceId()); if (damageEvent.getPlayerId().equals(getControllerId()) && permanent != null && permanent.isCreature()) { @@ -137,7 +137,7 @@ class ContestedWarZoneEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = (Permanent) source.getSourceObjectIfItStillExists(game); + Permanent permanent = game.getPermanent(source.getSourceId()); UUID controllerId = (UUID) game.getState().getValue(source.getSourceId().toString()); if (permanent != null && controllerId != null) { return permanent.changeControllerId(controllerId, game); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/FlashbackTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/FlashbackTest.java index e63d71f56b..30f0d24fb9 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/FlashbackTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/FlashbackTest.java @@ -29,6 +29,7 @@ package org.mage.test.cards.abilities.keywords; import mage.constants.PhaseStep; import mage.constants.Zone; +import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -512,4 +513,45 @@ public class FlashbackTest extends CardTestPlayerBase { assertExileCount(playerA, dReturn, 1); assertPermanentCount(playerA, bSable, 1); } + + /** + * I can play Force of Will with flashback paying his alternative mana cost. + * The ruling say no to it, because we only can choose one alternative cost + * to a spell, and the flashback cost is already an alternative cost. + */ + @Test + @Ignore + public void testSnapcasterMageSpellWithAlternateCost() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 1); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); + // When Snapcaster Mage enters the battlefield, target instant or sorcery card in your graveyard gains flashback until end of turn. + // The flashback cost is equal to its mana cost. + addCard(Zone.HAND, playerA, "Snapcaster Mage", 2); // Creature{1}{U} + + // You may pay 1 life and exile a blue card from your hand rather than pay Force of Will's mana cost. + // Counter target spell. + addCard(Zone.GRAVEYARD, playerA, "Force of Will"); + + addCard(Zone.HAND, playerB, "Lightning Bolt", 1); + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Snapcaster Mage"); + setChoice(playerA, "Force of Will"); + + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Lightning Bolt", "Snapcaster Mage"); + activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Flashback", null, "Lightning Bolt"); + addTarget(playerA, "Lightning Bolt"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertPermanentCount(playerA, "Snapcaster Mage", 0); + assertGraveyardCount(playerA, "Snapcaster Mage", 1); + + assertGraveyardCount(playerA, "Force of Will", 1); + assertGraveyardCount(playerB, "Lightning Bolt", 1); + + assertLife(playerA, 20); + + } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/AddManaOfAnyColorEffect.java b/Mage/src/main/java/mage/abilities/effects/common/AddManaOfAnyColorEffect.java index 4ccd4fcc5c..84551cb93c 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/AddManaOfAnyColorEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/AddManaOfAnyColorEffect.java @@ -72,6 +72,9 @@ public class AddManaOfAnyColorEffect extends BasicManaEffect { String mes = String.format("Select color of %d mana to add it to your mana pool", this.amount); ChoiceColor choice = new ChoiceColor(true, mes, game.getObject(source.getSourceId())); if (controller.choose(outcome, choice, game)) { + if (choice.getColor() == null) { + return false; + } Mana createdMana = choice.getMana(amount); if (createdMana != null) { checkToFirePossibleEvents(createdMana, game, source); diff --git a/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/PlayLandsFromGraveyardEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/PlayLandsFromGraveyardEffect.java index cb1000ed73..a6a5aa4e58 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/PlayLandsFromGraveyardEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/PlayLandsFromGraveyardEffect.java @@ -11,8 +11,6 @@ import mage.constants.SubLayer; import mage.game.Game; import mage.players.Player; -import java.util.UUID; - public class PlayLandsFromGraveyardEffect extends ContinuousEffectImpl { public PlayLandsFromGraveyardEffect() { @@ -33,11 +31,10 @@ public class PlayLandsFromGraveyardEffect extends ContinuousEffectImpl { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - for (UUID cardId: player.getGraveyard()) { - Card card = game.getCard(cardId); - if(card != null && card.isLand()){ + for (Card card : player.getGraveyard().getCards(game)) { + if (card != null && card.isLand()) { PlayLandFromGraveyardAbility ability = new PlayLandFromGraveyardAbility(card.getName()); - ability.setSourceId(cardId); + ability.setSourceId(card.getId()); ability.setControllerId(card.getOwnerId()); game.getState().addOtherAbility(card, ability); } diff --git a/Mage/src/main/java/mage/game/draft/DraftCube.java b/Mage/src/main/java/mage/game/draft/DraftCube.java index b84641a05c..052145752a 100644 --- a/Mage/src/main/java/mage/game/draft/DraftCube.java +++ b/Mage/src/main/java/mage/game/draft/DraftCube.java @@ -30,9 +30,7 @@ package mage.game.draft; import java.util.ArrayList; import java.util.List; import java.util.Objects; - import mage.cards.Card; -import mage.cards.repository.CardCriteria; import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; import mage.util.RandomUtil; From 1d09168857d19710ccb5dc3cb332b4a8af4de965 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 14 Feb 2018 23:05:43 +0100 Subject: [PATCH 8/9] Xmage 1.4.27V4 --- Mage.Common/src/main/java/mage/utils/MageVersion.java | 2 +- Mage/src/main/java/mage/cards/repository/CardRepository.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Mage.Common/src/main/java/mage/utils/MageVersion.java b/Mage.Common/src/main/java/mage/utils/MageVersion.java index 629c4494b2..2e87becec4 100644 --- a/Mage.Common/src/main/java/mage/utils/MageVersion.java +++ b/Mage.Common/src/main/java/mage/utils/MageVersion.java @@ -41,7 +41,7 @@ public class MageVersion implements Serializable, Comparable { public final static int MAGE_VERSION_MAJOR = 1; public final static int MAGE_VERSION_MINOR = 4; public final static int MAGE_VERSION_PATCH = 27; - public final static String MAGE_VERSION_MINOR_PATCH = "V3"; + public final static String MAGE_VERSION_MINOR_PATCH = "V4"; public final static String MAGE_VERSION_INFO = ""; private final int major; diff --git a/Mage/src/main/java/mage/cards/repository/CardRepository.java b/Mage/src/main/java/mage/cards/repository/CardRepository.java index 7fb0d61ca0..02b9c5abf5 100644 --- a/Mage/src/main/java/mage/cards/repository/CardRepository.java +++ b/Mage/src/main/java/mage/cards/repository/CardRepository.java @@ -58,7 +58,7 @@ public enum CardRepository { // raise this if db structure was changed private static final long CARD_DB_VERSION = 51; // raise this if new cards were added to the server - private static final long CARD_CONTENT_VERSION = 103; + private static final long CARD_CONTENT_VERSION = 104; private Dao cardDao; private Set classNames; From 9fb71b98c4f3a9122c74092a40baf22f15e4e48a Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Wed, 14 Feb 2018 23:05:59 +0100 Subject: [PATCH 9/9] Xmage 1.4.27V4 --- Mage.Client/serverlist.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Mage.Client/serverlist.txt b/Mage.Client/serverlist.txt index 7e8a86d50f..fdceb7823d 100644 --- a/Mage.Client/serverlist.txt +++ b/Mage.Client/serverlist.txt @@ -1,7 +1,7 @@ XMage.de 1 (Europe/Germany) fast :xmage.de:17171 -woogerworks (North America/USA) :xmage.woogerworks.com:17171 -play.xmage.net (North America/Canada) :play.xmage.net:17171 -XMageBr. (South America/Brazil) :magic.ncs3sistemas.com.br:17171 +old xmage.de (Europe/Germany) :185.3.232.200:17171 +xmage.us (North America/USA) :xmage.us:17171 +XMage Players MTG:xmageplayersmtg.ddns.net:17171 XMage.tahiti :xmage.tahiti.one:443 Seedds Server (Asia) :115.29.203.80:17171 localhost -> connect to your local server (must be started):localhost:17171