diff --git a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java index e7f90f20c4b..57def9ddfcb 100644 --- a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java @@ -33,6 +33,7 @@ import java.util.*; import java.util.Map.Entry; import mage.ConditionalMana; import mage.MageObject; +import mage.MageObjectReference; import mage.Mana; import mage.abilities.*; import mage.abilities.costs.VariableCost; @@ -1027,7 +1028,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { findPlayables(game); if (!playableAbilities.isEmpty()) { for (ActivatedAbility ability : playableAbilities) { - if (ability.canActivate(playerId, game)) { + if (ability.canActivate(playerId, game).canActivate()) { if (ability.getEffects().hasOutcome(Outcome.PutLandInPlay)) { if (this.activateAbility(ability, game)) { return true; @@ -1058,7 +1059,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { if (game.getStack().isEmpty()) { if (!playableNonInstant.isEmpty()) { for (Card card : playableNonInstant) { - if (card.getSpellAbility().canActivate(playerId, game)) { + if (card.getSpellAbility().canActivate(playerId, game).canActivate()) { if (this.activateAbility(card.getSpellAbility(), game)) { return true; } @@ -1067,7 +1068,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } if (!playableAbilities.isEmpty()) { for (ActivatedAbility ability : playableAbilities) { - if (ability.canActivate(playerId, game)) { + if (ability.canActivate(playerId, game).canActivate()) { if (!(ability.getEffects().get(0) instanceof BecomesCreatureSourceEffect)) { if (this.activateAbility(ability, game)) { return true; @@ -1187,7 +1188,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { for (Mana avail : available) { if (mana.enough(avail)) { SpellAbility ability = card.getSpellAbility(); - if (ability != null && ability.canActivate(playerId, game) + if (ability != null && ability.canActivate(playerId, game).canActivate() && game.getContinuousEffects().preventedByRuleModification(GameEvent.getEvent(GameEvent.EventType.CAST_SPELL, ability.getSourceId(), ability.getSourceId(), playerId), ability, game, true)) { if (card.getCardType().contains(CardType.INSTANT) || card.hasAbility(FlashAbility.getInstance().getId(), game)) { @@ -1204,7 +1205,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } for (Permanent permanent : game.getBattlefield().getAllActivePermanents(playerId)) { for (ActivatedAbility ability : permanent.getAbilities().getActivatedAbilities(Zone.BATTLEFIELD)) { - if (!(ability instanceof ActivatedManaAbilityImpl) && ability.canActivate(playerId, game)) { + if (!(ability instanceof ActivatedManaAbilityImpl) && ability.canActivate(playerId, game).canActivate()) { if (ability instanceof EquipAbility && permanent.getAttachedTo() != null) { continue; } @@ -1231,7 +1232,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } for (Card card : graveyard.getCards(game)) { for (ActivatedAbility ability : card.getAbilities().getActivatedAbilities(Zone.GRAVEYARD)) { - if (ability.canActivate(playerId, game)) { + if (ability.canActivate(playerId, game).canActivate()) { ManaOptions abilityOptions = ability.getManaCosts().getOptions(); if (abilityOptions.isEmpty()) { playableAbilities.add(ability); @@ -1264,7 +1265,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { protected boolean playManaHandling(Ability ability, ManaCost unpaid, final Game game) { // log.info("paying for " + unpaid.getText()); - UUID spendAnyManaId = game.getContinuousEffects().asThough(ability.getSourceId(), AsThoughEffectType.SPEND_OTHER_MANA, ability, ability.getControllerId(), game); + MageObjectReference permittingObject = game.getContinuousEffects().asThough(ability.getSourceId(), AsThoughEffectType.SPEND_OTHER_MANA, ability, ability.getControllerId(), game); ManaCost cost; List producers; if (unpaid instanceof ManaCosts) { @@ -1308,7 +1309,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { for (ActivatedManaAbilityImpl manaAbility : getManaAbilitiesSortedByManaCount(mageObject, game)) { if (cost instanceof ColoredManaCost) { for (Mana netMana : manaAbility.getNetMana(game)) { - if (cost.testPay(netMana) || spendAnyManaId != null) { + if (cost.testPay(netMana) || permittingObject != null) { if (netMana instanceof ConditionalMana && !((ConditionalMana) netMana).apply(ability, game, getId(), cost)) { continue; } @@ -1323,7 +1324,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { for (ActivatedManaAbilityImpl manaAbility : getManaAbilitiesSortedByManaCount(mageObject, game)) { if (cost instanceof SnowManaCost) { for (Mana netMana : manaAbility.getNetMana(game)) { - if (cost.testPay(netMana) || spendAnyManaId != null) { + if (cost.testPay(netMana) || permittingObject != null) { if (netMana instanceof ConditionalMana && !((ConditionalMana) netMana).apply(ability, game, getId(), cost)) { continue; } @@ -1338,7 +1339,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { for (ActivatedManaAbilityImpl manaAbility : getManaAbilitiesSortedByManaCount(mageObject, game)) { if (cost instanceof HybridManaCost) { for (Mana netMana : manaAbility.getNetMana(game)) { - if (cost.testPay(netMana) || spendAnyManaId != null) { + if (cost.testPay(netMana) || permittingObject != null) { if (netMana instanceof ConditionalMana && !((ConditionalMana) netMana).apply(ability, game, getId(), cost)) { continue; } @@ -1353,7 +1354,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { for (ActivatedManaAbilityImpl manaAbility : getManaAbilitiesSortedByManaCount(mageObject, game)) { if (cost instanceof MonoHybridManaCost) { for (Mana netMana : manaAbility.getNetMana(game)) { - if (cost.testPay(netMana) || spendAnyManaId != null) { + if (cost.testPay(netMana) || permittingObject != null) { if (netMana instanceof ConditionalMana && !((ConditionalMana) netMana).apply(ability, game, getId(), cost)) { continue; } @@ -1368,7 +1369,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { for (ActivatedManaAbilityImpl manaAbility : getManaAbilitiesSortedByManaCount(mageObject, game)) { if (cost instanceof ColorlessManaCost) { for (Mana netMana : manaAbility.getNetMana(game)) { - if (cost.testPay(netMana) || spendAnyManaId != null) { + if (cost.testPay(netMana) || permittingObject != null) { if (netMana instanceof ConditionalMana && !((ConditionalMana) netMana).apply(ability, game, getId(), cost)) { continue; } @@ -1383,7 +1384,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { for (ActivatedManaAbilityImpl manaAbility : getManaAbilitiesSortedByManaCount(mageObject, game)) { if (cost instanceof GenericManaCost) { for (Mana netMana : manaAbility.getNetMana(game)) { - if (cost.testPay(netMana) || spendAnyManaId != null) { + if (cost.testPay(netMana) || permittingObject != null) { if (netMana instanceof ConditionalMana && !((ConditionalMana) netMana).apply(ability, game, getId(), cost)) { continue; } @@ -1397,7 +1398,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } // pay phyrexian life costs if (cost instanceof PhyrexianManaCost) { - if (cost.pay(null, game, null, playerId, false, null) || spendAnyManaId != null) { + if (cost.pay(null, game, null, playerId, false, null) || permittingObject != null) { return true; } } @@ -2386,7 +2387,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { private void playRemoval(List creatures, Game game) { for (UUID creatureId : creatures) { for (Card card : this.playableInstant) { - if (card.getSpellAbility().canActivate(playerId, game)) { + if (card.getSpellAbility().canActivate(playerId, game).canActivate()) { for (Effect effect : card.getSpellAbility().getEffects()) { if (effect.getOutcome() == Outcome.DestroyPermanent || effect.getOutcome() == Outcome.ReturnToHand) { if (card.getSpellAbility().getTargets().get(0).canTarget(creatureId, card.getSpellAbility(), game)) { @@ -2405,7 +2406,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { for (UUID creatureId : creatures) { Permanent creature = game.getPermanent(creatureId); for (Card card : this.playableInstant) { - if (card.getSpellAbility().canActivate(playerId, game)) { + if (card.getSpellAbility().canActivate(playerId, game).canActivate()) { for (Effect effect : card.getSpellAbility().getEffects()) { if (effect instanceof DamageTargetEffect) { if (card.getSpellAbility().getTargets().get(0).canTarget(creatureId, card.getSpellAbility(), game)) { diff --git a/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/GameStateEvaluator.java b/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/GameStateEvaluator.java index df9e389d031..cc54d690120 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/GameStateEvaluator.java +++ b/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/GameStateEvaluator.java @@ -25,17 +25,16 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.player.ai; import java.util.UUID; -import mage.constants.CardType; -import mage.constants.Zone; import mage.abilities.ActivatedAbility; import mage.abilities.keyword.DoubleStrikeAbility; import mage.abilities.keyword.FirstStrikeAbility; import mage.abilities.keyword.TrampleAbility; import mage.abilities.mana.ActivatedManaAbilityImpl; +import mage.constants.CardType; +import mage.constants.Zone; import mage.counters.BoostCounter; import mage.counters.Counter; import mage.counters.CounterType; @@ -71,18 +70,20 @@ public final class GameStateEvaluator { Player player = game.getPlayer(playerId); Player opponent = game.getPlayer(game.getOpponents(playerId).iterator().next()); if (game.checkIfGameIsOver()) { - if (player.hasLost() || opponent.hasWon()) + if (player.hasLost() || opponent.hasWon()) { return LOSE_SCORE; - if (opponent.hasLost() || player.hasWon()) + } + if (opponent.hasLost() || player.hasWon()) { return WIN_SCORE; + } } int lifeScore = (player.getLife() - opponent.getLife()) * LIFE_FACTOR; int poisonScore = (opponent.getCounters().getCount(CounterType.POISON) - player.getCounters().getCount(CounterType.POISON)) * LIFE_FACTOR * 2; int permanentScore = 0; - for (Permanent permanent: game.getBattlefield().getAllActivePermanents(playerId)) { + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(playerId)) { permanentScore += evaluatePermanent(permanent, game, ignoreTapped); } - for (Permanent permanent: game.getBattlefield().getAllActivePermanents(opponent.getId())) { + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(opponent.getId())) { permanentScore -= evaluatePermanent(permanent, game, ignoreTapped); } permanentScore *= PERMANENT_FACTOR; @@ -92,26 +93,29 @@ public final class GameStateEvaluator { handScore *= HAND_FACTOR; int score = lifeScore + poisonScore + permanentScore + handScore; - if (logger.isDebugEnabled()) + if (logger.isDebugEnabled()) { logger.debug("game state for player " + player.getName() + " evaluated to- lifeScore:" + lifeScore + " permanentScore:" + permanentScore + " handScore:" + handScore + " total:" + score); + } return score; } public static int evaluatePermanent(Permanent permanent, Game game, boolean ignoreTapped) { int value = 0; - if (ignoreTapped) + if (ignoreTapped) { value = 5; - else - value = permanent.isTapped()?4:5; + } else { + value = permanent.isTapped() ? 4 : 5; + } if (permanent.getCardType().contains(CardType.CREATURE)) { value += evaluateCreature(permanent, game) * CREATURE_FACTOR; } value += permanent.getAbilities().getActivatedManaAbilities(Zone.BATTLEFIELD).size(); - for (ActivatedAbility ability: permanent.getAbilities().getActivatedAbilities(Zone.BATTLEFIELD)) { - if (!(ability instanceof ActivatedManaAbilityImpl) && ability.canActivate(ability.getControllerId(), game)) + for (ActivatedAbility ability : permanent.getAbilities().getActivatedAbilities(Zone.BATTLEFIELD)) { + if (!(ability instanceof ActivatedManaAbilityImpl) && ability.canActivate(ability.getControllerId(), game).canActivate()) { value += ability.getEffects().size(); + } } - for (Counter counter: permanent.getCounters(game).values()) { + for (Counter counter : permanent.getCounters(game).values()) { if (!(counter instanceof BoostCounter)) { value += counter.getCount(); } @@ -133,9 +137,9 @@ public final class GameStateEvaluator { // value += 2; value += creature.getAbilities().getEvasionAbilities().size(); value += creature.getAbilities().getProtectionAbilities().size(); - value += creature.getAbilities().containsKey(FirstStrikeAbility.getInstance().getId())?1:0; - value += creature.getAbilities().containsKey(DoubleStrikeAbility.getInstance().getId())?2:0; - value += creature.getAbilities().containsKey(TrampleAbility.getInstance().getId())?1:0; + value += creature.getAbilities().containsKey(FirstStrikeAbility.getInstance().getId()) ? 1 : 0; + value += creature.getAbilities().containsKey(DoubleStrikeAbility.getInstance().getId()) ? 2 : 0; + value += creature.getAbilities().containsKey(TrampleAbility.getInstance().getId()) ? 1 : 0; return value; } diff --git a/Mage.Sets/src/mage/cards/a/AetherworksMarvel.java b/Mage.Sets/src/mage/cards/a/AetherworksMarvel.java index 2cef8504452..5e51eb25188 100644 --- a/Mage.Sets/src/mage/cards/a/AetherworksMarvel.java +++ b/Mage.Sets/src/mage/cards/a/AetherworksMarvel.java @@ -29,6 +29,7 @@ package mage.cards.a; import java.util.Set; import java.util.UUID; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.PutIntoGraveFromBattlefieldAllTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -55,7 +56,7 @@ import mage.target.common.TargetCardInLibrary; public class AetherworksMarvel extends CardImpl { public AetherworksMarvel(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{4}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); addSuperType(SuperType.LEGENDARY); // Whenever a permanent you control is put into a graveyard, you get {E}. @@ -105,7 +106,7 @@ class AetherworksMarvelEffect extends OneShotEffect { TargetCard target = new TargetCardInLibrary(0, 1, new FilterNonlandCard("card to cast without paying its mana cost")); if (controller.choose(Outcome.PlayForFree, cards, target, game)) { Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); - if (card != null && controller.cast(card.getSpellAbility(), game, true)) { + if (card != null && controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game))) { cards.remove(card); } } diff --git a/Mage.Sets/src/mage/cards/b/BrainInAJar.java b/Mage.Sets/src/mage/cards/b/BrainInAJar.java index bf9b9a3a9c8..912cb77a4d3 100644 --- a/Mage.Sets/src/mage/cards/b/BrainInAJar.java +++ b/Mage.Sets/src/mage/cards/b/BrainInAJar.java @@ -28,6 +28,7 @@ package mage.cards.b; import java.util.UUID; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.RemoveVariableCountersSourceCost; @@ -114,7 +115,7 @@ class BrainInAJarCastEffect extends OneShotEffect { controller.chooseTarget(outcome, target, source, game); Card card = game.getCard(target.getFirstTarget()); if (card != null) { - controller.cast(card.getSpellAbility(), game, true); + controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } } return true; diff --git a/Mage.Sets/src/mage/cards/b/BrilliantUltimatum.java b/Mage.Sets/src/mage/cards/b/BrilliantUltimatum.java index f91c2b78046..2071278bc9f 100644 --- a/Mage.Sets/src/mage/cards/b/BrilliantUltimatum.java +++ b/Mage.Sets/src/mage/cards/b/BrilliantUltimatum.java @@ -31,6 +31,7 @@ import java.util.ArrayList; import java.util.List; import java.util.UUID; import mage.MageObject; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.*; @@ -50,7 +51,7 @@ import mage.target.common.TargetOpponent; public class BrilliantUltimatum extends CardImpl { public BrilliantUltimatum(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{W}{W}{U}{U}{U}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{W}{W}{U}{U}{U}{B}{B}"); // Exile the top five cards of your library. An opponent separates those cards into two piles. You may play any number of cards from one of those piles without paying their mana costs. this.getSpellAbility().addEffect(new BrilliantUltimatumEffect()); @@ -136,7 +137,7 @@ class BrilliantUltimatumEffect extends OneShotEffect { TargetCard targetExiledCard = new TargetCard(Zone.EXILED, new FilterCard()); if (controller.chooseTarget(Outcome.PlayForFree, selectedPile, targetExiledCard, source, game)) { Card card = selectedPile.get(targetExiledCard.getFirstTarget(), game); - if (controller.playCard(card, game, true, true)) { + if (controller.playCard(card, game, true, true, new MageObjectReference(source.getSourceObject(game), game))) { selectedPileCards.remove(card); selectedPile.remove(card); } diff --git a/Mage.Sets/src/mage/cards/b/BringToLight.java b/Mage.Sets/src/mage/cards/b/BringToLight.java index 34fbe118fb3..8ac6e6a55a9 100644 --- a/Mage.Sets/src/mage/cards/b/BringToLight.java +++ b/Mage.Sets/src/mage/cards/b/BringToLight.java @@ -28,6 +28,7 @@ package mage.cards.b; import java.util.UUID; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.dynamicvalue.common.ColorsOfManaSpentToCastCount; import mage.abilities.effects.OneShotEffect; @@ -54,7 +55,7 @@ import org.apache.log4j.Logger; public class BringToLight extends CardImpl { public BringToLight(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{G}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{G}{U}"); // Converge-Search your library for a creature, instant, or sorcery card with converted mana // cost less than or equal to the number of colors of mana spent to cast Bring to Light, exile that card, @@ -108,7 +109,7 @@ class BringToLightEffect extends OneShotEffect { if (card != null) { if (controller.chooseUse(outcome, "Cast " + card.getName() + " without paying its mana cost?", source, game)) { if (card.getSpellAbility() != null) { - controller.cast(card.getSpellAbility(), game, true); + controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } else { Logger.getLogger(BringToLightEffect.class).error("Bring to Light: spellAbility == null " + card.getName()); } diff --git a/Mage.Sets/src/mage/cards/c/ChandraAblaze.java b/Mage.Sets/src/mage/cards/c/ChandraAblaze.java index 912937767a5..d2cb672265f 100644 --- a/Mage.Sets/src/mage/cards/c/ChandraAblaze.java +++ b/Mage.Sets/src/mage/cards/c/ChandraAblaze.java @@ -29,6 +29,7 @@ package mage.cards.c; import java.util.Set; import java.util.UUID; +import mage.MageObjectReference; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; @@ -41,8 +42,8 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.SuperType; import mage.filter.FilterCard; import mage.filter.predicate.Predicates; @@ -51,8 +52,8 @@ import mage.filter.predicate.mageobject.ColorPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetCardInGraveyard; import mage.target.common.TargetAnyTarget; +import mage.target.common.TargetCardInGraveyard; import mage.target.common.TargetDiscard; /** @@ -62,7 +63,7 @@ import mage.target.common.TargetDiscard; public class ChandraAblaze extends CardImpl { public ChandraAblaze(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.PLANESWALKER},"{4}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{4}{R}{R}"); this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.CHANDRA); @@ -198,7 +199,7 @@ class ChandraAblazeEffect5 extends OneShotEffect { if (player.choose(outcome, target, source.getSourceId(), game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { - player.cast(card.getSpellAbility(), game, true); + player.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); player.getGraveyard().remove(card); cards.remove(card); } diff --git a/Mage.Sets/src/mage/cards/c/ChandraPyromaster.java b/Mage.Sets/src/mage/cards/c/ChandraPyromaster.java index 75c5b5f59f8..c49eedb0859 100644 --- a/Mage.Sets/src/mage/cards/c/ChandraPyromaster.java +++ b/Mage.Sets/src/mage/cards/c/ChandraPyromaster.java @@ -287,17 +287,18 @@ class ChandraPyromasterEffect3 extends OneShotEffect { if (controller.chooseTarget(Outcome.PlayForFree, cards, target, source, game)) { Card card = cards.get(target.getFirstTarget(), game); if (card != null) { + MageObjectReference mor = new MageObjectReference(source.getSourceObject(game), game); if (controller.chooseUse(outcome, "Do you wish to cast copy 1 of " + card.getName(), source, game)) { Card copy1 = game.copyCard(card, source, source.getControllerId()); - controller.cast(copy1.getSpellAbility(), game, true); + controller.cast(copy1.getSpellAbility(), game, true, mor); } if (controller.chooseUse(outcome, "Do you wish to cast copy 2 of " + card.getName(), source, game)) { Card copy2 = game.copyCard(card, source, source.getControllerId()); - controller.cast(copy2.getSpellAbility(), game, true); + controller.cast(copy2.getSpellAbility(), game, true, mor); } if (controller.chooseUse(outcome, "Do you wish to cast copy 3 of " + card.getName(), source, game)) { Card copy3 = game.copyCard(card, source, source.getControllerId()); - controller.cast(copy3.getSpellAbility(), game, true); + controller.cast(copy3.getSpellAbility(), game, true, mor); } return true; } diff --git a/Mage.Sets/src/mage/cards/c/ChandraTorchOfDefiance.java b/Mage.Sets/src/mage/cards/c/ChandraTorchOfDefiance.java index 3b8f4c0adbb..d004e96cea5 100644 --- a/Mage.Sets/src/mage/cards/c/ChandraTorchOfDefiance.java +++ b/Mage.Sets/src/mage/cards/c/ChandraTorchOfDefiance.java @@ -29,22 +29,23 @@ package mage.cards.c; import java.util.UUID; import mage.MageObject; +import mage.MageObjectReference; import mage.Mana; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.mana.BasicManaEffect; import mage.abilities.effects.common.DamagePlayersEffect; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.GetEmblemEffect; +import mage.abilities.effects.mana.BasicManaEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.SuperType; import mage.constants.TargetController; import mage.constants.Zone; @@ -120,7 +121,7 @@ class ChandraTorchOfDefianceEffect extends OneShotEffect { controller.moveCardToExileWithInfo(card, source.getSourceId(), sourceObject.getIdName(), source.getSourceId(), game, Zone.LIBRARY, true); if (!card.getManaCost().isEmpty()) { if (controller.chooseUse(Outcome.Benefit, "Cast the card? (You still pay the costs)", source, game) && !card.isLand()) { - exiledCardWasCast = controller.cast(card.getSpellAbility(), game, false); + exiledCardWasCast = controller.cast(card.getSpellAbility(), game, false, new MageObjectReference(source.getSourceObject(game), game)); } } if (!exiledCardWasCast) { diff --git a/Mage.Sets/src/mage/cards/c/CharmedPendant.java b/Mage.Sets/src/mage/cards/c/CharmedPendant.java index 325086fe560..f135dc3527f 100644 --- a/Mage.Sets/src/mage/cards/c/CharmedPendant.java +++ b/Mage.Sets/src/mage/cards/c/CharmedPendant.java @@ -98,12 +98,12 @@ class CharmedPendantAbility extends ActivatedManaAbilityImpl { } @Override - public boolean canActivate(UUID playerId, Game game) { + public ActivationStatus canActivate(UUID playerId, Game game) { Player player = game.getPlayer(playerId); if (player != null && !player.isInPayManaMode()) { // while paying the costs of a spell you cant activate this return super.canActivate(playerId, game); } - return false; + return ActivationStatus.getFalse(); } @Override diff --git a/Mage.Sets/src/mage/cards/c/Counterlash.java b/Mage.Sets/src/mage/cards/c/Counterlash.java index b1ad8d92250..e7ef1279a04 100644 --- a/Mage.Sets/src/mage/cards/c/Counterlash.java +++ b/Mage.Sets/src/mage/cards/c/Counterlash.java @@ -27,7 +27,11 @@ */ package mage.cards.c; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; import mage.MageObject; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; @@ -45,10 +49,6 @@ import mage.players.Player; import mage.target.TargetSpell; import mage.target.common.TargetCardInHand; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - /** * * @author BetaSteward @@ -56,8 +56,7 @@ import java.util.UUID; public class Counterlash extends CardImpl { public Counterlash(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{4}{U}{U}"); - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{U}{U}"); // Counter target spell. You may cast a nonland card in your hand that shares a card type with that spell without paying its mana cost. this.getSpellAbility().addTarget(new TargetSpell()); @@ -99,7 +98,7 @@ class CounterlashEffect extends OneShotEffect { if (player.chooseUse(Outcome.PutCardInPlay, "Cast a nonland card in your hand that shares a card type with that spell without paying its mana cost?", source, game)) { FilterCard filter = new FilterCard(); List> types = new ArrayList<>(); - for (CardType type: stackObject.getCardType()) { + for (CardType type : stackObject.getCardType()) { if (type != CardType.LAND) { types.add(new CardTypePredicate(type)); } @@ -109,7 +108,7 @@ class CounterlashEffect extends OneShotEffect { if (player.choose(Outcome.PutCardInPlay, target, source.getSourceId(), game)) { Card card = player.getHand().get(target.getFirstTarget(), game); if (card != null) { - player.cast(card.getSpellAbility(), game, true); + player.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } } } diff --git a/Mage.Sets/src/mage/cards/d/DarksteelGarrison.java b/Mage.Sets/src/mage/cards/d/DarksteelGarrison.java index bdbba6de0a0..472cd594df8 100644 --- a/Mage.Sets/src/mage/cards/d/DarksteelGarrison.java +++ b/Mage.Sets/src/mage/cards/d/DarksteelGarrison.java @@ -112,14 +112,15 @@ class FortifyAbility extends ActivatedAbilityImpl { } @Override - public boolean canActivate(UUID playerId, Game game) { - if (super.canActivate(playerId, game)) { + public ActivationStatus canActivate(UUID playerId, Game game) { + ActivationStatus activationStatus = super.canActivate(playerId, game); + if (activationStatus.canActivate()) { Permanent permanent = game.getPermanent(sourceId); if (permanent != null && permanent.hasSubtype(SubType.FORTIFICATION, game)) { - return true; + return activationStatus; } } - return false; + return ActivationStatus.getFalse(); } public FortifyAbility(final FortifyAbility ability) { diff --git a/Mage.Sets/src/mage/cards/d/DereviEmpyrialTactician.java b/Mage.Sets/src/mage/cards/d/DereviEmpyrialTactician.java index 2ac726055cf..78a54e30079 100644 --- a/Mage.Sets/src/mage/cards/d/DereviEmpyrialTactician.java +++ b/Mage.Sets/src/mage/cards/d/DereviEmpyrialTactician.java @@ -41,8 +41,8 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.SuperType; import mage.constants.Zone; import mage.game.Game; @@ -139,10 +139,10 @@ class DereviEmpyrialTacticianAbility extends ActivatedAbilityImpl { } @Override - public boolean canActivate(UUID playerId, Game game) { + public ActivationStatus canActivate(UUID playerId, Game game) { Zone currentZone = game.getState().getZone(this.getSourceId()); if (currentZone == null || currentZone != Zone.COMMAND) { - return false; + return ActivationStatus.getFalse(); } return super.canActivate(playerId, game); } diff --git a/Mage.Sets/src/mage/cards/d/DescendantsPath.java b/Mage.Sets/src/mage/cards/d/DescendantsPath.java index c1eabec49b9..d1902d961fe 100644 --- a/Mage.Sets/src/mage/cards/d/DescendantsPath.java +++ b/Mage.Sets/src/mage/cards/d/DescendantsPath.java @@ -29,6 +29,7 @@ package mage.cards.d; import java.util.UUID; import mage.MageObject; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -47,12 +48,12 @@ import mage.players.Player; /** * * @author noxx - + * */ public class DescendantsPath extends CardImpl { public DescendantsPath(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}"); // At the beginning of your upkeep, reveal the top card of your library. If it's a creature card that shares a creature type with a creature you control, you may cast that card without paying its mana cost. Otherwise, put that card on the bottom of your library. Ability ability = new BeginningOfUpkeepTriggeredAbility(new DescendantsPathEffect(), TargetController.YOU, false); @@ -99,7 +100,7 @@ class DescendantsPathEffect extends OneShotEffect { if (card.isCreature()) { FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); boolean found = false; - for (Permanent permanent: game.getBattlefield().getAllActivePermanents(filter, controller.getId(), game)) { + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, controller.getId(), game)) { if (card.shareSubtypes(permanent, game)) { found = true; break; @@ -108,7 +109,7 @@ class DescendantsPathEffect extends OneShotEffect { if (found) { game.informPlayers(sourceObject.getLogName() + ": Found a creature that shares a creature type with the revealed card."); if (controller.chooseUse(Outcome.Benefit, "Cast the card?", source, game)) { - controller.cast(card.getSpellAbility(), game, true); + controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } else { game.informPlayers(sourceObject.getLogName() + ": " + controller.getLogName() + " canceled casting the card."); controller.getLibrary().putOnBottom(card, game); @@ -128,4 +129,3 @@ class DescendantsPathEffect extends OneShotEffect { return false; } } - diff --git a/Mage.Sets/src/mage/cards/d/DiluvianPrimordial.java b/Mage.Sets/src/mage/cards/d/DiluvianPrimordial.java index 073afab4331..57a81ea366c 100644 --- a/Mage.Sets/src/mage/cards/d/DiluvianPrimordial.java +++ b/Mage.Sets/src/mage/cards/d/DiluvianPrimordial.java @@ -29,6 +29,7 @@ package mage.cards.d; import java.util.UUID; import mage.MageInt; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.ContinuousEffect; @@ -39,9 +40,9 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.Predicates; @@ -63,7 +64,7 @@ import mage.target.targetpointer.FixedTarget; public class DiluvianPrimordial extends CardImpl { public DiluvianPrimordial(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{U}{U}"); this.subtype.add(SubType.AVATAR); this.power = new MageInt(5); @@ -128,7 +129,7 @@ class DiluvianPrimordialEffect extends OneShotEffect { Card targetCard = game.getCard(target.getFirstTarget()); if (targetCard != null) { if (controller.chooseUse(outcome, "Cast " + targetCard.getLogName() + '?', source, game)) { - if (controller.cast(targetCard.getSpellAbility(), game, true)) { + if (controller.cast(targetCard.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game))) { ContinuousEffect effect = new DiluvianPrimordialReplacementEffect(); effect.setTargetPointer(new FixedTarget(targetCard.getId(), game.getState().getZoneChangeCounter(targetCard.getId()))); game.addEffect(effect, source); diff --git a/Mage.Sets/src/mage/cards/d/DjinnOfWishes.java b/Mage.Sets/src/mage/cards/d/DjinnOfWishes.java index a6ca79ebae6..e182723c98c 100644 --- a/Mage.Sets/src/mage/cards/d/DjinnOfWishes.java +++ b/Mage.Sets/src/mage/cards/d/DjinnOfWishes.java @@ -30,6 +30,7 @@ package mage.cards.d; import java.util.UUID; import mage.MageInt; import mage.MageObject; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -40,8 +41,8 @@ import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.*; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; @@ -56,7 +57,7 @@ public class DjinnOfWishes extends CardImpl { private static final String ruleText = "{this} enters the battlefield with three wish counters on it"; public DjinnOfWishes(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{U}"); this.subtype.add(SubType.DJINN); this.color.setBlue(true); @@ -103,8 +104,8 @@ class DjinnOfWishesEffect extends OneShotEffect { Cards cards = new CardsImpl(card); controller.revealCards(sourceObject.getIdName(), cards, game); if (!controller.chooseUse(Outcome.PlayForFree, "Play " + card.getName() + " without paying its mana cost?", source, game) - || !controller.playCard(card, game, true, true)) { - card.moveToZone(Zone.EXILED, source.getSourceId(), game, false); + || !controller.playCard(card, game, true, true, new MageObjectReference(source.getSourceObject(game), game))) { + controller.moveCards(card, Zone.EXILED, source, game); } return true; } diff --git a/Mage.Sets/src/mage/cards/d/DrainPower.java b/Mage.Sets/src/mage/cards/d/DrainPower.java index 8e81cc943cb..474aa972db4 100644 --- a/Mage.Sets/src/mage/cards/d/DrainPower.java +++ b/Mage.Sets/src/mage/cards/d/DrainPower.java @@ -102,7 +102,7 @@ class DrainPowerEffect extends OneShotEffect { List ignorePermanents = new ArrayList<>(); Map> manaAbilitiesMap = new HashMap<>(); TargetPermanent target = null; - + while (true) { manaAbilitiesMap.clear(); for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, targetPlayer.getId(), game)) { @@ -112,7 +112,7 @@ class DrainPowerEffect extends OneShotEffect { for (Ability ability : permanent.getAbilities()) { if (ability instanceof ActivatedAbility && ability.getAbilityType() == AbilityType.MANA) { ActivatedManaAbilityImpl manaAbility = (ActivatedManaAbilityImpl) ability; - if (manaAbility != null && manaAbility.canActivate(targetPlayer.getId(), game)) { + if (manaAbility != null && manaAbility.canActivate(targetPlayer.getId(), game).canActivate()) { // canActivate can't check for mana abilities that require a mana cost, if the payment isn't possible (Cabal Coffers etc) // so it's necessary to filter them out manually - might be buggy in some fringe cases for (ManaCost manaCost : manaAbility.getManaCosts()) { diff --git a/Mage.Sets/src/mage/cards/e/EliteArcanist.java b/Mage.Sets/src/mage/cards/e/EliteArcanist.java index adced54e581..69b5f382d07 100644 --- a/Mage.Sets/src/mage/cards/e/EliteArcanist.java +++ b/Mage.Sets/src/mage/cards/e/EliteArcanist.java @@ -29,6 +29,7 @@ package mage.cards.e; import java.util.UUID; import mage.MageInt; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -40,8 +41,8 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.mageobject.CardTypePredicate; @@ -57,7 +58,7 @@ import mage.target.TargetCard; public class EliteArcanist extends CardImpl { public EliteArcanist(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WIZARD); @@ -79,7 +80,7 @@ public class EliteArcanist extends CardImpl { @Override public void adjustCosts(Ability ability, Game game) { - if(ability instanceof SimpleActivatedAbility){ + if (ability instanceof SimpleActivatedAbility) { Permanent sourcePermanent = game.getPermanent(ability.getSourceId()); if (sourcePermanent != null && sourcePermanent.getImprinted() != null && !sourcePermanent.getImprinted().isEmpty()) { Card imprintedInstant = game.getCard(sourcePermanent.getImprinted().get(0)); @@ -103,7 +104,8 @@ public class EliteArcanist extends CardImpl { class EliteArcanistImprintEffect extends OneShotEffect { private static final FilterCard filter = new FilterCard("instant card from your hand"); - static { + + static { filter.add(new CardTypePredicate(CardType.INSTANT)); } @@ -174,10 +176,10 @@ class EliteArcanistCopyEffect extends OneShotEffect { if (controller != null) { Card copiedCard = game.copyCard(imprintedInstant, source, source.getControllerId()); if (copiedCard != null) { - game.getExile().add(source.getSourceId(), "",copiedCard); + game.getExile().add(source.getSourceId(), "", copiedCard); game.getState().setZone(copiedCard.getId(), Zone.EXILED); if (controller.chooseUse(outcome, "Cast the copied card without paying mana cost?", source, game)) { - return controller.cast(copiedCard.getSpellAbility(), game, true); + return controller.cast(copiedCard.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } } } diff --git a/Mage.Sets/src/mage/cards/e/EpicExperiment.java b/Mage.Sets/src/mage/cards/e/EpicExperiment.java index a387fb06561..98eed59786b 100644 --- a/Mage.Sets/src/mage/cards/e/EpicExperiment.java +++ b/Mage.Sets/src/mage/cards/e/EpicExperiment.java @@ -29,6 +29,7 @@ package mage.cards.e; import java.util.UUID; import mage.MageObject; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.*; @@ -51,7 +52,7 @@ import mage.target.TargetCard; public class EpicExperiment extends CardImpl { public EpicExperiment(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{U}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{U}{R}"); // Exile the top X cards of your library. For each instant and sorcery card with // converted mana cost X or less among them, you may cast that card without paying @@ -105,7 +106,7 @@ class EpicExperimentEffect extends OneShotEffect { if (controller.choose(Outcome.PlayForFree, cardsToCast, targetCard, game)) { Card card = game.getCard(targetCard.getFirstTarget()); if (card != null) { - if (controller.cast(card.getSpellAbility(), game, true)) { + if (controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game))) { cardsToCast.remove(card); } else { game.informPlayer(controller, "You're not able to cast " + card.getIdName() + " or you canceled the casting."); diff --git a/Mage.Sets/src/mage/cards/e/EtaliPrimalStorm.java b/Mage.Sets/src/mage/cards/e/EtaliPrimalStorm.java index f48ef2ec728..1f8b98ef32c 100644 --- a/Mage.Sets/src/mage/cards/e/EtaliPrimalStorm.java +++ b/Mage.Sets/src/mage/cards/e/EtaliPrimalStorm.java @@ -32,6 +32,7 @@ import java.util.Set; import java.util.UUID; import mage.MageInt; import mage.MageObject; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -41,8 +42,8 @@ import mage.cards.CardSetInfo; import mage.cards.Cards; import mage.cards.CardsImpl; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.SuperType; import mage.constants.Zone; import mage.filter.FilterCard; @@ -127,7 +128,7 @@ class EtaliPrimalStormEffect extends OneShotEffect { cardsToCast.addAll(currentExiledCards); boolean alreadyCast = false; while (!cardsToCast.isEmpty()) { - if (!controller.chooseUse(Outcome.PlayForFree, "Cast a" + (alreadyCast ? "nother" : "" ) + " card exiled with " + sourceObject.getLogName() + " without paying its mana cost?", source, game)) { + if (!controller.chooseUse(Outcome.PlayForFree, "Cast a" + (alreadyCast ? "nother" : "") + " card exiled with " + sourceObject.getLogName() + " without paying its mana cost?", source, game)) { break; } TargetCard targetCard = new TargetCard(1, Zone.EXILED, new FilterCard("nonland card to cast for free")); @@ -135,7 +136,7 @@ class EtaliPrimalStormEffect extends OneShotEffect { alreadyCast = true; Card card = game.getCard(targetCard.getFirstTarget()); if (card != null) { - if (controller.cast(card.getSpellAbility(), game, true)) { + if (controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game))) { cardsToCast.remove(card); } else { game.informPlayer(controller, "You're not able to cast " + card.getIdName() + " or you canceled the casting."); diff --git a/Mage.Sets/src/mage/cards/e/EyeOfTheStorm.java b/Mage.Sets/src/mage/cards/e/EyeOfTheStorm.java index 8739f843004..2672e128c6c 100644 --- a/Mage.Sets/src/mage/cards/e/EyeOfTheStorm.java +++ b/Mage.Sets/src/mage/cards/e/EyeOfTheStorm.java @@ -28,6 +28,7 @@ package mage.cards.e; import java.util.UUID; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; @@ -180,7 +181,7 @@ class EyeOfTheStormEffect1 extends OneShotEffect { if (cardToCopy != null) { Card copy = game.copyCard(cardToCopy, source, source.getControllerId()); if (spellController.chooseUse(outcome, "Cast " + copy.getIdName() + " without paying mana cost?", source, game)) { - spellController.cast(copy.getSpellAbility(), game, true); + spellController.cast(copy.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } } } diff --git a/Mage.Sets/src/mage/cards/g/Galvanoth.java b/Mage.Sets/src/mage/cards/g/Galvanoth.java index a8f996d0e40..9ba91c83f94 100644 --- a/Mage.Sets/src/mage/cards/g/Galvanoth.java +++ b/Mage.Sets/src/mage/cards/g/Galvanoth.java @@ -29,6 +29,7 @@ package mage.cards.g; import java.util.UUID; import mage.MageInt; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -86,7 +87,7 @@ class GalvanothEffect extends OneShotEffect { controller.lookAtCards(source, null, new CardsImpl(card), game); if (card.isInstant() || card.isSorcery()) { if (controller.chooseUse(Outcome.PlayForFree, "Cast " + card.getName() + " without paying its mana cost?", source, game)) { - controller.cast(card.getSpellAbility(), game, true); + controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } } } diff --git a/Mage.Sets/src/mage/cards/g/GoblinDarkDwellers.java b/Mage.Sets/src/mage/cards/g/GoblinDarkDwellers.java index 31b558779ce..bc7291219a8 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinDarkDwellers.java +++ b/Mage.Sets/src/mage/cards/g/GoblinDarkDwellers.java @@ -29,6 +29,7 @@ package mage.cards.g; import java.util.UUID; import mage.MageInt; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.ContinuousEffect; @@ -39,10 +40,10 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.ComparisonType; import mage.constants.Duration; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterInstantOrSorceryCard; import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; @@ -58,22 +59,22 @@ import mage.target.targetpointer.FixedTarget; * @author fireshoes */ public class GoblinDarkDwellers extends CardImpl { - + private static final FilterInstantOrSorceryCard filter = new FilterInstantOrSorceryCard("instant or sorcery card with converted mana cost 3 or less"); - + static { filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, 4)); } public GoblinDarkDwellers(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{R}"); this.subtype.add(SubType.GOBLIN); this.power = new MageInt(4); this.toughness = new MageInt(4); // Menace this.addAbility(new MenaceAbility()); - + // When Goblin Dark-Dwellers enters the battlefield, you may cast target instant or sorcery card with converted mana cost 3 or less // from your graveyard without paying its mana cost. If that card would be put into your graveyard this turn, exile it instead. Ability ability = new EntersBattlefieldTriggeredAbility(new GoblinDarkDwellersEffect()); @@ -115,7 +116,7 @@ class GoblinDarkDwellersEffect extends OneShotEffect { Card card = game.getCard(this.getTargetPointer().getFirst(game, source)); if (card != null) { if (controller.chooseUse(outcome, "Cast " + card.getLogName() + '?', source, game)) { - if (controller.cast(card.getSpellAbility(), game, true)) { + if (controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game))) { ContinuousEffect effect = new GoblinDarkDwellersReplacementEffect(card.getId()); effect.setTargetPointer(new FixedTarget(card.getId(), game.getState().getZoneChangeCounter(card.getId()))); game.addEffect(effect, source); diff --git a/Mage.Sets/src/mage/cards/g/GreaterGargadon.java b/Mage.Sets/src/mage/cards/g/GreaterGargadon.java index d7f6fd5b345..4a2ce4121df 100644 --- a/Mage.Sets/src/mage/cards/g/GreaterGargadon.java +++ b/Mage.Sets/src/mage/cards/g/GreaterGargadon.java @@ -53,10 +53,8 @@ import mage.target.common.TargetControlledPermanent; */ public class GreaterGargadon extends CardImpl { - - public GreaterGargadon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{9}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{9}{R}"); this.subtype.add(SubType.BEAST); this.power = new MageInt(9); @@ -78,14 +76,14 @@ public class GreaterGargadon extends CardImpl { } } - class GreaterGargadonAbility extends ActivatedAbilityImpl { - + private static final FilterControlledPermanent filter = new FilterControlledPermanent("artifact, creature, or land"); + static { filter.add(Predicates.or(new CardTypePredicate(CardType.ARTIFACT), new CardTypePredicate(CardType.CREATURE), new CardTypePredicate(CardType.LAND))); } - + public GreaterGargadonAbility() { super(Zone.EXILED, new RemoveCounterSourceEffect(CounterType.TIME.createInstance()), new SacrificeTargetCost(new TargetControlledPermanent(filter))); } @@ -100,16 +98,14 @@ class GreaterGargadonAbility extends ActivatedAbilityImpl { } @Override - public boolean canActivate(UUID playerId, Game game) { + public ActivationStatus canActivate(UUID playerId, Game game) { Card card = game.getCard(this.getSourceId()); - if(super.canActivate(playerId, game) && card != null && card.getCounters(game).getCount(CounterType.TIME) > 0){ - return true; + if (card == null || card.getCounters(game).getCount(CounterType.TIME) == 0) { + return ActivationStatus.getFalse(); } - return false; + return super.canActivate(playerId, game); } - - @Override public String getRule() { return super.getRule() + " Activate this ability only if Greater Gargadon is suspended."; diff --git a/Mage.Sets/src/mage/cards/g/GreenbeltRampager.java b/Mage.Sets/src/mage/cards/g/GreenbeltRampager.java index e7f78f9695f..bedf23abc9e 100644 --- a/Mage.Sets/src/mage/cards/g/GreenbeltRampager.java +++ b/Mage.Sets/src/mage/cards/g/GreenbeltRampager.java @@ -25,19 +25,19 @@ * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. */ - package mage.cards.g; import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.costs.common.PayEnergyCost; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; @@ -82,18 +82,18 @@ public class GreenbeltRampager extends CardImpl { @Override public boolean apply(Game game, Ability source) { - Permanent card = game.getPermanent(source.getSourceId()); - Player player = game.getPlayer(source.getControllerId()); - - if (card == null || player == null) return false; - - if (player.getCounters().getCount(CounterType.ENERGY) > 1) { - player.getCounters().removeCounter(CounterType.ENERGY, 2); - } else { - card.moveToZone(Zone.HAND, source.getSourceId(), game, true); - player.addCounters(CounterType.ENERGY.createInstance(), game); + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; } + if (!new PayEnergyCost(2).pay(source, game, source.getSourceId(), source.getControllerId(), true)) { + Permanent sourceObject = source.getSourcePermanentIfItStillExists(game); + if (sourceObject != null) { + controller.moveCards(sourceObject, Zone.HAND, source, game); + controller.addCounters(CounterType.ENERGY.createInstance(), game); + } + } return true; } diff --git a/Mage.Sets/src/mage/cards/g/Guile.java b/Mage.Sets/src/mage/cards/g/Guile.java index 33c35bd6b3a..5684559d104 100644 --- a/Mage.Sets/src/mage/cards/g/Guile.java +++ b/Mage.Sets/src/mage/cards/g/Guile.java @@ -29,6 +29,7 @@ package mage.cards.g; import java.util.UUID; import mage.MageInt; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.PutIntoGraveFromAnywhereSourceTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; @@ -39,9 +40,9 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; @@ -57,7 +58,7 @@ import mage.players.Player; public class Guile extends CardImpl { public Guile(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{U}{U}"); this.subtype.add(SubType.ELEMENTAL); this.subtype.add(SubType.INCARNATION); this.power = new MageInt(6); @@ -113,7 +114,7 @@ class GuileReplacementEffect extends ReplacementEffectImpl { if (!spell.isCopy()) { Card spellCard = spell.getCard(); if (spellCard != null && controller.chooseUse(Outcome.PlayForFree, "Cast " + spellCard.getIdName() + " for free?", source, game)) { - controller.playCard(spellCard, game, true, true); + controller.playCard(spellCard, game, true, true, new MageObjectReference(source.getSourceObject(game), game)); } return true; } diff --git a/Mage.Sets/src/mage/cards/h/HarnessTheStorm.java b/Mage.Sets/src/mage/cards/h/HarnessTheStorm.java index 2af3d7ebf86..01d8ed1e990 100644 --- a/Mage.Sets/src/mage/cards/h/HarnessTheStorm.java +++ b/Mage.Sets/src/mage/cards/h/HarnessTheStorm.java @@ -28,6 +28,7 @@ package mage.cards.h; import java.util.UUID; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.effects.Effect; @@ -55,7 +56,7 @@ import mage.watchers.common.CastFromHandWatcher; public class HarnessTheStorm extends CardImpl { public HarnessTheStorm(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}"); // Whenever you cast an instant or sorcery spell from your hand, you may cast target card with the same name as that spell from your graveyard. this.addAbility(new HarnessTheStormTriggeredAbility(new HarnessTheStormEffect(), @@ -132,7 +133,7 @@ class HarnessTheStormEffect extends OneShotEffect { Card card = controller.getGraveyard().get(getTargetPointer().getFirst(game, source), game); if (card != null) { if (controller.chooseUse(outcome, "Cast " + card.getIdName() + " from your graveyard?", source, game)) { - controller.cast(card.getSpellAbility(), game, false); + controller.cast(card.getSpellAbility(), game, false, new MageObjectReference(source.getSourceObject(game), game)); } } return true; diff --git a/Mage.Sets/src/mage/cards/h/HazoretsUndyingFury.java b/Mage.Sets/src/mage/cards/h/HazoretsUndyingFury.java index d8a68cf19d0..4bbd4879254 100644 --- a/Mage.Sets/src/mage/cards/h/HazoretsUndyingFury.java +++ b/Mage.Sets/src/mage/cards/h/HazoretsUndyingFury.java @@ -29,6 +29,7 @@ package mage.cards.h; import java.util.UUID; import mage.MageObject; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DontUntapInControllersUntapStepAllEffect; @@ -129,7 +130,7 @@ class HazoretsUndyingFuryEffect extends OneShotEffect { if (controller.choose(Outcome.PlayForFree, cardsToCast, targetCard, game)) { Card card = game.getCard(targetCard.getFirstTarget()); if (card != null) { - if (controller.cast(card.getSpellAbility(), game, true)) { + if (controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game))) { cardsToCast.remove(card); } else { game.informPlayer(controller, "You're not able to cast " + card.getIdName() + " or you canceled the casting."); diff --git a/Mage.Sets/src/mage/cards/h/HellcarverDemon.java b/Mage.Sets/src/mage/cards/h/HellcarverDemon.java index af8462e4b7e..6fd523e7b9b 100644 --- a/Mage.Sets/src/mage/cards/h/HellcarverDemon.java +++ b/Mage.Sets/src/mage/cards/h/HellcarverDemon.java @@ -32,21 +32,21 @@ import java.util.Objects; import java.util.Set; import java.util.UUID; import mage.MageInt; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.Card; import mage.cards.CardImpl; +import mage.cards.CardSetInfo; import mage.cards.Cards; import mage.cards.CardsImpl; -import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.FilterCard; -import mage.filter.common.FilterControlledPermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -110,14 +110,14 @@ class HellcarverDemonEffect extends OneShotEffect { Set currentExiledCards = new HashSet<>(); currentExiledCards.addAll(controller.getLibrary().getTopCards(game, 6)); controller.moveCardsToExile(currentExiledCards, source, game, true, source.getSourceId(), sourceObject.getIdName()); - + // cast the possible cards without paying the mana Cards cardsToCast = new CardsImpl(); cardsToCast.addAll(currentExiledCards); boolean alreadyCast = false; while (!cardsToCast.isEmpty() && controller.canRespond()) { - if (!controller.chooseUse(outcome, "Cast a" + (alreadyCast ? "nother" : "" ) + " card exiled with " + sourceObject.getLogName() + " without paying its mana cost?", source, game)) { + if (!controller.chooseUse(outcome, "Cast a" + (alreadyCast ? "nother" : "") + " card exiled with " + sourceObject.getLogName() + " without paying its mana cost?", source, game)) { break; } TargetCard targetCard = new TargetCard(1, Zone.EXILED, new FilterCard("nonland card to cast for free")); @@ -125,7 +125,7 @@ class HellcarverDemonEffect extends OneShotEffect { alreadyCast = true; Card card = game.getCard(targetCard.getFirstTarget()); if (card != null) { - if (controller.cast(card.getSpellAbility(), game, true)) { + if (controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game))) { cardsToCast.remove(card); } else { game.informPlayer(controller, "You're not able to cast " + card.getIdName() + " or you canceled the casting."); diff --git a/Mage.Sets/src/mage/cards/h/HordeOfNotions.java b/Mage.Sets/src/mage/cards/h/HordeOfNotions.java index 641dcf7b2f9..eacfd8f8413 100644 --- a/Mage.Sets/src/mage/cards/h/HordeOfNotions.java +++ b/Mage.Sets/src/mage/cards/h/HordeOfNotions.java @@ -29,6 +29,7 @@ package mage.cards.h; import java.util.UUID; import mage.MageInt; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; @@ -59,7 +60,7 @@ public class HordeOfNotions extends CardImpl { } public HordeOfNotions(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{W}{U}{B}{R}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{U}{B}{R}{G}"); addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.ELEMENTAL); this.power = new MageInt(5); @@ -110,7 +111,7 @@ class HordeOfNotionsEffect extends OneShotEffect { if (controller != null) { Card card = game.getCard(getTargetPointer().getFirst(game, source)); if (card != null && controller.chooseUse(outcome, "Play " + card.getName() + " from your graveyard for free?", source, game)) { - controller.playCard(card, game, true, true); + controller.playCard(card, game, true, true, new MageObjectReference(source.getSourceObject(game), game)); } return true; } diff --git a/Mage.Sets/src/mage/cards/i/IsochronScepter.java b/Mage.Sets/src/mage/cards/i/IsochronScepter.java index b7ac1defaf2..ded92dd8dfb 100644 --- a/Mage.Sets/src/mage/cards/i/IsochronScepter.java +++ b/Mage.Sets/src/mage/cards/i/IsochronScepter.java @@ -28,6 +28,7 @@ package mage.cards.i; import java.util.UUID; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -58,7 +59,7 @@ import org.apache.log4j.Logger; public class IsochronScepter extends CardImpl { public IsochronScepter(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); // Imprint - When Isochron Scepter enters the battlefield, you may exile an instant card with converted mana cost 2 or less from your hand. this.addAbility(new EntersBattlefieldTriggeredAbility(new IsochronScepterImprintEffect(), true, "Imprint — ")); @@ -162,7 +163,7 @@ class IsochronScepterCopyEffect extends OneShotEffect { game.getState().setZone(copiedCard.getId(), Zone.EXILED); if (controller.chooseUse(outcome, "Cast the copied card without paying mana cost?", source, game)) { if (copiedCard.getSpellAbility() != null) { - controller.cast(copiedCard.getSpellAbility(), game, true); + controller.cast(copiedCard.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } else { Logger.getLogger(IsochronScepterCopyEffect.class).error("Isochron Scepter: spell ability == null " + copiedCard.getName()); } diff --git a/Mage.Sets/src/mage/cards/i/IzzetChemister.java b/Mage.Sets/src/mage/cards/i/IzzetChemister.java index 2663fc9d5a6..1f004e586d7 100644 --- a/Mage.Sets/src/mage/cards/i/IzzetChemister.java +++ b/Mage.Sets/src/mage/cards/i/IzzetChemister.java @@ -29,6 +29,7 @@ package mage.cards.i; import java.util.UUID; import mage.MageInt; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeSourceCost; @@ -43,8 +44,8 @@ import mage.cards.CardSetInfo; import mage.cards.Cards; import mage.cards.CardsImpl; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.common.FilterOwnedCard; @@ -144,7 +145,7 @@ class IzzetChemisterCastFromExileEffect extends OneShotEffect { while (cardsToExile.count(filter, game) > 0 && controller.choose(Outcome.PlayForFree, cardsToExile, target, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { - controller.cast(card.getSpellAbility(), game, true); + controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); cardsToExile.remove(card); } else { break OuterLoop; diff --git a/Mage.Sets/src/mage/cards/j/JaceArchitectOfThought.java b/Mage.Sets/src/mage/cards/j/JaceArchitectOfThought.java index c8fddaa7ac4..493d1717085 100644 --- a/Mage.Sets/src/mage/cards/j/JaceArchitectOfThought.java +++ b/Mage.Sets/src/mage/cards/j/JaceArchitectOfThought.java @@ -30,6 +30,7 @@ package mage.cards.j; import java.util.ArrayList; import java.util.Set; import java.util.UUID; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.LoyaltyAbility; @@ -43,9 +44,9 @@ import mage.cards.CardSetInfo; import mage.cards.Cards; import mage.cards.CardsImpl; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.SuperType; import mage.constants.Zone; import mage.filter.FilterCard; @@ -290,7 +291,7 @@ class JaceArchitectOfThoughtEffect3 extends OneShotEffect { while (jaceExileZone.count(filter, game) > 0 && controller.choose(Outcome.PlayForFree, jaceExileZone, target, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { - if (controller.cast(card.getSpellAbility(), game, true)) { + if (controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game))) { game.getExile().removeCard(card, game); } } diff --git a/Mage.Sets/src/mage/cards/j/JacesMindseeker.java b/Mage.Sets/src/mage/cards/j/JacesMindseeker.java index 0df0bc549e8..99b271b5647 100644 --- a/Mage.Sets/src/mage/cards/j/JacesMindseeker.java +++ b/Mage.Sets/src/mage/cards/j/JacesMindseeker.java @@ -31,6 +31,7 @@ import java.util.HashSet; import java.util.Set; import java.util.UUID; import mage.MageInt; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -41,8 +42,8 @@ import mage.cards.CardSetInfo; import mage.cards.Cards; import mage.cards.CardsImpl; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.common.FilterInstantOrSorceryCard; @@ -132,7 +133,7 @@ class JaceMindseekerEffect extends OneShotEffect { && controller.choose(outcome, cardsToCast, target, game)) { Card card = cardsToCast.get(target.getFirstTarget(), game); if (card != null) { - controller.cast(card.getSpellAbility(), game, true); + controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } } } diff --git a/Mage.Sets/src/mage/cards/j/JelevaNephaliasScourge.java b/Mage.Sets/src/mage/cards/j/JelevaNephaliasScourge.java index 19aca22058d..6fc77c87de4 100644 --- a/Mage.Sets/src/mage/cards/j/JelevaNephaliasScourge.java +++ b/Mage.Sets/src/mage/cards/j/JelevaNephaliasScourge.java @@ -32,6 +32,7 @@ import java.util.Map; import java.util.UUID; import mage.MageInt; import mage.MageObject; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -41,8 +42,8 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.SuperType; import mage.constants.WatcherScope; import mage.filter.common.FilterInstantOrSorceryCard; @@ -155,7 +156,7 @@ class JelevaNephaliasCastEffect extends OneShotEffect { if (controller.choose(Outcome.PlayForFree, exileZone, target, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { - return controller.cast(card.getSpellAbility(), game, true); + return controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } } } diff --git a/Mage.Sets/src/mage/cards/k/KahoMinamoHistorian.java b/Mage.Sets/src/mage/cards/k/KahoMinamoHistorian.java index e9d1f218fbd..e55a525d10f 100644 --- a/Mage.Sets/src/mage/cards/k/KahoMinamoHistorian.java +++ b/Mage.Sets/src/mage/cards/k/KahoMinamoHistorian.java @@ -30,6 +30,7 @@ package mage.cards.k; import java.util.UUID; import mage.MageInt; import mage.MageObject; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -39,9 +40,9 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.SearchEffect; import mage.cards.*; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.ComparisonType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.SuperType; import mage.constants.Zone; import mage.filter.FilterCard; @@ -60,7 +61,7 @@ import mage.util.CardUtil; public class KahoMinamoHistorian extends CardImpl { public KahoMinamoHistorian(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{U}"); this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WIZARD); @@ -154,7 +155,7 @@ class KahoMinamoHistorianCastEffect extends OneShotEffect { if (!cards.isEmpty() && controller.choose(Outcome.PlayForFree, cards, target, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { - controller.cast(card.getSpellAbility(), game, true); + controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } } return true; diff --git a/Mage.Sets/src/mage/cards/k/KnowledgeExploitation.java b/Mage.Sets/src/mage/cards/k/KnowledgeExploitation.java index 366397c5896..fd58a9ea362 100644 --- a/Mage.Sets/src/mage/cards/k/KnowledgeExploitation.java +++ b/Mage.Sets/src/mage/cards/k/KnowledgeExploitation.java @@ -28,6 +28,7 @@ package mage.cards.k; import java.util.UUID; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.ProwlAbility; @@ -35,8 +36,8 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.filter.common.FilterInstantOrSorceryCard; import mage.game.Game; import mage.players.Player; @@ -50,12 +51,12 @@ import mage.target.common.TargetOpponent; public class KnowledgeExploitation extends CardImpl { public KnowledgeExploitation(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.TRIBAL,CardType.SORCERY},"{5}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.TRIBAL, CardType.SORCERY}, "{5}{U}{U}"); this.subtype.add(SubType.ROGUE); // Prowl {3}{U} this.addAbility(new ProwlAbility(this, "{3}{U}")); - + // Search target opponent's library for an instant or sorcery card. You may cast that card without paying its mana cost. Then that player shuffles their library. this.getSpellAbility().addEffect(new KnowledgeExploitationEffect()); this.getSpellAbility().addTarget(new TargetOpponent()); @@ -72,21 +73,21 @@ public class KnowledgeExploitation extends CardImpl { } class KnowledgeExploitationEffect extends OneShotEffect { - + KnowledgeExploitationEffect() { super(Outcome.Benefit); this.staticText = "Search target opponent's library for an instant or sorcery card. You may cast that card without paying its mana cost. Then that player shuffles their library"; } - + KnowledgeExploitationEffect(final KnowledgeExploitationEffect effect) { super(effect); } - + @Override public KnowledgeExploitationEffect copy() { return new KnowledgeExploitationEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); @@ -96,7 +97,7 @@ class KnowledgeExploitationEffect extends OneShotEffect { if (controller.searchLibrary(target, game, opponent.getId())) { Card card = opponent.getLibrary().remove(target.getFirstTarget(), game); if (card != null) { - controller.cast(card.getSpellAbility(), game, true); + controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } } opponent.shuffleLibrary(source, game); diff --git a/Mage.Sets/src/mage/cards/k/KnowledgePool.java b/Mage.Sets/src/mage/cards/k/KnowledgePool.java index 463766dc068..6c96e29546b 100644 --- a/Mage.Sets/src/mage/cards/k/KnowledgePool.java +++ b/Mage.Sets/src/mage/cards/k/KnowledgePool.java @@ -29,6 +29,7 @@ package mage.cards.k; import java.util.UUID; import mage.MageObject; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -58,7 +59,7 @@ import mage.util.CardUtil; public class KnowledgePool extends CardImpl { public KnowledgePool(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{6}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{6}"); // Imprint - When Knowledge Pool enters the battlefield, each player exiles the top three cards of their library this.addAbility(new EntersBattlefieldTriggeredAbility(new KnowledgePoolEffect1(), false)); @@ -177,7 +178,7 @@ class KnowledgePoolEffect2 extends OneShotEffect { while (player.choose(Outcome.PlayForFree, game.getExile().getExileZone(exileZoneId), target, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null && !card.getId().equals(spell.getSourceId())) { - return player.cast(card.getSpellAbility(), game, true); + return player.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } target.clearChosen(); } diff --git a/Mage.Sets/src/mage/cards/l/LeafCrownedElder.java b/Mage.Sets/src/mage/cards/l/LeafCrownedElder.java index 0680363bb10..d552036578a 100644 --- a/Mage.Sets/src/mage/cards/l/LeafCrownedElder.java +++ b/Mage.Sets/src/mage/cards/l/LeafCrownedElder.java @@ -29,6 +29,7 @@ package mage.cards.l; import java.util.UUID; import mage.MageInt; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.abilityword.KinshipAbility; import mage.abilities.effects.OneShotEffect; @@ -36,8 +37,8 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.game.Game; import mage.players.Player; @@ -48,7 +49,7 @@ import mage.players.Player; public class LeafCrownedElder extends CardImpl { public LeafCrownedElder(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{G}"); this.subtype.add(SubType.TREEFOLK); this.subtype.add(SubType.SHAMAN); @@ -88,7 +89,7 @@ class LeafCrownedElderPlayEffect extends OneShotEffect { Card card = game.getCard(getTargetPointer().getFirst(game, source)); if (controller != null && card != null) { if (controller.chooseUse(Outcome.PlayForFree, "Play " + card.getIdName() + " without paying its mana cost?", source, game)) { - controller.playCard(card, game, true, true); + controller.playCard(card, game, true, true, new MageObjectReference(source.getSourceObject(game), game)); } return true; } diff --git a/Mage.Sets/src/mage/cards/l/LionsEyeDiamond.java b/Mage.Sets/src/mage/cards/l/LionsEyeDiamond.java index d979ec7ba12..b5bdce5cfb2 100644 --- a/Mage.Sets/src/mage/cards/l/LionsEyeDiamond.java +++ b/Mage.Sets/src/mage/cards/l/LionsEyeDiamond.java @@ -1,4 +1,4 @@ - /* +/* * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are @@ -49,7 +49,7 @@ import mage.players.Player; public class LionsEyeDiamond extends CardImpl { public LionsEyeDiamond(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{0}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{0}"); // Sacrifice Lion's Eye Diamond, Discard your hand: Add three mana of any one color. Activate this ability only any time you could cast an instant. this.addAbility(new LionsEyeDiamondAbility()); @@ -65,18 +65,17 @@ public class LionsEyeDiamond extends CardImpl { } } - class LionsEyeDiamondAbility extends ActivatedManaAbilityImpl { public LionsEyeDiamondAbility() { super(Zone.BATTLEFIELD, new AddManaOfAnyColorEffect(3), new SacrificeSourceCost()); this.addCost(new DiscardHandCost()); - this.netMana.add(new Mana(0,0,0,0,0,0,3, 0)); + this.netMana.add(new Mana(0, 0, 0, 0, 0, 0, 3, 0)); } public LionsEyeDiamondAbility(Zone zone, Mana mana, Cost cost) { super(zone, new BasicManaEffect(mana), cost); - + } public LionsEyeDiamondAbility(final LionsEyeDiamondAbility ability) { @@ -84,12 +83,12 @@ class LionsEyeDiamondAbility extends ActivatedManaAbilityImpl { } @Override - public boolean canActivate(UUID playerId, Game game) { + public ActivationStatus canActivate(UUID playerId, Game game) { Player player = game.getPlayer(playerId); if (player != null && !player.isInPayManaMode()) { return super.canActivate(playerId, game); } - return false; + return ActivationStatus.getFalse(); } @Override @@ -102,4 +101,3 @@ class LionsEyeDiamondAbility extends ActivatedManaAbilityImpl { return super.getRule() + " Activate this ability only any time you could cast an instant."; } } - diff --git a/Mage.Sets/src/mage/cards/l/LivingLore.java b/Mage.Sets/src/mage/cards/l/LivingLore.java index f9ae3d30e3f..f6c08cde9b1 100644 --- a/Mage.Sets/src/mage/cards/l/LivingLore.java +++ b/Mage.Sets/src/mage/cards/l/LivingLore.java @@ -41,7 +41,6 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; import mage.constants.Layer; import mage.constants.Outcome; @@ -207,7 +206,7 @@ class LivingLoreSacrificeEffect extends OneShotEffect { } if (exiledCard != null) { if (exiledCard.getSpellAbility().canChooseTarget(game)) { - controller.cast(exiledCard.getSpellAbility(), game, true); + controller.cast(exiledCard.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } } } diff --git a/Mage.Sets/src/mage/cards/m/MaelstromArchangel.java b/Mage.Sets/src/mage/cards/m/MaelstromArchangel.java index 1c644aab712..720d4b2c32b 100644 --- a/Mage.Sets/src/mage/cards/m/MaelstromArchangel.java +++ b/Mage.Sets/src/mage/cards/m/MaelstromArchangel.java @@ -29,6 +29,7 @@ package mage.cards.m; import java.util.UUID; import mage.MageInt; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -37,8 +38,8 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.filter.FilterCard; import mage.filter.common.FilterNonlandCard; import mage.game.Game; @@ -53,7 +54,7 @@ import mage.target.common.TargetCardInHand; public class MaelstromArchangel extends CardImpl { public MaelstromArchangel(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{W}{U}{B}{R}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{U}{B}{R}{G}"); this.subtype.add(SubType.ANGEL); this.power = new MageInt(5); @@ -61,10 +62,10 @@ public class MaelstromArchangel extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); - + // Whenever Maelstrom Archangel deals combat damage to a player, you may cast a nonland card from your hand without paying its mana cost. this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new MaelstromArchangelCastEffect(), false)); - + } public MaelstromArchangel(final MaelstromArchangel card) { @@ -100,8 +101,8 @@ class MaelstromArchangelCastEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { Target target = new TargetCardInHand(filter); - if (target.canChoose(source.getSourceId(), controller.getId(), game) && - controller.chooseUse(outcome, "Cast a nonland card from your hand without paying its mana cost?", source, game)) { + if (target.canChoose(source.getSourceId(), controller.getId(), game) + && controller.chooseUse(outcome, "Cast a nonland card from your hand without paying its mana cost?", source, game)) { Card cardToCast = null; boolean cancel = false; while (controller.canRespond() && !cancel) { @@ -115,7 +116,7 @@ class MaelstromArchangelCastEffect extends OneShotEffect { } } if (cardToCast != null) { - controller.cast(cardToCast.getSpellAbility(), game, true); + controller.cast(cardToCast.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } } return true; diff --git a/Mage.Sets/src/mage/cards/m/ManaCache.java b/Mage.Sets/src/mage/cards/m/ManaCache.java index de03d528f3a..07f4adf03be 100644 --- a/Mage.Sets/src/mage/cards/m/ManaCache.java +++ b/Mage.Sets/src/mage/cards/m/ManaCache.java @@ -65,7 +65,7 @@ public class ManaCache extends CardImpl { // At the beginning of each player's end step, put a charge counter on Mana Cache for each untapped land that player controls. TriggeredAbility ability = new OnEventTriggeredAbility(GameEvent.EventType.END_TURN_STEP_PRE, "beginning of each player's end step", true, new ManaCacheEffect()); this.addAbility(ability); - + // Remove a charge counter from Mana Cache: Add {C}. Any player may activate this ability but only during their turn before the end step. this.addAbility(new ManaCacheManaAbility()); } @@ -83,6 +83,7 @@ public class ManaCache extends CardImpl { class ManaCacheEffect extends OneShotEffect { private static final FilterPermanent filter = new FilterControlledLandPermanent(); + static { filter.add(Predicates.not(new TappedPredicate())); } @@ -114,7 +115,7 @@ class ManaCacheManaAbility extends ActivatedManaAbilityImpl { public ManaCacheManaAbility() { super(Zone.BATTLEFIELD, new BasicManaEffect(Mana.ColorlessMana(1)), new RemoveCountersSourceCost(CounterType.CHARGE.createInstance(1))); - this.netMana.add(new Mana(0,0,0,0,0,0,0,1)); + this.netMana.add(new Mana(0, 0, 0, 0, 0, 0, 0, 1)); } public ManaCacheManaAbility(final ManaCacheManaAbility ability) { @@ -122,18 +123,18 @@ class ManaCacheManaAbility extends ActivatedManaAbilityImpl { } @Override - public boolean canActivate(UUID playerId, Game game) { + public ActivationStatus canActivate(UUID playerId, Game game) { if (!super.hasMoreActivationsThisTurn(game) || !(condition == null || condition.apply(game, this))) { - return false; + return ActivationStatus.getFalse(); } Player player = game.getPlayer(playerId); if (player != null && playerId.equals(game.getActivePlayerId()) && game.getStep().getType().isBefore(PhaseStep.END_TURN)) { if (costs.canPay(this, sourceId, playerId, game)) { this.setControllerId(playerId); - return true; + return ActivationStatus.getTrue(); } } - return false; + return ActivationStatus.getFalse(); } @Override diff --git a/Mage.Sets/src/mage/cards/m/Martyrdom.java b/Mage.Sets/src/mage/cards/m/Martyrdom.java index d57ed53505a..c6ad4435edb 100644 --- a/Mage.Sets/src/mage/cards/m/Martyrdom.java +++ b/Mage.Sets/src/mage/cards/m/Martyrdom.java @@ -126,7 +126,7 @@ class MartyrdomActivatedAbility extends ActivatedAbilityImpl { } @Override - public boolean canActivate(UUID playerId, Game game) { + public ActivationStatus canActivate(UUID playerId, Game game) { if (playerId.equals(caster)) { Permanent permanent = game.getBattlefield().getPermanent(this.getSourceId()); if (permanent != null) { @@ -135,7 +135,7 @@ class MartyrdomActivatedAbility extends ActivatedAbilityImpl { } } } - return false; + return ActivationStatus.getFalse(); } @Override diff --git a/Mage.Sets/src/mage/cards/m/MasterOfPredicaments.java b/Mage.Sets/src/mage/cards/m/MasterOfPredicaments.java index 67edf0fb6e3..a535a305814 100644 --- a/Mage.Sets/src/mage/cards/m/MasterOfPredicaments.java +++ b/Mage.Sets/src/mage/cards/m/MasterOfPredicaments.java @@ -29,6 +29,7 @@ package mage.cards.m; import java.util.UUID; import mage.MageInt; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -37,8 +38,8 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.filter.FilterCard; import mage.game.Game; import mage.players.Player; @@ -52,7 +53,7 @@ import mage.target.common.TargetCardInHand; public class MasterOfPredicaments extends CardImpl { public MasterOfPredicaments(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{U}"); this.subtype.add(SubType.SPHINX); this.power = new MageInt(4); @@ -125,7 +126,7 @@ class MasterOfPredicamentsEffect extends OneShotEffect { // If the revealed card is a land, you can't cast it. So nothing happens } else { if (controller.chooseUse(outcome, "Cast " + cardFromHand.getName() + " without paying its mana cost?", source, game)) { - controller.cast(cardFromHand.getSpellAbility(), game, true); + controller.cast(cardFromHand.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } } diff --git a/Mage.Sets/src/mage/cards/m/MemoryPlunder.java b/Mage.Sets/src/mage/cards/m/MemoryPlunder.java index 7eea6a6dc00..f6d4726edd6 100644 --- a/Mage.Sets/src/mage/cards/m/MemoryPlunder.java +++ b/Mage.Sets/src/mage/cards/m/MemoryPlunder.java @@ -28,6 +28,7 @@ package mage.cards.m; import java.util.UUID; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; @@ -49,6 +50,7 @@ import mage.target.common.TargetCardInOpponentsGraveyard; public class MemoryPlunder extends CardImpl { private static final FilterCard filter = new FilterCard("instant or sorcery card from an opponent's graveyard"); + static { filter.add(Predicates.or( new CardTypePredicate(CardType.INSTANT), @@ -56,8 +58,7 @@ public class MemoryPlunder extends CardImpl { } public MemoryPlunder(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{U/B}{U/B}{U/B}{U/B}"); - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U/B}{U/B}{U/B}{U/B}"); // You may cast target instant or sorcery card from an opponent's graveyard without paying its mana cost. this.getSpellAbility().addEffect(new MemoryPlunderEffect()); @@ -96,8 +97,8 @@ class MemoryPlunderEffect extends OneShotEffect { Card card = game.getCard(getTargetPointer().getFirst(game, source)); if (card != null) { Player player = game.getPlayer(source.getControllerId()); - if (player != null && player.chooseUse(Outcome.Benefit, "Cast " + card.getName() +" without paying cost?", source, game)) { - player.cast(card.getSpellAbility(), game, true); + if (player != null && player.chooseUse(Outcome.Benefit, "Cast " + card.getName() + " without paying cost?", source, game)) { + player.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } } return false; diff --git a/Mage.Sets/src/mage/cards/m/Merseine.java b/Mage.Sets/src/mage/cards/m/Merseine.java index f9a7ffb438c..9e74f0ed6ba 100644 --- a/Mage.Sets/src/mage/cards/m/Merseine.java +++ b/Mage.Sets/src/mage/cards/m/Merseine.java @@ -33,9 +33,9 @@ import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.SourceHasCounterCondition; -import mage.abilities.decorator.ConditionalContinuousRuleModifyingEffect; import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; +import mage.abilities.decorator.ConditionalContinuousRuleModifyingEffect; import mage.abilities.effects.Effect; import mage.abilities.effects.Effects; import mage.abilities.effects.common.AttachEffect; @@ -53,13 +53,13 @@ import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** - * + * * @author L_J */ public class Merseine extends CardImpl { public Merseine(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}{U}"); this.subtype.add(SubType.AURA); // Enchant creature @@ -74,9 +74,9 @@ public class Merseine extends CardImpl { this.addAbility(new EntersBattlefieldAbility(effect)); // Enchanted creature doesn't untap during its controller's untap step if Merseine has a net counter on it. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousRuleModifyingEffect(new DontUntapInControllersUntapStepEnchantedEffect(), - new SourceHasCounterCondition(CounterType.NET)).setText("Enchanted creature doesn't untap during its controller's untap step if Merseine has a net counter on it"))); - + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousRuleModifyingEffect(new DontUntapInControllersUntapStepEnchantedEffect(), + new SourceHasCounterCondition(CounterType.NET)).setText("Enchanted creature doesn't untap during its controller's untap step if Merseine has a net counter on it"))); + // Pay enchanted creature's mana cost: Remove a net counter from Merseine. Any player may activate this ability, but only if he or she controls the enchanted creature. SimpleActivatedAbility ability = new MerseineActivatedAbility(); ability.setMayActivate(TargetController.ANY); @@ -94,7 +94,7 @@ public class Merseine extends CardImpl { } class MerseineActivatedAbility extends SimpleActivatedAbility { - + public MerseineActivatedAbility() { super(Zone.BATTLEFIELD, new RemoveCounterSourceEffect(CounterType.NET.createInstance()), new MerseineCost()); } @@ -109,7 +109,7 @@ class MerseineActivatedAbility extends SimpleActivatedAbility { } @Override - public boolean canActivate(UUID playerId, Game game) { + public ActivationStatus canActivate(UUID playerId, Game game) { Permanent sourcePermanent = game.getBattlefield().getPermanent(this.getSourceId()); if (sourcePermanent != null) { Permanent attachedTo = game.getPermanent(sourcePermanent.getAttachedTo()); @@ -117,7 +117,7 @@ class MerseineActivatedAbility extends SimpleActivatedAbility { return super.canActivate(attachedTo.getControllerId(), game); } } - return false; + return ActivationStatus.getFalse(); } @Override diff --git a/Mage.Sets/src/mage/cards/m/MindclawShaman.java b/Mage.Sets/src/mage/cards/m/MindclawShaman.java index 343c7be3058..2656e750f01 100644 --- a/Mage.Sets/src/mage/cards/m/MindclawShaman.java +++ b/Mage.Sets/src/mage/cards/m/MindclawShaman.java @@ -30,6 +30,7 @@ package mage.cards.m; import java.util.UUID; import mage.MageInt; import mage.MageObject; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -37,8 +38,8 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.Predicates; @@ -55,7 +56,7 @@ import mage.target.common.TargetOpponent; public class MindclawShaman extends CardImpl { public MindclawShaman(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}"); this.subtype.add(SubType.VIASHINO); this.subtype.add(SubType.SHAMAN); @@ -81,13 +82,13 @@ public class MindclawShaman extends CardImpl { class MindclawShamanEffect extends OneShotEffect { private static final FilterCard filter = new FilterCard("instant or sorcery card"); - + static { filter.add(Predicates.or( - new CardTypePredicate(CardType.INSTANT), - new CardTypePredicate(CardType.SORCERY))); + new CardTypePredicate(CardType.INSTANT), + new CardTypePredicate(CardType.SORCERY))); } - + public MindclawShamanEffect() { super(Outcome.Discard); this.staticText = "target opponent reveals their hand. You may cast an instant or sorcery card from it without paying its mana cost"; @@ -106,7 +107,7 @@ class MindclawShamanEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player targetOpponent = game.getPlayer(source.getFirstTarget()); MageObject sourceObject = source.getSourceObject(game); - if (targetOpponent != null && sourceObject != null) { + if (targetOpponent != null && sourceObject != null) { if (!targetOpponent.getHand().isEmpty()) { targetOpponent.revealCards(sourceObject.getName(), targetOpponent.getHand(), game); Player controller = game.getPlayer(source.getControllerId()); @@ -117,9 +118,9 @@ class MindclawShamanEffect extends OneShotEffect { Card chosenCard = targetOpponent.getHand().get(target.getFirstTarget(), game); if (chosenCard != null) { if (controller.chooseUse(Outcome.Benefit, "Cast the chosen card?", source, game)) { - controller.cast(chosenCard.getSpellAbility(), game, true); + controller.cast(chosenCard.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } else { - game.informPlayers(sourceObject.getLogName() +": " + controller.getLogName() + " canceled casting the card."); + game.informPlayers(sourceObject.getLogName() + ": " + controller.getLogName() + " canceled casting the card."); } } } @@ -129,4 +130,4 @@ class MindclawShamanEffect extends OneShotEffect { } return false; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/m/MindleechMass.java b/Mage.Sets/src/mage/cards/m/MindleechMass.java index a604d7764aa..9778b112f63 100644 --- a/Mage.Sets/src/mage/cards/m/MindleechMass.java +++ b/Mage.Sets/src/mage/cards/m/MindleechMass.java @@ -29,6 +29,7 @@ package mage.cards.m; import java.util.UUID; import mage.MageInt; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -39,8 +40,8 @@ import mage.cards.CardSetInfo; import mage.cards.Cards; import mage.cards.CardsImpl; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterNonlandCard; import mage.game.Game; @@ -54,7 +55,7 @@ import mage.target.TargetCard; public class MindleechMass extends CardImpl { public MindleechMass(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{U}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{U}{B}{B}"); this.subtype.add(SubType.HORROR); this.power = new MageInt(6); @@ -62,7 +63,7 @@ public class MindleechMass extends CardImpl { // Trample this.addAbility(TrampleAbility.getInstance()); - + // Whenever Mindleech Mass deals combat damage to a player, you may look at that player's hand. If you do, you may cast a nonland card in it without paying that card's mana cost. this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new MindleechMassEffect(), true, true)); } @@ -96,18 +97,18 @@ class MindleechMassEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player opponent = game.getPlayer(getTargetPointer().getFirst(game, source)); - Player you = game.getPlayer(source.getControllerId()); - if (opponent != null && you != null) { + Player controller = game.getPlayer(source.getControllerId()); + if (opponent != null && controller != null) { Cards cardsInHand = new CardsImpl(); cardsInHand.addAll(opponent.getHand()); opponent.revealCards("Opponents hand", cardsInHand, game); if (!cardsInHand.isEmpty() && !cardsInHand.getCards(new FilterNonlandCard(), game).isEmpty()) { TargetCard target = new TargetCard(1, Zone.HAND, new FilterNonlandCard()); - if (you.chooseTarget(Outcome.PlayForFree, cardsInHand, target, source, game)) { + if (controller.chooseTarget(Outcome.PlayForFree, cardsInHand, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { - you.cast(card.getSpellAbility(), game, true); + controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } } } diff --git a/Mage.Sets/src/mage/cards/m/MindsDilation.java b/Mage.Sets/src/mage/cards/m/MindsDilation.java index e19befd169b..bbe23a80fba 100644 --- a/Mage.Sets/src/mage/cards/m/MindsDilation.java +++ b/Mage.Sets/src/mage/cards/m/MindsDilation.java @@ -30,6 +30,7 @@ package mage.cards.m; import java.util.List; import java.util.UUID; import mage.MageObject; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.SpellCastOpponentTriggeredAbility; import mage.abilities.effects.Effect; @@ -55,7 +56,7 @@ import mage.watchers.common.SpellsCastWatcher; public class MindsDilation extends CardImpl { public MindsDilation(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{5}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{5}{U}{U}"); // Whenever an opponent casts their first spell each turn, that player exiles the top card of their library. If it's a nonland card, // you may cast it without paying its mana cost. @@ -138,7 +139,7 @@ class MindsDilationEffect extends OneShotEffect { if (card != null && opponent.moveCards(card, Zone.EXILED, source, game)) { if (!card.isLand()) { if (controller.chooseUse(outcome, "Cast " + card.getLogName() + " without paying its mana cost from exile?", source, game)) { - controller.cast(card.getSpellAbility(), game, true); + controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } } } diff --git a/Mage.Sets/src/mage/cards/m/MizzixsMastery.java b/Mage.Sets/src/mage/cards/m/MizzixsMastery.java index fd3b892bd84..b2c167ca289 100644 --- a/Mage.Sets/src/mage/cards/m/MizzixsMastery.java +++ b/Mage.Sets/src/mage/cards/m/MizzixsMastery.java @@ -29,6 +29,7 @@ package mage.cards.m; import java.util.Set; import java.util.UUID; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; @@ -106,7 +107,7 @@ class MizzixsMasteryEffect extends OneShotEffect { Card cardCopy = game.copyCard(card, source, source.getControllerId()); if (cardCopy.getSpellAbility().canChooseTarget(game) && controller.chooseUse(outcome, "Cast copy of " + card.getName() + " without paying its mana cost?", source, game)) { - controller.cast(cardCopy.getSpellAbility(), game, true); + controller.cast(cardCopy.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } } } @@ -150,7 +151,7 @@ class MizzixsMasteryOverloadEffect extends OneShotEffect { if (controller.choose(outcome, copiedCards, targetCard, game)) { Card selectedCard = game.getCard(targetCard.getFirstTarget()); if (selectedCard != null && selectedCard.getSpellAbility().canChooseTarget(game)) { - if (controller.cast(selectedCard.getSpellAbility(), game, true)) { + if (controller.cast(selectedCard.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game))) { copiedCards.remove(selectedCard); } } diff --git a/Mage.Sets/src/mage/cards/o/OmenMachine.java b/Mage.Sets/src/mage/cards/o/OmenMachine.java index c8928fce4a7..6843ae9df59 100644 --- a/Mage.Sets/src/mage/cards/o/OmenMachine.java +++ b/Mage.Sets/src/mage/cards/o/OmenMachine.java @@ -28,6 +28,7 @@ package mage.cards.o; import java.util.UUID; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.BeginningOfDrawTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; @@ -126,7 +127,7 @@ class OmenMachineEffect2 extends OneShotEffect { if (card.isLand()) { player.moveCards(card, Zone.BATTLEFIELD, source, game); } else { - player.cast(card.getSpellAbility(), game, true); + player.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } } return true; diff --git a/Mage.Sets/src/mage/cards/o/OracleOfBones.java b/Mage.Sets/src/mage/cards/o/OracleOfBones.java index 607b7d4ae2b..015687d597b 100644 --- a/Mage.Sets/src/mage/cards/o/OracleOfBones.java +++ b/Mage.Sets/src/mage/cards/o/OracleOfBones.java @@ -29,6 +29,7 @@ package mage.cards.o; import java.util.UUID; import mage.MageInt; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.TriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -41,8 +42,8 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.filter.FilterCard; import mage.filter.common.FilterInstantOrSorceryCard; import mage.game.Game; @@ -57,7 +58,7 @@ import mage.target.common.TargetCardInHand; public class OracleOfBones extends CardImpl { public OracleOfBones(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{R}"); this.subtype.add(SubType.MINOTAUR); this.subtype.add(SubType.SHAMAN); @@ -107,8 +108,8 @@ class OracleOfBonesCastEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { Target target = new TargetCardInHand(filter); - if (target.canChoose(source.getSourceId(), controller.getId(), game) && - controller.chooseUse(outcome, "Cast an instant or sorcery card from your hand without paying its mana cost?", source, game)) { + if (target.canChoose(source.getSourceId(), controller.getId(), game) + && controller.chooseUse(outcome, "Cast an instant or sorcery card from your hand without paying its mana cost?", source, game)) { Card cardToCast = null; boolean cancel = false; while (controller.canRespond() && !cancel) { @@ -122,7 +123,7 @@ class OracleOfBonesCastEffect extends OneShotEffect { } } if (cardToCast != null) { - controller.cast(cardToCast.getSpellAbility(), game, true); + controller.cast(cardToCast.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } } return true; diff --git a/Mage.Sets/src/mage/cards/p/PanopticMirror.java b/Mage.Sets/src/mage/cards/p/PanopticMirror.java index c259a2c7bd9..4be62fb3a77 100644 --- a/Mage.Sets/src/mage/cards/p/PanopticMirror.java +++ b/Mage.Sets/src/mage/cards/p/PanopticMirror.java @@ -28,6 +28,7 @@ package mage.cards.p; import java.util.UUID; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -57,7 +58,7 @@ import mage.util.CardUtil; public class PanopticMirror extends CardImpl { public PanopticMirror(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{5}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{5}"); // Imprint - {X}, {tap}: You may exile an instant or sorcery card with converted mana cost X from your hand. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PanopticMirrorExileEffect(), new VariableManaCost()); @@ -114,7 +115,7 @@ class PanopticMirrorExileEffect extends OneShotEffect { if (card != null) { card.moveToExile(CardUtil.getCardExileZoneId(game, source), "Panoptic Mirror", source.getSourceId(), game); Permanent PanopticMirror = game.getPermanent(source.getSourceId()); - if(PanopticMirror != null){ + if (PanopticMirror != null) { PanopticMirror.imprint(card.getId(), game); } return true; @@ -149,31 +150,29 @@ class PanopticMirrorCastEffect extends OneShotEffect { } if (PanopticMirror != null && PanopticMirror.getImprinted() != null && !PanopticMirror.getImprinted().isEmpty() && controller != null) { CardsImpl cards = new CardsImpl(); - for(UUID uuid : PanopticMirror.getImprinted()){ + for (UUID uuid : PanopticMirror.getImprinted()) { Card card = game.getCard(uuid); - if(card != null){ - if(card.isSplitCard()){ - cards.add(((SplitCard)card).getLeftHalfCard()); - cards.add(((SplitCard)card).getRightHalfCard()); - } - else{ + if (card != null) { + if (card.isSplitCard()) { + cards.add(((SplitCard) card).getLeftHalfCard()); + cards.add(((SplitCard) card).getRightHalfCard()); + } else { cards.add(card); } } } Card cardToCopy; - if(cards.size() == 1){ + if (cards.size() == 1) { cardToCopy = cards.getCards(game).iterator().next(); - } - else{ + } else { TargetCard target = new TargetCard(1, Zone.EXILED, new FilterCard("card to copy")); controller.choose(Outcome.Copy, cards, target, game); cardToCopy = cards.get(target.getFirstTarget(), game); } - if(cardToCopy != null){ + if (cardToCopy != null) { Card copy = game.copyCard(cardToCopy, source, source.getControllerId()); if (controller.chooseUse(outcome, "Cast the copied card without paying mana cost?", source, game)) { - return controller.cast(copy.getSpellAbility(), game, true); + return controller.cast(copy.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } } return true; diff --git a/Mage.Sets/src/mage/cards/p/PossibilityStorm.java b/Mage.Sets/src/mage/cards/p/PossibilityStorm.java index 6ccd585beb2..d99782e3a0b 100644 --- a/Mage.Sets/src/mage/cards/p/PossibilityStorm.java +++ b/Mage.Sets/src/mage/cards/p/PossibilityStorm.java @@ -30,6 +30,7 @@ package mage.cards.p; import java.util.EnumSet; import java.util.UUID; import mage.MageObject; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; @@ -155,7 +156,7 @@ class PossibilityStormEffect extends OneShotEffect { && !card.isLand() && card.getSpellAbility().canChooseTarget(game)) { if (spellController.chooseUse(Outcome.PlayForFree, "Cast " + card.getLogName() + " without paying cost?", source, game)) { - spellController.cast(card.getSpellAbility(), game, true); + spellController.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } } diff --git a/Mage.Sets/src/mage/cards/q/QasaliAmbusher.java b/Mage.Sets/src/mage/cards/q/QasaliAmbusher.java index 4ff501b423c..1df9bc3a42c 100644 --- a/Mage.Sets/src/mage/cards/q/QasaliAmbusher.java +++ b/Mage.Sets/src/mage/cards/q/QasaliAmbusher.java @@ -29,6 +29,7 @@ package mage.cards.q; import java.util.UUID; import mage.MageInt; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.ActivatedAbilityImpl; import mage.abilities.SpellAbility; @@ -52,7 +53,7 @@ import mage.players.Player; public class QasaliAmbusher extends CardImpl { public QasaliAmbusher(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{W}"); this.subtype.add(SubType.CAT); this.subtype.add(SubType.WARRIOR); @@ -102,18 +103,16 @@ class QasaliAmbusherAbility extends ActivatedAbilityImpl { } @Override - public boolean canActivate(UUID playerId, Game game) { - if (super.canActivate(playerId, game)) { - if (!game.getBattlefield().getActivePermanents(filterPlains, this.getControllerId(), this.getSourceId(), game).isEmpty() - && !game.getBattlefield().getActivePermanents(filterForest, this.getControllerId(), this.getSourceId(), game).isEmpty()) { - for (CombatGroup group : game.getCombat().getGroups()) { - if (getControllerId().equals(group.getDefenderId())) { - return true; - } + public ActivationStatus canActivate(UUID playerId, Game game) { + if (!game.getBattlefield().getActivePermanents(filterPlains, this.getControllerId(), this.getSourceId(), game).isEmpty() + && !game.getBattlefield().getActivePermanents(filterForest, this.getControllerId(), this.getSourceId(), game).isEmpty()) { + for (CombatGroup group : game.getCombat().getGroups()) { + if (getControllerId().equals(group.getDefenderId())) { + return super.canActivate(playerId, game); } } } - return false; + return ActivationStatus.getFalse(); } @Override @@ -151,7 +150,7 @@ class QasaliAmbusherEffect extends OneShotEffect { if (controller != null) { SpellAbility spellAbility = card.getSpellAbility(); spellAbility.clear(); - return controller.cast(spellAbility, game, true); + return controller.cast(spellAbility, game, true, new MageObjectReference(source.getSourceObject(game), game)); } } return false; diff --git a/Mage.Sets/src/mage/cards/r/RashmiEternitiesCrafter.java b/Mage.Sets/src/mage/cards/r/RashmiEternitiesCrafter.java index d9942e4b18b..a0438b8eb5b 100644 --- a/Mage.Sets/src/mage/cards/r/RashmiEternitiesCrafter.java +++ b/Mage.Sets/src/mage/cards/r/RashmiEternitiesCrafter.java @@ -30,6 +30,7 @@ package mage.cards.r; import java.util.List; import java.util.UUID; import mage.MageInt; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.effects.Effect; @@ -39,8 +40,8 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.cards.CardsImpl; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.SuperType; import mage.constants.Zone; import mage.game.Game; @@ -56,7 +57,7 @@ import mage.watchers.common.SpellsCastWatcher; public class RashmiEternitiesCrafter extends CardImpl { public RashmiEternitiesCrafter(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{U}"); addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.ELF); this.subtype.add(SubType.DRUID); @@ -146,7 +147,7 @@ class RashmiEternitiesCrafterEffect extends OneShotEffect { || card.isLand() || card.getConvertedManaCost() >= (int) cmcObject || !controller.chooseUse(Outcome.PlayForFree, "Cast " + card.getName() + " without paying its mana cost?", source, game) - || !controller.cast(card.getSpellAbility(), game, true)) { + || !controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game))) { controller.moveCards(card, Zone.HAND, source, game); } } diff --git a/Mage.Sets/src/mage/cards/r/ReversalOfFortune.java b/Mage.Sets/src/mage/cards/r/ReversalOfFortune.java index 1af82ceb567..d1d3e1e4ac1 100644 --- a/Mage.Sets/src/mage/cards/r/ReversalOfFortune.java +++ b/Mage.Sets/src/mage/cards/r/ReversalOfFortune.java @@ -28,6 +28,7 @@ package mage.cards.r; import java.util.UUID; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; @@ -51,8 +52,7 @@ import mage.target.common.TargetOpponent; public class ReversalOfFortune extends CardImpl { public ReversalOfFortune(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{4}{R}{R}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{R}{R}"); // Target opponent reveals their hand. You may copy an instant or sorcery card in it. If you do, you may cast the copy without paying its mana cost. this.getSpellAbility().addEffect(new ReversalOfFortuneEffect()); @@ -69,7 +69,6 @@ public class ReversalOfFortune extends CardImpl { } } - class ReversalOfFortuneEffect extends OneShotEffect { public ReversalOfFortuneEffect() { @@ -88,28 +87,27 @@ class ReversalOfFortuneEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - + Player controller = game.getPlayer(source.getControllerId()); Player opponent = game.getPlayer(source.getFirstTarget()); if (controller != null && opponent != null) { // Target opponent reveals their hand - Cards revealedCards = new CardsImpl(); - revealedCards.addAll(opponent.getHand()); + Cards revealedCards = new CardsImpl(); + revealedCards.addAll(opponent.getHand()); opponent.revealCards("Reveal", revealedCards, game); - + //You may copy an instant or sorcery card in it - TargetCard target = new TargetCard(1, Zone.HAND, new FilterInstantOrSorceryCard()); + TargetCard target = new TargetCard(1, Zone.HAND, new FilterInstantOrSorceryCard()); target.setRequired(false); if (controller.choose(outcome, revealedCards, target, game)) { Card card = revealedCards.get((UUID) target.getFirstTarget(), game); //If you do, you may cast the copy without paying its mana cost - if(card != null){ + if (card != null) { Card copiedCard = game.copyCard(card, source, source.getControllerId()); if (controller.chooseUse(outcome, "Cast the copied card without paying mana cost?", source, game)) { - controller.cast(copiedCard.getSpellAbility(), game, true); + controller.cast(copiedCard.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } - } - else{ + } else { return false; } } @@ -117,4 +115,4 @@ class ReversalOfFortuneEffect extends OneShotEffect { } return false; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/r/RhysticCave.java b/Mage.Sets/src/mage/cards/r/RhysticCave.java index bca1ff1151d..9b2f08afe21 100644 --- a/Mage.Sets/src/mage/cards/r/RhysticCave.java +++ b/Mage.Sets/src/mage/cards/r/RhysticCave.java @@ -87,12 +87,12 @@ class RhysticCaveManaAbility extends ActivatedManaAbilityImpl { } @Override - public boolean canActivate(UUID playerId, Game game) { + public ActivationStatus canActivate(UUID playerId, Game game) { Player player = game.getPlayer(playerId); if (player != null && !player.isInPayManaMode()) { return super.canActivate(playerId, game); } - return false; + return ActivationStatus.getFalse(); } @Override diff --git a/Mage.Sets/src/mage/cards/s/ShellOfTheLastKappa.java b/Mage.Sets/src/mage/cards/s/ShellOfTheLastKappa.java index dfaeef31dc1..f5a93d049a2 100644 --- a/Mage.Sets/src/mage/cards/s/ShellOfTheLastKappa.java +++ b/Mage.Sets/src/mage/cards/s/ShellOfTheLastKappa.java @@ -28,6 +28,7 @@ package mage.cards.s; import java.util.UUID; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeSourceCost; @@ -157,7 +158,7 @@ class ShellOfTheLastKappaCastEffect extends OneShotEffect { Card card = game.getCard(target.getFirstTarget()); if (card != null) { game.getExile().removeCard(card, game); - return controller.cast(card.getSpellAbility(), game, true); + return controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } } } diff --git a/Mage.Sets/src/mage/cards/s/SilentBladeOni.java b/Mage.Sets/src/mage/cards/s/SilentBladeOni.java index 59b9ffce962..b8536d769bb 100644 --- a/Mage.Sets/src/mage/cards/s/SilentBladeOni.java +++ b/Mage.Sets/src/mage/cards/s/SilentBladeOni.java @@ -29,6 +29,7 @@ package mage.cards.s; import java.util.UUID; import mage.MageInt; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; @@ -40,8 +41,8 @@ import mage.cards.CardSetInfo; import mage.cards.Cards; import mage.cards.CardsImpl; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterNonlandCard; import mage.game.Game; @@ -55,7 +56,7 @@ import mage.target.TargetCard; public class SilentBladeOni extends CardImpl { public SilentBladeOni(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}{U}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{U}{B}{B}"); this.subtype.add(SubType.DEMON); this.subtype.add(SubType.NINJA); @@ -107,7 +108,7 @@ class SilentBladeOniEffect extends OneShotEffect { if (controller.chooseTarget(outcome, cardsInHand, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { - controller.cast(card.getSpellAbility(), game, true); + controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } } diff --git a/Mage.Sets/src/mage/cards/s/SpellQueller.java b/Mage.Sets/src/mage/cards/s/SpellQueller.java index 667e48e2ac6..f629c5ce8f1 100644 --- a/Mage.Sets/src/mage/cards/s/SpellQueller.java +++ b/Mage.Sets/src/mage/cards/s/SpellQueller.java @@ -31,6 +31,7 @@ import java.util.Set; import java.util.UUID; import mage.MageInt; import mage.MageObject; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.LeavesBattlefieldTriggeredAbility; @@ -42,9 +43,9 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.ComparisonType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.filter.FilterSpell; import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; import mage.game.ExileZone; @@ -69,7 +70,7 @@ public class SpellQueller extends CardImpl { } public SpellQueller(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{W}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{U}"); this.subtype.add(SubType.SPIRIT); this.power = new MageInt(2); this.toughness = new MageInt(3); @@ -160,13 +161,13 @@ class SpellQuellerLeavesEffect extends OneShotEffect { if (exile != null) { // null is valid if source left battlefield before enters the battlefield effect resolved Card card = null; Set exiledCards = exile.getCards(game); - if (exiledCards != null && !exiledCards.isEmpty()) { - card = exiledCards.iterator().next(); + if (exiledCards != null && !exiledCards.isEmpty()) { + card = exiledCards.iterator().next(); if (card != null) { Player cardOwner = game.getPlayer(card.getOwnerId()); if (cardOwner != null) { if (cardOwner.chooseUse(Outcome.PlayForFree, "Cast " + card.getLogName() + " without paying cost?", source, game)) { - cardOwner.cast(card.getSpellAbility(), game, true); + cardOwner.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } } } diff --git a/Mage.Sets/src/mage/cards/s/Spellbinder.java b/Mage.Sets/src/mage/cards/s/Spellbinder.java index 085fbde2337..2c4ad87d73a 100644 --- a/Mage.Sets/src/mage/cards/s/Spellbinder.java +++ b/Mage.Sets/src/mage/cards/s/Spellbinder.java @@ -28,6 +28,7 @@ package mage.cards.s; import java.util.UUID; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -38,8 +39,8 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.mageobject.CardTypePredicate; @@ -60,12 +61,12 @@ import org.apache.log4j.Logger; public class Spellbinder extends CardImpl { public Spellbinder(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{3}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); this.subtype.add(SubType.EQUIPMENT); // Imprint - When Spellbinder enters the battlefield, you may exile an instant card from your hand. this.addAbility(new EntersBattlefieldTriggeredAbility(new SpellbinderImprintEffect(), true, "Imprint — ")); - + // Whenever equipped creature deals combat damage to a player, you may copy the exiled card. If you do, you may cast the copy without paying its mana cost. this.addAbility(new SpellbinderTriggeredAbility()); @@ -197,7 +198,7 @@ class SpellbinderCopyEffect extends OneShotEffect { game.getState().setZone(copiedCard.getId(), Zone.EXILED); if (controller.chooseUse(outcome, "Cast the copied card without paying mana cost?", source, game)) { if (copiedCard.getSpellAbility() != null) { - controller.cast(copiedCard.getSpellAbility(), game, true); + controller.cast(copiedCard.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } else { Logger.getLogger(SpellbinderCopyEffect.class).error("Spellbinder: spell ability == null " + copiedCard.getName()); } @@ -210,4 +211,4 @@ class SpellbinderCopyEffect extends OneShotEffect { } return false; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/s/Spellshift.java b/Mage.Sets/src/mage/cards/s/Spellshift.java index bf93afa11cc..4ffe8a39144 100644 --- a/Mage.Sets/src/mage/cards/s/Spellshift.java +++ b/Mage.Sets/src/mage/cards/s/Spellshift.java @@ -28,6 +28,7 @@ package mage.cards.s; import java.util.UUID; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CounterTargetEffect; @@ -103,7 +104,7 @@ class SpellshiftEffect extends OneShotEffect { } spellController.revealCards(source, cardsToReveal, game); if (toCast != null && spellController.chooseUse(outcome, "Cast " + toCast.getLogName() + " without paying its mana cost?", source, game)) { - spellController.cast(toCast.getSpellAbility(), game, true); + spellController.cast(toCast.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } spellController.shuffleLibrary(source, game); return true; diff --git a/Mage.Sets/src/mage/cards/s/Spelltwine.java b/Mage.Sets/src/mage/cards/s/Spelltwine.java index bf0970a535f..9b046706d23 100644 --- a/Mage.Sets/src/mage/cards/s/Spelltwine.java +++ b/Mage.Sets/src/mage/cards/s/Spelltwine.java @@ -28,6 +28,7 @@ package mage.cards.s; import java.util.UUID; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ExileSpellEffect; @@ -65,7 +66,7 @@ public class Spelltwine extends CardImpl { } public Spelltwine(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{5}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{5}{U}"); // Exile target instant or sorcery card from your graveyard and target instant or sorcery card from an opponent's graveyard. Copy those cards. Cast the copies if able without paying their mana costs. Exile Spelltwine. this.getSpellAbility().addEffect(new SpelltwineEffect()); @@ -109,18 +110,19 @@ class SpelltwineEffect extends OneShotEffect { controller.moveCards(cardTwo, Zone.EXILED, source, game); } boolean castCardOne = true; + MageObjectReference mor = new MageObjectReference(source.getSourceObject(game), game); if (cardOne != null && controller.chooseUse(Outcome.Neutral, "Cast the copy of " + cardOne.getName() + " first?", source, game)) { Card copyOne = game.copyCard(cardOne, source, controller.getId()); - controller.cast(copyOne.getSpellAbility(), game, true); + controller.cast(copyOne.getSpellAbility(), game, true, mor); castCardOne = false; } if (cardTwo != null) { Card copyTwo = game.copyCard(cardTwo, source, controller.getId()); - controller.cast(copyTwo.getSpellAbility(), game, true); + controller.cast(copyTwo.getSpellAbility(), game, true, mor); } if (cardOne != null && castCardOne) { Card copyOne = game.copyCard(cardOne, source, controller.getId()); - controller.cast(copyOne.getSpellAbility(), game, true); + controller.cast(copyOne.getSpellAbility(), game, true, mor); } return true; } diff --git a/Mage.Sets/src/mage/cards/s/SpellweaverHelix.java b/Mage.Sets/src/mage/cards/s/SpellweaverHelix.java index ce0feffb925..7fb05d33d40 100644 --- a/Mage.Sets/src/mage/cards/s/SpellweaverHelix.java +++ b/Mage.Sets/src/mage/cards/s/SpellweaverHelix.java @@ -28,6 +28,7 @@ package mage.cards.s; import java.util.UUID; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -55,20 +56,21 @@ import mage.util.CardUtil; * @author emerald000 */ public class SpellweaverHelix extends CardImpl { - + private static final FilterCard filter = new FilterCard("sorcery cards from a single graveyard"); + static { filter.add(new CardTypePredicate(CardType.SORCERY)); } public SpellweaverHelix(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{3}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); // Imprint - When Spellweaver Helix enters the battlefield, you may exile two target sorcery cards from a single graveyard. Ability ability = new EntersBattlefieldTriggeredAbility(new SpellweaverHelixImprintEffect(), true, "Imprint — "); ability.addTarget(new TargetCardInASingleGraveyard(2, 2, filter)); this.addAbility(ability); - + // Whenever a player casts a card, if it has the same name as one of the cards exiled with Spellweaver Helix, you may copy the other. If you do, you may cast the copy without paying its mana cost. this.addAbility(new SpellweaverHelixTriggeredAbility()); } @@ -84,21 +86,21 @@ public class SpellweaverHelix extends CardImpl { } class SpellweaverHelixImprintEffect extends OneShotEffect { - + SpellweaverHelixImprintEffect() { super(Outcome.Exile); this.staticText = "you may exile two target sorcery cards from a single graveyard"; } - + SpellweaverHelixImprintEffect(final SpellweaverHelixImprintEffect effect) { super(effect); } - + @Override public SpellweaverHelixImprintEffect copy() { return new SpellweaverHelixImprintEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); @@ -120,20 +122,20 @@ class SpellweaverHelixImprintEffect extends OneShotEffect { } class SpellweaverHelixTriggeredAbility extends TriggeredAbilityImpl { - + SpellweaverHelixTriggeredAbility() { super(Zone.BATTLEFIELD, new SpellweaverHelixCastEffect(), false); } - + SpellweaverHelixTriggeredAbility(final SpellweaverHelixTriggeredAbility ability) { super(ability); } - + @Override public SpellweaverHelixTriggeredAbility copy() { return new SpellweaverHelixTriggeredAbility(this); } - + @Override public boolean checkEventType(GameEvent event, Game game) { return event.getType() == GameEvent.EventType.SPELL_CAST; @@ -169,7 +171,7 @@ class SpellweaverHelixTriggeredAbility extends TriggeredAbilityImpl { } return false; } - + @Override public String getRule() { return "Whenever a player casts a card, if it has the same name as one of the cards exiled with Spellweaver Helix, you may copy the other. If you do, you may cast the copy without paying its mana cost."; @@ -177,28 +179,28 @@ class SpellweaverHelixTriggeredAbility extends TriggeredAbilityImpl { } class SpellweaverHelixCastEffect extends OneShotEffect { - + private String spellName = ""; - + SpellweaverHelixCastEffect() { super(Outcome.Benefit); this.staticText = "you may copy the other. If you do, you may cast the copy without paying its mana cost"; } - + SpellweaverHelixCastEffect(final SpellweaverHelixCastEffect effect) { super(effect); this.spellName = effect.spellName; } - + @Override public SpellweaverHelixCastEffect copy() { return new SpellweaverHelixCastEffect(this); } - + public void setSpellName(String spellName) { this.spellName = spellName; } - + @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); @@ -211,12 +213,11 @@ class SpellweaverHelixCastEffect extends OneShotEffect { if (card != null) { if (!foundSpellWithSameName && card.getName().equals(spellName)) { foundSpellWithSameName = true; - } - else { + } else { if (controller.chooseUse(Outcome.Copy, "Copy " + card.getIdName(), source, game)) { Card copy = game.copyCard(card, source, source.getControllerId()); if (controller.chooseUse(Outcome.PlayForFree, "Cast " + copy.getIdName() + " without paying its mana cost?", source, game)) { - controller.cast(copy.getSpellAbility(), game, true); + controller.cast(copy.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } } } diff --git a/Mage.Sets/src/mage/cards/s/SpellweaverVolute.java b/Mage.Sets/src/mage/cards/s/SpellweaverVolute.java index ea17f9d45c0..d75eb814f19 100644 --- a/Mage.Sets/src/mage/cards/s/SpellweaverVolute.java +++ b/Mage.Sets/src/mage/cards/s/SpellweaverVolute.java @@ -28,6 +28,7 @@ package mage.cards.s; import java.util.UUID; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -119,7 +120,7 @@ class SpellweaverVoluteEffect extends OneShotEffect { game.getState().setZone(copiedCard.getId(), Zone.GRAVEYARD); if (controller.chooseUse(outcome, "Cast the copied card without paying mana cost?", source, game)) { if (copiedCard.getSpellAbility() != null) { - controller.cast(copiedCard.getSpellAbility(), game, true); + controller.cast(copiedCard.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } if (controller.moveCards(enchantedCard, Zone.EXILED, source, game)) { FilterCard filter = new FilterCard("instant card in a graveyard"); diff --git a/Mage.Sets/src/mage/cards/s/SunbirdsInvocation.java b/Mage.Sets/src/mage/cards/s/SunbirdsInvocation.java index 1481a10263e..176d66d9d20 100644 --- a/Mage.Sets/src/mage/cards/s/SunbirdsInvocation.java +++ b/Mage.Sets/src/mage/cards/s/SunbirdsInvocation.java @@ -29,6 +29,7 @@ package mage.cards.s; import java.util.UUID; import mage.MageObject; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.effects.Effect; @@ -156,7 +157,7 @@ class SunbirdsInvocationEffect extends OneShotEffect { Card card = cards.get(target.getFirstTarget(), game); if (card != null) { if (controller.chooseUse(Outcome.Benefit, "Cast " + card.getLogName() + " without paying its mana cost?", source, game)) { - controller.cast(card.getSpellAbility(), game, true); + controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); cards.remove(card); } } diff --git a/Mage.Sets/src/mage/cards/s/Sunforger.java b/Mage.Sets/src/mage/cards/s/Sunforger.java index cd54573746c..7013d39aaf8 100644 --- a/Mage.Sets/src/mage/cards/s/Sunforger.java +++ b/Mage.Sets/src/mage/cards/s/Sunforger.java @@ -28,6 +28,7 @@ package mage.cards.s; import java.util.UUID; +import mage.MageObjectReference; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.SpellAbility; @@ -44,10 +45,10 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.ComparisonType; import mage.constants.Duration; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.Predicate; @@ -133,7 +134,7 @@ class SunforgerEffect extends OneShotEffect { UUID targetId = target.getFirstTarget(); Card card = game.getCard(targetId); if (card != null) { - controller.cast(card.getSpellAbility(), game, true); + controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } } } diff --git a/Mage.Sets/src/mage/cards/t/TalentOfTheTelepath.java b/Mage.Sets/src/mage/cards/t/TalentOfTheTelepath.java index 68475d200ce..be932551d26 100644 --- a/Mage.Sets/src/mage/cards/t/TalentOfTheTelepath.java +++ b/Mage.Sets/src/mage/cards/t/TalentOfTheTelepath.java @@ -30,6 +30,7 @@ package mage.cards.t; import java.util.Set; import java.util.UUID; import mage.MageObject; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.condition.common.SpellMasteryCondition; import mage.abilities.effects.OneShotEffect; @@ -55,7 +56,7 @@ import mage.target.common.TargetOpponent; public class TalentOfTheTelepath extends CardImpl { public TalentOfTheTelepath(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{U}{U}"); // Target opponent reveals the top seven cards of their library. You may cast an instant or sorcery card from among them without paying its mana cost. Then that player puts the rest into their graveyard. // Spell mastery — If there are two or more instant and/or sorcery cards in your graveyard, you may cast up to two revealed instant and/or sorcery cards instead of one. @@ -127,7 +128,7 @@ class TalentOfTheTelepathEffect extends OneShotEffect { && controller.choose(outcome, cardsToCast, target, game)) { Card card = cardsToCast.get(target.getFirstTarget(), game); if (card != null) { - controller.cast(card.getSpellAbility(), game, true); + controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); numberOfSpells--; cardsToCast.remove(card); allCards.remove(card); diff --git a/Mage.Sets/src/mage/cards/t/ThunderbladeCharge.java b/Mage.Sets/src/mage/cards/t/ThunderbladeCharge.java index 73f3e813c30..8760a683b51 100644 --- a/Mage.Sets/src/mage/cards/t/ThunderbladeCharge.java +++ b/Mage.Sets/src/mage/cards/t/ThunderbladeCharge.java @@ -28,6 +28,7 @@ package mage.cards.t; import java.util.UUID; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.ControlledCreaturesDealCombatDamagePlayerTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; @@ -96,7 +97,7 @@ class ThunderbladeChargeCastEffect extends OneShotEffect { if (controller != null && sourceCard != null && Zone.GRAVEYARD == game.getState().getZone(sourceCard.getId())) { - controller.cast(sourceCard.getSpellAbility(), game, true); + controller.cast(sourceCard.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); return true; } return false; diff --git a/Mage.Sets/src/mage/cards/t/TorrentialGearhulk.java b/Mage.Sets/src/mage/cards/t/TorrentialGearhulk.java index 838bf4f9ad9..bdce562404e 100644 --- a/Mage.Sets/src/mage/cards/t/TorrentialGearhulk.java +++ b/Mage.Sets/src/mage/cards/t/TorrentialGearhulk.java @@ -29,6 +29,7 @@ package mage.cards.t; import java.util.UUID; import mage.MageInt; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.ContinuousEffect; @@ -39,9 +40,9 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.mageobject.CardTypePredicate; @@ -115,7 +116,7 @@ class TorrentialGearhulkEffect extends OneShotEffect { Card card = game.getCard(this.getTargetPointer().getFirst(game, source)); if (card != null && card.getSpellAbility() != null) { if (controller.chooseUse(outcome, "Cast " + card.getLogName() + '?', source, game)) { - if (controller.cast(card.getSpellAbility(), game, true)) { + if (controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game))) { ContinuousEffect effect = new TorrentialGearhulkReplacementEffect(card.getId()); effect.setTargetPointer(new FixedTarget(card.getId(), game.getState().getZoneChangeCounter(card.getId()))); game.addEffect(effect, source); diff --git a/Mage.Sets/src/mage/cards/t/ToshiroUmezawa.java b/Mage.Sets/src/mage/cards/t/ToshiroUmezawa.java index 5352b3dd2b5..28e7381a398 100644 --- a/Mage.Sets/src/mage/cards/t/ToshiroUmezawa.java +++ b/Mage.Sets/src/mage/cards/t/ToshiroUmezawa.java @@ -29,6 +29,7 @@ package mage.cards.t; import java.util.UUID; import mage.MageInt; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.DiesCreatureTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -115,7 +116,7 @@ class ToshiroUmezawaEffect extends OneShotEffect { if (controller != null) { Card card = game.getCard(getTargetPointer().getFirst(game, source)); if (card != null) { - controller.cast(card.getSpellAbility(), game, false); + controller.cast(card.getSpellAbility(), game, false, new MageObjectReference(source.getSourceObject(game), game)); game.addEffect(new ToshiroUmezawaReplacementEffect(card.getId()), source); } } diff --git a/Mage.Sets/src/mage/cards/t/TreasureKeeper.java b/Mage.Sets/src/mage/cards/t/TreasureKeeper.java index ada27fe5b99..6c748828ee0 100644 --- a/Mage.Sets/src/mage/cards/t/TreasureKeeper.java +++ b/Mage.Sets/src/mage/cards/t/TreasureKeeper.java @@ -29,6 +29,7 @@ package mage.cards.t; import java.util.UUID; import mage.MageInt; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.DiesTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -97,7 +98,7 @@ class TreasureKeeperEffect extends OneShotEffect { } controller.revealCards(source, toReveal, game); if (nonLandCard != null && controller.chooseUse(outcome, "Cast " + nonLandCard.getLogName() + "without paying its mana cost?", source, game)) { - controller.cast(nonLandCard.getSpellAbility(), game, true); + controller.cast(nonLandCard.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); toReveal.remove(nonLandCard); } controller.putCardsOnBottomOfLibrary(toReveal, game, source, false); diff --git a/Mage.Sets/src/mage/cards/t/TwinningGlass.java b/Mage.Sets/src/mage/cards/t/TwinningGlass.java index 687ecc7ab79..f0748923a73 100644 --- a/Mage.Sets/src/mage/cards/t/TwinningGlass.java +++ b/Mage.Sets/src/mage/cards/t/TwinningGlass.java @@ -29,6 +29,7 @@ package mage.cards.t; import java.util.List; import java.util.UUID; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; @@ -121,7 +122,7 @@ class TwinningGlassEffect extends OneShotEffect { Card chosenCard = game.getCard(target.getFirstTarget()); if (chosenCard != null) { if (controller.chooseUse(outcome, "Cast the card without paying mana cost?", source, game)) { - return controller.cast(chosenCard.getSpellAbility(), game, true); + return controller.cast(chosenCard.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } } } diff --git a/Mage.Sets/src/mage/cards/u/UnexpectedResults.java b/Mage.Sets/src/mage/cards/u/UnexpectedResults.java index 7b2fc870937..c4d95769dd4 100644 --- a/Mage.Sets/src/mage/cards/u/UnexpectedResults.java +++ b/Mage.Sets/src/mage/cards/u/UnexpectedResults.java @@ -28,6 +28,7 @@ package mage.cards.u; import java.util.UUID; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; @@ -126,7 +127,7 @@ class UnexpectedResultEffect extends OneShotEffect { } } else { if (controller.chooseUse(outcome, new StringBuilder("Cast ").append(card.getName()).append(" without paying its mana cost?").toString(), source, game)) { - return controller.cast(card.getSpellAbility(), game, true); + return controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } } return true; diff --git a/Mage.Sets/src/mage/cards/v/VillainousWealth.java b/Mage.Sets/src/mage/cards/v/VillainousWealth.java index f33f371f908..632a61bd862 100644 --- a/Mage.Sets/src/mage/cards/v/VillainousWealth.java +++ b/Mage.Sets/src/mage/cards/v/VillainousWealth.java @@ -29,6 +29,7 @@ package mage.cards.v; import java.util.UUID; import mage.MageObject; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.*; @@ -110,7 +111,7 @@ class VillainousWealthEffect extends OneShotEffect { while (cardsToExile.count(filter, game) > 0 && controller.choose(Outcome.PlayForFree, cardsToExile, target, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { - controller.cast(card.getSpellAbility(), game, true); + controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); cardsToExile.remove(card); } else { break OuterLoop; diff --git a/Mage.Sets/src/mage/cards/w/WellOfKnowledge.java b/Mage.Sets/src/mage/cards/w/WellOfKnowledge.java index 6a18a11d475..065b0b931ff 100644 --- a/Mage.Sets/src/mage/cards/w/WellOfKnowledge.java +++ b/Mage.Sets/src/mage/cards/w/WellOfKnowledge.java @@ -89,14 +89,14 @@ class WellOfKnowledgeConditionalActivatedAbility extends ActivatedAbilityImpl { } @Override - public boolean canActivate(UUID playerId, Game game) { + public ActivationStatus canActivate(UUID playerId, Game game) { if (condition.apply(game, this) && costs.canPay(this, sourceId, playerId, game) && game.getActivePlayerId().equals(playerId)) { this.activatorId = playerId; - return true; + return ActivationStatus.getTrue(); } - return false; + return ActivationStatus.getFalse(); } diff --git a/Mage.Sets/src/mage/cards/w/WildEvocation.java b/Mage.Sets/src/mage/cards/w/WildEvocation.java index ef18829166e..f9442a56b93 100644 --- a/Mage.Sets/src/mage/cards/w/WildEvocation.java +++ b/Mage.Sets/src/mage/cards/w/WildEvocation.java @@ -29,6 +29,7 @@ package mage.cards.w; import java.util.UUID; import mage.MageObject; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -96,7 +97,7 @@ class WildEvocationEffect extends OneShotEffect { player.moveCards(card, Zone.BATTLEFIELD, source, game); } else if (card.getSpellAbility() != null && card.getSpellAbility().getTargets().canChoose(player.getId(), game)) { - player.cast(card.getSpellAbility(), game, true); + player.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } else { game.informPlayers(GameLog.getColoredObjectName(card) + " can't be cast now by " + player.getLogName()); } diff --git a/Mage.Sets/src/mage/cards/w/WildfireEternal.java b/Mage.Sets/src/mage/cards/w/WildfireEternal.java index c489232bbd0..40d3ea4c1f6 100644 --- a/Mage.Sets/src/mage/cards/w/WildfireEternal.java +++ b/Mage.Sets/src/mage/cards/w/WildfireEternal.java @@ -29,6 +29,7 @@ package mage.cards.w; import java.util.UUID; import mage.MageInt; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.AttacksAndIsNotBlockedTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -37,8 +38,8 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.filter.FilterCard; import mage.filter.common.FilterInstantOrSorceryCard; import mage.game.Game; @@ -104,7 +105,7 @@ class WildfireEternalCastEffect extends OneShotEffect { controller.chooseTarget(outcome, target, source, game); Card card = game.getCard(target.getFirstTarget()); if (card != null) { - controller.cast(card.getSpellAbility(), game, true); + controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } } return true; diff --git a/Mage.Sets/src/mage/cards/w/WrexialTheRisenDeep.java b/Mage.Sets/src/mage/cards/w/WrexialTheRisenDeep.java index a98bd2de1e2..b9ec932e4a7 100644 --- a/Mage.Sets/src/mage/cards/w/WrexialTheRisenDeep.java +++ b/Mage.Sets/src/mage/cards/w/WrexialTheRisenDeep.java @@ -29,6 +29,7 @@ package mage.cards.w; import java.util.UUID; import mage.MageInt; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -119,7 +120,7 @@ class WrexialEffect extends OneShotEffect { if (controller.chooseTarget(Outcome.PlayForFree, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { - controller.cast(card.getSpellAbility(), game, true); + controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); game.addEffect(new WrexialReplacementEffect(card.getId()), source); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/FiendOfTheShadowsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/FiendOfTheShadowsTest.java index 9c5b8ca20e4..bdde801cd48 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/FiendOfTheShadowsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/FiendOfTheShadowsTest.java @@ -39,6 +39,8 @@ public class FiendOfTheShadowsTest extends CardTestPlayerBase { @Test public void testCardExile1() { + // Whenever Fiend of the Shadows deals combat damage to a player, that player exiles a card from their hand. You may play that card for as long as it remains exiled. + // Sacrifice a Human: Regenerate Fiend of the Shadows. addCard(Zone.BATTLEFIELD, playerA, "Fiend of the Shadows"); removeAllCardsFromHand(playerB); addCard(Zone.HAND, playerB, "Swamp"); diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java index 627f0930642..78f47f0315a 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java @@ -495,7 +495,7 @@ public class TestPlayer implements Player { List manaPermsWithCost = computerPlayer.getAvailableManaProducersWithCost(game); for (Permanent perm : manaPermsWithCost) { for (ActivatedManaAbilityImpl manaAbility : perm.getAbilities().getAvailableActivatedManaAbilities(Zone.BATTLEFIELD, game)) { - if (manaAbility.toString().startsWith(groups[0]) && manaAbility.canActivate(computerPlayer.getId(), game)) { + if (manaAbility.toString().startsWith(groups[0]) && manaAbility.canActivate(computerPlayer.getId(), game).canActivate()) { Ability newManaAbility = manaAbility.copy(); computerPlayer.activateAbility((ActivatedAbility) newManaAbility, game); actions.remove(action); @@ -1598,13 +1598,13 @@ public class TestPlayer implements Player { } @Override - public boolean cast(SpellAbility ability, Game game, boolean noMana) { - return computerPlayer.cast(ability, game, noMana); + public boolean cast(SpellAbility ability, Game game, boolean noMana, MageObjectReference reference) { + return computerPlayer.cast(ability, game, noMana, reference); } @Override - public boolean playCard(Card card, Game game, boolean noMana, boolean ignoreTiming) { - return computerPlayer.playCard(card, game, noMana, ignoreTiming); + public boolean playCard(Card card, Game game, boolean noMana, boolean ignoreTiming, MageObjectReference reference) { + return computerPlayer.playCard(card, game, noMana, ignoreTiming, reference); } @Override diff --git a/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java b/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java index 79da1b98fa8..2b79823cf43 100644 --- a/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java +++ b/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java @@ -30,6 +30,7 @@ package org.mage.test.stub; import java.io.Serializable; import java.util.*; import mage.MageObject; +import mage.MageObjectReference; import mage.abilities.*; import mage.abilities.costs.AlternativeSourceCosts; import mage.abilities.costs.Cost; @@ -564,7 +565,7 @@ public class PlayerStub implements Player { } @Override - public boolean cast(SpellAbility ability, Game game, boolean noMana) { + public boolean cast(SpellAbility ability, Game game, boolean noMana, MageObjectReference reference) { return false; } @@ -619,7 +620,7 @@ public class PlayerStub implements Player { } @Override - public boolean playCard(Card card, Game game, boolean noMana, boolean checkTiming) { + public boolean playCard(Card card, Game game, boolean noMana, boolean checkTiming, MageObjectReference reference) { return false; } diff --git a/Mage/src/main/java/mage/abilities/AbilitiesImpl.java b/Mage/src/main/java/mage/abilities/AbilitiesImpl.java index 4b99d2d8ed0..8e79524bf53 100644 --- a/Mage/src/main/java/mage/abilities/AbilitiesImpl.java +++ b/Mage/src/main/java/mage/abilities/AbilitiesImpl.java @@ -157,7 +157,7 @@ public class AbilitiesImpl extends ArrayList implements Ab return stream() .filter(ability -> ability instanceof ActivatedManaAbilityImpl) .filter(ability -> ability.getZone().match(zone)) - .filter(ability -> (((ActivatedManaAbilityImpl) ability).canActivate(ability.getControllerId(), game))) + .filter(ability -> (((ActivatedManaAbilityImpl) ability).canActivate(ability.getControllerId(), game).canActivate())) .map(ability -> (ActivatedManaAbilityImpl) ability) .collect(Collectors.toCollection(AbilitiesImpl::new)); diff --git a/Mage/src/main/java/mage/abilities/ActivatedAbility.java b/Mage/src/main/java/mage/abilities/ActivatedAbility.java index b8d15bffcd8..22e9f8ecb39 100644 --- a/Mage/src/main/java/mage/abilities/ActivatedAbility.java +++ b/Mage/src/main/java/mage/abilities/ActivatedAbility.java @@ -28,6 +28,7 @@ package mage.abilities; import java.util.UUID; +import mage.MageObjectReference; import mage.abilities.mana.ManaOptions; import mage.constants.TargetController; import mage.game.Game; @@ -38,9 +39,36 @@ import mage.game.Game; */ public interface ActivatedAbility extends Ability { - boolean canActivate(UUID playerId, Game game); + final public class ActivationStatus { - public void setMayActivate(TargetController mayActivate); + private final boolean canActivate; + private final MageObjectReference permittingObject; + + public ActivationStatus(boolean canActivate, MageObjectReference permittingObject) { + this.canActivate = canActivate; + this.permittingObject = permittingObject; + } + + public boolean canActivate() { + return canActivate; + } + + public MageObjectReference getPermittingObject() { + return permittingObject; + } + + public static ActivationStatus getFalse() { + return new ActivationStatus(false, null); + } + + public static ActivationStatus getTrue() { + return new ActivationStatus(true, null); + } + } + + ActivationStatus canActivate(UUID playerId, Game game); // has to return a reference to the permitting ability/source + + void setMayActivate(TargetController mayActivate); /** * Returns the minimal possible cost for what the ability can be activated diff --git a/Mage/src/main/java/mage/abilities/ActivatedAbilityImpl.java b/Mage/src/main/java/mage/abilities/ActivatedAbilityImpl.java index f199003774e..aaa4eeffd21 100644 --- a/Mage/src/main/java/mage/abilities/ActivatedAbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/ActivatedAbilityImpl.java @@ -29,6 +29,7 @@ package mage.abilities; import java.util.UUID; import mage.MageObject; +import mage.MageObjectReference; import mage.abilities.condition.Condition; import mage.abilities.costs.Cost; import mage.abilities.costs.Costs; @@ -177,38 +178,39 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa public abstract ActivatedAbilityImpl copy(); @Override - public boolean canActivate(UUID playerId, Game game) { + public ActivationStatus canActivate(UUID playerId, Game game) { //20091005 - 602.2 if (!(hasMoreActivationsThisTurn(game) && (condition == null || condition.apply(game, this)))) { - return false; + return ActivationStatus.getFalse(); } switch (mayActivate) { case ANY: break; + case NOT_YOU: if (controlsAbility(playerId, game)) { - return false; + return ActivationStatus.getFalse(); } break; case TEAM: if (game.getPlayer(controllerId).hasOpponent(playerId, game)) { - return false; + return ActivationStatus.getFalse(); } break; case OPPONENT: if (!game.getPlayer(controllerId).hasOpponent(playerId, game)) { - return false; + return ActivationStatus.getFalse(); } break; case OWNER: Permanent permanent = game.getPermanent(getSourceId()); if (!permanent.getOwnerId().equals(playerId)) { - return false; + return ActivationStatus.getFalse(); } break; case YOU: if (!controlsAbility(playerId, game)) { - return false; + return ActivationStatus.getFalse(); } break; case CONTROLLER_ATTACHED_TO: @@ -219,17 +221,17 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa break; } } - return false; + return ActivationStatus.getFalse(); } //20091005 - 602.5d/602.5e - if (timing == TimingRule.INSTANT || game.canPlaySorcery(playerId) - || null != game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.ACTIVATE_AS_INSTANT, this, controllerId, game)) { + MageObjectReference permittingObject = game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.ACTIVATE_AS_INSTANT, this, controllerId, game); + if (timing == TimingRule.INSTANT || game.canPlaySorcery(playerId) || null != permittingObject) { if (costs.canPay(this, sourceId, playerId, game) && canChooseTarget(game)) { this.activatorId = playerId; - return true; + return new ActivationStatus(true, permittingObject); } } - return false; + return ActivationStatus.getFalse(); } @Override @@ -310,10 +312,12 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa return false; } + @Override public void setMaxActivationsPerTurn(int maxActivationsPerTurn) { this.maxActivationsPerTurn = maxActivationsPerTurn; } + @Override public int getMaxActivationsPerTurn(Game game) { return maxActivationsPerTurn; } diff --git a/Mage/src/main/java/mage/abilities/PlayLandAbility.java b/Mage/src/main/java/mage/abilities/PlayLandAbility.java index 5aa10fb6cd9..65d6a17b11c 100644 --- a/Mage/src/main/java/mage/abilities/PlayLandAbility.java +++ b/Mage/src/main/java/mage/abilities/PlayLandAbility.java @@ -28,6 +28,7 @@ package mage.abilities; import java.util.UUID; +import mage.MageObjectReference; import mage.constants.AbilityType; import mage.constants.AsThoughEffectType; import mage.constants.Zone; @@ -50,13 +51,13 @@ public class PlayLandAbility extends ActivatedAbilityImpl { } @Override - public boolean canActivate(UUID playerId, Game game) { - if (!controlsAbility(playerId, game) - && null == game.getContinuousEffects().asThough(getSourceId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, playerId, game)) { - return false; + public ActivationStatus canActivate(UUID playerId, Game game) { + MageObjectReference permittingObject = game.getContinuousEffects().asThough(getSourceId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, null, playerId, game); + if (!controlsAbility(playerId, game) && null == permittingObject) { + return ActivationStatus.getFalse(); } //20091005 - 114.2a - return game.getActivePlayerId().equals(playerId) && game.getPlayer(playerId).canPlayLand() && game.canPlaySorcery(playerId); + return new ActivationStatus(game.getActivePlayerId().equals(playerId) && game.getPlayer(playerId).canPlayLand() && game.canPlaySorcery(playerId), permittingObject); } @Override diff --git a/Mage/src/main/java/mage/abilities/SpellAbility.java b/Mage/src/main/java/mage/abilities/SpellAbility.java index 84491fb0096..00c2144b06b 100644 --- a/Mage/src/main/java/mage/abilities/SpellAbility.java +++ b/Mage/src/main/java/mage/abilities/SpellAbility.java @@ -29,6 +29,7 @@ package mage.abilities; import java.util.UUID; import mage.MageObject; +import mage.MageObjectReference; import mage.abilities.costs.Cost; import mage.abilities.costs.VariableCost; import mage.abilities.costs.mana.ManaCost; @@ -91,48 +92,49 @@ public class SpellAbility extends ActivatedAbilityImpl { } @Override - public boolean canActivate(UUID playerId, Game game) { + public ActivationStatus canActivate(UUID playerId, Game game) { if (null != game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.CAST_AS_INSTANT, this, playerId, game) // check this first to allow Offering in main phase || this.spellCanBeActivatedRegularlyNow(playerId, game)) { if (spellAbilityType == SpellAbilityType.SPLIT || spellAbilityType == SpellAbilityType.SPLIT_AFTERMATH) { - return false; + return ActivationStatus.getFalse(); } // fix for Gitaxian Probe and casting opponent's spells - if (null == game.getContinuousEffects().asThough(getSourceId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, playerId, game)) { + MageObjectReference permittingSource = game.getContinuousEffects().asThough(getSourceId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, null, playerId, game); + if (permittingSource == null) { Card card = game.getCard(sourceId); if (!(card != null && card.getOwnerId().equals(playerId))) { - return false; + return ActivationStatus.getFalse(); } } // Check if rule modifying events prevent to cast the spell in check playable mode if (this.isCheckPlayableMode()) { if (game.getContinuousEffects().preventedByRuleModification( GameEvent.getEvent(GameEvent.EventType.CAST_SPELL, this.getId(), this.getSourceId(), playerId), this, game, true)) { - return false; + return ActivationStatus.getFalse(); } } // Alternate spell abilities (Flashback, Overload) can't be cast with no mana to pay option if (getSpellAbilityType() == SpellAbilityType.BASE_ALTERNATE) { Player player = game.getPlayer(playerId); if (player != null && getSourceId().equals(player.getCastSourceIdWithAlternateMana())) { - return false; + return ActivationStatus.getFalse(); } } if (costs.canPay(this, sourceId, controllerId, game)) { if (getSpellAbilityType() == SpellAbilityType.SPLIT_FUSED) { SplitCard splitCard = (SplitCard) game.getCard(getSourceId()); if (splitCard != null) { - return (splitCard.getLeftHalfCard().getSpellAbility().canChooseTarget(game) - && splitCard.getRightHalfCard().getSpellAbility().canChooseTarget(game)); + return new ActivationStatus(splitCard.getLeftHalfCard().getSpellAbility().canChooseTarget(game) + && splitCard.getRightHalfCard().getSpellAbility().canChooseTarget(game), null); } - return false; + return ActivationStatus.getFalse(); } else { - return canChooseTarget(game); + return new ActivationStatus(canChooseTarget(game), permittingSource); } } } - return false; + return ActivationStatus.getFalse(); } @Override diff --git a/Mage/src/main/java/mage/abilities/common/PassAbility.java b/Mage/src/main/java/mage/abilities/common/PassAbility.java index 1c64b2a05c9..9220ecfdc76 100644 --- a/Mage/src/main/java/mage/abilities/common/PassAbility.java +++ b/Mage/src/main/java/mage/abilities/common/PassAbility.java @@ -1,16 +1,16 @@ /* * 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 @@ -20,18 +20,17 @@ * 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.abilities.common; import java.util.UUID; -import mage.constants.Zone; import mage.abilities.ActivatedAbilityImpl; import mage.abilities.effects.common.PassEffect; +import mage.constants.Zone; import mage.game.Game; /** @@ -55,8 +54,8 @@ public class PassAbility extends ActivatedAbilityImpl { } @Override - public boolean canActivate(UUID playerId, Game game) { - return true; + public ActivationStatus canActivate(UUID playerId, Game game) { + return ActivationStatus.getTrue(); } @Override diff --git a/Mage/src/main/java/mage/abilities/costs/common/TapSourceCost.java b/Mage/src/main/java/mage/abilities/costs/common/TapSourceCost.java index d127b664918..c321bcc54ee 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/TapSourceCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/TapSourceCost.java @@ -63,7 +63,7 @@ public class TapSourceCost extends CostImpl { Permanent permanent = game.getPermanent(sourceId); if (permanent != null) { return !permanent.isTapped() - && (permanent.canTap() || null != game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.ACTIVATE_HASTE, controllerId, game)); + && (permanent.canTap() || null != game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.ACTIVATE_HASTE, ability, controllerId, game)); } return false; } diff --git a/Mage/src/main/java/mage/abilities/costs/common/UntapSourceCost.java b/Mage/src/main/java/mage/abilities/costs/common/UntapSourceCost.java index 15af412080f..f1fce810e5c 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/UntapSourceCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/UntapSourceCost.java @@ -62,7 +62,7 @@ public class UntapSourceCost extends CostImpl { public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { Permanent permanent = game.getPermanent(sourceId); if (permanent != null) { - return permanent.isTapped() && (permanent.canTap() || null != game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.ACTIVATE_HASTE, controllerId, game)); + return permanent.isTapped() && (permanent.canTap() || null != game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.ACTIVATE_HASTE, ability, controllerId, game)); } return false; } diff --git a/Mage/src/main/java/mage/abilities/decorator/ConditionalGainActivatedAbility.java b/Mage/src/main/java/mage/abilities/decorator/ConditionalGainActivatedAbility.java index 41660dda3e3..deedcca4468 100644 --- a/Mage/src/main/java/mage/abilities/decorator/ConditionalGainActivatedAbility.java +++ b/Mage/src/main/java/mage/abilities/decorator/ConditionalGainActivatedAbility.java @@ -82,9 +82,9 @@ public class ConditionalGainActivatedAbility extends ActivatedAbilityImpl { } @Override - public boolean canActivate(UUID playerId, Game game) { + public ActivationStatus canActivate(UUID playerId, Game game) { if (!condition.apply(game, this)) { - return false; + return ActivationStatus.getFalse(); } return super.canActivate(playerId, game); } diff --git a/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java b/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java index 880e67ad440..cd4a15c37e2 100644 --- a/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java +++ b/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java @@ -32,6 +32,7 @@ import java.util.*; import java.util.Map.Entry; import java.util.stream.Collectors; import mage.MageObject; +import mage.MageObjectReference; import mage.abilities.*; import mage.abilities.effects.common.continuous.BecomesFaceDownCreatureEffect; import mage.abilities.effects.common.continuous.CommanderReplacementEffect; @@ -502,19 +503,6 @@ public class ContinuousEffects implements Serializable { return spliceEffects; } - /** - * - * @param objectId - * @param type - * @param controllerId - * @param game - * @return sourceId of the permitting effect if any exists otherwise returns - * null - */ - public UUID asThough(UUID objectId, AsThoughEffectType type, UUID controllerId, Game game) { - return asThough(objectId, type, null, controllerId, game); - } - /** * * @param objectId @@ -525,17 +513,17 @@ public class ContinuousEffects implements Serializable { * @return sourceId of the permitting effect if any exists otherwise returns * null */ - public UUID asThough(UUID objectId, AsThoughEffectType type, Ability affectedAbility, UUID controllerId, Game game) { + public MageObjectReference asThough(UUID objectId, AsThoughEffectType type, Ability affectedAbility, UUID controllerId, Game game) { List asThoughEffectsList = getApplicableAsThoughEffects(type, game); for (AsThoughEffect effect : asThoughEffectsList) { Set abilities = asThoughEffectsMap.get(type).getAbility(effect.getId()); for (Ability ability : abilities) { if (affectedAbility == null) { if (effect.applies(objectId, ability, controllerId, game)) { - return ability.getSourceId(); + return new MageObjectReference(ability.getSourceObject(game), game); } } else if (effect.applies(objectId, affectedAbility, ability, game)) { - return ability.getSourceId(); + return new MageObjectReference(ability.getSourceObject(game), game); } } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/CastCardFromOutsideTheGameEffect.java b/Mage/src/main/java/mage/abilities/effects/common/CastCardFromOutsideTheGameEffect.java index c8e1052d3a5..eb4a8df758b 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CastCardFromOutsideTheGameEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CastCardFromOutsideTheGameEffect.java @@ -28,6 +28,7 @@ package mage.abilities.effects.common; import java.util.Set; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; @@ -88,7 +89,7 @@ public class CastCardFromOutsideTheGameEffect extends OneShotEffect { } return false; } - + Cards filteredCards = new CardsImpl(); for (Card card : filtered) { filteredCards.add(card.getId()); @@ -98,7 +99,7 @@ public class CastCardFromOutsideTheGameEffect extends OneShotEffect { if (player.choose(Outcome.Benefit, filteredCards, target, game)) { Card card = player.getSideboard().get(target.getFirstTarget(), game); if (card != null) { - player.cast(card.getSpellAbility(), game, true); + player.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } } } @@ -106,4 +107,4 @@ public class CastCardFromOutsideTheGameEffect extends OneShotEffect { return true; } -} \ No newline at end of file +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/CipherEffect.java b/Mage/src/main/java/mage/abilities/effects/common/CipherEffect.java index bd4dc4146f4..9d66979137f 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CipherEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CipherEffect.java @@ -28,6 +28,7 @@ package mage.abilities.effects.common; import java.util.UUID; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.SpellAbility; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; @@ -151,7 +152,7 @@ class CipherStoreEffect extends OneShotEffect { } ability.getEffects().remove(cipherEffect); if (ability instanceof SpellAbility) { - controller.cast(ability, game, true); + controller.cast(ability, game, true, new MageObjectReference(source.getSourceObject(game), game)); } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/HideawayPlayEffect.java b/Mage/src/main/java/mage/abilities/effects/common/HideawayPlayEffect.java index 8fed10126d3..94a428f49b4 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/HideawayPlayEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/HideawayPlayEffect.java @@ -27,6 +27,8 @@ */ package mage.abilities.effects.common; +import java.util.UUID; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; @@ -36,8 +38,6 @@ import mage.game.Game; import mage.players.Player; import mage.util.CardUtil; -import java.util.UUID; - /** * @author LevelX2 * @@ -82,7 +82,7 @@ public class HideawayPlayEffect extends OneShotEffect { } } - if (!controller.playCard(card, game, true, true)) { + if (!controller.playCard(card, game, true, true, new MageObjectReference(source.getSourceObject(game), game))) { if (card.getZoneChangeCounter(game) == zcc) { card.setFaceDown(true, game); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/PlayTargetWithoutPayingManaEffect.java b/Mage/src/main/java/mage/abilities/effects/common/PlayTargetWithoutPayingManaEffect.java index 08612e5e187..8b3356482d0 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/PlayTargetWithoutPayingManaEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/PlayTargetWithoutPayingManaEffect.java @@ -24,16 +24,16 @@ * 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.abilities.effects.common; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; +import mage.constants.Outcome; +import mage.constants.Zone; import mage.game.Game; import mage.players.Player; import mage.target.Target; @@ -62,7 +62,7 @@ public class PlayTargetWithoutPayingManaEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); Card target = (Card) game.getObject(source.getFirstTarget()); if (controller != null && target != null) { - return controller.cast(target.getSpellAbility(), game, true); + return controller.cast(target.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } return false; } @@ -74,8 +74,7 @@ public class PlayTargetWithoutPayingManaEffect extends OneShotEffect { Target target = mode.getTargets().get(0); if (mode.getTargets().get(0).getZone() == Zone.HAND) { sb.append("you may put ").append(target.getTargetName()).append(" from your hand onto the battlefield"); - } - else { + } else { sb.append("you may cast target ").append(target.getTargetName()).append(" without paying its mana cost"); } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/cost/CastWithoutPayingManaCostEffect.java b/Mage/src/main/java/mage/abilities/effects/common/cost/CastWithoutPayingManaCostEffect.java index c389ece434b..43c43b1cf18 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/cost/CastWithoutPayingManaCostEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/cost/CastWithoutPayingManaCostEffect.java @@ -27,6 +27,7 @@ */ package mage.abilities.effects.common.cost; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; @@ -101,7 +102,7 @@ public class CastWithoutPayingManaCostEffect extends OneShotEffect { } } if (cardToCast != null) { - controller.cast(cardToCast.getSpellAbility(), game, true); + controller.cast(cardToCast.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } } return true; diff --git a/Mage/src/main/java/mage/abilities/effects/mana/AddConditionalManaOfAnyColorEffect.java b/Mage/src/main/java/mage/abilities/effects/mana/AddConditionalManaOfAnyColorEffect.java index 8cdb5f50276..359171a0ab7 100644 --- a/Mage/src/main/java/mage/abilities/effects/mana/AddConditionalManaOfAnyColorEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/mana/AddConditionalManaOfAnyColorEffect.java @@ -38,12 +38,15 @@ import mage.choices.ChoiceColor; import mage.game.Game; import mage.players.Player; import mage.util.CardUtil; +import org.apache.log4j.Logger; /** * @author noxx */ public class AddConditionalManaOfAnyColorEffect extends ManaEffect { + private static final Logger logger = Logger.getLogger(AddConditionalManaOfAnyColorEffect.class); + private final DynamicValue amount; private final ConditionalManaBuilder manaBuilder; private final boolean oneChoice; @@ -87,8 +90,13 @@ public class AddConditionalManaOfAnyColorEffect extends ManaEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - checkToFirePossibleEvents(getMana(game, source), game, source); - controller.getManaPool().addMana(getMana(game, source), game, source); + Mana mana = getMana(game, source); + if (mana != null) { + checkToFirePossibleEvents(mana, game, source); + controller.getManaPool().addMana(mana, game, source); + } else { + logger.error("There was no mana created: " + source.getSourceObject(game).getName() + " - Ability: " + source.getRule()); + } return true; } return false; diff --git a/Mage/src/main/java/mage/abilities/keyword/AssistAbility.java b/Mage/src/main/java/mage/abilities/keyword/AssistAbility.java index f56fd58e589..f1ebade5524 100644 --- a/Mage/src/main/java/mage/abilities/keyword/AssistAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/AssistAbility.java @@ -1,158 +1,159 @@ -/* - * 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.abilities.keyword; - -import mage.Mana; -import mage.abilities.Ability; -import mage.abilities.SpecialAction; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.costs.Cost; -import mage.abilities.costs.mana.AlternateManaPaymentAbility; -import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.costs.mana.ManaCost; -import mage.abilities.effects.OneShotEffect; -import mage.constants.AbilityType; -import mage.constants.ManaType; -import mage.constants.Outcome; -import mage.constants.TargetController; -import mage.constants.Zone; -import mage.filter.FilterPlayer; -import mage.filter.predicate.other.PlayerPredicate; -import mage.game.Game; -import mage.players.ManaPool; -import mage.players.Player; -import mage.target.Target; -import mage.target.TargetPlayer; - -/* - * @author emerald000 - */ -public class AssistAbility extends SimpleStaticAbility implements AlternateManaPaymentAbility { - - private static final FilterPlayer filter = new FilterPlayer("another player"); - static { - filter.add(new PlayerPredicate(TargetController.NOT_YOU)); - } - - public AssistAbility() { - super(Zone.STACK, null); - this.setRuleAtTheTop(true); - } - - public AssistAbility(final AssistAbility ability) { - super(ability); - } - - @Override - public AssistAbility copy() { - return new AssistAbility(this); - } - - @Override - public void addSpecialAction(Ability source, Game game, ManaCost unpaid) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null - && source.getAbilityType() == AbilityType.SPELL - && unpaid.getMana().getGeneric() >= 1 - && game.getState().getValue(source.getSourceId().toString() + game.getState().getZoneChangeCounter(source.getSourceId())) == null) { - SpecialAction specialAction = new AssistSpecialAction(unpaid); - specialAction.setControllerId(source.getControllerId()); - specialAction.setSourceId(source.getSourceId()); - Target target = new TargetPlayer(1, 1, true, filter); - specialAction.addTarget(target); - if (specialAction.canActivate(source.getControllerId(), game)) { - game.getState().getSpecialActions().add(specialAction); - } - } - } - - @Override - public String getRule() { - return "Assist (Another player can help pay the generic mana of this spell's cost.)"; - } -} - -class AssistSpecialAction extends SpecialAction { - - AssistSpecialAction(ManaCost unpaid) { - super(Zone.ALL, true); - setRuleVisible(false); - this.addEffect(new AssistEffect(unpaid)); - } - - AssistSpecialAction(final AssistSpecialAction ability) { - super(ability); - } - - @Override - public AssistSpecialAction copy() { - return new AssistSpecialAction(this); - } -} - -class AssistEffect extends OneShotEffect { - - private final ManaCost unpaid; - - AssistEffect(ManaCost unpaid) { - super(Outcome.Benefit); - this.unpaid = unpaid; - this.staticText = "Assist (Another player can help pay the generic mana of this spell's cost.)"; - } - - AssistEffect(final AssistEffect effect) { - super(effect); - this.unpaid = effect.unpaid; - } - - @Override - public AssistEffect copy() { - return new AssistEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - Player targetPlayer = game.getPlayer(this.getTargetPointer().getFirst(game, source)); - if (controller != null && targetPlayer != null) { - int amountToPay = targetPlayer.announceXMana(0, unpaid.getMana().getGeneric(), "How much mana to pay?", game, source); - if (amountToPay > 0) { - Cost cost = new GenericManaCost(amountToPay); - if (cost.pay(source, game, source.getSourceId(), targetPlayer.getId(), false)) { - ManaPool manaPool = controller.getManaPool(); - manaPool.addMana(Mana.ColorlessMana(amountToPay), game, source); - manaPool.unlockManaType(ManaType.COLORLESS); - game.informPlayers(targetPlayer.getLogName() + " paid " + amountToPay + " mana."); - game.getState().setValue(source.getSourceId().toString() + game.getState().getZoneChangeCounter(source.getSourceId()), true); - } - } - return true; - } - return false; - } -} +/* + * 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.abilities.keyword; + +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.SpecialAction; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.mana.AlternateManaPaymentAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.costs.mana.ManaCost; +import mage.abilities.effects.OneShotEffect; +import mage.constants.AbilityType; +import mage.constants.ManaType; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.FilterPlayer; +import mage.filter.predicate.other.PlayerPredicate; +import mage.game.Game; +import mage.players.ManaPool; +import mage.players.Player; +import mage.target.Target; +import mage.target.TargetPlayer; + +/* + * @author emerald000 + */ +public class AssistAbility extends SimpleStaticAbility implements AlternateManaPaymentAbility { + + private static final FilterPlayer filter = new FilterPlayer("another player"); + + static { + filter.add(new PlayerPredicate(TargetController.NOT_YOU)); + } + + public AssistAbility() { + super(Zone.STACK, null); + this.setRuleAtTheTop(true); + } + + public AssistAbility(final AssistAbility ability) { + super(ability); + } + + @Override + public AssistAbility copy() { + return new AssistAbility(this); + } + + @Override + public void addSpecialAction(Ability source, Game game, ManaCost unpaid) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null + && source.getAbilityType() == AbilityType.SPELL + && unpaid.getMana().getGeneric() >= 1 + && game.getState().getValue(source.getSourceId().toString() + game.getState().getZoneChangeCounter(source.getSourceId())) == null) { + SpecialAction specialAction = new AssistSpecialAction(unpaid); + specialAction.setControllerId(source.getControllerId()); + specialAction.setSourceId(source.getSourceId()); + Target target = new TargetPlayer(1, 1, true, filter); + specialAction.addTarget(target); + if (specialAction.canActivate(source.getControllerId(), game).canActivate()) { + game.getState().getSpecialActions().add(specialAction); + } + } + } + + @Override + public String getRule() { + return "Assist (Another player can help pay the generic mana of this spell's cost.)"; + } +} + +class AssistSpecialAction extends SpecialAction { + + AssistSpecialAction(ManaCost unpaid) { + super(Zone.ALL, true); + setRuleVisible(false); + this.addEffect(new AssistEffect(unpaid)); + } + + AssistSpecialAction(final AssistSpecialAction ability) { + super(ability); + } + + @Override + public AssistSpecialAction copy() { + return new AssistSpecialAction(this); + } +} + +class AssistEffect extends OneShotEffect { + + private final ManaCost unpaid; + + AssistEffect(ManaCost unpaid) { + super(Outcome.Benefit); + this.unpaid = unpaid; + this.staticText = "Assist (Another player can help pay the generic mana of this spell's cost.)"; + } + + AssistEffect(final AssistEffect effect) { + super(effect); + this.unpaid = effect.unpaid; + } + + @Override + public AssistEffect copy() { + return new AssistEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player targetPlayer = game.getPlayer(this.getTargetPointer().getFirst(game, source)); + if (controller != null && targetPlayer != null) { + int amountToPay = targetPlayer.announceXMana(0, unpaid.getMana().getGeneric(), "How much mana to pay?", game, source); + if (amountToPay > 0) { + Cost cost = new GenericManaCost(amountToPay); + if (cost.pay(source, game, source.getSourceId(), targetPlayer.getId(), false)) { + ManaPool manaPool = controller.getManaPool(); + manaPool.addMana(Mana.ColorlessMana(amountToPay), game, source); + manaPool.unlockManaType(ManaType.COLORLESS); + game.informPlayers(targetPlayer.getLogName() + " paid " + amountToPay + " mana."); + game.getState().setValue(source.getSourceId().toString() + game.getState().getZoneChangeCounter(source.getSourceId()), true); + } + } + return true; + } + return false; + } +} diff --git a/Mage/src/main/java/mage/abilities/keyword/CascadeAbility.java b/Mage/src/main/java/mage/abilities/keyword/CascadeAbility.java index 4c59a830136..25044b2db97 100644 --- a/Mage/src/main/java/mage/abilities/keyword/CascadeAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/CascadeAbility.java @@ -27,6 +27,7 @@ */ package mage.abilities.keyword; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.OneShotEffect; @@ -124,7 +125,7 @@ class CascadeEffect extends OneShotEffect { if (card != null) { if (controller.chooseUse(outcome, "Use cascade effect on " + card.getLogName() + '?', source, game)) { - controller.cast(card.getSpellAbility(), game, true); + controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } } // Move the remaining cards to the buttom of the library in a random order diff --git a/Mage/src/main/java/mage/abilities/keyword/ConvokeAbility.java b/Mage/src/main/java/mage/abilities/keyword/ConvokeAbility.java index 2f0b744d3a2..6cf69788585 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ConvokeAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ConvokeAbility.java @@ -145,7 +145,7 @@ public class ConvokeAbility extends SimpleStaticAbility implements AlternateMana Target target = new TargetControlledCreaturePermanent(1, 1, filter, true); target.setTargetName("creature to convoke"); specialAction.addTarget(target); - if (specialAction.canActivate(source.getControllerId(), game)) { + if (specialAction.canActivate(source.getControllerId(), game).canActivate()) { game.getState().getSpecialActions().add(specialAction); } } diff --git a/Mage/src/main/java/mage/abilities/keyword/DelveAbility.java b/Mage/src/main/java/mage/abilities/keyword/DelveAbility.java index 97c03922d16..59071c34714 100644 --- a/Mage/src/main/java/mage/abilities/keyword/DelveAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/DelveAbility.java @@ -110,7 +110,7 @@ public class DelveAbility extends SimpleStaticAbility implements AlternateManaPa } specialAction.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard( 0, Math.min(controller.getGraveyard().size(), unpaidAmount), new FilterCard(), true))); - if (specialAction.canActivate(source.getControllerId(), game)) { + if (specialAction.canActivate(source.getControllerId(), game).canActivate()) { game.getState().getSpecialActions().add(specialAction); } } diff --git a/Mage/src/main/java/mage/abilities/keyword/EmergeAbility.java b/Mage/src/main/java/mage/abilities/keyword/EmergeAbility.java index ce1c24afdd2..8dea409e830 100644 --- a/Mage/src/main/java/mage/abilities/keyword/EmergeAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/EmergeAbility.java @@ -1,140 +1,140 @@ -/* - * 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.abilities.keyword; - -import java.util.UUID; -import mage.Mana; -import mage.abilities.SpellAbility; -import mage.abilities.costs.common.SacrificeTargetCost; -import mage.abilities.costs.mana.ManaCost; -import mage.abilities.costs.mana.ManaCosts; -import mage.abilities.mana.ManaOptions; -import mage.cards.Card; -import mage.constants.Outcome; -import mage.constants.SpellAbilityType; -import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.mageobject.CardIdPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.target.TargetPermanent; -import mage.target.common.TargetControlledCreaturePermanent; -import mage.util.CardUtil; - -/** - * - * @author emerald000 - */ -public class EmergeAbility extends SpellAbility { - - private final ManaCosts emergeCost; - - public EmergeAbility(Card card, ManaCosts emergeCost) { - super(emergeCost, card.getName() + " with emerge", Zone.HAND, SpellAbilityType.BASE_ALTERNATE); - this.getCosts().addAll(card.getSpellAbility().getCosts().copy()); - this.getEffects().addAll(card.getSpellAbility().getEffects().copy()); - this.getTargets().addAll(card.getSpellAbility().getTargets().copy()); - this.timing = card.getSpellAbility().getTiming(); - this.setRuleAtTheTop(true); - this.emergeCost = emergeCost.copy(); - } - - public EmergeAbility(final EmergeAbility ability) { - super(ability); - this.emergeCost = ability.emergeCost.copy(); - } - - @Override - public boolean canActivate(UUID playerId, Game game) { - if (super.canActivate(playerId, game)) { - Player controller = game.getPlayer(this.getControllerId()); - if (controller != null) { - for (Permanent creature : game.getBattlefield().getActivePermanents(new FilterControlledCreaturePermanent(), this.getControllerId(), this.getSourceId(), game)) { - ManaCost costToPay = CardUtil.reduceCost(emergeCost.copy(), creature.getConvertedManaCost()); - if (costToPay.canPay(this, this.getSourceId(), this.getControllerId(), game)) { - return true; - } - } - } - } - return false; - } - - @Override - public ManaOptions getMinimumCostToActivate(UUID playerId, Game game) { - int maxCMC = 0; - for (Permanent creature : game.getBattlefield().getActivePermanents(new FilterControlledCreaturePermanent(), playerId, this.getSourceId(), game)) { - int cmc = creature.getConvertedManaCost(); - if (cmc > maxCMC) { - maxCMC = cmc; - } - } - ManaOptions manaOptions = super.getMinimumCostToActivate(playerId, game); - for (Mana mana : manaOptions) { - if (mana.getGeneric() > maxCMC) { - mana.setGeneric(mana.getGeneric() - maxCMC); - } else { - mana.setGeneric(0); - } - } - return manaOptions; - } - - @Override - public boolean activate(Game game, boolean noMana) { - Player controller = game.getPlayer(this.getControllerId()); - if (controller != null) { - TargetPermanent target = new TargetControlledCreaturePermanent(new FilterControlledCreaturePermanent("creature to sacrifice for emerge")); - if (controller.choose(Outcome.Sacrifice, target, this.getSourceId(), game)) { - Permanent creature = game.getPermanent(target.getFirstTarget()); - CardUtil.reduceCost(this, creature.getConvertedManaCost()); - FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(creature.getLogName()); - filter.add(new CardIdPredicate(creature.getId())); - this.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(filter))); - return super.activate(game, false); - } - } - return false; - } - - @Override - public EmergeAbility copy() { - return new EmergeAbility(this); - } - - @Override - public String getRule(boolean all) { - return getRule(); - } - - @Override - public String getRule() { - return "Emerge " + emergeCost.getText() + " (You may cast this spell by sacrificing a creature and paying the emerge cost reduced by that creature's converted mana cost.)"; - } -} +/* + * 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.abilities.keyword; + +import java.util.UUID; +import mage.Mana; +import mage.abilities.SpellAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.mana.ManaCost; +import mage.abilities.costs.mana.ManaCosts; +import mage.abilities.mana.ManaOptions; +import mage.cards.Card; +import mage.constants.Outcome; +import mage.constants.SpellAbilityType; +import mage.constants.Zone; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.mageobject.CardIdPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.util.CardUtil; + +/** + * + * @author emerald000 + */ +public class EmergeAbility extends SpellAbility { + + private final ManaCosts emergeCost; + + public EmergeAbility(Card card, ManaCosts emergeCost) { + super(emergeCost, card.getName() + " with emerge", Zone.HAND, SpellAbilityType.BASE_ALTERNATE); + this.getCosts().addAll(card.getSpellAbility().getCosts().copy()); + this.getEffects().addAll(card.getSpellAbility().getEffects().copy()); + this.getTargets().addAll(card.getSpellAbility().getTargets().copy()); + this.timing = card.getSpellAbility().getTiming(); + this.setRuleAtTheTop(true); + this.emergeCost = emergeCost.copy(); + } + + public EmergeAbility(final EmergeAbility ability) { + super(ability); + this.emergeCost = ability.emergeCost.copy(); + } + + @Override + public ActivationStatus canActivate(UUID playerId, Game game) { + if (super.canActivate(playerId, game).canActivate()) { + Player controller = game.getPlayer(this.getControllerId()); + if (controller != null) { + for (Permanent creature : game.getBattlefield().getActivePermanents(new FilterControlledCreaturePermanent(), this.getControllerId(), this.getSourceId(), game)) { + ManaCost costToPay = CardUtil.reduceCost(emergeCost.copy(), creature.getConvertedManaCost()); + if (costToPay.canPay(this, this.getSourceId(), this.getControllerId(), game)) { + return ActivationStatus.getTrue(); + } + } + } + } + return ActivationStatus.getFalse(); + } + + @Override + public ManaOptions getMinimumCostToActivate(UUID playerId, Game game) { + int maxCMC = 0; + for (Permanent creature : game.getBattlefield().getActivePermanents(new FilterControlledCreaturePermanent(), playerId, this.getSourceId(), game)) { + int cmc = creature.getConvertedManaCost(); + if (cmc > maxCMC) { + maxCMC = cmc; + } + } + ManaOptions manaOptions = super.getMinimumCostToActivate(playerId, game); + for (Mana mana : manaOptions) { + if (mana.getGeneric() > maxCMC) { + mana.setGeneric(mana.getGeneric() - maxCMC); + } else { + mana.setGeneric(0); + } + } + return manaOptions; + } + + @Override + public boolean activate(Game game, boolean noMana) { + Player controller = game.getPlayer(this.getControllerId()); + if (controller != null) { + TargetPermanent target = new TargetControlledCreaturePermanent(new FilterControlledCreaturePermanent("creature to sacrifice for emerge")); + if (controller.choose(Outcome.Sacrifice, target, this.getSourceId(), game)) { + Permanent creature = game.getPermanent(target.getFirstTarget()); + CardUtil.reduceCost(this, creature.getConvertedManaCost()); + FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(creature.getLogName()); + filter.add(new CardIdPredicate(creature.getId())); + this.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(filter))); + return super.activate(game, false); + } + } + return false; + } + + @Override + public EmergeAbility copy() { + return new EmergeAbility(this); + } + + @Override + public String getRule(boolean all) { + return getRule(); + } + + @Override + public String getRule() { + return "Emerge " + emergeCost.getText() + " (You may cast this spell by sacrificing a creature and paying the emerge cost reduced by that creature's converted mana cost.)"; + } +} diff --git a/Mage/src/main/java/mage/abilities/keyword/EquipAbility.java b/Mage/src/main/java/mage/abilities/keyword/EquipAbility.java index f6ae708cf97..8fc907d4eb8 100644 --- a/Mage/src/main/java/mage/abilities/keyword/EquipAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/EquipAbility.java @@ -27,6 +27,7 @@ */ package mage.abilities.keyword; +import java.util.UUID; import mage.abilities.ActivatedAbilityImpl; import mage.abilities.costs.Cost; import mage.abilities.effects.common.AttachEffect; @@ -39,8 +40,6 @@ import mage.game.permanent.Permanent; import mage.target.Target; import mage.target.common.TargetControlledCreaturePermanent; -import java.util.UUID; - /** * @author BetaSteward_at_googlemail.com */ @@ -57,14 +56,15 @@ public class EquipAbility extends ActivatedAbilityImpl { } @Override - public boolean canActivate(UUID playerId, Game game) { - if (super.canActivate(playerId, game)) { + public ActivationStatus canActivate(UUID playerId, Game game) { + ActivationStatus activationStatus = super.canActivate(playerId, game); + if (activationStatus.canActivate()) { Permanent permanent = game.getPermanent(sourceId); if (permanent != null && permanent.hasSubtype(SubType.EQUIPMENT, game)) { - return true; + return activationStatus; } } - return false; + return activationStatus; } public EquipAbility(final EquipAbility ability) { diff --git a/Mage/src/main/java/mage/abilities/keyword/EquipLegendaryAbility.java b/Mage/src/main/java/mage/abilities/keyword/EquipLegendaryAbility.java index 585a3577131..8ea4c9ef442 100644 --- a/Mage/src/main/java/mage/abilities/keyword/EquipLegendaryAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/EquipLegendaryAbility.java @@ -1,96 +1,95 @@ -/* - * 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.abilities.keyword; - -import mage.abilities.ActivatedAbilityImpl; -import mage.abilities.costs.Cost; -import mage.abilities.effects.common.AttachEffect; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.constants.TimingRule; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.target.Target; -import mage.target.common.TargetControlledCreaturePermanent; - -import java.util.UUID; -import mage.constants.SuperType; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.mageobject.SupertypePredicate; - -/** - * @author Rystan - */ -public class EquipLegendaryAbility extends ActivatedAbilityImpl { - - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("legendary creature you control"); - - static { - filter.add(new SupertypePredicate(SuperType.LEGENDARY)); - } - - public EquipLegendaryAbility(Outcome outcome, Cost cost) { - this(outcome, cost, new TargetControlledCreaturePermanent(filter)); - } - - public EquipLegendaryAbility(Outcome outcome, Cost cost, Target target) { - super(Zone.BATTLEFIELD, new AttachEffect(outcome, "Equip"), cost); - this.addTarget(target); - this.timing = TimingRule.SORCERY; - } - - @Override - public boolean canActivate(UUID playerId, Game game) { - if (super.canActivate(playerId, game)) { - Permanent permanent = game.getPermanent(sourceId); - if (permanent != null && permanent.hasSubtype(SubType.EQUIPMENT, game)) { - return true; - } - } - return false; - } - - public EquipLegendaryAbility(final EquipLegendaryAbility ability) { - super(ability); - } - - @Override - public EquipLegendaryAbility copy() { - return new EquipLegendaryAbility(this); - } - - @Override - public String getRule() { - return "Equip legendary creature " + costs.getText() + - manaCosts.getText() + " (" + manaCosts.getText() + - ": Attach to target legendary creature you control. Equip only as a sorcery.)"; - } - -} +/* + * 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.abilities.keyword; + +import java.util.UUID; +import mage.abilities.ActivatedAbilityImpl; +import mage.abilities.costs.Cost; +import mage.abilities.effects.common.AttachEffect; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.constants.TimingRule; +import mage.constants.Zone; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.mageobject.SupertypePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.Target; +import mage.target.common.TargetControlledCreaturePermanent; + +/** + * @author Rystan + */ +public class EquipLegendaryAbility extends ActivatedAbilityImpl { + + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("legendary creature you control"); + + static { + filter.add(new SupertypePredicate(SuperType.LEGENDARY)); + } + + public EquipLegendaryAbility(Outcome outcome, Cost cost) { + this(outcome, cost, new TargetControlledCreaturePermanent(filter)); + } + + public EquipLegendaryAbility(Outcome outcome, Cost cost, Target target) { + super(Zone.BATTLEFIELD, new AttachEffect(outcome, "Equip"), cost); + this.addTarget(target); + this.timing = TimingRule.SORCERY; + } + + @Override + public ActivationStatus canActivate(UUID playerId, Game game) { + ActivationStatus activationStatus = super.canActivate(playerId, game); + if (activationStatus.canActivate()) { + Permanent permanent = game.getPermanent(sourceId); + if (permanent != null && permanent.hasSubtype(SubType.EQUIPMENT, game)) { + return activationStatus; + } + } + return activationStatus; + } + + public EquipLegendaryAbility(final EquipLegendaryAbility ability) { + super(ability); + } + + @Override + public EquipLegendaryAbility copy() { + return new EquipLegendaryAbility(this); + } + + @Override + public String getRule() { + return "Equip legendary creature " + costs.getText() + + manaCosts.getText() + " (" + manaCosts.getText() + + ": Attach to target legendary creature you control. Equip only as a sorcery.)"; + } + +} diff --git a/Mage/src/main/java/mage/abilities/keyword/FlashbackAbility.java b/Mage/src/main/java/mage/abilities/keyword/FlashbackAbility.java index 13f489dd365..f7d7fbe0697 100644 --- a/Mage/src/main/java/mage/abilities/keyword/FlashbackAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/FlashbackAbility.java @@ -83,13 +83,14 @@ public class FlashbackAbility extends SpellAbility { } @Override - public boolean canActivate(UUID playerId, Game game) { - if (super.canActivate(playerId, game)) { + public ActivationStatus canActivate(UUID playerId, Game game) { + ActivationStatus activationStatus = super.canActivate(playerId, game); + if (activationStatus.canActivate()) { Card card = game.getCard(getSourceId()); if (card != null) { // Cards with no Mana Costs cant't be flashbacked (e.g. Ancestral Vision) if (card.getManaCost().isEmpty()) { - return false; + return ActivationStatus.getFalse(); } // Flashback can never cast a split card by Fuse, because Fuse only works from hand if (card.isSplitCard()) { @@ -102,7 +103,7 @@ public class FlashbackAbility extends SpellAbility { return card.getSpellAbility().canActivate(playerId, game); } } - return false; + return activationStatus; } @Override diff --git a/Mage/src/main/java/mage/abilities/keyword/ForecastAbility.java b/Mage/src/main/java/mage/abilities/keyword/ForecastAbility.java index fdbfe871ffe..2d3a2fbf2d6 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ForecastAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ForecastAbility.java @@ -43,10 +43,10 @@ import mage.game.Game; * * 702.56b A forecast ability may be activated only during the upkeep step of * the card's owner and only once each turn. The controller of the forecast - * ability reveals the card with that ability from their hand as the - * ability is activated. That player plays with that card revealed in their - * hand until it leaves the player's hand or until a step or phase that isn't an - * upkeep step begins, whichever comes first. + * ability reveals the card with that ability from their hand as the ability is + * activated. That player plays with that card revealed in their hand until it + * leaves the player's hand or until a step or phase that isn't an upkeep step + * begins, whichever comes first. * * @author LevelX2 * @@ -68,11 +68,11 @@ public class ForecastAbility extends LimitedTimesPerTurnActivatedAbility { } @Override - public boolean canActivate(UUID playerId, Game game) { + public ActivationStatus canActivate(UUID playerId, Game game) { // May be activated only during the upkeep step of the card's owner // Because it can only be activated from a players hand it should be ok to check here with controllerId instead of card.getOwnerId(). if (!game.getActivePlayerId().equals(controllerId) || PhaseStep.UPKEEP != game.getStep().getType()) { - return false; + return ActivationStatus.getFalse(); } return super.canActivate(playerId, game); } diff --git a/Mage/src/main/java/mage/abilities/keyword/ImproviseAbility.java b/Mage/src/main/java/mage/abilities/keyword/ImproviseAbility.java index 738537f59d1..f3a9f36d652 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ImproviseAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ImproviseAbility.java @@ -6,7 +6,6 @@ package mage.abilities.keyword; import java.util.UUID; - import mage.Mana; import mage.abilities.Ability; import mage.abilities.SpecialAction; @@ -69,7 +68,7 @@ public class ImproviseAbility extends SimpleStaticAbility implements AlternateMa Target target = new TargetControlledPermanent(1, unpaid.getMana().getGeneric(), filter, true); target.setTargetName("artifact to Improvise"); specialAction.addTarget(target); - if (specialAction.canActivate(source.getControllerId(), game)) { + if (specialAction.canActivate(source.getControllerId(), game).canActivate()) { game.getState().getSpecialActions().add(specialAction); } } diff --git a/Mage/src/main/java/mage/abilities/keyword/MadnessAbility.java b/Mage/src/main/java/mage/abilities/keyword/MadnessAbility.java index 44153d7f32b..b07de0e0b0e 100644 --- a/Mage/src/main/java/mage/abilities/keyword/MadnessAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/MadnessAbility.java @@ -2,6 +2,7 @@ package mage.abilities.keyword; import java.util.UUID; import mage.MageObject; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.SpellAbility; import mage.abilities.StaticAbility; @@ -33,10 +34,10 @@ import mage.players.Player; * first ability is applied. * * "Madness [cost]" means "If a player would discard this card, that player - * discards it, but may exile it instead of putting it into their - * graveyard" and "When this card is exiled this way, its owner may cast it by - * paying [cost] rather than paying its mana cost. If that player doesn't, he or - * she puts this card into their graveyard. + * discards it, but may exile it instead of putting it into their graveyard" and + * "When this card is exiled this way, its owner may cast it by paying [cost] + * rather than paying its mana cost. If that player doesn't, he or she puts this + * card into their graveyard. * * 702.33b. Casting a spell using its madness ability follows the rules for * paying alternative costs in rules 601.2b and 601.2e-g. @@ -219,7 +220,7 @@ class MadnessCastEffect extends OneShotEffect { castByMadness.setSpellAbilityCastMode(SpellAbilityCastMode.MADNESS); costRef.clear(); costRef.add(madnessCost); - boolean result = owner.cast(castByMadness, game, false); + boolean result = owner.cast(castByMadness, game, false, new MageObjectReference(source.getSourceObject(game), game)); return result; } diff --git a/Mage/src/main/java/mage/abilities/keyword/MiracleAbility.java b/Mage/src/main/java/mage/abilities/keyword/MiracleAbility.java index ed50e9b7b00..5cc3b7f6066 100644 --- a/Mage/src/main/java/mage/abilities/keyword/MiracleAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/MiracleAbility.java @@ -27,6 +27,7 @@ */ package mage.abilities.keyword; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.SpellAbility; import mage.abilities.TriggeredAbilityImpl; @@ -52,8 +53,8 @@ import mage.watchers.common.MiracleWatcher; * cost." * * 702.92b If a player chooses to reveal a card using its miracle ability, he or - * she plays with that card revealed until that card leaves their hand, - * that ability resolves, or that ability otherwise leaves the stack. + * she plays with that card revealed until that card leaves their hand, that + * ability resolves, or that ability otherwise leaves the stack. * * You can cast a card for its miracle cost only as the miracle triggered * ability resolves. If you don't want to cast it at that time (or you can't @@ -172,7 +173,7 @@ class MiracleEffect extends OneShotEffect { // replace with the new cost costRef.clear(); costRef.add(miracleCosts); - controller.cast(abilityToCast, game, false); + controller.cast(abilityToCast, game, false, new MageObjectReference(source.getSourceObject(game), game)); return true; } return false; diff --git a/Mage/src/main/java/mage/abilities/keyword/ReboundAbility.java b/Mage/src/main/java/mage/abilities/keyword/ReboundAbility.java index 17bcf1d600e..6766d6d53a8 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ReboundAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ReboundAbility.java @@ -28,6 +28,7 @@ package mage.abilities.keyword; import java.util.UUID; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.SpellAbility; @@ -206,7 +207,7 @@ class ReboundCastSpellFromExileEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); if (player != null && reboundCard != null) { SpellAbility ability = reboundCard.getSpellAbility(); - player.cast(ability, game, true); + player.cast(ability, game, true, new MageObjectReference(source.getSourceObject(game), game)); zone.remove(reboundCard.getId()); return true; } diff --git a/Mage/src/main/java/mage/abilities/keyword/RippleAbility.java b/Mage/src/main/java/mage/abilities/keyword/RippleAbility.java index 80bab29d568..8dbd4b8e92f 100644 --- a/Mage/src/main/java/mage/abilities/keyword/RippleAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/RippleAbility.java @@ -1,6 +1,7 @@ package mage.abilities.keyword; import mage.MageObject; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.OneShotEffect; @@ -103,7 +104,7 @@ class RippleEffect extends OneShotEffect { while (player.canRespond() && cards.count(sameNameFilter, game) > 0 && player.choose(Outcome.PlayForFree, cards, target1, game)) { Card card = cards.get(target1.getFirstTarget(), game); if (card != null) { - player.cast(card.getSpellAbility(), game, true); + player.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); cards.remove(card); } target1.clearChosen(); diff --git a/Mage/src/main/java/mage/abilities/keyword/SpliceOntoArcaneAbility.java b/Mage/src/main/java/mage/abilities/keyword/SpliceOntoArcaneAbility.java index 0a4f96049be..9932427baff 100644 --- a/Mage/src/main/java/mage/abilities/keyword/SpliceOntoArcaneAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/SpliceOntoArcaneAbility.java @@ -27,6 +27,7 @@ */ package mage.abilities.keyword; +import java.util.Iterator; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.SpellAbility; @@ -42,63 +43,66 @@ import mage.game.Game; import mage.game.stack.Spell; import mage.players.Player; -import java.util.Iterator; - - /** * 702.45. Splice * - * 702.45a Splice is a static ability that functions while a card is in your hand. - * "Splice onto [subtype] [cost]" means "You may reveal this card from your hand - * as you cast a [subtype] spell. If you do, copy this card's text box onto that - * spell and pay [cost] as an additional cost to cast that spell." Paying a card's - * splice cost follows the rules for paying additional costs in rules 601.2b and - * 601.2e-g. + * 702.45a Splice is a static ability that functions while a card is in your + * hand. "Splice onto [subtype] [cost]" means "You may reveal this card from + * your hand as you cast a [subtype] spell. If you do, copy this card's text box + * onto that spell and pay [cost] as an additional cost to cast that spell." + * Paying a card's splice cost follows the rules for paying additional costs in + * rules 601.2b and 601.2e-g. * - * Example: Since the card with splice remains in the player's hand, it can later - * be cast normally or spliced onto another spell. It can even be discarded to pay - * a "discard a card" cost of the spell it's spliced onto. + * Example: Since the card with splice remains in the player's hand, it can + * later be cast normally or spliced onto another spell. It can even be + * discarded to pay a "discard a card" cost of the spell it's spliced onto. * - * 702.45b You can't choose to use a splice ability if you can't make the required - * choices (targets, etc.) for that card's instructions. You can't splice any one - * card onto the same spell more than once. If you're splicing more than one card - * onto a spell, reveal them all at once and choose the order in which their - * instructions will be followed. The instructions on the main spell have to be - * followed first. + * 702.45b You can't choose to use a splice ability if you can't make the + * required choices (targets, etc.) for that card's instructions. You can't + * splice any one card onto the same spell more than once. If you're splicing + * more than one card onto a spell, reveal them all at once and choose the order + * in which their instructions will be followed. The instructions on the main + * spell have to be followed first. * - * 702.45c The spell has the characteristics of the main spell, plus the text boxes - * of each of the spliced cards. The spell doesn't gain any other characteristics - * (name, mana cost, color, supertypes, card types, subtypes, etc.) of the spliced - * cards. Text copied onto the spell that refers to a card by name refers to the spell - * on the stack, not the card from which the text was copied. + * 702.45c The spell has the characteristics of the main spell, plus the text + * boxes of each of the spliced cards. The spell doesn't gain any other + * characteristics (name, mana cost, color, supertypes, card types, subtypes, + * etc.) of the spliced cards. Text copied onto the spell that refers to a card + * by name refers to the spell on the stack, not the card from which the text + * was copied. * - * Example: Glacial Ray is a red card with splice onto Arcane that reads, "Glacial - * Ray deals 2 damage to any target." Suppose Glacial Ray is spliced - * onto Reach Through Mists, a blue spell. The spell is still blue, and Reach Through - * Mists deals the damage. This means that the ability can target a creature with - * protection from red and deal 2 damage to that creature. + * Example: Glacial Ray is a red card with splice onto Arcane that reads, + * "Glacial Ray deals 2 damage to any target." Suppose Glacial Ray is spliced + * onto Reach Through Mists, a blue spell. The spell is still blue, and Reach + * Through Mists deals the damage. This means that the ability can target a + * creature with protection from red and deal 2 damage to that creature. * - * 702.45d Choose targets for the added text normally (see rule 601.2c). Note that a - * spell with one or more targets will be countered if all of its targets are illegal - * on resolution. + * 702.45d Choose targets for the added text normally (see rule 601.2c). Note + * that a spell with one or more targets will be countered if all of its targets + * are illegal on resolution. * - * 702.45e The spell loses any splice changes once it leaves the stack (for example, - * when it's countered, it's exiled, or it resolves). + * 702.45e The spell loses any splice changes once it leaves the stack (for + * example, when it's countered, it's exiled, or it resolves). * - * Rulings + * Rulings * - * You must reveal all of the cards you intend to splice at the same time. Each individual card can only be spliced once onto a spell. - * If you have more than one card with the same name in your hand, you may splice both of them onto the spell. - * A card with a splice ability can't be spliced onto itself because the spell is on the stack (and not in your hand) when you reveal the cards you want to splice onto it. - * The target for a card that's spliced onto a spell may be the same as the target chosen for the original spell or for another spliced-on card. (A recent change to the targeting rules allows this, but most other cards are unaffected by the change.) - * If you splice a targeted card onto an untargeted spell, the entire spell will be countered if the target isn't legal when the spell resolves. - * If you splice an untargeted card onto a targeted spell, the entire spell will be countered if the target isn't legal when the spell resolves. - * A spell is countered on resolution only if *all* of its targets are illegal (or the spell is countered by an effect). + * You must reveal all of the cards you intend to splice at the same time. Each + * individual card can only be spliced once onto a spell. If you have more than + * one card with the same name in your hand, you may splice both of them onto + * the spell. A card with a splice ability can't be spliced onto itself because + * the spell is on the stack (and not in your hand) when you reveal the cards + * you want to splice onto it. The target for a card that's spliced onto a spell + * may be the same as the target chosen for the original spell or for another + * spliced-on card. (A recent change to the targeting rules allows this, but + * most other cards are unaffected by the change.) If you splice a targeted card + * onto an untargeted spell, the entire spell will be countered if the target + * isn't legal when the spell resolves. If you splice an untargeted card onto a + * targeted spell, the entire spell will be countered if the target isn't legal + * when the spell resolves. A spell is countered on resolution only if *all* of + * its targets are illegal (or the spell is countered by an effect). * * @author LevelX2 */ - - public class SpliceOntoArcaneAbility extends SimpleStaticAbility { private static final String KEYWORD_TEXT = "Splice onto Arcane"; @@ -134,8 +138,8 @@ public class SpliceOntoArcaneAbility extends SimpleStaticAbility { @Override public String getRule() { StringBuilder sb = new StringBuilder(); - sb.append(KEYWORD_TEXT).append(nonManaCosts?"-":" "); - sb.append(spliceCosts.getText()).append(nonManaCosts?". ":" "); + sb.append(KEYWORD_TEXT).append(nonManaCosts ? "-" : " "); + sb.append(spliceCosts.getText()).append(nonManaCosts ? ". " : " "); sb.append("(As you cast an Arcane spell, you may reveal this card from your hand and pay its splice cost. If you do, add this card's effects to that spell.)"); return sb.toString(); } @@ -193,7 +197,7 @@ class SpliceOntoArcaneEffect extends SpliceCardEffectImpl { if (card.getManaCost().isEmpty()) { // e.g. Evermind return card.getSpellAbility().spellCanBeActivatedRegularlyNow(source.getControllerId(), game); } else { - return card.getSpellAbility().canActivate(source.getControllerId(), game); + return card.getSpellAbility().canActivate(source.getControllerId(), game).canActivate(); } } return false; diff --git a/Mage/src/main/java/mage/abilities/keyword/SurgeAbility.java b/Mage/src/main/java/mage/abilities/keyword/SurgeAbility.java index d03a394d6be..041331417c6 100644 --- a/Mage/src/main/java/mage/abilities/keyword/SurgeAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/SurgeAbility.java @@ -66,7 +66,7 @@ public class SurgeAbility extends SpellAbility { } @Override - public boolean canActivate(UUID playerId, Game game) { + public ActivationStatus canActivate(UUID playerId, Game game) { // check if controller or teammate has already cast a spell this turn CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get(CastSpellLastTurnWatcher.class.getSimpleName()); if (watcher != null) { @@ -81,7 +81,7 @@ public class SurgeAbility extends SpellAbility { } } } - return false; + return ActivationStatus.getFalse(); } @Override diff --git a/Mage/src/main/java/mage/abilities/keyword/SuspendAbility.java b/Mage/src/main/java/mage/abilities/keyword/SuspendAbility.java index b19ca7db21c..11a9163cb54 100644 --- a/Mage/src/main/java/mage/abilities/keyword/SuspendAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/SuspendAbility.java @@ -31,6 +31,7 @@ import java.util.ArrayList; import java.util.List; import java.util.UUID; import mage.MageObject; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.SpecialAction; import mage.abilities.TriggeredAbilityImpl; @@ -228,16 +229,16 @@ public class SuspendAbility extends SpecialAction { } @Override - public boolean canActivate(UUID playerId, Game game) { + public ActivationStatus canActivate(UUID playerId, Game game) { if (game.getState().getZone(getSourceId()) != Zone.HAND) { // Supend can only be activated from hand - return false; + return ActivationStatus.getFalse(); } MageObject object = game.getObject(sourceId); - return (object.isInstant() + return new ActivationStatus(object.isInstant() || object.hasAbility(FlashAbility.getInstance().getId(), game) || null != game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.CAST_AS_INSTANT, this, playerId, game) - || game.canPlaySorcery(playerId)); + || game.canPlaySorcery(playerId), null); } @Override @@ -376,7 +377,7 @@ class SuspendPlayCardEffect extends OneShotEffect { card.getAbilities().removeAll(abilitiesToRemove); } // cast the card for free - if (player.cast(card.getSpellAbility(), game, true)) { + if (player.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game))) { if (card.isCreature()) { ContinuousEffect effect = new GainHasteEffect(); effect.setTargetPointer(new FixedTarget(card.getId(), card.getZoneChangeCounter(game) + 1)); diff --git a/Mage/src/main/java/mage/abilities/mana/ActivateOncePerTurnManaAbility.java b/Mage/src/main/java/mage/abilities/mana/ActivateOncePerTurnManaAbility.java index d647995c9b9..623e8d51c09 100644 --- a/Mage/src/main/java/mage/abilities/mana/ActivateOncePerTurnManaAbility.java +++ b/Mage/src/main/java/mage/abilities/mana/ActivateOncePerTurnManaAbility.java @@ -58,7 +58,7 @@ public class ActivateOncePerTurnManaAbility extends ActivatedManaAbilityImpl { @Override public boolean activate(Game game, boolean noMana) { - if (canActivate(this.controllerId, game)) { + if (canActivate(this.controllerId, game).canActivate()) { return super.activate(game, noMana); } return false; diff --git a/Mage/src/main/java/mage/abilities/mana/ActivatedManaAbilityImpl.java b/Mage/src/main/java/mage/abilities/mana/ActivatedManaAbilityImpl.java index eb065d69270..6b95b9685e9 100644 --- a/Mage/src/main/java/mage/abilities/mana/ActivatedManaAbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/mana/ActivatedManaAbilityImpl.java @@ -69,21 +69,21 @@ public abstract class ActivatedManaAbilityImpl extends ActivatedAbilityImpl impl } @Override - public boolean canActivate(UUID playerId, Game game) { + public ActivationStatus canActivate(UUID playerId, Game game) { if (!super.hasMoreActivationsThisTurn(game) || !(condition == null || condition.apply(game, this))) { - return false; + return ActivationStatus.getFalse(); } if (!controlsAbility(playerId, game)) { - return false; + return ActivationStatus.getFalse(); } if (timing == TimingRule.SORCERY && !game.canPlaySorcery(playerId) && null == game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.ACTIVATE_AS_INSTANT, this, controllerId, game)) { - return false; + return ActivationStatus.getFalse(); } // check if player is in the process of playing spell costs and he is no longer allowed to use activated mana abilities (e.g. because he started to use improvise) //20091005 - 605.3a - return costs.canPay(this, sourceId, controllerId, game); + return new ActivationStatus(costs.canPay(this, sourceId, controllerId, game), null); } diff --git a/Mage/src/main/java/mage/filter/common/FilterCreatureForCombatBlock.java b/Mage/src/main/java/mage/filter/common/FilterCreatureForCombatBlock.java index f4e35180ca2..99d99fd8a06 100644 --- a/Mage/src/main/java/mage/filter/common/FilterCreatureForCombatBlock.java +++ b/Mage/src/main/java/mage/filter/common/FilterCreatureForCombatBlock.java @@ -61,7 +61,7 @@ class BlockTappedPredicate implements Predicate { @Override public boolean apply(Permanent input, Game game) { - return !input.isTapped() || null != game.getState().getContinuousEffects().asThough(input.getId(), AsThoughEffectType.BLOCK_TAPPED, input.getControllerId(), game); + return !input.isTapped() || null != game.getState().getContinuousEffects().asThough(input.getId(), AsThoughEffectType.BLOCK_TAPPED, null, input.getControllerId(), game); } @Override diff --git a/Mage/src/main/java/mage/game/events/GameEvent.java b/Mage/src/main/java/mage/game/events/GameEvent.java index cee8547a817..33a8a29080a 100644 --- a/Mage/src/main/java/mage/game/events/GameEvent.java +++ b/Mage/src/main/java/mage/game/events/GameEvent.java @@ -31,6 +31,7 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.UUID; +import mage.MageObjectReference; import mage.constants.Zone; /** @@ -48,6 +49,7 @@ public class GameEvent implements Serializable { protected String data; protected Zone zone; protected List appliedEffects = new ArrayList<>(); + protected MageObjectReference reference; // e.g. the permitting object for casting a spell from non hand zone protected UUID customEventType = null; public enum EventType { @@ -232,7 +234,7 @@ public class GameEvent implements Serializable { FLIP_COIN, COIN_FLIPPED, SCRY, FATESEAL, ROLL_DICE, DICE_ROLLED, ROLL_PLANAR_DIE, PLANAR_DIE_ROLLED, - PLANESWALK, PLANESWALKED, + PLANESWALK, PLANESWALKED, PAID_CUMULATIVE_UPKEEP, DIDNT_PAY_CUMULATIVE_UPKEEP, //permanent events @@ -334,21 +336,14 @@ public class GameEvent implements Serializable { CUSTOM_EVENT } - private GameEvent(EventType type, UUID customEventType, - UUID targetId, UUID sourceId, UUID playerId, int amount, boolean flag) { - this.type = type; - this.customEventType = customEventType; - this.targetId = targetId; - this.sourceId = sourceId; - this.amount = amount; - this.playerId = playerId; - this.flag = flag; - } - public GameEvent(EventType type, UUID targetId, UUID sourceId, UUID playerId) { this(type, null, targetId, sourceId, playerId, 0, false); } + public GameEvent(EventType type, UUID targetId, UUID sourceId, UUID playerId, MageObjectReference reference) { + this(type, null, targetId, sourceId, playerId, 0, false, reference); + } + public GameEvent(EventType type, UUID targetId, UUID sourceId, UUID playerId, int amount, boolean flag) { this(type, null, targetId, sourceId, playerId, amount, flag); } @@ -369,6 +364,10 @@ public class GameEvent implements Serializable { return new GameEvent(type, targetId, sourceId, playerId); } + public static GameEvent getEvent(EventType type, UUID targetId, UUID sourceId, UUID playerId, MageObjectReference reference) { + return new GameEvent(type, targetId, sourceId, playerId, reference); + } + public static GameEvent getEvent(EventType type, UUID targetId, UUID playerId) { return new GameEvent(type, targetId, null, playerId); } @@ -399,6 +398,23 @@ public class GameEvent implements Serializable { return event; } + private GameEvent(EventType type, UUID customEventType, + UUID targetId, UUID sourceId, UUID playerId, int amount, boolean flag) { + this(type, customEventType, targetId, sourceId, playerId, amount, flag, null); + } + + private GameEvent(EventType type, UUID customEventType, + UUID targetId, UUID sourceId, UUID playerId, int amount, boolean flag, MageObjectReference reference) { + this.type = type; + this.customEventType = customEventType; + this.targetId = targetId; + this.sourceId = sourceId; + this.amount = amount; + this.playerId = playerId; + this.flag = flag; + this.reference = reference; + } + public EventType getType() { return type; } @@ -455,6 +471,14 @@ public class GameEvent implements Serializable { this.zone = zone; } + public MageObjectReference getAdditionalReference() { + return reference; + } + + public void setAdditionalReference(MageObjectReference additionalReference) { + this.reference = additionalReference; + } + /** * used to store which replacement effects were already applied to an event * or or any modified events that may replace it diff --git a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java index 1f6eeacb014..e033640c13a 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java @@ -935,20 +935,20 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { public boolean canBeTargetedBy(MageObject source, UUID sourceControllerId, Game game) { if (source != null) { if (abilities.containsKey(ShroudAbility.getInstance().getId())) { - if (null == game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.SHROUD, sourceControllerId, game)) { + if (null == game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.SHROUD, null, sourceControllerId, game)) { return false; } } if (abilities.containsKey(HexproofAbility.getInstance().getId())) { if (game.getPlayer(this.getControllerId()).hasOpponent(sourceControllerId, game) - && null == game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.HEXPROOF, sourceControllerId, game)) { + && null == game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.HEXPROOF, null, sourceControllerId, game)) { return false; } } if (abilities.containsKey(HexproofFromBlackAbility.getInstance().getId())) { if (game.getPlayer(this.getControllerId()).hasOpponent(sourceControllerId, game) - && null == game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.HEXPROOF, sourceControllerId, game) + && null == game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.HEXPROOF, null, sourceControllerId, game) && source.getColor(game).isBlack()) { return false; } @@ -956,7 +956,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { if (abilities.containsKey(HexproofFromWhiteAbility.getInstance().getId())) { if (game.getPlayer(this.getControllerId()).hasOpponent(sourceControllerId, game) - && null == game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.HEXPROOF, sourceControllerId, game) + && null == game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.HEXPROOF, null, sourceControllerId, game) && source.getColor(game).isWhite()) { return false; } @@ -1096,7 +1096,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { @Override public boolean canAttackInPrinciple(UUID defenderId, Game game) { if (hasSummoningSickness() - && null == game.getContinuousEffects().asThough(this.objectId, AsThoughEffectType.ATTACK_AS_HASTE, this.getControllerId(), game)) { + && null == game.getContinuousEffects().asThough(this.objectId, AsThoughEffectType.ATTACK_AS_HASTE, null, this.getControllerId(), game)) { return false; } //20101001 - 508.1c @@ -1116,7 +1116,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { } return !abilities.containsKey(DefenderAbility.getInstance().getId()) - || null != game.getContinuousEffects().asThough(this.objectId, AsThoughEffectType.ATTACK, this.getControllerId(), game); + || null != game.getContinuousEffects().asThough(this.objectId, AsThoughEffectType.ATTACK, null, this.getControllerId(), game); } private boolean canAttackCheckRestrictionEffects(UUID defenderId, Game game) { @@ -1136,7 +1136,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { @Override public boolean canBlock(UUID attackerId, Game game) { - if (tapped && null == game.getState().getContinuousEffects().asThough(this.getId(), AsThoughEffectType.BLOCK_TAPPED, this.getControllerId(), game)) { + if (tapped && null == game.getState().getContinuousEffects().asThough(this.getId(), AsThoughEffectType.BLOCK_TAPPED, null, this.getControllerId(), game)) { return false; } Permanent attacker = game.getPermanent(attackerId); @@ -1169,7 +1169,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { @Override public boolean canBlockAny(Game game) { - if (tapped && null == game.getState().getContinuousEffects().asThough(this.getId(), AsThoughEffectType.BLOCK_TAPPED, this.getControllerId(), game)) { + if (tapped && null == game.getState().getContinuousEffects().asThough(this.getId(), AsThoughEffectType.BLOCK_TAPPED, null, this.getControllerId(), game)) { return false; } diff --git a/Mage/src/main/java/mage/players/Player.java b/Mage/src/main/java/mage/players/Player.java index b2510b262fb..d8d7e36ce5e 100644 --- a/Mage/src/main/java/mage/players/Player.java +++ b/Mage/src/main/java/mage/players/Player.java @@ -36,6 +36,7 @@ import java.util.Set; import java.util.UUID; import mage.MageItem; import mage.MageObject; +import mage.MageObjectReference; import mage.abilities.Abilities; import mage.abilities.Ability; import mage.abilities.ActivatedAbility; @@ -359,7 +360,7 @@ public interface Player extends MageItem, Copyable { int drawCards(int num, Game game, List appliedEffects); - boolean cast(SpellAbility ability, Game game, boolean noMana); + boolean cast(SpellAbility ability, Game game, boolean noMana, MageObjectReference reference); SpellAbility chooseSpellAbilityForCast(SpellAbility ability, Game game, boolean noMana); @@ -399,7 +400,7 @@ public interface Player extends MageItem, Copyable { * to be the turn of the player playing that card. * @return */ - boolean playCard(Card card, Game game, boolean noMana, boolean ignoreTiming); + boolean playCard(Card card, Game game, boolean noMana, boolean ignoreTiming, MageObjectReference reference); /** * diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index bdb8a60a3e1..9ba76bbb6fc 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -33,8 +33,10 @@ import java.util.*; import java.util.Map.Entry; import mage.ConditionalMana; import mage.MageObject; +import mage.MageObjectReference; import mage.Mana; import mage.abilities.*; +import mage.abilities.ActivatedAbility.ActivationStatus; import mage.abilities.common.PassAbility; import mage.abilities.common.WhileSearchingPlayFromLibraryAbility; import mage.abilities.common.delayed.AtTheEndOfTurnStepPostDelayedTriggeredAbility; @@ -610,7 +612,7 @@ public abstract class PlayerImpl implements Player, Serializable { } if (abilities.containsKey(HexproofAbility.getInstance().getId())) { if (sourceControllerId != null && this.hasOpponent(sourceControllerId, game) - && null == game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.HEXPROOF, this.getId(), game)) { + && null == game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.HEXPROOF, null, this.getId(), game)) { return false; } } @@ -1010,7 +1012,7 @@ public abstract class PlayerImpl implements Player, Serializable { } @Override - public boolean playCard(Card card, Game game, boolean noMana, boolean ignoreTiming) { + public boolean playCard(Card card, Game game, boolean noMana, boolean ignoreTiming, MageObjectReference reference) { if (card == null) { return false; } @@ -1018,7 +1020,7 @@ public abstract class PlayerImpl implements Player, Serializable { if (card.isLand()) { result = playLand(card, game, ignoreTiming); } else { - result = cast(card.getSpellAbility(), game, noMana); + result = cast(card.getSpellAbility(), game, noMana, reference); } if (!result) { game.informPlayer(this, "You can't play " + card.getIdName() + '.'); @@ -1027,7 +1029,7 @@ public abstract class PlayerImpl implements Player, Serializable { } @Override - public boolean cast(SpellAbility ability, Game game, boolean noMana) { + public boolean cast(SpellAbility ability, Game game, boolean noMana, MageObjectReference permittingObject) { if (game == null || ability == null) { return false; } @@ -1046,7 +1048,7 @@ public abstract class PlayerImpl implements Player, Serializable { } Card card = game.getCard(ability.getSourceId()); if (card != null) { - if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.CAST_SPELL, ability.getId(), ability.getSourceId(), playerId), ability)) { + if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.CAST_SPELL, ability.getId(), ability.getSourceId(), playerId, permittingObject), ability)) { int bookmark = game.bookmarkState(); Zone fromZone = game.getState().getZone(card.getMainCard().getId()); card.cast(game, fromZone, ability, playerId); @@ -1074,10 +1076,10 @@ public abstract class PlayerImpl implements Player, Serializable { } } setCastSourceIdWithAlternateMana(null, null, null); - GameEvent event = GameEvent.getEvent(GameEvent.EventType.CAST_SPELL, spell.getSpellAbility().getId(), spell.getSpellAbility().getSourceId(), playerId); + GameEvent event = GameEvent.getEvent(GameEvent.EventType.CAST_SPELL, spell.getSpellAbility().getId(), spell.getSpellAbility().getSourceId(), playerId, permittingObject); game.fireEvent(event); if (spell.activate(game, noMana)) { - event = GameEvent.getEvent(GameEvent.EventType.SPELL_CAST, spell.getSpellAbility().getId(), spell.getSpellAbility().getSourceId(), playerId); + event = GameEvent.getEvent(GameEvent.EventType.SPELL_CAST, spell.getSpellAbility().getId(), spell.getSpellAbility().getSourceId(), playerId, permittingObject); event.setZone(fromZone); game.fireEvent(event); if (!game.isSimulation()) { @@ -1116,7 +1118,7 @@ public abstract class PlayerImpl implements Player, Serializable { SpellAbility spellAbility = new SpellAbility(null, "", game.getState().getZone(card.getId()), SpellAbilityType.FACE_DOWN_CREATURE); spellAbility.setControllerId(this.getId()); spellAbility.setSourceId(card.getId()); - if (cast(spellAbility, game, false)) { + if (cast(spellAbility, game, false, null)) { return true; } } @@ -1124,17 +1126,18 @@ public abstract class PlayerImpl implements Player, Serializable { return false; } //20091005 - 114.2a - if (!ignoreTiming && !playLandAbility.canActivate(this.playerId, game)) { + ActivationStatus activationStatus = playLandAbility.canActivate(this.playerId, game); + if (!ignoreTiming && !activationStatus.canActivate()) { return false; } //20091005 - 305.1 - if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.PLAY_LAND, card.getId(), card.getId(), playerId))) { + if (!game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.PLAY_LAND, card.getId(), card.getId(), playerId, activationStatus.getPermittingObject()))) { // int bookmark = game.bookmarkState(); - game.fireEvent(GameEvent.getEvent(GameEvent.EventType.PLAY_LAND, card.getId(), card.getId(), playerId)); + game.fireEvent(GameEvent.getEvent(GameEvent.EventType.PLAY_LAND, card.getId(), card.getId(), playerId, activationStatus.getPermittingObject())); if (moveCards(card, Zone.BATTLEFIELD, playLandAbility, game, false, false, false, null)) { landsPlayed++; - game.fireEvent(GameEvent.getEvent(GameEvent.EventType.LAND_PLAYED, card.getId(), card.getId(), playerId)); + game.fireEvent(GameEvent.getEvent(GameEvent.EventType.LAND_PLAYED, card.getId(), card.getId(), playerId, activationStatus.getPermittingObject())); game.fireInformEvent(getLogName() + " plays " + card.getLogName()); // game.removeBookmark(bookmark); resetStoredBookmark(game); // prevent undo after playing a land @@ -1239,7 +1242,8 @@ public abstract class PlayerImpl implements Player, Serializable { Card card = game.getCard(ability.getSourceId()); result = playLand(card, game, false); } else { - if (!ability.canActivate(this.playerId, game)) { + ActivationStatus activationStatus = ability.canActivate(this.playerId, game); + if (!activationStatus.canActivate()) { return false; } @@ -1251,7 +1255,7 @@ public abstract class PlayerImpl implements Player, Serializable { result = playManaAbility((ActivatedManaAbilityImpl) ability.copy(), game); break; case SPELL: - result = cast((SpellAbility) ability.copy(), game, false); + result = cast((SpellAbility) ability.copy(), game, false, activationStatus.getPermittingObject()); break; default: result = playAbility(ability.copy(), game); @@ -1357,7 +1361,7 @@ public abstract class PlayerImpl implements Player, Serializable { if (ability.getZone().match(zone)) { if (ability instanceof ActivatedAbility) { if (ability instanceof ActivatedManaAbilityImpl) { - if (((ActivatedAbility) ability).canActivate(playerId, game)) { + if (((ActivatedAbility) ability).canActivate(playerId, game).canActivate()) { output.put(ability.getId(), (ActivatedAbility) ability); } } else if (canPlay(((ActivatedAbility) ability), availableMana, object, game)) { @@ -1379,19 +1383,19 @@ public abstract class PlayerImpl implements Player, Serializable { if (Zone.GRAVEYARD == zone && canPlayCardsFromGraveyard()) { for (ActivatedAbility ability : candidateAbilites.getPlayableAbilities(Zone.HAND)) { if (canUse || ability.getAbilityType() == AbilityType.SPECIAL_ACTION) { - if (ability.canActivate(playerId, game)) { + if (ability.canActivate(playerId, game).canActivate()) { output.put(ability.getId(), ability); } } } } if (zone != Zone.BATTLEFIELD - && null != game.getContinuousEffects().asThough(object.getId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, this.getId(), game)) { + && null != game.getContinuousEffects().asThough(object.getId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, null, this.getId(), game)) { for (Ability ability : candidateAbilites) { if (canUse || ability.getAbilityType() == AbilityType.SPECIAL_ACTION) { ability.setControllerId(this.getId()); if (ability instanceof ActivatedAbility && ability.getZone().match(Zone.HAND) - && ((ActivatedAbility) ability).canActivate(playerId, game)) { + && ((ActivatedAbility) ability).canActivate(playerId, game).canActivate()) { output.put(ability.getId(), (ActivatedAbility) ability); } } @@ -1439,7 +1443,7 @@ public abstract class PlayerImpl implements Player, Serializable { flashbackAbility.setControllerId(card.getOwnerId()); flashbackAbility.setSpellAbilityType(SpellAbilityType.SPLIT_LEFT); flashbackAbility.setAbilityName(((SplitCard) card).getLeftHalfCard().getName()); - if (flashbackAbility.canActivate(playerId, game)) { + if (flashbackAbility.canActivate(playerId, game).canActivate()) { useable.put(flashbackAbility.getId(), flashbackAbility); } // Right Half @@ -1452,7 +1456,7 @@ public abstract class PlayerImpl implements Player, Serializable { flashbackAbility.setControllerId(card.getOwnerId()); flashbackAbility.setSpellAbilityType(SpellAbilityType.SPLIT_RIGHT); flashbackAbility.setAbilityName(((SplitCard) card).getRightHalfCard().getName()); - if (flashbackAbility.canActivate(playerId, game)) { + if (flashbackAbility.canActivate(playerId, game).canActivate()) { useable.put(flashbackAbility.getId(), flashbackAbility); } @@ -1469,7 +1473,7 @@ public abstract class PlayerImpl implements Player, Serializable { boolean canUse = !(object instanceof Permanent) || ((Permanent) object).canUseActivatedAbilities(game); for (ActivatedManaAbilityImpl ability : object.getAbilities().getActivatedManaAbilities(zone)) { if (canUse || ability.getAbilityType() == AbilityType.SPECIAL_ACTION) { - if (ability.canActivate(playerId, game)) { + if (ability.canActivate(playerId, game).canActivate()) { useable.put(ability.getId(), ability); } } @@ -2477,7 +2481,7 @@ public abstract class PlayerImpl implements Player, Serializable { Card card = game.getCard(entry.getKey()); if (card != null) { // TODO: fix costs (why is Panglacial Wurm automatically accepting payment?) - player.cast(card.getSpellAbility(), game, false); + player.cast(card.getSpellAbility(), game, false, null); } chooseCard.clearChoice(); libraryCastableCardTracker.clear(); @@ -2633,7 +2637,7 @@ public abstract class PlayerImpl implements Player, Serializable { if (canUse == null) { canUse = permanent.canUseActivatedAbilities(game); } - if (canUse && ability.canActivate(playerId, game)) { + if (canUse && ability.canActivate(playerId, game).canActivate()) { canAdd = true; if (!ability.getManaCosts().isEmpty()) { withCost = true; @@ -2677,7 +2681,7 @@ public abstract class PlayerImpl implements Player, Serializable { if (canUse == null) { canUse = permanent.canUseActivatedAbilities(game); } - if (canUse && ability.canActivate(playerId, game)) { + if (canUse && ability.canActivate(playerId, game).canActivate()) { canAdd = true; } } @@ -2692,7 +2696,7 @@ public abstract class PlayerImpl implements Player, Serializable { canAdd = false; break; } - if (ability.canActivate(playerId, game)) { + if (ability.canActivate(playerId, game).canActivate()) { canAdd = true; } } @@ -2712,7 +2716,7 @@ public abstract class PlayerImpl implements Player, Serializable { if (canUse == null) { canUse = permanent.canUseActivatedAbilities(game); } - if (canUse && ability.canActivate(playerId, game) && !ability.getManaCosts().isEmpty()) { + if (canUse && ability.canActivate(playerId, game).canActivate() && !ability.getManaCosts().isEmpty()) { result.add(permanent); break; } @@ -2732,7 +2736,7 @@ public abstract class PlayerImpl implements Player, Serializable { if (!(ability instanceof ActivatedManaAbilityImpl)) { ActivatedAbility copy = ability.copy(); copy.setCheckPlayableMode(); // prevents from endless loops for asking player to use effects by checking this mode - if (!copy.canActivate(playerId, game)) { + if (!copy.canActivate(playerId, game).canActivate()) { return false; } if (available != null) { @@ -2765,10 +2769,10 @@ public abstract class PlayerImpl implements Player, Serializable { if (available == null) { return true; } - UUID spendAnyManaSourceId = game.getContinuousEffects().asThough(ability.getSourceId(), AsThoughEffectType.SPEND_OTHER_MANA, ability, ability.getControllerId(), game); + MageObjectReference permittingObject = game.getContinuousEffects().asThough(ability.getSourceId(), AsThoughEffectType.SPEND_OTHER_MANA, ability, ability.getControllerId(), game); for (Mana mana : abilityOptions) { for (Mana avail : available) { - if (spendAnyManaSourceId != null && mana.count() <= avail.count()) { + if (permittingObject != null && mana.count() <= avail.count()) { return true; } if (mana.enough(avail)) { // here we need to check if spend mana as though allow to pay the mana cost @@ -2893,13 +2897,13 @@ public abstract class PlayerImpl implements Player, Serializable { } private void getPlayableFromGraveyardCard(Game game, Card card, Abilities candidateAbilities, ManaOptions availableMana, List output) { - UUID asThoughtCastSourceId = game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, this.getId(), game); + MageObjectReference permittingObject = game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, null, this.getId(), game); for (ActivatedAbility ability : candidateAbilities.getActivatedAbilities(Zone.ALL)) { boolean possible = false; if (ability.getZone().match(Zone.GRAVEYARD)) { possible = true; } else if (ability.getZone().match(Zone.HAND) && (ability instanceof SpellAbility || ability instanceof PlayLandAbility)) { - if (asThoughtCastSourceId != null || canPlayCardsFromGraveyard()) { + if (permittingObject != null || canPlayCardsFromGraveyard()) { possible = true; } } @@ -2968,12 +2972,12 @@ public abstract class PlayerImpl implements Player, Serializable { } for (ExileZone exile : game.getExile().getExileZones()) { for (Card card : exile.getCards(game)) { - if (null != game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, this.getId(), game)) { + if (null != game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, null, this.getId(), game)) { for (Ability ability : card.getAbilities()) { if (ability.getZone().match(Zone.HAND)) { ability.setControllerId(this.getId()); // controller must be set for case owner != caster if (ability instanceof ActivatedAbility) { - if (((ActivatedAbility) ability).canActivate(playerId, game)) { + if (((ActivatedAbility) ability).canActivate(playerId, game).canActivate()) { playable.add(ability); } } @@ -2986,7 +2990,7 @@ public abstract class PlayerImpl implements Player, Serializable { // Check to play revealed cards for (Cards cards : game.getState().getRevealed().values()) { for (Card card : cards.getCards(game)) { - if (null != game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, this.getId(), game)) { + if (null != game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, null, this.getId(), game)) { for (ActivatedAbility ability : card.getAbilities().getActivatedAbilities(Zone.HAND)) { if (ability instanceof SpellAbility || ability instanceof PlayLandAbility) { playable.add(ability); @@ -3001,7 +3005,7 @@ public abstract class PlayerImpl implements Player, Serializable { if (player != null) { if (/*player.isTopCardRevealed() &&*/player.getLibrary().hasCards()) { Card card = player.getLibrary().getFromTop(game); - if (null != game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, getId(), game)) { + if (null != game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, null, getId(), game)) { for (ActivatedAbility ability : card.getAbilities().getActivatedAbilities(Zone.HAND)) { if (ability instanceof SpellAbility || ability instanceof PlayLandAbility) { playable.add(ability); @@ -3354,7 +3358,7 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean lookAtFaceDownCard(Card card, Game game ) { - if (null != game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.LOOK_AT_FACE_DOWN, this.getId(), game)) { + if (null != game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.LOOK_AT_FACE_DOWN, card.getSpellAbility(), this.getId(), game)) { if (chooseUse(Outcome.Benefit, "Look at that card?", null, game)) { Cards cards = new CardsImpl(card); this.lookAtCards(getName() + " - " + sdf.format(System.currentTimeMillis()), cards, game);