Initial check-in for Phasing

Note: Auras and Equipped Equipment Phasing Directly is currently unsupported (not "reattaching" itself when phasing in) and AI for AF_Phases isn't functional yet.
Add the following Phasing related cards:
Breezekeeper, Cloak of Invisibility, Crystal Golem, Dream Fighter, Merfolk Raiders, Mist Dragon, Rainbow Efreet, Sandbar Crocodile, Teferi's Drake, Teferi's Honor Guard, Teferi's Isle, Tolarian Drake, Vanishing, Vaporous Djinn, Vodalian Illusionist
This commit is contained in:
Sol
2011-09-30 12:11:19 +00:00
parent f5b3d6abc2
commit 535a905f9a
34 changed files with 710 additions and 20 deletions

15
.gitattributes vendored
View File

@@ -981,6 +981,7 @@ res/cardsfolder/b/breath_of_malfegor.txt svneol=native#text/plain
res/cardsfolder/b/breathstealer.txt svneol=native#text/plain
res/cardsfolder/b/breeding_pit.txt svneol=native#text/plain
res/cardsfolder/b/breeding_pool.txt svneol=native#text/plain
res/cardsfolder/b/breezekeeper.txt -text
res/cardsfolder/b/briar_patch.txt svneol=native#text/plain
res/cardsfolder/b/briar_shield.txt svneol=native#text/plain
res/cardsfolder/b/briarberry_cohort.txt svneol=native#text/plain
@@ -1365,6 +1366,7 @@ res/cardsfolder/c/clifftop_retreat.txt -text
res/cardsfolder/c/clinging_darkness.txt svneol=native#text/plain
res/cardsfolder/c/cloak_of_confusion.txt svneol=native#text/plain
res/cardsfolder/c/cloak_of_feathers.txt svneol=native#text/plain
res/cardsfolder/c/cloak_of_invisibility.txt -text
res/cardsfolder/c/cloak_of_mists.txt svneol=native#text/plain
res/cardsfolder/c/clock_of_omens.txt svneol=native#text/plain
res/cardsfolder/c/clockwork_avian.txt -text
@@ -1632,6 +1634,7 @@ res/cardsfolder/c/cryptic_command.txt svneol=native#text/plain
res/cardsfolder/c/cryptwailing.txt svneol=native#text/plain
res/cardsfolder/c/crystal_ball.txt svneol=native#text/plain
res/cardsfolder/c/crystal_chimes.txt svneol=native#text/plain
res/cardsfolder/c/crystal_golem.txt -text
res/cardsfolder/c/crystal_quarry.txt svneol=native#text/plain
res/cardsfolder/c/crystal_rod.txt svneol=native#text/plain
res/cardsfolder/c/crystal_seer.txt svneol=native#text/plain
@@ -2092,6 +2095,7 @@ res/cardsfolder/d/dread_warlock.txt svneol=native#text/plain
res/cardsfolder/d/dreadship_reef.txt svneol=native#text/plain
res/cardsfolder/d/dreadwing.txt svneol=native#text/plain
res/cardsfolder/d/dream_cache.txt svneol=native#text/plain
res/cardsfolder/d/dream_fighter.txt -text
res/cardsfolder/d/dream_fracture.txt svneol=native#text/plain
res/cardsfolder/d/dream_prowler.txt svneol=native#text/plain
res/cardsfolder/d/dream_stalker.txt svneol=native#text/plain
@@ -4834,6 +4838,7 @@ res/cardsfolder/m/merfolk_looter.txt svneol=native#text/plain
res/cardsfolder/m/merfolk_mesmerist.txt svneol=native#text/plain
res/cardsfolder/m/merfolk_observer.txt svneol=native#text/plain
res/cardsfolder/m/merfolk_of_the_pearl_trident.txt svneol=native#text/plain
res/cardsfolder/m/merfolk_raiders.txt -text
res/cardsfolder/m/merfolk_seastalkers.txt svneol=native#text/plain
res/cardsfolder/m/merfolk_seer.txt svneol=native#text/plain
res/cardsfolder/m/merfolk_skyscout.txt svneol=native#text/plain
@@ -4969,6 +4974,7 @@ res/cardsfolder/m/mishras_groundbreaker.txt svneol=native#text/plain
res/cardsfolder/m/mishras_helix.txt svneol=native#text/plain
res/cardsfolder/m/misinformation.txt svneol=native#text/plain
res/cardsfolder/m/misshapen_fiend.txt svneol=native#text/plain
res/cardsfolder/m/mist_dragon.txt -text
res/cardsfolder/m/mist_leopard.txt svneol=native#text/plain
res/cardsfolder/m/mistbind_clique.txt svneol=native#text/plain
res/cardsfolder/m/mistblade_shinobi.txt svneol=native#text/plain
@@ -6098,6 +6104,7 @@ res/cardsfolder/r/rain_of_rust.txt svneol=native#text/plain
res/cardsfolder/r/rain_of_salt.txt svneol=native#text/plain
res/cardsfolder/r/rain_of_tears.txt svneol=native#text/plain
res/cardsfolder/r/rainbow_crow.txt -text
res/cardsfolder/r/rainbow_efreet.txt -text
res/cardsfolder/r/rainbow_vale.txt svneol=native#text/plain
res/cardsfolder/r/raise_dead.txt svneol=native#text/plain
res/cardsfolder/r/raise_the_alarm.txt svneol=native#text/plain
@@ -6589,6 +6596,7 @@ res/cardsfolder/s/sanctum_gargoyle.txt svneol=native#text/plain
res/cardsfolder/s/sanctum_plowbeast.txt svneol=native#text/plain
res/cardsfolder/s/sand_silos.txt svneol=native#text/plain
res/cardsfolder/s/sand_squid.txt svneol=native#text/plain
res/cardsfolder/s/sandbar_crocodile.txt -text
res/cardsfolder/s/sandbar_merfolk.txt svneol=native#text/plain
res/cardsfolder/s/sandbar_serpent.txt svneol=native#text/plain
res/cardsfolder/s/sandskin.txt svneol=native#text/plain
@@ -7920,6 +7928,9 @@ res/cardsfolder/t/tectonic_rift.txt -text
res/cardsfolder/t/teekas_dragon.txt svneol=native#text/plain
res/cardsfolder/t/teetering_peaks.txt svneol=native#text/plain
res/cardsfolder/t/teferis_care.txt -text
res/cardsfolder/t/teferis_drake.txt -text
res/cardsfolder/t/teferis_honor_guard.txt -text
res/cardsfolder/t/teferis_isle.txt -text
res/cardsfolder/t/teferis_puzzle_box.txt svneol=native#text/plain
res/cardsfolder/t/teferis_response.txt svneol=native#text/plain
res/cardsfolder/t/tek.txt svneol=native#text/plain
@@ -8167,6 +8178,7 @@ res/cardsfolder/t/toil_to_renown.txt svneol=native#text/plain
res/cardsfolder/t/toils_of_night_and_day.txt svneol=native#text/plain
res/cardsfolder/t/tolaria_west.txt svneol=native#text/plain
res/cardsfolder/t/tolarian_academy.txt svneol=native#text/plain
res/cardsfolder/t/tolarian_drake.txt -text
res/cardsfolder/t/tolarian_emissary.txt svneol=native#text/plain
res/cardsfolder/t/tolarian_entrancer.txt svneol=native#text/plain
res/cardsfolder/t/tolarian_sentinel.txt svneol=native#text/plain
@@ -8496,8 +8508,10 @@ res/cardsfolder/v/vampiric_spirit.txt svneol=native#text/plain
res/cardsfolder/v/vampiric_touch.txt svneol=native#text/plain
res/cardsfolder/v/vampiric_tutor.txt svneol=native#text/plain
res/cardsfolder/v/vampirism.txt svneol=native#text/plain
res/cardsfolder/v/vanishing.txt -text
res/cardsfolder/v/vanquish.txt svneol=native#text/plain
res/cardsfolder/v/vapor_snag.txt svneol=native#text/plain
res/cardsfolder/v/vaporous_djinn.txt -text
res/cardsfolder/v/varchilds_crusader.txt svneol=native#text/plain
res/cardsfolder/v/vastwood_animist.txt svneol=native#text/plain
res/cardsfolder/v/vastwood_gorger.txt svneol=native#text/plain
@@ -8671,6 +8685,7 @@ res/cardsfolder/v/vivify.txt svneol=native#text/plain
res/cardsfolder/v/vivisection.txt svneol=native#text/plain
res/cardsfolder/v/vizzerdrix.txt svneol=native#text/plain
res/cardsfolder/v/vodalian_hypnotist.txt svneol=native#text/plain
res/cardsfolder/v/vodalian_illusionist.txt -text
res/cardsfolder/v/vodalian_knights.txt svneol=native#text/plain
res/cardsfolder/v/vodalian_mage.txt svneol=native#text/plain
res/cardsfolder/v/vodalian_merchant.txt svneol=native#text/plain

View File

@@ -0,0 +1,12 @@
Name:Breezekeeper
ManaCost:3 U
Types:Creature Djinn
Text:no text
PT:4/4
K:Flying
K:Phasing
SVar:Rarity:Common
SVar:Picture:http://www.wizards.com/global/images/magic/general/breezekeeper.jpg
Oracle:Flying\nPhasing (This phases in or out before you untap during each of your untap steps. While it's phased out, it's treated as though it doesn't exist.)
SetInfo:VIS|Common|http://magiccards.info/scans/en/vi/27.jpg
End

View File

@@ -0,0 +1,12 @@
Name:Cloak of Invisibility
ManaCost:U
Types:Enchantment Aura
Text:no text
K:Enchant creature
A:SP$ Attach | Cost$ U | ValidTgts$ Creature | AILogic$ Pump
S:Mode$ Continuous | Affected$ Permanent.EnchantedBy | AddKeyword$ Phasing & HIDDEN CARDNAME can't be blocked except by Walls. | Description$ Enchanted creature has phasing and can't be blocked except by Walls.
SVar:Rarity:Common
SVar:Picture:http://www.wizards.com/global/images/magic/general/cloak_of_invisibility.jpg
SetInfo:MIR|Common|http://magiccards.info/scans/en/mr/58.jpg
Oracle:Enchant creature\nEnchanted creature has phasing and can't be blocked except by Walls. (It phases in or out before its controller untaps during each of his or her untap steps. While it's phased out, it's treated as though it doesn't exist.)
End

View File

@@ -0,0 +1,12 @@
Name:Crystal Golem
ManaCost:4
Types:Artifact Creature Golem
Text:no text
PT:3/3
T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | Execute$ TrigPhase | TriggerZones$ Battlefield | TriggerDescription$ At the beginning of your end step, CARDNAME phases out.
SVar:TrigPhase:DB$ Phases | Defined$ Self
SVar:Rarity:Uncommon
SVar:Picture:http://www.wizards.com/global/images/magic/general/crystal_golem.jpg
SetInfo:MIR|Uncommon|http://magiccards.info/scans/en/mr/263.jpg
Oracle:At the beginning of your end step, Crystal Golem phases out. (While it's phased out, it's treated as though it doesn't exist. It phases in before you untap during your next untap step.)
End

View File

@@ -0,0 +1,15 @@
Name:Dream Fighter
ManaCost:2 U
Types:Creature Human Soldier
Text:no text
PT:1/1
T:Mode$ Blocks | ValidCard$ Card.Self | ValidAttacker$ Creature | Execute$ TrigPhaseAttacker | TriggerDescription$ Whenever CARDNAME blocks or becomes blocked by a creature, Dream Fighter and that creature phase out.
T:Mode$ Blocks | ValidCard$ Creature | ValidAttacker$ Card.Self | Execute$ TrigPhaseBlocker | Secondary$ True | TriggerDescription$ Whenever CARDNAME blocks or becomes blocked by a creature, Dream Fighter and that creature phase out.
SVar:TrigPhaseAttacker:DB$ Phase | Defined$ TriggeredAttacker | SubAbility$ SVar=DBPhaseSelf
SVar:TrigPhaseBlocker:DB$ Phase | Defined$ TriggeredBlocker | SubAbility$ SVar=DBPhaseSelf
SVar:DBPhaseSelf:DB$ Phase | Defined$ Self
SVar:Rarity:Common
SVar:Picture:http://www.wizards.com/global/images/magic/general/dream_fighter.jpg
SetInfo:MIR|Common|http://magiccards.info/scans/en/mr/63.jpg
Oracle:Whenever Dream Fighter blocks or becomes blocked by a creature, Dream Fighter and that creature phase out. (While they're phased out, they're treated as though they don't exist. Each one phases in before its controller untaps during his or her next untap step.)
End

View File

@@ -0,0 +1,12 @@
Name:Merfolk Raiders
ManaCost:1 U
Types:Creature Merfolk Soldier
Text:no text
PT:2/3
K:Islandwalk
K:Phasing
SVar:Rarity:Common
SVar:Picture:http://www.wizards.com/global/images/magic/general/merfolk_raiders.jpg
Oracle:Islandwalk\nPhasing (This phases in or out before you untap during each of your untap steps. While it's phased out, it's treated as though it doesn't exist.)
SetInfo:MIR|Common|http://magiccards.info/scans/en/mr/75.jpg
End

View File

@@ -0,0 +1,14 @@
Name:Mist Dragon
ManaCost:4 U U
Types:Creature Dragon
Text:no text
PT:4/4
A:AB$ Pump | Cost$ 0 | Defined$ Self | KW$ Flying | Permanent$ True | SpellDescription$ CARDNAME gains flying. (This effect lasts indefinitely.)
A:AB$ Debuff | Cost$ 0 | Defined$ Self | Keywords$ Flying | Permanent$ True | SpellDescription$ CARDNAME loses flying. (This effect lasts indefinitely.)
A:AB$ Phases | Cost$ 3 U U | Defined$ Self | SpellDescription$ CARDNAME phases out.
SVar:RemAIDeck:True
SVar:Rarity:Rare
SVar:Picture:http://www.wizards.com/global/images/magic/general/mist_dragon.jpg
SetInfo:MIR|Rare|http://magiccards.info/scans/en/mr/79.jpg
Oracle:{0}: Mist Dragon gains flying. (This effect lasts indefinitely.)\n{0}: Mist Dragon loses flying. (This effect lasts indefinitely.)\n{3}{U}{U}: Mist Dragon phases out. (While it's phased out, it's treated as though it doesn't exist. It phases in before you untap during your next untap step.)
End

View File

@@ -0,0 +1,13 @@
Name:Rainbow Efreet
ManaCost:3 U
Types:Creature Efreet
Text:no text
PT:3/1
K:Flying
A:AB$ Phases | Cost$ U U | Defined$ Self | SpellDescription$ CARDNAME phases out.
SVar:RemAIDeck:True
SVar:Rarity:Rare
SVar:Picture:http://www.wizards.com/global/images/magic/general/rainbow_efreet.jpg
SetInfo:VIS|Rare|http://magiccards.info/scans/en/vi/41.jpg
Oracle:Flying\n{U}{U}: Rainbow Efreet phases out. (While it's phased out, it's treated as though it doesn't exist. It phases in before you untap during your next untap step.)
End

View File

@@ -0,0 +1,11 @@
Name:Sandbar Crocodile
ManaCost:4 U
Types:Creature Crocodile
Text:no text
PT:6/5
K:Phasing
SVar:Rarity:Common
SVar:Picture:http://www.wizards.com/global/images/magic/general/sandbar_crocodile.jpg
Oracle:Phasing (This phases in or out before you untap during each of your untap steps. While it's phased out, it's treated as though it doesn't exist.)
SetInfo:MIR|Common|http://magiccards.info/scans/en/mr/88.jpg
End

View File

@@ -0,0 +1,12 @@
Name:Teferi's Drake
ManaCost:2 U
Types:Creature Drake
Text:no text
PT:3/2
K:Flying
K:Phasing
SVar:Rarity:Common
SVar:Picture:http://www.wizards.com/global/images/magic/general/teferis_drake.jpg
Oracle:Flying\nPhasing (This phases in or out before you untap during each of your untap steps. While it's phased out, it's treated as though it doesn't exist.)
SetInfo:MIR|Common|http://magiccards.info/scans/en/mr/97.jpg
End

View File

@@ -0,0 +1,13 @@
Name:Teferi's Honor Guard
ManaCost:2 W
Types:Creature Human Knight
Text:no text
PT:2/2
K:Flanking
A:AB$ Phases | Cost$ U U | Defined$ Self | SpellDescription$ CARDNAME phases out.
SVar:RemAIDeck:True
SVar:Rarity:Rare
SVar:Picture:http://www.wizards.com/global/images/magic/general/teferis_honor_guard.jpg
SetInfo:VIS|Uncommon|http://magiccards.info/scans/en/vi/122.jpg
Oracle:Flanking (Whenever a creature without flanking blocks this creature, the blocking creature gets -1/-1 until end of turn.)\n{U}{U}: Teferi's Honor Guard phases out. (While it's phased out, it's treated as though it doesn't exist. It phases in before you untap during your next untap step.)
End

View File

@@ -0,0 +1,12 @@
Name:Teferi's Isle
ManaCost:no cost
Types:Legendary Land
Text:no text
K:Phasing
K:CARDNAME enters the battlefield tapped.
A:AB$ Mana | Cost$ T | Produced$ U | Amount$ 2 | SpellDescription$ Add U U to your mana pool.
SVar:Rarity:Rare
SVar:Picture:http://www.wizards.com/global/images/magic/general/teferis_isle.jpg
Oracle:Phasing (This phases in or out before you untap during each of your untap steps. While it's phased out, it's treated as though it doesn't exist.)\nTeferi's Isle enters the battlefield tapped.\n{T}: Add {U}{U} to your mana pool.
SetInfo:MIR|Rare|http://magiccards.info/scans/en/mr/315.jpg
End

View File

@@ -0,0 +1,12 @@
Name:Tolarian Drake
ManaCost:2 U
Types:Creature Drake
Text:no text
PT:2/4
K:Flying
K:Phasing
SVar:Rarity:Common
SVar:Picture:http://www.wizards.com/global/images/magic/general/tolarian_drake.jpg
Oracle:Flying\nPhasing (This phases in or out before you untap during each of your untap steps. While it's phased out, it's treated as though it doesn't exist.)
SetInfo:WTH|Common|http://magiccards.info/scans/en/wl/55.jpg
End

View File

@@ -0,0 +1,13 @@
Name:Vanishing
ManaCost:U
Types:Enchantment Aura
Text:no text
K:Enchant creature
A:SP$ Attach | Cost$ U | ValidTgts$ Creature | AILogic$ Curse
A:AB$ Phases | Cost$ U U | Defined$ Enchanted | SpellDescription$ Enchanted creature phases out.
SVar:RemAIDeck:True
SVar:Rarity:Rare
SVar:Picture:http://www.wizards.com/global/images/magic/general/vanishing.jpg
SetInfo:VIS|Common|http://magiccards.info/scans/en/vi/48.jpg
Oracle:Enchant creature\n{U}{U}: Enchanted creature phases out. (While it's phased out, it's treated as though it doesn't exist. It phases in before its controller untaps during his or her next untap step.)
End

View File

@@ -0,0 +1,14 @@
Name:Vaporous Djinn
ManaCost:2 U U
Types:Creature Djinn
Text:no text
PT:3/4
K:Flying
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | Execute$ TrigPhase | TriggerZones$ Battlefield | TriggerDescription$ At the beginning of your upkeep, CARDNAME phases out unless you pay {U}{U}.
SVar:TrigPhase:DB$ Phases | Defined$ Self | UnlessCost$ U U | UnlessPayer$ You
SVar:RemAIDeck:True
SVar:Rarity:Uncommon
SVar:Picture:http://www.wizards.com/global/images/magic/general/vaporous_djinn.jpg
SetInfo:MIR|Uncommon|http://magiccards.info/scans/en/mr/101.jpg
Oracle:Flying\nAt the beginning of your upkeep, Vaporous Djinn phases out unless you pay {U}{U}. (While it's phased out, it's treated as though it doesn't exist. It phases in before you untap during your next untap step.)
End

View File

@@ -0,0 +1,13 @@
Name:Vodalian Illusionist
ManaCost:2 U
Types:Creature Merfolk Wizard
Text:no text
PT:2/2
K:Flanking
A:AB$ Phases | Cost$ U U | ValidTgts$ Creature | SpellDescription$ Target creature phases out.
SVar:RemAIDeck:True
SVar:Rarity:Rare
SVar:Picture:http://www.wizards.com/global/images/magic/general/vodalian_illusionist.jpg
SetInfo:WTH|Uncommon|http://magiccards.info/scans/en/wl/58.jpg
Oracle:{U}{U}, {T}: Target creature phases out. (While it's phased out, it's treated as though it doesn't exist. It phases in before its controller untaps during his or her next untap step.)
End

View File

@@ -249,9 +249,10 @@ public abstract class AllZoneUtil {
all.addAll(player.getZone(Zone.Graveyard).getCards());
all.addAll(player.getZone(Zone.Hand).getCards());
all.addAll(player.getZone(Zone.Library).getCards()); // not sure if library should be included.
all.addAll(player.getZone(Zone.Battlefield).getCards());
all.addAll(player.getZone(Zone.Battlefield).getCards(false));
all.addAll(player.getZone(Zone.Exile).getCards()); // Spawnsire of Ulamog plays spells from here?
}
all.addAll(AllZone.getStackZone().getCards());
return all;
}

View File

@@ -114,6 +114,9 @@ public class Card extends GameEntity implements Comparable<Card> {
private boolean suspendCast = false;
private boolean suspend = false;
private boolean phasedOut = false;
private boolean directlyPhasedOut = true;
//for Vanguard / Manapool / Emblems etc.
private boolean isImmutable = false;
@@ -4692,6 +4695,71 @@ public class Card extends GameEntity implements Comparable<Card> {
return kicked;
}
public boolean isPhasedOut() {
return phasedOut;
}
public void setPhasedOut(boolean phasedOut) {
this.phasedOut = phasedOut;
}
public void phase(){
this.phase(true);
}
public void phase(boolean direct){
boolean phasingIn = this.isPhasedOut();
if (!this.switchPhaseState()){
// Switch Phase State returns False if the Permanent can't Phase Out
return;
}
if (!phasingIn){
this.setDirectlyPhasedOut(direct);
}
for (Card eq : this.getEquippedBy()){
if (eq.isPhasedOut() == phasingIn){
eq.phase(false);
}
}
for (Card aura : this.getEnchantedBy()){
if (aura.isPhasedOut() == phasingIn){
aura.phase(false);
}
}
}
private boolean switchPhaseState(){
if (!this.phasedOut && this.hasKeyword("CARDNAME can't phase out.")){
return false;
}
this.phasedOut = !this.phasedOut;
if (this.phasedOut && isToken()){
// 702.23k Phased-out tokens cease to exist as a state-based action. See rule 704.5d.
// 702.23d The phasing event doesn't actually cause a permanent to change zones or control,
// even though it's treated as though it's not on the battlefield and not under its controller's control while it's phased out.
// Zone-change triggers don't trigger when a permanent phases in or out.
// Suppressed Exiling is as close as we can get to "ceasing to exist"
AllZone.getTriggerHandler().suppressMode("ChangesZone");
AllZone.getGameAction().exile(this);
AllZone.getTriggerHandler().clearSuppression("ChangesZone");
}
return true;
}
public boolean isDirectlyPhasedOut(){
return this.directlyPhasedOut;
}
public void setDirectlyPhasedOut(boolean direct){
this.directlyPhasedOut = direct;
}
/**
* <p>isReflectedLand.</p>
*

View File

@@ -65,7 +65,7 @@ public class CombatUtil {
if (blocker.isTapped() && !AllZoneUtil.isCardInPlay("Masako the Humorless", blocker.getController()))
return false;
if (blocker.hasKeyword("CARDNAME can't block.") || blocker.hasKeyword("CARDNAME can't attack or block."))
if (blocker.hasKeyword("CARDNAME can't block.") || blocker.hasKeyword("CARDNAME can't attack or block.") || blocker.isPhasedOut())
return false;
CardList kulrath = AllZoneUtil.getCardsIn(Zone.Battlefield, "Kulrath Knight");
@@ -463,7 +463,7 @@ public class CombatUtil {
* @return a boolean.
*/
public static boolean canAttack(Card c) {
if (c.isTapped() || (c.hasSickness() && !c.isEnchantedBy("Instill Energy"))) return false;
if (c.isTapped() || c.isPhasedOut() || (c.hasSickness() && !c.isEnchantedBy("Instill Energy"))) return false;
return canAttackNextTurn(c);
}

View File

@@ -1061,7 +1061,7 @@ public class ComputerUtil {
* @return a {@link forge.CardList} object.
*/
static public CardList chooseExileFrom(Constant.Zone zone, String type, Card activate, Card target, int amount) {
CardList typeList = new CardList(AllZone.getComputerPlayer().getZone(zone).getCards());
CardList typeList = AllZone.getComputerPlayer().getCardsIn(zone);
typeList = typeList.getValidCards(type.split(","), activate.getController(), activate);
if (target != null && target.getController().isComputer() && typeList.contains(target))
typeList.remove(target); // don't exile the card we're pumping

View File

@@ -17,7 +17,7 @@ public class DefaultPlayerZone extends PlayerZone implements java.io.Serializabl
/** Constant <code>serialVersionUID=-5687652485777639176L</code>. */
private static final long serialVersionUID = -5687652485777639176L;
private List<Card> cards = new ArrayList<Card>();
protected List<Card> cards = new ArrayList<Card>();
private final Constant.Zone zoneName;
private final Player player;
private boolean update = true;
@@ -260,7 +260,13 @@ public class DefaultPlayerZone extends PlayerZone implements java.io.Serializabl
*
* @return an array of {@link forge.Card} objects.
*/
public final Card[] getCards() {
public Card[] getCards() {
return getCards(true);
}
@Override
public Card[] getCards(boolean filter) {
// Non-Battlefield PlayerZones don't care about the filter
Card[] c = new Card[cards.size()];
cards.toArray(c);
return c;

View File

@@ -836,7 +836,7 @@ public class GuiDisplay4 extends JFrame implements CardContainer, Display, NewCo
public void update(final Observable a, final Object b) {
PlayerZone pZone = (PlayerZone) a;
Card[] c = pZone.getCards();
Card[] c = pZone.getCards(false);
GuiDisplayUtil.setupPlayZone(playerPlayPanel, c);
}
@@ -850,7 +850,7 @@ public class GuiDisplay4 extends JFrame implements CardContainer, Display, NewCo
public void update(final Observable a, final Object b) {
PlayerZone pZone = (PlayerZone) a;
Card[] c = pZone.getCards();
Card[] c = pZone.getCards(false);
GuiDisplayUtil.setupPlayZone(oppPlayPanel, c);
}

View File

@@ -79,6 +79,7 @@ interface IPlayerZone {
*
* @return an array of {@link forge.Card} objects.
*/
Card[] getCards(boolean filter);
Card[] getCards();
Card[] getCards(int n);

View File

@@ -48,7 +48,7 @@ public class PhaseUtil {
// For tokens a player starts the game with they don't recover from Sum. Sickness on first turn
if (turn.getTurn() > 0) {
CardList list = turn.getCardsIn(Zone.Battlefield);
CardList list = turn.getCardsIncludePhasingIn(Zone.Battlefield);
for (Card c : list)
c.setSickness(false);
}
@@ -56,8 +56,7 @@ public class PhaseUtil {
AllZone.getGameAction().resetActivationsPerTurn();
CardList lands = AllZoneUtil.getPlayerLandsInPlay(turn);
lands = lands.filter(CardListFilter.untapped);
CardList lands = AllZoneUtil.getPlayerLandsInPlay(turn).filter(CardListFilter.untapped);
turn.setNumPowerSurgeLands(lands.size());
// anything before this point happens regardless of whether the Untap phase is skipped
@@ -68,6 +67,7 @@ public class PhaseUtil {
}
// Phasing would happen here
doPhasing(turn);
doUntap();
@@ -77,6 +77,43 @@ public class PhaseUtil {
AllZone.getPhase().setNeedToNextPhase(true);
}
private static void doPhasing(Player turn){
// Needs to include phased out cards
CardList list = turn.getCardsIncludePhasingIn(Constant.Zone.Battlefield).filter(new CardListFilter() {
@Override
public boolean addCard(Card c) {
return ((c.isPhasedOut() && c.isDirectlyPhasedOut()) || c.hasKeyword("Phasing"));
}
});
// If c has things attached to it, they phase out simultaneously, and will phase back in with it
// If c is attached to something, it will phase out on its own, and try to attach back to that thing when it comes back
for(Card c : list){
if (c.isPhasedOut()){
c.phase();
}
else if (c.hasKeyword("Phasing")){
// 702.23g If an object would simultaneously phase out directly and indirectly, it just phases out indirectly.
if (c.isAura()){
GameEntity ent = c.getEnchanting();
if (ent instanceof Card && list.contains((Card)ent)){
continue;
}
}
else if (c.isEquipment() && c.isEquipping()){
if (list.contains(c.getEquippingCard())){
continue;
}
}
// TODO: Fortification
c.phase();
}
}
}
/**
* <p>doUntap.</p>
*/

View File

@@ -871,6 +871,11 @@ public abstract class Player extends GameEntity {
return new CardList(cards);
}
public CardList getCardsIncludePhasingIn(final Constant.Zone zone) {
Card[] cards = zone == Zone.Stack ? AllZone.getStackZone().getCards() : getZone(zone).getCards(false);
return new CardList(cards);
}
/**
* gets a list of first N cards in the requested zone. This function makes a CardList from Card[].
*

View File

@@ -1,5 +1,8 @@
package forge;
import java.util.ArrayList;
import java.util.Iterator;
import forge.Constant.Zone;
import forge.card.cardFactory.CardFactoryUtil;
import forge.card.spellability.Ability;
@@ -311,4 +314,28 @@ public class PlayerZone_ComesIntoPlay extends DefaultPlayerZone {
trigger = b;
leavesTrigger = b;
}
@Override
public Card[] getCards(boolean filter) {
// Battlefield filters out Phased Out cards by default. Needs to call getCards(false) to get Phased Out cards
Card[] c;
if (!filter){
c = new Card[cards.size()];
cards.toArray(c);
}
else{
Iterator<Card> itr = cards.iterator();
ArrayList<Card> list = new ArrayList<Card>();
while(itr.hasNext()){
Card crd = itr.next();
if (!crd.isPhasedOut()){
list.add(crd);
}
}
c = new Card[list.size()];
list.toArray(c);
}
return c;
}
}

View File

@@ -552,6 +552,16 @@ public class AbilityFactory {
}
}
else if (API.equals("Phases")) {
if (isAb) {
SA = AbilityFactory_PermanentState.createAbilityPhases(this);
} else if (isSp) {
SA = AbilityFactory_PermanentState.createSpellPhases(this);
} else if (isDb) {
SA = AbilityFactory_PermanentState.createDrawbackPhases(this);
}
}
else if (API.equals("PreventDamage")) {
if (isAb) {
SA = AbilityFactory_PreventDamage.getAbilityPreventDamage(this);

View File

@@ -1676,6 +1676,330 @@ public class AbilityFactory_PermanentState {
}
}
//Phasing? Something else? Who knows!
// ******************************************
// ************** Phases ********************
// ******************************************
// Phases generally Phase Out. Time and Tide is the only card that can force
// Phased Out cards in.
/**
* <p>
* createAbilityPhases.
* </p>
*
* @param af a {@link forge.card.abilityFactory.AbilityFactory} object.
* @return a {@link forge.card.spellability.SpellAbility} object.
*/
public static SpellAbility createAbilityPhases(final AbilityFactory af) {
final SpellAbility abPhases = new Ability_Activated(af.getHostCard(), af.getAbCost(), af.getAbTgt()) {
private static final long serialVersionUID = 5445572699000471299L;
@Override
public String getStackDescription() {
return phasesStackDescription(af, this);
}
@Override
public boolean canPlayAI() {
return phasesCanPlayAI(af, this);
}
@Override
public void resolve() {
phasesResolve(af, this);
}
@Override
public boolean doTrigger(boolean mandatory) {
return phasesTrigger(af, this, mandatory);
}
};
return abPhases;
}
/**
* <p>
* createSpellPhases.
* </p>
*
* @param af a {@link forge.card.abilityFactory.AbilityFactory} object.
* @return a {@link forge.card.spellability.SpellAbility} object.
*/
public static SpellAbility createSpellPhases(final AbilityFactory af) {
final SpellAbility spPhases = new Spell(af.getHostCard(), af.getAbCost(), af.getAbTgt()) {
private static final long serialVersionUID = -4990932993654533449L;
@Override
public String getStackDescription() {
return phasesStackDescription(af, this);
}
@Override
public boolean canPlayAI() {
return phasesCanPlayAI(af, this);
}
@Override
public void resolve() {
phasesResolve(af, this);
}
};
return spPhases;
}
/**
* <p>
* createDrawbackPhases.
* </p>
*
* @param af a {@link forge.card.abilityFactory.AbilityFactory} object.
* @return a {@link forge.card.spellability.SpellAbility} object.
*/
public static SpellAbility createDrawbackPhases(final AbilityFactory af) {
final SpellAbility dbPhases = new Ability_Sub(af.getHostCard(), af.getAbTgt()) {
private static final long serialVersionUID = -4990932993654533449L;
@Override
public String getStackDescription() {
return phasesStackDescription(af, this);
}
@Override
public void resolve() {
phasesResolve(af, this);
}
@Override
public boolean chkAI_Drawback() {
return phasesPlayDrawbackAI(af, this);
}
@Override
public boolean doTrigger(boolean mandatory) {
return phasesTrigger(af, this, mandatory);
}
};
return dbPhases;
}
/**
* <p>
* phasesStackDescription.
* </p>
*
* @param af a {@link forge.card.abilityFactory.AbilityFactory} object.
* @param sa a {@link forge.card.spellability.SpellAbility} object.
* @return a {@link java.lang.String} object.
*/
private static String phasesStackDescription(AbilityFactory af, SpellAbility sa) {
// when getStackDesc is called, just build exactly what is happening
StringBuilder sb = new StringBuilder();
final HashMap<String, String> params = af.getMapParams();
Card source = sa.getSourceCard();
if (sa instanceof Ability_Sub)
sb.append(" ");
else
sb.append(sa.getSourceCard()).append(" - ");
ArrayList<Card> tgtCards;
Target tgt = af.getAbTgt();
if (tgt != null)
tgtCards = tgt.getTargetCards();
else {
tgtCards = AbilityFactory.getDefinedCards(source, params.get("Defined"), sa);
}
Iterator<Card> it = tgtCards.iterator();
while (it.hasNext()) {
sb.append(it.next());
if (it.hasNext())
sb.append(", ");
}
sb.append(" Phases Out.");
Ability_Sub subAb = sa.getSubAbility();
if (subAb != null)
sb.append(subAb.getStackDescription());
return sb.toString();
}
/**
* <p>
* phasesCanPlayAI.
* </p>
*
* @param af a {@link forge.card.abilityFactory.AbilityFactory} object.
* @param sa a {@link forge.card.spellability.SpellAbility} object.
* @return a boolean.
*/
private static boolean phasesCanPlayAI(final AbilityFactory af, SpellAbility sa) {
// This still needs to be fleshed out
Target tgt = sa.getTarget();
Card source = sa.getSourceCard();
final HashMap<String, String> params = af.getMapParams();
Random r = MyRandom.random;
boolean randomReturn = r.nextFloat() <= Math.pow(.6667, sa.getActivationsThisTurn() + 1);
ArrayList<Card> tgtCards;
if (tgt == null) {
tgtCards = AbilityFactory.getDefinedCards(source, params.get("Defined"), sa);
if (tgtCards.contains(source)) {
// Protect it from something
} else {
//Card def = tgtCards.get(0);
// Phase this out if it might attack me, or before it can be
// declared as a blocker
}
return false;
} else {
if (!phasesPrefTargeting(tgt, af, sa, false))
return false;
}
Ability_Sub subAb = sa.getSubAbility();
if (subAb != null)
randomReturn &= subAb.chkAI_Drawback();
return randomReturn;
}
/**
* <p>
* phasesTrigger.
* </p>
*
* @param af a {@link forge.card.abilityFactory.AbilityFactory} object.
* @param sa a {@link forge.card.spellability.SpellAbility} object.
* @param mandatory a boolean.
* @return a boolean.
*/
private static boolean phasesTrigger(AbilityFactory af, SpellAbility sa, boolean mandatory) {
Target tgt = sa.getTarget();
if (tgt == null) {
if (mandatory)
return true;
return false;
} else {
if (phasesPrefTargeting(tgt, af, sa, mandatory)) {
return true;
} else if (mandatory) {
// not enough preferred targets, but mandatory so keep going:
return phasesUnpreferredTargeting(af, sa, mandatory);
}
}
return false;
}
/**
* <p>
* phasesPlayDrawbackAI.
* </p>
*
* @param af a {@link forge.card.abilityFactory.AbilityFactory} object.
* @param sa a {@link forge.card.spellability.SpellAbility} object.
* @return a boolean.
*/
private static boolean phasesPlayDrawbackAI(final AbilityFactory af, SpellAbility sa) {
// AI cannot use this properly until he can use SAs during Humans turn
Target tgt = af.getAbTgt();
boolean randomReturn = true;
if (tgt == null) {
} else {
if (!phasesPrefTargeting(tgt, af, sa, false))
return false;
}
Ability_Sub subAb = sa.getSubAbility();
if (subAb != null)
randomReturn &= subAb.chkAI_Drawback();
return randomReturn;
}
/**
* <p>
* phasesPrefTargeting.
* </p>
*
* @param tgt a {@link forge.card.spellability.Target} object.
* @param af a {@link forge.card.abilityFactory.AbilityFactory} object.
* @param sa a {@link forge.card.spellability.SpellAbility} object.
* @param mandatory a boolean.
* @return a boolean.
*/
private static boolean phasesPrefTargeting(Target tgt, AbilityFactory af, SpellAbility sa, boolean mandatory) {
//Card source = sa.getSourceCard();
//CardList phaseList = AllZoneUtil.getCardsIn(Zone.Battlefield).getTargetableCards(source)
// .getValidCards(tgt.getValidTgts(), source.getController(), source);
//CardList aiPhaseList = phaseList.getController(AllZone.getComputerPlayer());
// If Something in the Phase List might die from a bad combat, or a
// spell on the stack save it
//CardList humanPhaseList = phaseList.getController(AllZone.getHumanPlayer());
// If something in the Human List is causing issues, phase it out
return false;
}
/**
* <p>
* phasesUnpreferredTargeting.
* </p>
*
* @param af a {@link forge.card.abilityFactory.AbilityFactory} object.
* @param sa a {@link forge.card.spellability.SpellAbility} object.
* @param mandatory a boolean.
* @return a boolean.
*/
private static boolean phasesUnpreferredTargeting(AbilityFactory af, SpellAbility sa, boolean mandatory) {
Card source = sa.getSourceCard();
Target tgt = sa.getTarget();
CardList list = AllZoneUtil.getCardsIn(Zone.Battlefield);
list = list.getValidCards(tgt.getValidTgts(), source.getController(), source).getTargetableCards(source);
return false;
}
/**
* <p>
* phasesResolve.
* </p>
*
* @param af a {@link forge.card.abilityFactory.AbilityFactory} object.
* @param sa a {@link forge.card.spellability.SpellAbility} object.
*/
private static void phasesResolve(final AbilityFactory af, final SpellAbility sa) {
HashMap<String, String> params = af.getMapParams();
Card card = sa.getSourceCard();
Target tgt = sa.getTarget();
ArrayList<Card> tgtCards = null;
if (tgt != null)
tgtCards = tgt.getTargetCards();
else {
tgtCards = AbilityFactory.getDefinedCards(card, params.get("Defined"), sa);
}
for (Card tgtC : tgtCards) {
tgtC.phase();
}
}
}// end of AbilityFactory_PermanentState class

View File

@@ -1385,7 +1385,7 @@ public class CardFactoryUtil {
// An animated artifact equipmemt can't equip a creature
@Override
public boolean canPlay() {
return AllZone.getZoneOf(sourceCard).is(Constant.Zone.Battlefield) && !sourceCard.isCreature()
return super.canPlay() && !sourceCard.isCreature()
&& Phase.canCastSorcery(sourceCard.getController());
}

View File

@@ -85,16 +85,17 @@ public class CostExile extends CostPartWithList {
@Override
public boolean canPay(SpellAbility ability, Card source, Player activator, Cost cost) {
PlayerZone zone = activator.getZone(getFrom());
CardList typeList = activator.getCardsIn(getFrom());
if (!getThis()) {
CardList typeList = new CardList(zone.getCards());
typeList = typeList.getValidCards(getType().split(";"), activator, source);
Integer amount = convertAmount();
if (amount != null && typeList.size() < amount)
if (amount != null && typeList.size() < amount){
return false;
} else if (!zone.contains(source))
}
} else if (!typeList.contains(source)){
return false;
}
return true;
}

View File

@@ -136,7 +136,7 @@ public class SpellAbility_Restriction extends SpellAbility_Variables {
* @return a boolean.
*/
public boolean canPlay(Card c, SpellAbility sa) {
if (!AllZone.getZoneOf(c).is(zone))
if (!AllZone.getZoneOf(c).is(zone) || c.isPhasedOut())
return false;
Player activator = sa.getActivatingPlayer();

View File

@@ -176,7 +176,7 @@ public class StaticAbility {
if (mapParams.containsKey("EffectZone"))
effectZone = Zone.smartValueOf(mapParams.get("EffectZone"));
if( effectZone != null && !AllZone.getZoneOf(hostCard).getZoneType().equals(effectZone))
if( effectZone != null && (!AllZone.getZoneOf(hostCard).getZoneType().equals(effectZone) || hostCard.isPhasedOut()))
return false;
if(mapParams.containsKey("Threshold") && !controller.hasThreshold())

View File

@@ -228,7 +228,7 @@ public abstract class Trigger {
if (AllZone.getZoneOf(hostCard) == null) {
return false;
}
if (!triggerZones.contains(AllZone.getZoneOf(hostCard).getZoneType())) {
if (!triggerZones.contains(AllZone.getZoneOf(hostCard).getZoneType()) || hostCard.isPhasedOut()) {
return false;
}
}

View File

@@ -191,6 +191,11 @@ public class CardDetailPanel extends JPanel implements CardContainer {
area.append(text);
}
if (card.isPhasedOut()){
if (area.length() != 0) area.append("\n");
area.append("Phased Out");
}
//counter text
Counters[] counters = Counters.values();
for (Counters counter : counters) {