Merge branch 'teferiInstantSpeedRework' into 'master'

make Teferi's use CastWithFlash for the Effect that allows PW abilities at instant speed

See merge request core-developers/forge!5992
This commit is contained in:
Michael Kamensky
2021-12-28 19:59:23 +00:00
33 changed files with 48 additions and 61 deletions

View File

@@ -1151,7 +1151,7 @@ public class ComputerUtilCard {
if (c.isEquipped()) {
valueTempo *= 2;
}
if (SpellAbilityAi.isSorcerySpeed(sa)) {
if (SpellAbilityAi.isSorcerySpeed(sa, ai)) {
valueTempo *= 2; //sorceries have less usage opportunities
}
if (!c.canBeDestroyed()) {
@@ -1329,7 +1329,7 @@ public class ComputerUtilCard {
// will the creature attack (only relevant for sorcery speed)?
if (phase.getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS)
&& phase.isPlayerTurn(ai)
&& (SpellAbilityAi.isSorcerySpeed(sa) || main1Preferred)
&& (SpellAbilityAi.isSorcerySpeed(sa, ai) || main1Preferred)
&& power > 0
&& doesCreatureAttackAI(ai, c)) {
return true;

View File

@@ -251,11 +251,11 @@ public abstract class SpellAbilityAi {
* a {@link forge.game.spellability.SpellAbility} object.
* @return a boolean.
*/
protected static boolean isSorcerySpeed(final SpellAbility sa) {
protected static boolean isSorcerySpeed(final SpellAbility sa, Player ai) {
return (sa.getRootAbility().isSpell() && sa.getHostCard().isSorcery())
|| (sa.getRootAbility().isActivatedAbility() && sa.getRestrictions().isSorcerySpeed())
|| (sa.getRootAbility().isAdventure() && sa.getHostCard().getState(CardStateName.Adventure).getType().isSorcery())
|| (sa.isPwAbility() && !sa.getHostCard().hasKeyword("CARDNAME's loyalty abilities can be activated at instant speed."));
|| (sa.isPwAbility() && !sa.withFlash(sa.getHostCard(), ai));
}
/**

View File

@@ -87,7 +87,7 @@ public class AnimateAi extends SpellAbilityAi {
}
}
// Don't use instant speed animate abilities before AI's COMBAT_BEGIN
if (!ph.is(PhaseType.COMBAT_BEGIN) && ph.isPlayerTurn(ai) && !SpellAbilityAi.isSorcerySpeed(sa)
if (!ph.is(PhaseType.COMBAT_BEGIN) && ph.isPlayerTurn(ai) && !SpellAbilityAi.isSorcerySpeed(sa, ai)
&& !sa.hasParam("ActivationPhases") && !"Permanent".equals(sa.getParam("Duration"))) {
return false;
}
@@ -175,7 +175,7 @@ public class AnimateAi extends SpellAbilityAi {
}
}
if (!SpellAbilityAi.isSorcerySpeed(sa) && !"Permanent".equals(sa.getParam("Duration"))) {
if (!SpellAbilityAi.isSorcerySpeed(sa, aiPlayer) && !"Permanent".equals(sa.getParam("Duration"))) {
if (sa.hasParam("Crew") && c.isCreature()) {
// Do not try to crew a vehicle which is already a creature
return false;

View File

@@ -1059,7 +1059,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
}
if (!immediately && (!game.getPhaseHandler().getNextTurn().equals(ai)
|| game.getPhaseHandler().getPhase().isBefore(PhaseType.END_OF_TURN))
&& !sa.hasParam("PlayerTurn") && !SpellAbilityAi.isSorcerySpeed(sa)
&& !sa.hasParam("PlayerTurn") && !SpellAbilityAi.isSorcerySpeed(sa, ai)
&& !ComputerUtil.activateForCost(sa, ai)) {
return false;
}

View File

@@ -243,7 +243,7 @@ public class CloneAi extends SpellAbilityAi {
// don't use instant speed clone abilities outside computers
// Combat_Begin step
if (!ph.is(PhaseType.COMBAT_BEGIN)
&& ph.isPlayerTurn(ai) && !SpellAbilityAi.isSorcerySpeed(sa)
&& ph.isPlayerTurn(ai) && !SpellAbilityAi.isSorcerySpeed(sa, ai)
&& !sa.hasParam("ActivationPhases") && sa.hasParam("Duration")) {
return false;
}

View File

@@ -83,7 +83,7 @@ public class CountersMultiplyAi extends SpellAbilityAi {
if (ph.getPhase().isBefore(PhaseType.MAIN2) && !ComputerUtil.castSpellInMain1(ai, sa)) {
return false;
}
if (ph.isPlayerTurn(ai) && !isSorcerySpeed(sa)) {
if (ph.isPlayerTurn(ai) && !isSorcerySpeed(sa, ai)) {
return false;
}
}

View File

@@ -448,7 +448,7 @@ public class CountersPutAi extends CountersAi {
}
}
if (!ai.getGame().getStack().isEmpty() && !SpellAbilityAi.isSorcerySpeed(sa)) {
if (!ai.getGame().getStack().isEmpty() && !SpellAbilityAi.isSorcerySpeed(sa, ai)) {
// only evaluates case where all tokens are placed on a single target
if (sa.usesTargeting() && sa.getMinTargets() < 2) {
if (ComputerUtilCard.canPumpAgainstRemoval(ai, sa)) {
@@ -557,7 +557,7 @@ public class CountersPutAi extends CountersAi {
if (sa.isCurse()) {
choice = chooseCursedTarget(list, type, amount, ai);
} else {
if (type.equals("P1P1") && !SpellAbilityAi.isSorcerySpeed(sa)) {
if (type.equals("P1P1") && !SpellAbilityAi.isSorcerySpeed(sa, ai)) {
for (Card c : list) {
if (ComputerUtilCard.shouldPumpCard(ai, sa, c, amount, amount,
Lists.newArrayList())) {
@@ -619,7 +619,7 @@ public class CountersPutAi extends CountersAi {
return false;
}
// Instant +1/+1
if (type.equals("P1P1") && !SpellAbilityAi.isSorcerySpeed(sa)) {
if (type.equals("P1P1") && !SpellAbilityAi.isSorcerySpeed(sa, ai)) {
if (!(ph.getNextTurn() == ai && ph.is(PhaseType.END_OF_TURN) && abCost.isReusuableResource())) {
return false; // only if next turn and cost is reusable
}
@@ -641,7 +641,7 @@ public class CountersPutAi extends CountersAi {
if (ph.getPhase().isBefore(PhaseType.MAIN2) && !ComputerUtil.castSpellInMain1(ai, sa)) {
return false;
}
if (ph.isPlayerTurn(ai) && !isSorcerySpeed(sa)) {
if (ph.isPlayerTurn(ai) && !isSorcerySpeed(sa, ai)) {
return false;
}
}

View File

@@ -126,7 +126,7 @@ public abstract class DamageAiBase extends SpellAbilityAi {
// chance to burn player based on current hand size
if (hand.size() > 2) {
float value = 0;
if (SpellAbilityAi.isSorcerySpeed(sa)) {
if (SpellAbilityAi.isSorcerySpeed(sa, comp)) {
//lower chance for sorcery as other spells may be cast in main2
if (phase.isPlayerTurn(comp) && phase.is(PhaseType.MAIN2)) {
value = 1.0f * restDamage / enemy.getLife();

View File

@@ -761,7 +761,7 @@ public class DamageDealAi extends DamageAiBase {
// TODO: Improve Damage, we shouldn't just target the player just because we can
if (sa.canTarget(enemy) && tcs.size() < tgt.getMaxTargets(source, sa)) {
if (((phase.is(PhaseType.END_OF_TURN) && phase.getNextTurn().equals(ai))
|| (SpellAbilityAi.isSorcerySpeed(sa) && phase.is(PhaseType.MAIN2))
|| (SpellAbilityAi.isSorcerySpeed(sa, ai) && phase.is(PhaseType.MAIN2))
|| ("PingAfterAttack".equals(logic) && phase.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS) && phase.isPlayerTurn(ai))
|| immediately || shouldTgtP(ai, sa, dmg, noPrevention)) &&
(!avoidTargetP(ai, sa))) {

View File

@@ -14,7 +14,7 @@ public class DayTimeAi extends SpellAbilityAi {
if ((sa.getHostCard().isCreature() && sa.getPayCosts().hasTapCost()) || sa.getPayCosts().hasManaCost()) {
// If it involves a cost that may put us at a disadvantage, better activate before own turn if possible
if (!SpellAbilityAi.isSorcerySpeed(sa)) {
if (!SpellAbilityAi.isSorcerySpeed(sa, aiPlayer)) {
return ph.is(PhaseType.END_OF_TURN) && ph.getNextTurn() == aiPlayer;
} else {
return ph.is(PhaseType.MAIN2, aiPlayer); // Give other things a chance to be cast (e.g. Celestus)

View File

@@ -60,7 +60,7 @@ public class DebuffAi extends SpellAbilityAi {
|| !game.getStack().isEmpty()) {
// Instant-speed pumps should not be cast outside of combat when the
// stack is empty
if (!SpellAbilityAi.isSorcerySpeed(sa)) {
if (!SpellAbilityAi.isSorcerySpeed(sa, ai)) {
return false;
}
}

View File

@@ -108,7 +108,7 @@ public class DigAi extends SpellAbilityAi {
if ((!game.getPhaseHandler().getNextTurn().equals(ai)
|| game.getPhaseHandler().getPhase().isBefore(PhaseType.END_OF_TURN))
&& !sa.hasParam("PlayerTurn") && !SpellAbilityAi.isSorcerySpeed(sa)
&& !sa.hasParam("PlayerTurn") && !SpellAbilityAi.isSorcerySpeed(sa, ai)
&& (ai.getCardsIn(ZoneType.Hand).size() > 1 || game.getPhaseHandler().getPhase().isBefore(PhaseType.DRAW))
&& !ComputerUtil.activateForCost(sa, ai)) {
return false;

View File

@@ -66,7 +66,7 @@ public class DigMultipleAi extends SpellAbilityAi {
if ((!game.getPhaseHandler().getNextTurn().equals(ai)
|| game.getPhaseHandler().getPhase().isBefore(PhaseType.END_OF_TURN))
&& !sa.hasParam("PlayerTurn") && !SpellAbilityAi.isSorcerySpeed(sa)
&& !sa.hasParam("PlayerTurn") && !SpellAbilityAi.isSorcerySpeed(sa, ai)
&& (ai.getCardsIn(ZoneType.Hand).size() > 1 || game.getPhaseHandler().getPhase().isBefore(PhaseType.DRAW))
&& !ComputerUtil.activateForCost(sa, ai)) {
return false;

View File

@@ -24,7 +24,7 @@ public class DigUntilAi extends SpellAbilityAi {
Card source = sa.getHostCard();
final String logic = sa.getParamOrDefault("AILogic", "");
double chance = .4; // 40 percent chance with instant speed stuff
if (SpellAbilityAi.isSorcerySpeed(sa)) {
if (SpellAbilityAi.isSorcerySpeed(sa, ai)) {
chance = .667; // 66.7% chance for sorcery speed (since it will
// never activate EOT)
}

View File

@@ -166,7 +166,7 @@ public class DrawAi extends SpellAbilityAi {
@Override
protected boolean checkPhaseRestrictions(Player ai, SpellAbility sa, PhaseHandler ph, String logic) {
if ((!ph.getNextTurn().equals(ai) || ph.getPhase().isBefore(PhaseType.END_OF_TURN))
&& !sa.hasParam("PlayerTurn") && !SpellAbilityAi.isSorcerySpeed(sa)
&& !sa.hasParam("PlayerTurn") && !SpellAbilityAi.isSorcerySpeed(sa, ai)
&& ai.getCardsIn(ZoneType.Hand).size() > 1 && !ComputerUtil.activateForCost(sa, ai)
&& !"YawgmothsBargain".equals(logic)) {
return false;

View File

@@ -18,7 +18,7 @@ public class FlipOntoBattlefieldAi extends SpellAbilityAi {
PhaseHandler ph = sa.getHostCard().getGame().getPhaseHandler();
String logic = sa.getParamOrDefault("AILogic", "");
if (!SpellAbilityAi.isSorcerySpeed(sa) && sa.getPayCosts().hasManaCost()) {
if (!SpellAbilityAi.isSorcerySpeed(sa, aiPlayer) && sa.getPayCosts().hasManaCost()) {
return ph.is(PhaseType.END_OF_TURN);
}

View File

@@ -111,7 +111,7 @@ public class LifeGainAi extends SpellAbilityAi {
return lifeCritical || activateForCost
|| (ph.getNextTurn().equals(ai) && !ph.getPhase().isBefore(PhaseType.END_OF_TURN))
|| sa.hasParam("PlayerTurn") || SpellAbilityAi.isSorcerySpeed(sa);
|| sa.hasParam("PlayerTurn") || SpellAbilityAi.isSorcerySpeed(sa, ai);
}
/*
@@ -180,7 +180,7 @@ public class LifeGainAi extends SpellAbilityAi {
return true;
}
if (SpellAbilityAi.isSorcerySpeed(sa)
if (SpellAbilityAi.isSorcerySpeed(sa, ai)
|| sa.getSubAbility() != null || SpellAbilityAi.playReusable(ai, sa)) {
return true;
}

View File

@@ -144,7 +144,7 @@ public class LifeLoseAi extends SpellAbilityAi {
return false;
}
if (SpellAbilityAi.isSorcerySpeed(sa) || sa.hasParam("ActivationPhases") || SpellAbilityAi.playReusable(ai, sa)
if (SpellAbilityAi.isSorcerySpeed(sa, ai) || sa.hasParam("ActivationPhases") || SpellAbilityAi.playReusable(ai, sa)
|| ComputerUtil.activateForCost(sa, ai)) {
return true;
}

View File

@@ -66,7 +66,7 @@ public class ManifestAi extends SpellAbilityAi {
if (!buff) {
return false;
}
} else if (!SpellAbilityAi.isSorcerySpeed(sa)) {
} else if (!SpellAbilityAi.isSorcerySpeed(sa, ai)) {
return false;
}
} else {

View File

@@ -53,7 +53,7 @@ public class MillAi extends SpellAbilityAi {
return (ph.is(PhaseType.MAIN1) || ph.is(PhaseType.MAIN2)) && ph.isPlayerTurn(ai); // Chandra, Torch of Defiance and similar
}
if (!sa.isPwAbility()) { // Planeswalker abilities are only activated at sorcery speed
if ("You".equals(sa.getParam("Defined")) && !(!SpellAbilityAi.isSorcerySpeed(sa) && ph.is(PhaseType.END_OF_TURN)
if ("You".equals(sa.getParam("Defined")) && !(!SpellAbilityAi.isSorcerySpeed(sa, ai) && ph.is(PhaseType.END_OF_TURN)
&& ph.getNextTurn().equals(ai))) {
return false; // only self-mill at opponent EOT
}

View File

@@ -164,7 +164,7 @@ public class ProtectAi extends SpellAbilityAi {
protected boolean checkPhaseRestrictions(final Player ai, final SpellAbility sa, final PhaseHandler ph) {
final boolean notAiMain1 = !(ph.getPlayerTurn() == ai && ph.getPhase() == PhaseType.MAIN1);
// sorceries can only give protection in order to create an unblockable attacker
return !SpellAbilityAi.isSorcerySpeed(sa) || !notAiMain1;
return !SpellAbilityAi.isSorcerySpeed(sa, ai) || !notAiMain1;
}
@Override

View File

@@ -81,7 +81,7 @@ public class PumpAi extends PumpAiBase {
return true;
}
return SpellAbilityAi.isSorcerySpeed(sa) || (ph.getNextTurn().equals(ai) && !ph.getPhase().isBefore(PhaseType.END_OF_TURN));
return SpellAbilityAi.isSorcerySpeed(sa, ai) || (ph.getNextTurn().equals(ai) && !ph.getPhase().isBefore(PhaseType.END_OF_TURN));
} else if (logic.equals("Aristocrat")) {
final boolean isThreatened = ComputerUtil.predictThreatenedObjects(ai, null, true).contains(sa.getHostCard());
if (!ph.is(PhaseType.COMBAT_DECLARE_BLOCKERS) && !isThreatened) {
@@ -112,7 +112,7 @@ public class PumpAi extends PumpAiBase {
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS))) {
// Instant-speed pumps should not be cast outside of combat when the
// stack is empty
return sa.isCurse() || SpellAbilityAi.isSorcerySpeed(sa) || main1Preferred;
return sa.isCurse() || SpellAbilityAi.isSorcerySpeed(sa, ai) || main1Preferred;
}
return true;
}
@@ -364,7 +364,7 @@ public class PumpAi extends PumpAiBase {
if (ComputerUtilCard.shouldPumpCard(ai, sa, card, defense, attack, keywords, false)) {
return true;
} else if (containsUsefulKeyword(ai, keywords, card, sa, attack)) {
if (game.getPhaseHandler().isPreCombatMain() && SpellAbilityAi.isSorcerySpeed(sa) ||
if (game.getPhaseHandler().isPreCombatMain() && SpellAbilityAi.isSorcerySpeed(sa, ai) ||
game.getPhaseHandler().is(PhaseType.COMBAT_DECLARE_ATTACKERS, ai) ||
game.getPhaseHandler().is(PhaseType.COMBAT_BEGIN, ai)) {
Card pumped = ComputerUtilCard.getPumpedCreature(ai, sa, card, 0, 0, keywords);

View File

@@ -55,7 +55,7 @@ public class ScryAi extends SpellAbilityAi {
// even if there's no mana cost.
if (sa.getPayCosts().hasTapCost()
&& (sa.getPayCosts().hasManaCost() || (sa.getHostCard() != null && sa.getHostCard().isCreature()))
&& !SpellAbilityAi.isSorcerySpeed(sa)) {
&& !SpellAbilityAi.isSorcerySpeed(sa, ai)) {
return ph.getNextTurn() == ai && ph.is(PhaseType.END_OF_TURN);
}
@@ -67,7 +67,7 @@ public class ScryAi extends SpellAbilityAi {
// in the playerturn Scry should only be done in Main1 or in upkeep if able
if (ph.isPlayerTurn(ai)) {
if (SpellAbilityAi.isSorcerySpeed(sa)) {
if (SpellAbilityAi.isSorcerySpeed(sa, ai)) {
return ph.is(PhaseType.MAIN1) || sa.isPwAbility();
} else {
return ph.is(PhaseType.UPKEEP);
@@ -119,7 +119,7 @@ public class ScryAi extends SpellAbilityAi {
}
double chance = .4; // 40 percent chance of milling with instant speed stuff
if (SpellAbilityAi.isSorcerySpeed(sa)) {
if (SpellAbilityAi.isSorcerySpeed(sa, ai)) {
chance = .667; // 66.7% chance for sorcery speed (since it will never activate EOT)
}
boolean randomReturn = MyRandom.getRandom().nextFloat() <= Math.pow(chance, sa.getActivationsThisTurn() + 1);

View File

@@ -52,13 +52,13 @@ public class SurveilAi extends SpellAbilityAi {
// even if there's no mana cost.
if (sa.getPayCosts().hasTapCost()
&& (sa.getPayCosts().hasManaCost() || (sa.getHostCard() != null && sa.getHostCard().isCreature()))
&& !SpellAbilityAi.isSorcerySpeed(sa)) {
&& !SpellAbilityAi.isSorcerySpeed(sa, ai)) {
return ph.getNextTurn() == ai && ph.is(PhaseType.END_OF_TURN);
}
// in the player's turn Surveil should only be done in Main1 or in Upkeep if able
if (ph.isPlayerTurn(ai)) {
if (SpellAbilityAi.isSorcerySpeed(sa)) {
if (SpellAbilityAi.isSorcerySpeed(sa, ai)) {
return ph.is(PhaseType.MAIN1) || sa.isPwAbility();
} else {
return ph.is(PhaseType.UPKEEP);
@@ -102,7 +102,7 @@ public class SurveilAi extends SpellAbilityAi {
}
double chance = .4; // 40 percent chance for instant speed
if (SpellAbilityAi.isSorcerySpeed(sa)) {
if (SpellAbilityAi.isSorcerySpeed(sa, ai)) {
chance = .667; // 66.7% chance for sorcery speed (since it will never activate EOT)
}

View File

@@ -18,7 +18,7 @@ public class TapAi extends TapAiBase {
if (turn.isOpponentOf(ai) && phase.getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS)) {
// Tap things down if it's Human's turn
} else if (turn.equals(ai)) {
if (SpellAbilityAi.isSorcerySpeed(sa) && phase.getPhase().isBefore(PhaseType.COMBAT_BEGIN)) {
if (SpellAbilityAi.isSorcerySpeed(sa, ai) && phase.getPhase().isBefore(PhaseType.COMBAT_BEGIN)) {
// Cast it if it's a sorcery.
} else if (phase.getPhase().isBefore(PhaseType.COMBAT_DECLARE_BLOCKERS)) {
// Aggro Brains are willing to use TapEffects aggressively instead of defensively

View File

@@ -134,7 +134,7 @@ public class TokenAi extends SpellAbilityAi {
}
}
if ((ph.isPlayerTurn(ai) || ph.getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS))
&& !sa.hasParam("ActivationPhases") && !sa.hasParam("PlayerTurn") && !SpellAbilityAi.isSorcerySpeed(sa)
&& !sa.hasParam("ActivationPhases") && !sa.hasParam("PlayerTurn") && !SpellAbilityAi.isSorcerySpeed(sa, ai)
&& !haste && !pwMinus) {
return false;
}

View File

@@ -20,7 +20,7 @@ public class VentureAi extends SpellAbilityAi {
// If this has a mana cost, do it at opponent's EOT if able to prevent spending mana early; if sorcery, do it in Main2
PhaseHandler ph = aiPlayer.getGame().getPhaseHandler();
if (sa.getPayCosts().hasManaCost() || sa.getPayCosts().hasTapCost()) {
if (SpellAbilityAi.isSorcerySpeed(sa)) {
if (SpellAbilityAi.isSorcerySpeed(sa, aiPlayer)) {
return ph.is(PhaseType.MAIN2, aiPlayer);
} else {
return ph.is(PhaseType.END_OF_TURN) && ph.getNextTurn() == aiPlayer;

View File

@@ -154,7 +154,7 @@ public class SpellAbilityPicker {
return !sa.withFlash(sa.getHostCard(), player);
}
if (sa.isPwAbility()) {
return !sa.getHostCard().hasKeyword("CARDNAME's loyalty abilities can be activated at instant speed.");
return !sa.withFlash(sa.getHostCard(), player);
}
return sa.isActivatedAbility() && sa.getRestrictions().isSorcerySpeed();
}

View File

@@ -2393,8 +2393,8 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
}
if (isActivatedAbility()) {
// Activated Abillties are instant speed per default
return !getRestrictions().isSorcerySpeed();
// Activated Abilities are instant speed per default, except Planeswalker abilities
return !isPwAbility() && !getRestrictions().isSorcerySpeed();
}
return true;
}
@@ -2403,11 +2403,9 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
if (getRestrictions().isInstantSpeed()) {
return true;
}
if (isSpell()) {
if (hasSVar("IsCastFromPlayEffect") || host.isInstant() || host.hasKeyword(Keyword.FLASH)) {
if (isSpell() && (hasSVar("IsCastFromPlayEffect") || host.isInstant() || host.hasKeyword(Keyword.FLASH))) {
return true;
}
}
return StaticAbilityCastWithFlash.anyWithFlash(this, host, activator);
}

View File

@@ -479,11 +479,6 @@ public class SpellAbilityRestriction extends SpellAbilityVariables {
}
if (sa.isPwAbility()) {
if (!c.hasKeyword("CARDNAME's loyalty abilities can be activated at instant speed.")
&& !activator.canCastSorcery()) {
return false;
}
final int initialLimit = c.hasKeyword("CARDNAME's loyalty abilities can be activated twice each turn rather than only once") ? 1 : 0;
final int limits = c.getAmountOfKeyword("May activate CARDNAME's loyalty abilities once") + initialLimit;

View File

@@ -1,9 +1,6 @@
package forge.game.staticability;
import com.google.common.collect.Iterables;
import forge.game.Game;
import forge.game.GameObjectPredicates;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.player.Player;
@@ -72,7 +69,6 @@ public class StaticAbilityCastWithFlash {
}
public static boolean applyWithFlashAbility(final StaticAbility stAb, final SpellAbility sa, final Card card, final Player activator) {
final Card hostCard = stAb.getHostCard();
if (!commonParts(stAb, sa, card, activator)) {
return false;
@@ -83,8 +79,7 @@ public class StaticAbilityCastWithFlash {
return false;
}
String[] valids = stAb.getParam("Targeting").split(",");
if (!Iterables.any(sa.getTargets(), GameObjectPredicates.restriction(valids, hostCard.getController(), hostCard, stAb))) {
if (!stAb.matchesValidParam("Targeting", sa.getTargets())) {
return false;
}
}

View File

@@ -2,7 +2,7 @@ Name:Teferi, Master of Time
ManaCost:2 U U
Types:Legendary Planeswalker Teferi
Loyalty:3
S:Mode$ Continuous | Affected$ Card.Self | AddHiddenKeyword$ CARDNAME's loyalty abilities can be activated at instant speed. | Description$ You may activate loyalty abilities of CARDNAME on any player's turn any time you could cast an instant.
S:Mode$ CastWithFlash | ValidCard$ Card.Self | ValidSA$ Activated.Loyalty | Caster$ You | Description$ You may activate loyalty abilities of CARDNAME on any player's turn any time you could cast an instant.
A:AB$ Draw | Cost$ AddCounter<1/LOYALTY> | Planeswalker$ True | NumCards$ 1 | SubAbility$ DBDiscard | SpellDescription$ Draw a card, then discard a card.
SVar:DBDiscard:DB$ Discard | Defined$ You | NumCards$ 1 | Mode$ TgtChoose
A:AB$ Phases | Cost$ SubCounter<3/LOYALTY> | Planeswalker$ True | ValidTgts$ Creature.YouDontCtrl | TgtPrompt$ Select target creature you don't control | IsCurse$ True | SpellDescription$ Target creature you don't control phases out. (Treat it and anything attached to it as though they don't exist until its controllers's next turn.)

View File

@@ -6,6 +6,5 @@ Text:CARDNAME can be your commander.
A:AB$ Dig | Cost$ AddCounter<1/LOYALTY> | Planeswalker$ True | DigNum$ 2 | SpellDescription$ Look at the top two cards of your library. Put one of them into your hand and the other on the bottom of your library.
A:AB$ Untap | Cost$ SubCounter<1/LOYALTY> | Planeswalker$ True | ValidTgts$ Permanent | TargetMin$ 0 | TargetMax$ 4 | SpellDescription$ Untap up to four target permanents.
A:AB$ Effect | Cost$ SubCounter<10/LOYALTY> | Planeswalker$ True | Ultimate$ True | Name$ Emblem - Teferi, Temporal Archmage | Image$ emblem_teferi_temporal_archmage | StaticAbilities$ InstantPlaneswalkers | Stackable$ False | Duration$ Permanent | AILogic$ Always | SpellDescription$ You get an emblem with "You may activate loyalty abilities of planeswalkers you control on any player's turn any time you could cast an instant."
SVar:InstantPlaneswalkers:Mode$ Continuous | EffectZone$ Command | Affected$ Planeswalker.YouCtrl | AddHiddenKeyword$ CARDNAME's loyalty abilities can be activated at instant speed. | Description$ You may activate loyalty abilities of planeswalkers you control on any player's turn any time you could cast an instant.
SVar:Picture:http://www.wizards.com/global/images/magic/general/teferi_temporal_archmage.jpg
SVar:InstantPlaneswalkers:Mode$ CastWithFlash | ValidCard$ Planeswalker.YouCtrl | ValidSA$ Activated.Loyalty | Caster$ You | Description$ You may activate loyalty abilities of planeswalkers you control on any player's turn any time you could cast an instant.
Oracle:[+1]: Look at the top two cards of your library. Put one of them into your hand and the other on the bottom of your library.\n[1]: Untap up to four target permanents.\n[10]: You get an emblem with "You may activate loyalty abilities of planeswalkers you control on any player's turn any time you could cast an instant."\nTeferi, Temporal Archmage can be your commander.