mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-15 02:08:00 +00:00
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:
@@ -1151,7 +1151,7 @@ public class ComputerUtilCard {
|
|||||||
if (c.isEquipped()) {
|
if (c.isEquipped()) {
|
||||||
valueTempo *= 2;
|
valueTempo *= 2;
|
||||||
}
|
}
|
||||||
if (SpellAbilityAi.isSorcerySpeed(sa)) {
|
if (SpellAbilityAi.isSorcerySpeed(sa, ai)) {
|
||||||
valueTempo *= 2; //sorceries have less usage opportunities
|
valueTempo *= 2; //sorceries have less usage opportunities
|
||||||
}
|
}
|
||||||
if (!c.canBeDestroyed()) {
|
if (!c.canBeDestroyed()) {
|
||||||
@@ -1329,7 +1329,7 @@ public class ComputerUtilCard {
|
|||||||
// will the creature attack (only relevant for sorcery speed)?
|
// will the creature attack (only relevant for sorcery speed)?
|
||||||
if (phase.getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS)
|
if (phase.getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS)
|
||||||
&& phase.isPlayerTurn(ai)
|
&& phase.isPlayerTurn(ai)
|
||||||
&& (SpellAbilityAi.isSorcerySpeed(sa) || main1Preferred)
|
&& (SpellAbilityAi.isSorcerySpeed(sa, ai) || main1Preferred)
|
||||||
&& power > 0
|
&& power > 0
|
||||||
&& doesCreatureAttackAI(ai, c)) {
|
&& doesCreatureAttackAI(ai, c)) {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -251,11 +251,11 @@ public abstract class SpellAbilityAi {
|
|||||||
* a {@link forge.game.spellability.SpellAbility} object.
|
* a {@link forge.game.spellability.SpellAbility} object.
|
||||||
* @return a boolean.
|
* @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())
|
return (sa.getRootAbility().isSpell() && sa.getHostCard().isSorcery())
|
||||||
|| (sa.getRootAbility().isActivatedAbility() && sa.getRestrictions().isSorcerySpeed())
|
|| (sa.getRootAbility().isActivatedAbility() && sa.getRestrictions().isSorcerySpeed())
|
||||||
|| (sa.getRootAbility().isAdventure() && sa.getHostCard().getState(CardStateName.Adventure).getType().isSorcery())
|
|| (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));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ public class AnimateAi extends SpellAbilityAi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Don't use instant speed animate abilities before AI's COMBAT_BEGIN
|
// 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"))) {
|
&& !sa.hasParam("ActivationPhases") && !"Permanent".equals(sa.getParam("Duration"))) {
|
||||||
return false;
|
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()) {
|
if (sa.hasParam("Crew") && c.isCreature()) {
|
||||||
// Do not try to crew a vehicle which is already a creature
|
// Do not try to crew a vehicle which is already a creature
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -1059,7 +1059,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
|
|||||||
}
|
}
|
||||||
if (!immediately && (!game.getPhaseHandler().getNextTurn().equals(ai)
|
if (!immediately && (!game.getPhaseHandler().getNextTurn().equals(ai)
|
||||||
|| game.getPhaseHandler().getPhase().isBefore(PhaseType.END_OF_TURN))
|
|| 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)) {
|
&& !ComputerUtil.activateForCost(sa, ai)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -243,7 +243,7 @@ public class CloneAi extends SpellAbilityAi {
|
|||||||
// don't use instant speed clone abilities outside computers
|
// don't use instant speed clone abilities outside computers
|
||||||
// Combat_Begin step
|
// Combat_Begin step
|
||||||
if (!ph.is(PhaseType.COMBAT_BEGIN)
|
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")) {
|
&& !sa.hasParam("ActivationPhases") && sa.hasParam("Duration")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ public class CountersMultiplyAi extends SpellAbilityAi {
|
|||||||
if (ph.getPhase().isBefore(PhaseType.MAIN2) && !ComputerUtil.castSpellInMain1(ai, sa)) {
|
if (ph.getPhase().isBefore(PhaseType.MAIN2) && !ComputerUtil.castSpellInMain1(ai, sa)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (ph.isPlayerTurn(ai) && !isSorcerySpeed(sa)) {
|
if (ph.isPlayerTurn(ai) && !isSorcerySpeed(sa, ai)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
// only evaluates case where all tokens are placed on a single target
|
||||||
if (sa.usesTargeting() && sa.getMinTargets() < 2) {
|
if (sa.usesTargeting() && sa.getMinTargets() < 2) {
|
||||||
if (ComputerUtilCard.canPumpAgainstRemoval(ai, sa)) {
|
if (ComputerUtilCard.canPumpAgainstRemoval(ai, sa)) {
|
||||||
@@ -557,7 +557,7 @@ public class CountersPutAi extends CountersAi {
|
|||||||
if (sa.isCurse()) {
|
if (sa.isCurse()) {
|
||||||
choice = chooseCursedTarget(list, type, amount, ai);
|
choice = chooseCursedTarget(list, type, amount, ai);
|
||||||
} else {
|
} else {
|
||||||
if (type.equals("P1P1") && !SpellAbilityAi.isSorcerySpeed(sa)) {
|
if (type.equals("P1P1") && !SpellAbilityAi.isSorcerySpeed(sa, ai)) {
|
||||||
for (Card c : list) {
|
for (Card c : list) {
|
||||||
if (ComputerUtilCard.shouldPumpCard(ai, sa, c, amount, amount,
|
if (ComputerUtilCard.shouldPumpCard(ai, sa, c, amount, amount,
|
||||||
Lists.newArrayList())) {
|
Lists.newArrayList())) {
|
||||||
@@ -619,7 +619,7 @@ public class CountersPutAi extends CountersAi {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Instant +1/+1
|
// 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())) {
|
if (!(ph.getNextTurn() == ai && ph.is(PhaseType.END_OF_TURN) && abCost.isReusuableResource())) {
|
||||||
return false; // only if next turn and cost is reusable
|
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)) {
|
if (ph.getPhase().isBefore(PhaseType.MAIN2) && !ComputerUtil.castSpellInMain1(ai, sa)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (ph.isPlayerTurn(ai) && !isSorcerySpeed(sa)) {
|
if (ph.isPlayerTurn(ai) && !isSorcerySpeed(sa, ai)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ public abstract class DamageAiBase extends SpellAbilityAi {
|
|||||||
// chance to burn player based on current hand size
|
// chance to burn player based on current hand size
|
||||||
if (hand.size() > 2) {
|
if (hand.size() > 2) {
|
||||||
float value = 0;
|
float value = 0;
|
||||||
if (SpellAbilityAi.isSorcerySpeed(sa)) {
|
if (SpellAbilityAi.isSorcerySpeed(sa, comp)) {
|
||||||
//lower chance for sorcery as other spells may be cast in main2
|
//lower chance for sorcery as other spells may be cast in main2
|
||||||
if (phase.isPlayerTurn(comp) && phase.is(PhaseType.MAIN2)) {
|
if (phase.isPlayerTurn(comp) && phase.is(PhaseType.MAIN2)) {
|
||||||
value = 1.0f * restDamage / enemy.getLife();
|
value = 1.0f * restDamage / enemy.getLife();
|
||||||
|
|||||||
@@ -761,7 +761,7 @@ public class DamageDealAi extends DamageAiBase {
|
|||||||
// TODO: Improve Damage, we shouldn't just target the player just because we can
|
// 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 (sa.canTarget(enemy) && tcs.size() < tgt.getMaxTargets(source, sa)) {
|
||||||
if (((phase.is(PhaseType.END_OF_TURN) && phase.getNextTurn().equals(ai))
|
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))
|
|| ("PingAfterAttack".equals(logic) && phase.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS) && phase.isPlayerTurn(ai))
|
||||||
|| immediately || shouldTgtP(ai, sa, dmg, noPrevention)) &&
|
|| immediately || shouldTgtP(ai, sa, dmg, noPrevention)) &&
|
||||||
(!avoidTargetP(ai, sa))) {
|
(!avoidTargetP(ai, sa))) {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ public class DayTimeAi extends SpellAbilityAi {
|
|||||||
|
|
||||||
if ((sa.getHostCard().isCreature() && sa.getPayCosts().hasTapCost()) || sa.getPayCosts().hasManaCost()) {
|
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 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;
|
return ph.is(PhaseType.END_OF_TURN) && ph.getNextTurn() == aiPlayer;
|
||||||
} else {
|
} else {
|
||||||
return ph.is(PhaseType.MAIN2, aiPlayer); // Give other things a chance to be cast (e.g. Celestus)
|
return ph.is(PhaseType.MAIN2, aiPlayer); // Give other things a chance to be cast (e.g. Celestus)
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ public class DebuffAi extends SpellAbilityAi {
|
|||||||
|| !game.getStack().isEmpty()) {
|
|| !game.getStack().isEmpty()) {
|
||||||
// Instant-speed pumps should not be cast outside of combat when the
|
// Instant-speed pumps should not be cast outside of combat when the
|
||||||
// stack is empty
|
// stack is empty
|
||||||
if (!SpellAbilityAi.isSorcerySpeed(sa)) {
|
if (!SpellAbilityAi.isSorcerySpeed(sa, ai)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ public class DigAi extends SpellAbilityAi {
|
|||||||
|
|
||||||
if ((!game.getPhaseHandler().getNextTurn().equals(ai)
|
if ((!game.getPhaseHandler().getNextTurn().equals(ai)
|
||||||
|| game.getPhaseHandler().getPhase().isBefore(PhaseType.END_OF_TURN))
|
|| 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))
|
&& (ai.getCardsIn(ZoneType.Hand).size() > 1 || game.getPhaseHandler().getPhase().isBefore(PhaseType.DRAW))
|
||||||
&& !ComputerUtil.activateForCost(sa, ai)) {
|
&& !ComputerUtil.activateForCost(sa, ai)) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ public class DigMultipleAi extends SpellAbilityAi {
|
|||||||
|
|
||||||
if ((!game.getPhaseHandler().getNextTurn().equals(ai)
|
if ((!game.getPhaseHandler().getNextTurn().equals(ai)
|
||||||
|| game.getPhaseHandler().getPhase().isBefore(PhaseType.END_OF_TURN))
|
|| 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))
|
&& (ai.getCardsIn(ZoneType.Hand).size() > 1 || game.getPhaseHandler().getPhase().isBefore(PhaseType.DRAW))
|
||||||
&& !ComputerUtil.activateForCost(sa, ai)) {
|
&& !ComputerUtil.activateForCost(sa, ai)) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ public class DigUntilAi extends SpellAbilityAi {
|
|||||||
Card source = sa.getHostCard();
|
Card source = sa.getHostCard();
|
||||||
final String logic = sa.getParamOrDefault("AILogic", "");
|
final String logic = sa.getParamOrDefault("AILogic", "");
|
||||||
double chance = .4; // 40 percent chance with instant speed stuff
|
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
|
chance = .667; // 66.7% chance for sorcery speed (since it will
|
||||||
// never activate EOT)
|
// never activate EOT)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ public class DrawAi extends SpellAbilityAi {
|
|||||||
@Override
|
@Override
|
||||||
protected boolean checkPhaseRestrictions(Player ai, SpellAbility sa, PhaseHandler ph, String logic) {
|
protected boolean checkPhaseRestrictions(Player ai, SpellAbility sa, PhaseHandler ph, String logic) {
|
||||||
if ((!ph.getNextTurn().equals(ai) || ph.getPhase().isBefore(PhaseType.END_OF_TURN))
|
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)
|
&& ai.getCardsIn(ZoneType.Hand).size() > 1 && !ComputerUtil.activateForCost(sa, ai)
|
||||||
&& !"YawgmothsBargain".equals(logic)) {
|
&& !"YawgmothsBargain".equals(logic)) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ public class FlipOntoBattlefieldAi extends SpellAbilityAi {
|
|||||||
PhaseHandler ph = sa.getHostCard().getGame().getPhaseHandler();
|
PhaseHandler ph = sa.getHostCard().getGame().getPhaseHandler();
|
||||||
String logic = sa.getParamOrDefault("AILogic", "");
|
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);
|
return ph.is(PhaseType.END_OF_TURN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ public class LifeGainAi extends SpellAbilityAi {
|
|||||||
|
|
||||||
return lifeCritical || activateForCost
|
return lifeCritical || activateForCost
|
||||||
|| (ph.getNextTurn().equals(ai) && !ph.getPhase().isBefore(PhaseType.END_OF_TURN))
|
|| (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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SpellAbilityAi.isSorcerySpeed(sa)
|
if (SpellAbilityAi.isSorcerySpeed(sa, ai)
|
||||||
|| sa.getSubAbility() != null || SpellAbilityAi.playReusable(ai, sa)) {
|
|| sa.getSubAbility() != null || SpellAbilityAi.playReusable(ai, sa)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ public class LifeLoseAi extends SpellAbilityAi {
|
|||||||
return false;
|
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)) {
|
|| ComputerUtil.activateForCost(sa, ai)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ public class ManifestAi extends SpellAbilityAi {
|
|||||||
if (!buff) {
|
if (!buff) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (!SpellAbilityAi.isSorcerySpeed(sa)) {
|
} else if (!SpellAbilityAi.isSorcerySpeed(sa, ai)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -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
|
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 (!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))) {
|
&& ph.getNextTurn().equals(ai))) {
|
||||||
return false; // only self-mill at opponent EOT
|
return false; // only self-mill at opponent EOT
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ public class ProtectAi extends SpellAbilityAi {
|
|||||||
protected boolean checkPhaseRestrictions(final Player ai, final SpellAbility sa, final PhaseHandler ph) {
|
protected boolean checkPhaseRestrictions(final Player ai, final SpellAbility sa, final PhaseHandler ph) {
|
||||||
final boolean notAiMain1 = !(ph.getPlayerTurn() == ai && ph.getPhase() == PhaseType.MAIN1);
|
final boolean notAiMain1 = !(ph.getPlayerTurn() == ai && ph.getPhase() == PhaseType.MAIN1);
|
||||||
// sorceries can only give protection in order to create an unblockable attacker
|
// sorceries can only give protection in order to create an unblockable attacker
|
||||||
return !SpellAbilityAi.isSorcerySpeed(sa) || !notAiMain1;
|
return !SpellAbilityAi.isSorcerySpeed(sa, ai) || !notAiMain1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ public class PumpAi extends PumpAiBase {
|
|||||||
return true;
|
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")) {
|
} else if (logic.equals("Aristocrat")) {
|
||||||
final boolean isThreatened = ComputerUtil.predictThreatenedObjects(ai, null, true).contains(sa.getHostCard());
|
final boolean isThreatened = ComputerUtil.predictThreatenedObjects(ai, null, true).contains(sa.getHostCard());
|
||||||
if (!ph.is(PhaseType.COMBAT_DECLARE_BLOCKERS) && !isThreatened) {
|
if (!ph.is(PhaseType.COMBAT_DECLARE_BLOCKERS) && !isThreatened) {
|
||||||
@@ -112,7 +112,7 @@ public class PumpAi extends PumpAiBase {
|
|||||||
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS))) {
|
|| ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_BLOCKERS))) {
|
||||||
// Instant-speed pumps should not be cast outside of combat when the
|
// Instant-speed pumps should not be cast outside of combat when the
|
||||||
// stack is empty
|
// stack is empty
|
||||||
return sa.isCurse() || SpellAbilityAi.isSorcerySpeed(sa) || main1Preferred;
|
return sa.isCurse() || SpellAbilityAi.isSorcerySpeed(sa, ai) || main1Preferred;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -364,7 +364,7 @@ public class PumpAi extends PumpAiBase {
|
|||||||
if (ComputerUtilCard.shouldPumpCard(ai, sa, card, defense, attack, keywords, false)) {
|
if (ComputerUtilCard.shouldPumpCard(ai, sa, card, defense, attack, keywords, false)) {
|
||||||
return true;
|
return true;
|
||||||
} else if (containsUsefulKeyword(ai, keywords, card, sa, attack)) {
|
} 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_DECLARE_ATTACKERS, ai) ||
|
||||||
game.getPhaseHandler().is(PhaseType.COMBAT_BEGIN, ai)) {
|
game.getPhaseHandler().is(PhaseType.COMBAT_BEGIN, ai)) {
|
||||||
Card pumped = ComputerUtilCard.getPumpedCreature(ai, sa, card, 0, 0, keywords);
|
Card pumped = ComputerUtilCard.getPumpedCreature(ai, sa, card, 0, 0, keywords);
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ public class ScryAi extends SpellAbilityAi {
|
|||||||
// even if there's no mana cost.
|
// even if there's no mana cost.
|
||||||
if (sa.getPayCosts().hasTapCost()
|
if (sa.getPayCosts().hasTapCost()
|
||||||
&& (sa.getPayCosts().hasManaCost() || (sa.getHostCard() != null && sa.getHostCard().isCreature()))
|
&& (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);
|
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
|
// in the playerturn Scry should only be done in Main1 or in upkeep if able
|
||||||
if (ph.isPlayerTurn(ai)) {
|
if (ph.isPlayerTurn(ai)) {
|
||||||
if (SpellAbilityAi.isSorcerySpeed(sa)) {
|
if (SpellAbilityAi.isSorcerySpeed(sa, ai)) {
|
||||||
return ph.is(PhaseType.MAIN1) || sa.isPwAbility();
|
return ph.is(PhaseType.MAIN1) || sa.isPwAbility();
|
||||||
} else {
|
} else {
|
||||||
return ph.is(PhaseType.UPKEEP);
|
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
|
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)
|
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);
|
boolean randomReturn = MyRandom.getRandom().nextFloat() <= Math.pow(chance, sa.getActivationsThisTurn() + 1);
|
||||||
|
|||||||
@@ -52,13 +52,13 @@ public class SurveilAi extends SpellAbilityAi {
|
|||||||
// even if there's no mana cost.
|
// even if there's no mana cost.
|
||||||
if (sa.getPayCosts().hasTapCost()
|
if (sa.getPayCosts().hasTapCost()
|
||||||
&& (sa.getPayCosts().hasManaCost() || (sa.getHostCard() != null && sa.getHostCard().isCreature()))
|
&& (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);
|
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
|
// in the player's turn Surveil should only be done in Main1 or in Upkeep if able
|
||||||
if (ph.isPlayerTurn(ai)) {
|
if (ph.isPlayerTurn(ai)) {
|
||||||
if (SpellAbilityAi.isSorcerySpeed(sa)) {
|
if (SpellAbilityAi.isSorcerySpeed(sa, ai)) {
|
||||||
return ph.is(PhaseType.MAIN1) || sa.isPwAbility();
|
return ph.is(PhaseType.MAIN1) || sa.isPwAbility();
|
||||||
} else {
|
} else {
|
||||||
return ph.is(PhaseType.UPKEEP);
|
return ph.is(PhaseType.UPKEEP);
|
||||||
@@ -102,7 +102,7 @@ public class SurveilAi extends SpellAbilityAi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
double chance = .4; // 40 percent chance for instant speed
|
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)
|
chance = .667; // 66.7% chance for sorcery speed (since it will never activate EOT)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ public class TapAi extends TapAiBase {
|
|||||||
if (turn.isOpponentOf(ai) && phase.getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS)) {
|
if (turn.isOpponentOf(ai) && phase.getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS)) {
|
||||||
// Tap things down if it's Human's turn
|
// Tap things down if it's Human's turn
|
||||||
} else if (turn.equals(ai)) {
|
} 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.
|
// Cast it if it's a sorcery.
|
||||||
} else if (phase.getPhase().isBefore(PhaseType.COMBAT_DECLARE_BLOCKERS)) {
|
} else if (phase.getPhase().isBefore(PhaseType.COMBAT_DECLARE_BLOCKERS)) {
|
||||||
// Aggro Brains are willing to use TapEffects aggressively instead of defensively
|
// Aggro Brains are willing to use TapEffects aggressively instead of defensively
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ public class TokenAi extends SpellAbilityAi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((ph.isPlayerTurn(ai) || ph.getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS))
|
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) {
|
&& !haste && !pwMinus) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
// 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();
|
PhaseHandler ph = aiPlayer.getGame().getPhaseHandler();
|
||||||
if (sa.getPayCosts().hasManaCost() || sa.getPayCosts().hasTapCost()) {
|
if (sa.getPayCosts().hasManaCost() || sa.getPayCosts().hasTapCost()) {
|
||||||
if (SpellAbilityAi.isSorcerySpeed(sa)) {
|
if (SpellAbilityAi.isSorcerySpeed(sa, aiPlayer)) {
|
||||||
return ph.is(PhaseType.MAIN2, aiPlayer);
|
return ph.is(PhaseType.MAIN2, aiPlayer);
|
||||||
} else {
|
} else {
|
||||||
return ph.is(PhaseType.END_OF_TURN) && ph.getNextTurn() == aiPlayer;
|
return ph.is(PhaseType.END_OF_TURN) && ph.getNextTurn() == aiPlayer;
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ public class SpellAbilityPicker {
|
|||||||
return !sa.withFlash(sa.getHostCard(), player);
|
return !sa.withFlash(sa.getHostCard(), player);
|
||||||
}
|
}
|
||||||
if (sa.isPwAbility()) {
|
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();
|
return sa.isActivatedAbility() && sa.getRestrictions().isSorcerySpeed();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2393,8 +2393,8 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isActivatedAbility()) {
|
if (isActivatedAbility()) {
|
||||||
// Activated Abillties are instant speed per default
|
// Activated Abilities are instant speed per default, except Planeswalker abilities
|
||||||
return !getRestrictions().isSorcerySpeed();
|
return !isPwAbility() && !getRestrictions().isSorcerySpeed();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -2403,11 +2403,9 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
|||||||
if (getRestrictions().isInstantSpeed()) {
|
if (getRestrictions().isInstantSpeed()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (isSpell()) {
|
if (isSpell() && (hasSVar("IsCastFromPlayEffect") || host.isInstant() || host.hasKeyword(Keyword.FLASH))) {
|
||||||
if (hasSVar("IsCastFromPlayEffect") || host.isInstant() || host.hasKeyword(Keyword.FLASH)) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return StaticAbilityCastWithFlash.anyWithFlash(this, host, activator);
|
return StaticAbilityCastWithFlash.anyWithFlash(this, host, activator);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -479,11 +479,6 @@ public class SpellAbilityRestriction extends SpellAbilityVariables {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (sa.isPwAbility()) {
|
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 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;
|
final int limits = c.getAmountOfKeyword("May activate CARDNAME's loyalty abilities once") + initialLimit;
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
package forge.game.staticability;
|
package forge.game.staticability;
|
||||||
|
|
||||||
import com.google.common.collect.Iterables;
|
|
||||||
|
|
||||||
import forge.game.Game;
|
import forge.game.Game;
|
||||||
import forge.game.GameObjectPredicates;
|
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.card.CardCollection;
|
import forge.game.card.CardCollection;
|
||||||
import forge.game.player.Player;
|
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) {
|
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)) {
|
if (!commonParts(stAb, sa, card, activator)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -83,8 +79,7 @@ public class StaticAbilityCastWithFlash {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
String[] valids = stAb.getParam("Targeting").split(",");
|
if (!stAb.matchesValidParam("Targeting", sa.getTargets())) {
|
||||||
if (!Iterables.any(sa.getTargets(), GameObjectPredicates.restriction(valids, hostCard.getController(), hostCard, stAb))) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ Name:Teferi, Master of Time
|
|||||||
ManaCost:2 U U
|
ManaCost:2 U U
|
||||||
Types:Legendary Planeswalker Teferi
|
Types:Legendary Planeswalker Teferi
|
||||||
Loyalty:3
|
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.
|
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
|
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.)
|
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.)
|
||||||
|
|||||||
@@ -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$ 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$ 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."
|
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: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.
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/teferi_temporal_archmage.jpg
|
|
||||||
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.
|
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.
|
||||||
|
|||||||
Reference in New Issue
Block a user