diff --git a/.gitattributes b/.gitattributes index 772c8acae9c..dd80ed6ced9 100644 --- a/.gitattributes +++ b/.gitattributes @@ -13670,7 +13670,6 @@ src/main/java/forge/card/cardfactory/CardFactory.java svneol=native#text/plain src/main/java/forge/card/cardfactory/CardFactoryArtifacts.java -text src/main/java/forge/card/cardfactory/CardFactoryCreatures.java svneol=native#text/plain src/main/java/forge/card/cardfactory/CardFactoryLands.java svneol=native#text/plain -src/main/java/forge/card/cardfactory/CardFactoryPlaneswalkers.java svneol=native#text/plain src/main/java/forge/card/cardfactory/CardFactorySorceries.java svneol=native#text/plain src/main/java/forge/card/cardfactory/CardFactoryUtil.java svneol=native#text/plain src/main/java/forge/card/cardfactory/CardStorageReader.java svneol=native#text/plain diff --git a/CHANGES.txt b/CHANGES.txt index 1591f52536b..412ade5923b 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -48,6 +48,10 @@ The display of clones and copied cards is now a matter of user preference. A use Flippable cards -- cards that have an alternate card printed upside-down at the bottom -- will now flip their appearance on the battlefield when in a flipped state. They are now also flippable in the card viewer by clicking on the card image, just like double-sided "transform" cards have been. When flipped this way, the details of the flipped side can be examined in the Card Details oracle text. +- High Quality Booster Pictures - +Forge will now download high quality booster pictures. If you are interested in these high quality booster pictures, then you should delete the pictures that are found in your /pics/boosters/ directory. Then download the new pictures by using the Home View -> Game Settings -> Content Downloaders -> Download Quest Images button. + + --------- New Cards --------- @@ -70,9 +74,15 @@ Thieves' Auction Infinite Reflection Laccolith Rig Paroxysm +Essence Leak +Mistform Warchief +Whipkeeper +Sanctum Guardian -New Planes: +---------- +New Planes +---------- Bant Turri Island diff --git a/res/cardsfolder/a/academy_at_tolaria_west.txt b/res/cardsfolder/a/academy_at_tolaria_west.txt index 177ab7861dd..7af66086eef 100644 --- a/res/cardsfolder/a/academy_at_tolaria_west.txt +++ b/res/cardsfolder/a/academy_at_tolaria_west.txt @@ -5,10 +5,6 @@ T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | TriggerZones$ Command | SVar:AcademicDraw:AB$ Draw | Cost$ 0 | Defined$ You | NumCards$ 7 T:Mode$ PlanarDice | Result$ Chaos | TriggerZones$ Command | Execute$ RolledChaos | TriggerDescription$ Whenever you roll Chaos, discard your hand. SVar:RolledChaos:AB$ Discard | Cost$ 0 | Mode$ Hand | Defined$ You -T:Mode$ PlanarDice | Result$ Planeswalk | TriggerZones$ Command | Execute$ RolledWalk | Secondary$ True | TriggerDescription$ Whenever you roll Planeswalk, put this card on the bottom of its owner's planar deck face down, then move the top card of your planar deck off that planar deck and turn it face up -SVar:RolledWalk:AB$ Planeswalk | Cost$ 0 -A:AB$ RollPlanarDice | Cost$ X | SorcerySpeed$ True | ActivationZone$ Command | SpellDescription$ Roll the planar dice. -SVar:X:Count$RolledThisTurn SVar:Picture:http://www.wizards.com/global/images/magic/general/academy_at_tolaria_west.jpg Oracle:At the beginning of your end step, if you have no cards in hand, draw seven cards.\nWhenever you roll {C}, discard your hand. SetInfo:HOP Common \ No newline at end of file diff --git a/res/cardsfolder/a/aretopolis.txt b/res/cardsfolder/a/aretopolis.txt index 41e42a54bb6..22abe9b61b6 100644 --- a/res/cardsfolder/a/aretopolis.txt +++ b/res/cardsfolder/a/aretopolis.txt @@ -10,10 +10,6 @@ T:Mode$ Always | TriggerZones$ Command | CheckSVar$ NumScrolls | SVarCompare$ GE T:Mode$ PlanarDice | Result$ Chaos | TriggerZones$ Command | Execute$ RolledChaos | TriggerDescription$ Whenever you roll Chaos, put a scroll counter on CARDNAME, then draw cards equal to the number of scroll counters on it. SVar:RolledChaos:AB$ PutCounter | Cost$ 0 | Defined$ Self | CounterType$ SCROLL | CounterNum$ 1 | SubAbility$ ScrollsOfKnowledge SVar:ScrollsOfKnowledge:DB$ Draw | Defined$ You | NumCards$ NumScrolls | References$ NumScrolls -T:Mode$ PlanarDice | Result$ Planeswalk | TriggerZones$ Command | Execute$ RolledWalk | Secondary$ True | TriggerDescription$ Whenever you roll Planeswalk, put this card on the bottom of its owner's planar deck face down, then move the top card of your planar deck off that planar deck and turn it face up -SVar:RolledWalk:AB$ Planeswalk | Cost$ 0 -A:AB$ RollPlanarDice | Cost$ X | SorcerySpeed$ True | ActivationZone$ Command | SpellDescription$ Roll the planar dice. -SVar:X:Count$RolledThisTurn SVar:Picture:http://www.wizards.com/global/images/magic/general/aretopolis.jpg Oracle:When you planeswalk to Aretopolis or at the beginning of your upkeep, put a scroll counter on Aretopolis, then you gain life equal to the number of scroll counters on it.\nWhen Aretopolis has ten or more scroll counters on it, planeswalk.\nWhenever you roll {C}, put a scroll counter on Aretopolis, then draw cards equal to the number of scroll counters on it. SetInfo:PC2 Common \ No newline at end of file diff --git a/res/cardsfolder/b/bant.txt b/res/cardsfolder/b/bant.txt index cf61fd6396c..00e4e52f046 100644 --- a/res/cardsfolder/b/bant.txt +++ b/res/cardsfolder/b/bant.txt @@ -6,10 +6,6 @@ T:Mode$ PlanarDice | Result$ Chaos | TriggerZones$ Command | Execute$ RolledChao SVar:RolledChaos:AB$ PutCounter | Cost$ 0 | ValidTgts$ Creature.Green,Creature.White,Creature.Blue | CounterType$ DIVINITY | CounterNum$ 1 | SubAbility$ DivineCharacter SVar:DivineCharacter:DB$ Animate | Defined$ Targeted | staticAbilities$ IndestructibleAspect | Permanent$ True SVar:IndestructibleAspect:Mode$ Continuous | EffectZone$ Battlefield | Affected$ Card.Self+counters_GE1_DIVINITY | AddHiddenKeyword$ Indestructible -T:Mode$ PlanarDice | Result$ Planeswalk | TriggerZones$ Command | Execute$ RolledWalk | Secondary$ True | TriggerDescription$ Whenever you roll Planeswalk, put this card on the bottom of its owner's planar deck face down, then move the top card of your planar deck off that planar deck and turn it face up -SVar:RolledWalk:AB$ Planeswalk | Cost$ 0 -A:AB$ RollPlanarDice | Cost$ X | SorcerySpeed$ True | ActivationZone$ Command | SpellDescription$ Roll the planar dice. -SVar:X:Count$RolledThisTurn SVar:Picture:http://www.wizards.com/global/images/magic/general/bant.jpg Oracle:All creatures have exalted. (Whenever a creature attacks alone, it gets +1/+1 until end of turn for each instance of exalted among permanents its controller controls.)\nWhenever you roll {C}, put a divinity counter on target green, white, or blue creature. That creature is indestructible as long as it has a divinity counter on it. SetInfo:HOP Common \ No newline at end of file diff --git a/res/cardsfolder/f/feeding_grounds.txt b/res/cardsfolder/f/feeding_grounds.txt index ec93f1e7a57..014085a6a67 100644 --- a/res/cardsfolder/f/feeding_grounds.txt +++ b/res/cardsfolder/f/feeding_grounds.txt @@ -4,12 +4,8 @@ Types:Plane Muraganda S:Mode$ ReduceCost | EffectZone$ Command | ValidCard$ Card.Green | Type$ Spell | Amount$ 1 | Description$ Green spells cost 1 less to cast. S:Mode$ ReduceCost | EffectZone$ Command | ValidCard$ Card.Red | Type$ Spell | Amount$ 1 | Description$ Red spells cost 1 less to cast. T:Mode$ PlanarDice | Result$ Chaos | TriggerZones$ Command | Execute$ DBPutCounter | TriggerDescription$ Whenever you roll Chaos, put X +1/+1 counters on target creature, where X is that creature's converted mana cost. -T:Mode$ PlanarDice | Result$ Planeswalk | TriggerZones$ Command | Execute$ RolledWalk | Secondary$ True | TriggerDescription$ Whenever you roll Planeswalk, put this card on the bottom of its owner's planar deck face down, then move the top card of your planar deck off that planar deck and turn it face up -SVar:RolledWalk:AB$ Planeswalk | Cost$ 0 -A:AB$ RollPlanarDice | Cost$ X | SorcerySpeed$ True | ActivationZone$ Command | SpellDescription$ Roll the planar dice. SVar:DBPutCounter:DB$ PutCounter | ValidTgts$ Creature | TgtPrompt$ Select target creature | CounterType$ P1P1 | CounterNum$ Y SVar:Y:Targeted$CardManaCost -SVar:X:Count$RolledThisTurn SVar:Picture:http://www.wizards.com/global/images/magic/general/feeding_grounds.jpg Oracle:Red spells cost {1} less to cast.\nGreen spells cost {1} less to cast.\nWhenever you roll {C}, put X +1/+1 counters on target creature, where X is that creature's converted mana cost. SetInfo:HOP Common \ No newline at end of file diff --git a/res/cardsfolder/f/fields_of_summer.txt b/res/cardsfolder/f/fields_of_summer.txt index 5557e6984ec..7f3f28ea602 100644 --- a/res/cardsfolder/f/fields_of_summer.txt +++ b/res/cardsfolder/f/fields_of_summer.txt @@ -5,10 +5,6 @@ T:Mode$ SpellCast | OptionalDecider$ TriggeredPlayer | TriggerZones$ Command | E SVar:LifeSummer:AB$ GainLife | Cost$ 0 | Defined$ TriggeredPlayer | LifeAmount$ 2 T:Mode$ PlanarDice | Result$ Chaos | OptionalDecider$ You | TriggerZones$ Command | Execute$ RolledChaos | TriggerDescription$ Whenever you roll Chaos, you may gain 10 life. SVar:RolledChaos:AB$ GainLife | Cost$ 0 | LifeAmount$ 10 | Defined$ You -T:Mode$ PlanarDice | Result$ Planeswalk | TriggerZones$ Command | Execute$ RolledWalk | Secondary$ True | TriggerDescription$ Whenever you roll Planeswalk, put this card on the bottom of its owner's planar deck face down, then move the top card of your planar deck off that planar deck and turn it face up. -SVar:RolledWalk:AB$ Planeswalk | Cost$ 0 -A:AB$ RollPlanarDice | Cost$ X | SorcerySpeed$ True | ActivationZone$ Command | SpellDescription$ Roll the planar dice. -SVar:X:Count$RolledThisTurn SVar:Picture:http://www.wizards.com/global/images/magic/general/fields_of_summer.jpg Oracle:Whenever a player casts a spell, that player may gain 2 life.\nWhenever you roll {C}, you may gain 10 life. SetInfo:HOP Common \ No newline at end of file diff --git a/res/cardsfolder/g/goldmeadow.txt b/res/cardsfolder/g/goldmeadow.txt index ad665016c51..3471216ae4f 100644 --- a/res/cardsfolder/g/goldmeadow.txt +++ b/res/cardsfolder/g/goldmeadow.txt @@ -5,10 +5,6 @@ T:Mode$ ChangesZone | ValidCard$ Land | Destination$ Battlefield | Execute$ Trip SVar:TripleGoat:AB$ Token | Cost$ 0 | TokenName$ Goat | TokenTypes$ Creature,Goat | TokenPower$ 0 | TokenToughness$ 1 | TokenColors$ White | TokenOwner$ TriggeredCardController | TokenImage$ W 0 1 Goat | TokenAmount$ 3 T:Mode$ PlanarDice | Result$ Chaos | TriggerZones$ Command | Execute$ RolledChaos | TriggerDescription$ Whenever you roll Chaos, put a 0/1 white Goat creature token onto the battlefield. SVar:RolledChaos:AB$ Token | Cost$ 0 | TokenName$ Goat | TokenTypes$ Creature,Goat | TokenPower$ 0 | TokenToughness$ 1 | TokenColors$ White | TokenOwner$ TriggeredPlayer | TokenImage$ W 0 1 Goat | TokenAmount$ 1 -T:Mode$ PlanarDice | Result$ Planeswalk | TriggerZones$ Command | Execute$ RolledWalk | Secondary$ True | TriggerDescription$ Whenever you roll Planeswalk, put this card on the bottom of its owner's planar deck face down, then move the top card of your planar deck off that planar deck and turn it face up -SVar:RolledWalk:AB$ Planeswalk | Cost$ 0 -A:AB$ RollPlanarDice | Cost$ X | SorcerySpeed$ True | ActivationZone$ Command | SpellDescription$ Roll the planar dice. -SVar:X:Count$RolledThisTurn SVar:Picture:http://www.wizards.com/global/images/magic/general/goldmeadow.jpg Oracle:Whenever a land enters the battlefield, that land's controller puts three 0/1 white Goat creature tokens onto the battlefield.\nWhenever you roll {C}, put a 0/1 white Goat creature token onto the battlefield. SetInfo:HOP Common \ No newline at end of file diff --git a/res/cardsfolder/h/horizon_boughs.txt b/res/cardsfolder/h/horizon_boughs.txt index 0d110f7f815..76e37b34e92 100644 --- a/res/cardsfolder/h/horizon_boughs.txt +++ b/res/cardsfolder/h/horizon_boughs.txt @@ -3,11 +3,7 @@ ManaCost:no cost Types:Plane Pyrulea S:Mode$ Continuous | EffectZone$ Command | Affected$ Permanent | AddHiddenKeyword$ CARDNAME untaps during each other player's untap step. | Description$ All permanents untap during each player's untap step. T:Mode$ PlanarDice | Result$ Chaos | TriggerZones$ Command | Execute$ DBFetch | TriggerDescription$ Whenever you roll Chaos, you may search your library for up to three basic land cards, put them onto the battlefield tapped, then shuffle your library. -T:Mode$ PlanarDice | Result$ Planeswalk | TriggerZones$ Command | Execute$ RolledWalk | Secondary$ True | TriggerDescription$ Whenever you roll Planeswalk, put this card on the bottom of its owner's planar deck face down, then move the top card of your planar deck off that planar deck and turn it face up -SVar:RolledWalk:AB$ Planeswalk | Cost$ 0 -A:AB$ RollPlanarDice | Cost$ X | SorcerySpeed$ True | ActivationZone$ Command | SpellDescription$ Roll the planar dice. SVar:DBFetch:DB$ChangeZone | Origin$ Library | Destination$ Battlefield | Tapped$ True | ChangeType$ Land.Basic | ChangeNum$ 3 -SVar:X:Count$RolledThisTurn SVar:Picture:http://www.cardforge.org/fpics/lq_planes_promos/horizon_boughs.jpg Oracle:All permanents untap during each player's untap step.\nWhenever you roll {C}, you may search your library for up to three basic land cards, put them onto the battlefield tapped, then shuffle your library. SetInfo:HOP Common \ No newline at end of file diff --git a/res/cardsfolder/k/krosa.txt b/res/cardsfolder/k/krosa.txt index 7aefafd54d4..45923c31d5b 100644 --- a/res/cardsfolder/k/krosa.txt +++ b/res/cardsfolder/k/krosa.txt @@ -4,10 +4,6 @@ Types:Plane Dominaria S:Mode$ Continuous | EffectZone$ Command | Affected$ Creature | AddPower$ 2 | AddPower$ 2 | Description$ All Creatures get +2/+2. T:Mode$ PlanarDice | Result$ Chaos | OptionalDecider$ You | TriggerZones$ Command | Execute$ RolledChaos | TriggerDescription$ Whenever you roll Chaos, you may add W U B R G to your mana pool. SVar:RolledChaos:AB$ Mana | Cost$ 0 | Produced$ W U B R G -T:Mode$ PlanarDice | Result$ Planeswalk | TriggerZones$ Command | Execute$ RolledWalk | Secondary$ True | TriggerDescription$ Whenever you roll Planeswalk, put this card on the bottom of its owner's planar deck face down, then move the top card of your planar deck off that planar deck and turn it face up. -SVar:RolledWalk:AB$ Planeswalk | Cost$ 0 -A:AB$ RollPlanarDice | Cost$ X | SorcerySpeed$ True | ActivationZone$ Command | SpellDescription$ Roll the planar dice. -SVar:X:Count$RolledThisTurn SVar:Picture:http://www.wizards.com/global/images/magic/general/krosa.jpg Oracle:All creatures get +2/+2.\nWhenever you roll {C}, you may add {W}{U}{B}{R}{G} to your mana pool. SetInfo:HOP Common \ No newline at end of file diff --git a/res/cardsfolder/k/kyscu_drake.txt b/res/cardsfolder/k/kyscu_drake.txt index bf18202d398..189d9fe6c28 100644 --- a/res/cardsfolder/k/kyscu_drake.txt +++ b/res/cardsfolder/k/kyscu_drake.txt @@ -3,7 +3,7 @@ ManaCost:3 G Types:Creature Drake PT:2/2 K:Flying -A:AB$ Pump | Cost$ G | NumAtt$ +1 | ActivationLimit$ 1 | SpellDescription$ CARDNAME gets +1/+0 until end of turn. Activate this ability only once each turn. +A:AB$ Pump | Cost$ G | NumDef$ +1 | ActivationLimit$ 1 | SpellDescription$ CARDNAME gets +0/+1 until end of turn. Activate this ability only once each turn. A:AB$ ChangeZone | Cost$ Sac<1/CARDNAME> Sac<1/Creature.namedSpitting Drake/creature named Spitting Drake> | Origin$ Library | Destination$ Battlefield | ChangeType$ Card.namedViashivan Dragon | ChangeNum$ 1 | SpellDescription$ Search your library for a card named Viashivan Dragon and put that card onto the battlefield. Then shuffle your library. SVar:Picture:http://www.wizards.com/global/images/magic/general/kyscu_drake.jpg Oracle:Flying\n{G}: Kyscu Drake gets +0/+1 until end of turn. Activate this ability only once each turn.\nSacrifice Kyscu Drake and a creature named Spitting Drake: Search your library for a card named Viashivan Dragon and put that card onto the battlefield. Then shuffle your library. diff --git a/res/cardsfolder/l/lethe_lake.txt b/res/cardsfolder/l/lethe_lake.txt index 6cd5e9ad6a7..0930eb66c88 100644 --- a/res/cardsfolder/l/lethe_lake.txt +++ b/res/cardsfolder/l/lethe_lake.txt @@ -5,10 +5,6 @@ T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Command | Execu SVar:LetheMill:AB$ Mill | Cost$ 0 | Defined$ You | NumCards$ 10 T:Mode$ PlanarDice | Result$ Chaos | TriggerZones$ Command | Execute$ RolledChaos | TriggerDescription$ Whenever you roll Chaos, target player puts the top 10 cards of his or her library into his or her graveyard. SVar:RolledChaos:AB$ Mill | Cost$ 0 | ValidTgts$ Player | TgtPrompt$ Choose target player to mill. | NumCards$ 10 -T:Mode$ PlanarDice | Result$ Planeswalk | TriggerZones$ Command | Execute$ RolledWalk | Secondary$ True | TriggerDescription$ Whenever you roll Planeswalk, put this card on the bottom of its owner's planar deck face down, then move the top card of your planar deck off that planar deck and turn it face up -SVar:RolledWalk:AB$ Planeswalk | Cost$ 0 -A:AB$ RollPlanarDice | Cost$ X | SorcerySpeed$ True | ActivationZone$ Command | SpellDescription$ Roll the planar dice. -SVar:X:Count$RolledThisTurn SVar:Picture:http://www.wizards.com/global/images/magic/general/lethe_lake.jpg Oracle:At the beginning of your upkeep, put the top ten cards of your library into your graveyard.\nWhenever you roll {C}, target player puts the top ten cards of his or her library into his or her graveyard. SetInfo:HOP Common \ No newline at end of file diff --git a/res/cardsfolder/l/llanowar.txt b/res/cardsfolder/l/llanowar.txt index c76c391ab26..04b3c29bb97 100644 --- a/res/cardsfolder/l/llanowar.txt +++ b/res/cardsfolder/l/llanowar.txt @@ -5,10 +5,6 @@ S:Mode$ Continuous | Affected$ Creature | EffectZone$ Command | AddAbility$ Llan SVar:LlanowarAb:AB$ Mana | Cost$ T | Amount$ 2 | Produced$ G | SpellDescription$ Add G G to your mana pool. T:Mode$ PlanarDice | Result$ Chaos | TriggerZones$ Command | Execute$ RolledChaos | TriggerDescription$ Whenever you roll Chaos, untap all creatures you control. SVar:RolledChaos:AB$ UntapAll | Cost$ 0 | ValidCards$ Creature.YouCtrl -T:Mode$ PlanarDice | Result$ Planeswalk | TriggerZones$ Command | Execute$ RolledWalk | Secondary$ True | TriggerDescription$ Whenever you roll Planeswalk, put this card on the bottom of its owner's planar deck face down, then move the top card of your planar deck off that planar deck and turn it face up -SVar:RolledWalk:AB$ Planeswalk | Cost$ 0 -A:AB$ RollPlanarDice | Cost$ X | SorcerySpeed$ True | ActivationZone$ Command | SpellDescription$ Roll the planar dice. -SVar:X:Count$RolledThisTurn SVar:Picture:http://www.wizards.com/global/images/magic/general/llanowar.jpg Oracle:All creatures have "{T}: Add {G}{G} to your mana pool."\nWhenever you roll {C}, untap all creatures you control. SetInfo:HOP Common \ No newline at end of file diff --git a/res/cardsfolder/p/panopticon.txt b/res/cardsfolder/p/panopticon.txt index 9081d0c08c6..d57f16ff28b 100644 --- a/res/cardsfolder/p/panopticon.txt +++ b/res/cardsfolder/p/panopticon.txt @@ -5,10 +5,6 @@ T:Mode$ PlaneswalkedTo | ValidCard$ Card.Self | TriggerZones$ Command | Execute$ T:Mode$ Phase | Phase$ Draw | ValidPlayer$ You | Execute$ PanopticonDraw | TriggerDescription$ At the beginning of your draw step, draw an additional card. T:Mode$ PlanarDice | Result$ Chaos | TriggerZones$ Command | Execute$ PanopticonDraw | TriggerDescription$ Whenever you roll Chaos, draw a card. SVar:PanopticonDraw:AB$ Draw | Cost$ 0 | Defined$ You | NumCards$ 1 -T:Mode$ PlanarDice | Result$ Planeswalk | TriggerZones$ Command | Execute$ RolledWalk | Secondary$ True | TriggerDescription$ Whenever you roll Planeswalk, put this card on the bottom of its owner's planar deck face down, then move the top card of your planar deck off that planar deck and turn it face up -SVar:RolledWalk:AB$ Planeswalk | Cost$ 0 -A:AB$ RollPlanarDice | Cost$ X | SorcerySpeed$ True | ActivationZone$ Command | SpellDescription$ Roll the planar dice. -SVar:X:Count$RolledThisTurn SVar:Picture:http://www.wizards.com/global/images/magic/general/panopticon.jpg Oracle:When you planeswalk to Panopticon, draw a card.\nAt the beginning of your draw step, draw an additional card.\nWhenever you roll {C}, draw a card. SetInfo:HOP Common \ No newline at end of file diff --git a/res/cardsfolder/r/ravens_run.txt b/res/cardsfolder/r/ravens_run.txt index 48cbb825067..aeac1bb1ff8 100644 --- a/res/cardsfolder/r/ravens_run.txt +++ b/res/cardsfolder/r/ravens_run.txt @@ -7,10 +7,6 @@ SVar:RolledChaos1:AB$ PutCounter | Cost$ 0 | ValidTgts$ Creature | CounterType$ SVar:RolledChaos2:DB$ PutCounter | ValidTgts$ Creature.IsNotRemembered | CounterType$ M1M1 | CounterNum$ 2 | RememberTargets$ True | SubAbility$ RolledChaos3 SVar:RolledChaos3:DB$ PutCounter | ValidTgts$ Creature.IsNotRemembered | CounterType$ M1M1 | CounterNum$ 3 | SubAbility$ RolledChaosCleanup SVar:RolledChaosCleanup:DB$ Cleanup | ClearRemembered$ True -T:Mode$ PlanarDice | Result$ Planeswalk | TriggerZones$ Command | Execute$ RolledWalk | Secondary$ True | TriggerDescription$ Whenever you roll Planeswalk, put this card on the bottom of its owner's planar deck face down, then move the top card of your planar deck off that planar deck and turn it face up. -SVar:RolledWalk:AB$ Planeswalk | Cost$ 0 -A:AB$ RollPlanarDice | Cost$ X | SorcerySpeed$ True | ActivationZone$ Command | SpellDescription$ Roll the planar dice. -SVar:X:Count$RolledThisTurn SVar:Picture:http://www.cardforge.org/fpics/lq_planes_promos/ravens_run.jpg Oracle:All creatures have wither. (They deal damage to creatures in the form of -1/-1 counters.)\nWhenever you roll {C}, put a -1/-1 counter on target creature, two -1/-1 counters on another target creature, and three -1/-1 counters on a third target creature. SetInfo:HOP Common \ No newline at end of file diff --git a/res/cardsfolder/t/takenuma.txt b/res/cardsfolder/t/takenuma.txt index 061444ba34c..c0bac0f0be5 100644 --- a/res/cardsfolder/t/takenuma.txt +++ b/res/cardsfolder/t/takenuma.txt @@ -5,10 +5,6 @@ T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | ValidCard$ Creatu SVar:TakenumaDraw:AB$ Draw | Cost$ 0 | Defined$ TriggeredCardController | NumCards$ 1 T:Mode$ PlanarDice | Result$ Chaos | TriggerZones$ Command | Execute$ RolledChaos | TriggerDescription$ Whenever you roll Chaos, return target creature you control to its owner's hand. SVar:RolledChaos:AB$ ChangeZone | Cost$ 0 | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature to return to your hand | Origin$ Battlefield | Destination$ Hand -T:Mode$ PlanarDice | Result$ Planeswalk | TriggerZones$ Command | Execute$ RolledWalk | Secondary$ True | TriggerDescription$ Whenever you roll Planeswalk, put this card on the bottom of its owner's planar deck face down, then move the top card of your planar deck off that planar deck and turn it face up -SVar:RolledWalk:AB$ Planeswalk | Cost$ 0 -A:AB$ RollPlanarDice | Cost$ X | SorcerySpeed$ True | ActivationZone$ Command | SpellDescription$ Roll the planar dice. -SVar:X:Count$RolledThisTurn SVar:Picture:http://www.wizards.com/global/images/magic/general/takenuma.jpg Oracle:Whenever a creature leaves the battlefield, its controller draws a card.\nWhenever you roll {C}, return target creature you control to its owner's hand. SetInfo:PC2 Common \ No newline at end of file diff --git a/res/cardsfolder/t/talon_gates.txt b/res/cardsfolder/t/talon_gates.txt index 18e6578015b..bacd6267f0e 100644 --- a/res/cardsfolder/t/talon_gates.txt +++ b/res/cardsfolder/t/talon_gates.txt @@ -9,10 +9,6 @@ SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:GateX:Remembered$CardManaCost T:Mode$ PlanarDice | Result$ Chaos | TriggerZones$ Command | Execute$ RolledChaos | TriggerDescription$ Whenever you roll Chaos, remove two time counters from each suspended card you own. SVar:RolledChaos:AB$ RemoveCounterAll | Cost$ 0 | ValidCards$ Card.suspended+YouOwn | CounterType$ TIME | CounterNum$ 2 | ValidZone$ Exile -T:Mode$ PlanarDice | Result$ Planeswalk | TriggerZones$ Command | Execute$ RolledWalk | Secondary$ True | TriggerDescription$ Whenever you roll Planeswalk, put this card on the bottom of its owner's planar deck face down, then move the top card of your planar deck off that planar deck and turn it face up -SVar:RolledWalk:AB$ Planeswalk | Cost$ 0 -A:AB$ RollPlanarDice | Cost$ X | SorcerySpeed$ True | ActivationZone$ Command | SpellDescription$ Roll the planar dice. -SVar:X:Count$RolledThisTurn SVar:Picture:http://www.wizards.com/global/images/magic/general/talon_gates.jpg Oracle:Any time you could cast a sorcery, you may exile a nonland card from your hand with X time counters on it, where X is its converted mana cost. If the exiled card doesn't have suspend, it gains suspend. (At the beginning of its owner's upkeep, he or she removes a time counter. When the last is removed, the player casts it without paying its mana cost. If it's a creature, it has haste.)\nWhenever you roll {C}, remove two time counters from each suspended card you own. SetInfo:PC2 Common \ No newline at end of file diff --git a/res/cardsfolder/t/the_aether_flues.txt b/res/cardsfolder/t/the_aether_flues.txt index 051b1aa9f02..722b76c4577 100644 --- a/res/cardsfolder/t/the_aether_flues.txt +++ b/res/cardsfolder/t/the_aether_flues.txt @@ -8,10 +8,6 @@ SVar:FluesDig:DB$ DigUntil | Valid$ Creature | ValidDescription$ creature | Foun SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True T:Mode$ PlanarDice | Result$ Chaos | TriggerZones$ Command | Execute$ RolledChaos | TriggerDescription$ Whenever you roll Chaos, you may put a creature card from your hand onto the battlefield. SVar:RolledChaos:AB$ ChangeZone | Cost$ 0 | ChangeType$ Creature | ChangeNum$ 1 | Origin$ Hand | Destination$ Battlefield -T:Mode$ PlanarDice | Result$ Planeswalk | TriggerZones$ Command | Execute$ RolledWalk | Secondary$ True | TriggerDescription$ Whenever you roll Planeswalk, put this card on the bottom of its owner's planar deck face down, then move the top card of your planar deck off that planar deck and turn it face up -SVar:RolledWalk:AB$ Planeswalk | Cost$ 0 -A:AB$ RollPlanarDice | Cost$ X | SorcerySpeed$ True | ActivationZone$ Command | SpellDescription$ Roll the planar dice. -SVar:X:Count$RolledThisTurn SVar:Picture:http://www.wizards.com/global/images/magic/general/the_aether_flues.jpg Oracle:When you planeswalk to The AEther Flues or at the beginning of your upkeep, you may sacrifice a creature. If you do, reveal cards from the top of your library until you reveal a creature card, put that card onto the battlefield, then shuffle all other cards revealed this way into your library.\nWhenever you roll {C}, you may put a creature card from your hand onto the battlefield. SetInfo:HOP Common \ No newline at end of file diff --git a/res/cardsfolder/t/the_fourth_sphere.txt b/res/cardsfolder/t/the_fourth_sphere.txt index 5ff54eec2c7..c8c2e048840 100644 --- a/res/cardsfolder/t/the_fourth_sphere.txt +++ b/res/cardsfolder/t/the_fourth_sphere.txt @@ -5,10 +5,6 @@ T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Command | Execu SVar:FourthSac:AB$ Sacrifice | Cost$ 0 | Defined$ You | SacValid$ Creature.nonBlack T:Mode$ PlanarDice | Result$ Chaos | TriggerZones$ Command | Execute$ RolledChaos | TriggerDescription$ Whenever you roll Chaos, put a 2/2 black zombie token onto the battlefield. SVar:RolledChaos:AB$Token | Cost$ 0 | TokenImage$ B 2 2 Zombie | TokenName$ Zombie | TokenColors$ Black | TokenTypes$ Creature,Zombie | TokenPower$ 2 | TokenToughness$ 2 | TokenOwner$ You | TokenAmount$ 2 -T:Mode$ PlanarDice | Result$ Planeswalk | TriggerZones$ Command | Execute$ RolledWalk | Secondary$ True | TriggerDescription$ Whenever you roll Planeswalk, put this card on the bottom of its owner's planar deck face down, then move the top card of your planar deck off that planar deck and turn it face up -SVar:RolledWalk:AB$ Planeswalk | Cost$ 0 -A:AB$ RollPlanarDice | Cost$ X | SorcerySpeed$ True | ActivationZone$ Command | SpellDescription$ Roll the planar dice. -SVar:X:Count$RolledThisTurn SVar:Picture:http://www.wizards.com/global/images/magic/general/the_fourth_sphere.jpg Oracle:At the beginning of your upkeep, sacrifice a nonblack creature.\nWhenever you roll {C}, put a 2/2 black Zombie creature token onto the battlefield. SetInfo:HOP Common \ No newline at end of file diff --git a/res/cardsfolder/t/the_great_forest.txt b/res/cardsfolder/t/the_great_forest.txt index 8dd01962cfb..e0b0205a348 100644 --- a/res/cardsfolder/t/the_great_forest.txt +++ b/res/cardsfolder/t/the_great_forest.txt @@ -4,10 +4,6 @@ Types:Plane Lorwyn S:Mode$ Continuous | EffectZone$ Command | GlobalRule$ Each creature assigns combat damage equal to its toughness rather than its power. | Description$ Each creature assigns combat damage equal to its toughness rather than its power. T:Mode$ PlanarDice | Result$ Chaos | TriggerZones$ Command | Execute$ RolledChaos | TriggerDescription$ Whenever you roll Chaos,creatures you control get +0/+2 and gain trample until end of turn. SVar:RolledChaos:AB$ PumpAll | Cost$ 0 | ValidCards$ Creature.ActivePlayerCtrl | NumDef$ 2 | KW$ Trample -T:Mode$ PlanarDice | Result$ Planeswalk | TriggerZones$ Command | Execute$ RolledWalk | Secondary$ True | TriggerDescription$ Whenever you roll Planeswalk, put this card on the bottom of its owner's planar deck face down, then move the top card of your planar deck off that planar deck and turn it face up -SVar:RolledWalk:AB$ Planeswalk | Cost$ 0 -A:AB$ RollPlanarDice | Cost$ X | SorcerySpeed$ True | ActivationZone$ Command | SpellDescription$ Roll the planar dice. -SVar:X:Count$RolledThisTurn SVar:Picture:http://www.wizards.com/global/images/magic/general/the_great_forest.jpg Oracle:Each creature assigns combat damage equal to its toughness rather than its power.\nWhenever you roll {C}, creatures you control get +0/+2 and gain trample until end of turn. SetInfo:HOP Common \ No newline at end of file diff --git a/res/cardsfolder/t/the_hippodrome.txt b/res/cardsfolder/t/the_hippodrome.txt index 41cc3255ca3..a1d1f67e2bc 100644 --- a/res/cardsfolder/t/the_hippodrome.txt +++ b/res/cardsfolder/t/the_hippodrome.txt @@ -5,10 +5,6 @@ S:Mode$ Continuous | EffectZone$ Command | Affected$ Creature | AddPower$ -5 | D T:Mode$ PlanarDice | Result$ Chaos | OptionalDecider$ You | TriggerZones$ Command | Execute$ RolledChaos | TriggerDescription$ Whenever you roll Chaos, you may destroy target creature if it's power is 0 or less. SVar:RolledChaos:AB$ Destroy | Cost$ 0 | ValidTgts$ Creature | ConditionCheckSVar$ TgtPow | ConditionCompareSVar$ EQ1 | AITgts$ Creature.OpponentCtrl+powerLE0 SVar:TgtPow:Targeted$Valid Creature.powerLE0 -T:Mode$ PlanarDice | Result$ Planeswalk | TriggerZones$ Command | Execute$ RolledWalk | Secondary$ True | TriggerDescription$ Whenever you roll Planeswalk, put this card on the bottom of its owner's planar deck face down, then move the top card of your planar deck off that planar deck and turn it face up. -SVar:RolledWalk:AB$ Planeswalk | Cost$ 0 -A:AB$ RollPlanarDice | Cost$ X | SorcerySpeed$ True | ActivationZone$ Command | SpellDescription$ Roll the planar dice. -SVar:X:Count$RolledThisTurn SVar:Picture:http://www.wizards.com/global/images/magic/general/the_hippodrome.jpg Oracle:All creatures get -5/-0.\nWhenever you roll {C}, you may destroy target creature if its power is 0 or less. SetInfo:HOP Common \ No newline at end of file diff --git a/res/cardsfolder/t/trail_of_the_mage_rings.txt b/res/cardsfolder/t/trail_of_the_mage_rings.txt index 0df8cc058a5..2f83a607563 100644 --- a/res/cardsfolder/t/trail_of_the_mage_rings.txt +++ b/res/cardsfolder/t/trail_of_the_mage_rings.txt @@ -4,10 +4,6 @@ Types:Plane Vryn S:Mode$ Continuous | AddKeyword$ Rebound | Affected$ Instant,Sorcery | AffectedZone$ Stack | EffectZone$ Command | Description$ Instant and sorcery spells have rebound. (The spell's controller exiles the spell as it resolves if he or she cast it from his or her hand. At the beginning of that player's next upkeep, he or she may cast that card from exile without paying its mana cost.) T:Mode$ PlanarDice | Result$ Chaos | TriggerZones$ Command | Execute$ RolledChaos | TriggerDescription$ Whenever you roll Chaos, you may search your library for an instant or sorcery card, reveal it, put it into your hand, then shuffle your library. SVar:RolledChaos:AB$ ChangeZone | Cost$ 0 | Origin$ Library | Destination$ Hand | ChangeType$ Instant,Sorcery | ChangeNum$ 1 -T:Mode$ PlanarDice | Result$ Planeswalk | TriggerZones$ Command | Execute$ RolledWalk | Secondary$ True | TriggerDescription$ Whenever you roll Planeswalk, put this card on the bottom of its owner's planar deck face down, then move the top card of your planar deck off that planar deck and turn it face up -SVar:RolledWalk:AB$ Planeswalk | Cost$ 0 -A:AB$ RollPlanarDice | Cost$ X | SorcerySpeed$ True | ActivationZone$ Command | SpellDescription$ Roll the planar dice. -SVar:X:Count$RolledThisTurn SVar:Picture:http://www.wizards.com/global/images/magic/general/trail_of_the_mage_rings.jpg Oracle:Instant and sorcery spells have rebound. (The spell's controller exiles the spell as it resolves if he or she cast it from his or her hand. At the beginning of that player's next upkeep, he or she may cast that card from exile without paying its mana cost.)\nWhenever you roll {C}, you may search your library for an instant or sorcery card, reveal it, put it into your hand, then shuffle your library. SetInfo:PC2 Common \ No newline at end of file diff --git a/res/cardsfolder/t/truga_jungle.txt b/res/cardsfolder/t/truga_jungle.txt index c0afd3b32bd..4a6fc2a9c99 100644 --- a/res/cardsfolder/t/truga_jungle.txt +++ b/res/cardsfolder/t/truga_jungle.txt @@ -5,10 +5,6 @@ S:Mode$ Continuous | EffectZone$ Command | AffectedZone$ Battlefield | Affected$ SVar:AnyMana:AB$ Mana | Cost$ T | Produced$ Any | Amount$ 1 | SpellDescription$ Add one mana of any color to your mana pool. T:Mode$ PlanarDice | Result$ Chaos | TriggerZones$ Command | Execute$ RolledChaos | TriggerDescription$ Whenever you roll Chaos, reveal the top three cards of your library. Put all land cards revealed this way into your hand and the rest on the bottom of your library in any order. SVar:RolledChaos:DB$ Dig | DigNum$ 3 | Reveal$ True | ChangeNum$ All | ChangeValid$ Land -T:Mode$ PlanarDice | Result$ Planeswalk | TriggerZones$ Command | Execute$ RolledWalk | Secondary$ True | TriggerDescription$ Whenever you roll Planeswalk, put this card on the bottom of its owner's planar deck face down, then move the top card of your planar deck off that planar deck and turn it face up -SVar:RolledWalk:AB$ Planeswalk | Cost$ 0 -A:AB$ RollPlanarDice | Cost$ X | SorcerySpeed$ True | ActivationZone$ Command | SpellDescription$ Roll the planar dice. -SVar:X:Count$RolledThisTurn SVar:Picture:http://www.wizards.com/global/images/magic/general/truga_jungle.jpg Oracle:All lands have "{T}: Add one mana of any color to your mana pool."\nWhenever you roll {C}, reveal the top three cards of your library. Put all land cards revealed this way into your hand and the rest on the bottom of your library in any order. SetInfo:PC2 Common \ No newline at end of file diff --git a/res/cardsfolder/t/turri_island.txt b/res/cardsfolder/t/turri_island.txt index db477f25647..21ceb77cbee 100644 --- a/res/cardsfolder/t/turri_island.txt +++ b/res/cardsfolder/t/turri_island.txt @@ -4,10 +4,6 @@ Types:Plane Ir S:Mode$ ReduceCost | EffectZone$ Command | ValidCard$ Creature | Type$ Spell | Amount$ 2 | Description$ Creature spells cost 2 less to cast. T:Mode$ PlanarDice | Result$ Chaos | TriggerZones$ Command | Execute$ RolledChaos | TriggerDescription$ Whenever you roll Chaos, reveal the top three cards of your library. Put all creature cards revealed this way into your hand and the rest into your graveyard. SVar:RolledChaos:AB$ Dig | Cost$ 0 | DigNum$ 3 | Reveal$ True | ChangeNum$ All | ChangeValid$ Creature | DestinationZone2$ Graveyard -T:Mode$ PlanarDice | Result$ Planeswalk | TriggerZones$ Command | Execute$ RolledWalk | Secondary$ True | TriggerDescription$ Whenever you roll Planeswalk, put this card on the bottom of its owner's planar deck face down, then move the top card of your planar deck off that planar deck and turn it face up -SVar:RolledWalk:AB$ Planeswalk | Cost$ 0 -A:AB$ RollPlanarDice | Cost$ X | SorcerySpeed$ True | ActivationZone$ Command | SpellDescription$ Roll the planar dice. -SVar:X:Count$RolledThisTurn SVar:Picture:http://www.wizards.com/global/images/magic/general/turri_island.jpg Oracle:Creature spells cost {2} less to cast.\nWhenever you roll {C}, reveal the top three cards of your library. Put all creature cards revealed this way into your hand and the rest into your graveyard. SetInfo:HOP Common \ No newline at end of file diff --git a/res/cardsfolder/u/undercity_reaches.txt b/res/cardsfolder/u/undercity_reaches.txt index 32a278c3fc7..7225f9274db 100644 --- a/res/cardsfolder/u/undercity_reaches.txt +++ b/res/cardsfolder/u/undercity_reaches.txt @@ -6,10 +6,6 @@ SVar:TrigDraw:AB$ Draw | Cost$ 0 | Defined$ TriggeredSourceController | NumCards T:Mode$ PlanarDice | Result$ Chaos | TriggerZones$ Command | Execute$ RolledChaos | TriggerDescription$ Whenever you roll Chaos, you have no maximum hand size for the rest of the game. SVar:RolledChaos:AB$ Effect | Cost$ 0 | Effect | Name$ Undercity Reaches Effect | StaticAbilities$ STHandSize | Duration$ Permanent SVar:STHandSize:Mode$ Continuous | EffectZone$ Command | Affected$ You | SetMaxHandSize$ Unlimited | Description$ You have no maximum hand size. -T:Mode$ PlanarDice | Result$ Planeswalk | TriggerZones$ Command | Execute$ RolledWalk | Secondary$ True | TriggerDescription$ Whenever you roll Planeswalk, put this card on the bottom of its owner's planar deck face down, then move the top card of your planar deck off that planar deck and turn it face up. -SVar:RolledWalk:AB$ Planeswalk | Cost$ 0 -A:AB$ RollPlanarDice | Cost$ X | SorcerySpeed$ True | ActivationZone$ Command | SpellDescription$ Roll the planar dice. -SVar:X:Count$RolledThisTurn SVar:Picture:http://www.wizards.com/global/images/magic/general/undercity_reaches.jpg Oracle:Whenever a creature deals combat damage to a player, its controller may draw a card.\nWhenever you roll {C}, you have no maximum hand size for the rest of the game. SetInfo:HOP Common \ No newline at end of file diff --git a/res/cardsfolder/u/undiscovered_paradise.txt b/res/cardsfolder/u/undiscovered_paradise.txt index de42f5ef3b9..e69b499f04e 100644 --- a/res/cardsfolder/u/undiscovered_paradise.txt +++ b/res/cardsfolder/u/undiscovered_paradise.txt @@ -1,7 +1,7 @@ Name:Undiscovered Paradise ManaCost:no cost Types:Land -A:AB$ Mana | Cost$ T | Produced$ Any | SpellDescription$ Add one mana of any color to your mana pool | SubAbility$ DBReturn +A:AB$ Mana | Cost$ T | Produced$ Any | SpellDescription$ Add one mana of any color to your mana pool. During your next untap step, as you untap your permanents, return Undiscovered Paradise to its owner's hand. | SubAbility$ DBReturn SVar:DBReturn:DB$ Pump | Defined$ Self | KW$ HIDDEN During your next untap step, as you untap your permanents, return CARDNAME to its owner's hand. | Permanent$ True SVar:Picture:http://www.wizards.com/global/images/magic/general/undiscovered_paradise.jpg Oracle:{T}: Add one mana of any color to your mana pool. During your next untap step, as you untap your permanents, return Undiscovered Paradise to its owner's hand. diff --git a/res/cardsfolder/v/velis_vel.txt b/res/cardsfolder/v/velis_vel.txt index 3178a54889b..7b52c3aa5dd 100644 --- a/res/cardsfolder/v/velis_vel.txt +++ b/res/cardsfolder/v/velis_vel.txt @@ -5,10 +5,6 @@ S:Mode$ Continuous | Affected$ Creature | AddPower$ AffectedX | AddToughness$ Af SVar:AffectedX:Count$Valid Creature.sharesCreatureTypeWith+Other T:Mode$ PlanarDice | Result$ Chaos | TriggerZones$ Command | Execute$ RolledChaos | TriggerDescription$ Whenever you roll Chaos, target creature gains all creature types until end of turn. SVar:RolledChaos:AB$ Animate | Cost$ 0 | ValidTgts$ Creature | TgtPrompt$ Select target creature | Types$ AllCreatureTypes -T:Mode$ PlanarDice | Result$ Planeswalk | TriggerZones$ Command | Execute$ RolledWalk | Secondary$ True | TriggerDescription$ Whenever you roll Planeswalk, put this card on the bottom of its owner's planar deck face down, then move the top card of your planar deck off that planar deck and turn it face up -SVar:RolledWalk:AB$ Planeswalk | Cost$ 0 -A:AB$ RollPlanarDice | Cost$ X | SorcerySpeed$ True | ActivationZone$ Command | SpellDescription$ Roll the planar dice. -SVar:X:Count$RolledThisTurn SVar:Picture:http://www.wizards.com/global/images/magic/general/velis_vel.jpg Oracle:Each creature gets +1/+1 for each other creature on the battlefield that shares at least one creature type with it. (For example, if two Elemental Shamans and an Elemental Spirit are on the battlefield, each gets +2/+2.)\nWhenever you roll {C}, target creature gains all creature types until end of turn. SetInfo:HOP Common \ No newline at end of file diff --git a/src/main/java/forge/ImageCache.java b/src/main/java/forge/ImageCache.java index adee70608ba..5997146fd3d 100644 --- a/src/main/java/forge/ImageCache.java +++ b/src/main/java/forge/ImageCache.java @@ -18,8 +18,10 @@ package forge; import java.awt.image.BufferedImage; -import java.io.IOException; +import java.io.File; import java.io.InputStream; +import java.util.HashSet; +import java.util.Set; import java.util.concurrent.ExecutionException; import javax.imageio.ImageIO; @@ -70,22 +72,30 @@ public class ImageCache { public static final String PRECON_PREFIX = "p:"; public static final String TOURNAMENTPACK_PREFIX = "o:"; - static private final LoadingCache CACHE = CacheBuilder.newBuilder().softValues().build(new ImageLoader()); - private static final BufferedImage emptyImage = new BufferedImage(10, 10, BufferedImage.TYPE_INT_ARGB); - private static BufferedImage defaultImage = emptyImage; - static { + private static final Set _missingIconKeys = new HashSet(); + private static final LoadingCache _CACHE = CacheBuilder.newBuilder().softValues().build(new ImageLoader()); + private static final BufferedImage _defaultImage; + static { + BufferedImage defImage = null; try { ClassLoader cl = Thread.currentThread().getContextClassLoader(); InputStream isNoCardJpg = cl.getResourceAsStream("no_card.jpg"); - defaultImage = ImageIO.read(isNoCardJpg); - } catch (IOException e) { - // TODO Auto-generated catch block ignores the exception, but sends it to System.err and probably forge.log. - e.printStackTrace(); + defImage = ImageIO.read(isNoCardJpg); + } catch (Exception e) { + // resource not found; perhaps we're running straight from source + try { + defImage = ImageIO.read(new File("src/main/resources/no_card.jpg")); + } catch (Exception ex) { + System.err.println("could not load default card image"); + } + } finally { + _defaultImage = (null == defImage) ? new BufferedImage(10, 10, BufferedImage.TYPE_INT_ARGB) : defImage; } } public static void clear() { - CACHE.invalidateAll(); + _CACHE.invalidateAll(); + _missingIconKeys.clear(); } /** @@ -99,7 +109,7 @@ public class ImageCache { } else { key = card.getImageKey(); } - return scaleImage(key, width, height); + return scaleImage(key, width, height, true); } /** @@ -107,7 +117,7 @@ public class ImageCache { * and cannot be loaded from disk. pass -1 for width and/or height to avoid resizing in that dimension. */ public static BufferedImage getImage(InventoryItem ii, int width, int height) { - return scaleImage(getImageKey(ii, false), width, height); + return scaleImage(getImageKey(ii, false), width, height, true); } /** @@ -115,40 +125,42 @@ public class ImageCache { * in the cache and cannot be loaded from disk. */ public static ImageIcon getIcon(IHasIcon ihi) { - BufferedImage i = scaleImage(ihi.getIconImageKey(), -1, -1); - if (null == i) { + String imageKey = ihi.getIconImageKey(); + final BufferedImage i; + if (_missingIconKeys.contains(imageKey) || + null == (i = scaleImage(ihi.getIconImageKey(), -1, -1, false))) { + _missingIconKeys.add(imageKey); return FSkin.getIcon(FSkin.InterfaceIcons.ICO_UNKNOWN); } return new ImageIcon(i); } - private static BufferedImage scaleImage(String key, final int width, final int height) { + private static BufferedImage scaleImage(String key, final int width, final int height, boolean useDefaultImage) { if (StringUtils.isEmpty(key) || (3 > width && -1 != width) || (3 > height && -1 != height)) { // picture too small or key not defined; return a blank return null; } - StringBuilder rsKey = new StringBuilder(key); - rsKey.append("#").append(width).append('x').append(height); - String resizedKey = rsKey.toString(); + String resizedKey = String.format("%s#%dx%d", key, width, height); - final BufferedImage cached = CACHE.getIfPresent(resizedKey); + final BufferedImage cached = _CACHE.getIfPresent(resizedKey); if (null != cached) { + //System.out.println("found cached image: " + resizedKey); return cached; } - boolean mayEnlarge = Singletons.getModel().getPreferences().getPrefBoolean(FPref.UI_SCALE_LARGER); BufferedImage original = getImage(key); - if (null == original) { - original = defaultImage; - CACHE.put(key, defaultImage); // This instructs cache to give up finding a picture if it was not found once - } - - if (original == emptyImage) { // the found image is a placeholder for missing picture? - return null; + if (!useDefaultImage) { + return null; + } + + // henceforth use a default picture for this key if image not found + original = _defaultImage; + _CACHE.put(key, _defaultImage); } + boolean mayEnlarge = Singletons.getModel().getPreferences().getPrefBoolean(FPref.UI_SCALE_LARGER); double scale = Math.min( -1 == width ? 1 : (double)width / original.getWidth(), -1 == height? 1 : (double)height / original.getHeight()); @@ -162,12 +174,22 @@ public class ImageCache { } else { int destWidth = (int)(original.getWidth() * scale); int destHeight = (int)(original.getHeight() * scale); - ResampleOp resampler = new ResampleOp(destWidth, destHeight); - result = resampler.filter(original, null); - CACHE.put(resizedKey, result); + // if this scale has been used before, get the cached version instead of rescaling + String effectiveResizedKey = String.format("%s#%dx%d", key, destWidth, destHeight); + result = _CACHE.getIfPresent(effectiveResizedKey); + if (null == result) { + ResampleOp resampler = new ResampleOp(destWidth, destHeight); + result = resampler.filter(original, null); + //System.out.println("caching resized image: " + effectiveResizedKey); + _CACHE.put(effectiveResizedKey, result); + //} else { + // System.out.println("retrieved resized image: " + effectiveResizedKey); + } } + //System.out.println("caching image: " + resizedKey); + _CACHE.put(resizedKey, result); return result; } @@ -176,7 +198,7 @@ public class ImageCache { */ private static BufferedImage getImage(final String key) { try { - return ImageCache.CACHE.get(key); + return ImageCache._CACHE.get(key); } catch (final ExecutionException ex) { if (ex.getCause() instanceof NullPointerException) { return null; diff --git a/src/main/java/forge/card/ability/ai/RegenerateAi.java b/src/main/java/forge/card/ability/ai/RegenerateAi.java index d9c7924f906..42e45397e45 100644 --- a/src/main/java/forge/card/ability/ai/RegenerateAi.java +++ b/src/main/java/forge/card/ability/ai/RegenerateAi.java @@ -148,6 +148,9 @@ public class RegenerateAi extends SpellAbilityAi { } } } + if (tgt.getTargets().isEmpty()) { + return false; + } } return chance; diff --git a/src/main/java/forge/card/cardfactory/CardFactory.java b/src/main/java/forge/card/cardfactory/CardFactory.java index 2f280ccfe6a..2eef426fda5 100644 --- a/src/main/java/forge/card/cardfactory/CardFactory.java +++ b/src/main/java/forge/card/cardfactory/CardFactory.java @@ -27,11 +27,14 @@ import forge.CardCharacteristicName; import forge.CardColor; import forge.CardUtil; import forge.Color; +import forge.Command; +import forge.CounterType; import forge.ImageCache; import forge.card.CardCharacteristics; import forge.card.CardRules; import forge.card.CardSplitType; import forge.card.ICardFace; +import forge.card.ability.AbilityFactory; import forge.card.cost.Cost; import forge.card.mana.ManaCost; import forge.card.replacement.ReplacementHandler; @@ -40,6 +43,7 @@ import forge.card.spellability.AbilitySub; import forge.card.spellability.SpellAbility; import forge.card.spellability.SpellPermanent; import forge.card.spellability.Target; +import forge.card.trigger.Trigger; import forge.card.trigger.TriggerHandler; import forge.game.player.Player; import forge.item.CardDb; @@ -296,20 +300,56 @@ public class CardFactory { if (card.isCreature()) { CardFactoryCreatures.buildCard(card, cardName); } else if (card.isPlaneswalker()) { - CardFactoryPlaneswalkers.buildCard(card); + buildPlaneswalkerAbilities(card); } else if (card.isLand()) { CardFactoryLands.buildCard(card, cardName); } else if (card.isSorcery()) { CardFactorySorceries.buildCard(card, cardName); } else if (card.isArtifact()) { CardFactoryArtifacts.buildCard(card, cardName); + } else if (card.isType("Plane")) { + buildPlaneAbilities(card); } CardFactoryUtil.setupKeywordedAbilities(card); } // getCard2 + private static void buildPlaneAbilities(Card card) { + StringBuilder triggerSB = new StringBuilder(); + triggerSB.append("Mode$ PlanarDice | Result$ Planeswalk | TriggerZones$ Command | Execute$ RolledWalk | "); + triggerSB.append("Secondary$ True | TriggerDescription$ Whenever you roll Planeswalk, put this card on the "); + triggerSB.append("bottom of its owner's planar deck face down, then move the top card of your planar deck off "); + triggerSB.append("that planar deck and turn it face up"); + + StringBuilder saSB = new StringBuilder(); + saSB.append("AB$ RollPlanarDice | Cost$ X | SorcerySpeed$ True | AnyPlayer$ True | ActivationZone$ Command | "); + saSB.append("SpellDescription$ Roll the planar dice. X is equal to the amount of times the planar die has been rolled this turn."); + + card.setSVar("RolledWalk", "DB$ Planeswalk | Cost$ 0"); + Trigger planesWalkTrigger = TriggerHandler.parseTrigger(triggerSB.toString(), card, true); + card.addTrigger(planesWalkTrigger); + + card.setSVar("X", "Count$RolledThisTurn"); + SpellAbility planarRoll = AbilityFactory.getAbility(saSB.toString(), card); + card.addSpellAbility(planarRoll); + } + + private static void buildPlaneswalkerAbilities(Card card) { + if (card.getBaseLoyalty() > 0) { + Command cmd = CardFactoryUtil.entersBattleFieldWithCounters(card, CounterType.LOYALTY, card.getBaseLoyalty()); + card.addComesIntoPlayCommand(cmd); + } + + //Planeswalker damage redirection + card.addReplacementEffect(ReplacementHandler.parseReplacement("Event$ DamageDone | ActiveZones$ Battlefield | IsCombat$ False | ValidSource$ Card.YouDontCtrl" + + " | ValidTarget$ You | Optional$ True | OptionalDecider$ Opponent | ReplaceWith$ DamagePW | Secondary$ True" + + " | AICheckSVar$ DamagePWAI | AISVarCompare$ GT4 | Description$ Redirect damage to " + card.toString(), card)); + card.setSVar("DamagePW", "AB$DealDamage | Cost$ 0 | Defined$ Self | NumDmg$ DamagePWX | DamageSource$ ReplacedSource | References$ DamagePWX,DamagePWAI"); + card.setSVar("DamagePWX", "ReplaceCount$DamageAmount"); + card.setSVar("DamagePWAI", "ReplaceCount$DamageAmount/NMinus.DamagePWY"); + card.setSVar("DamagePWY", "Count$YourLifeTotal"); + } - private static Card readCard(final CardRules rules) { final Card card = new Card(); diff --git a/src/main/java/forge/card/cardfactory/CardFactoryPlaneswalkers.java b/src/main/java/forge/card/cardfactory/CardFactoryPlaneswalkers.java deleted file mode 100644 index 95448bb9640..00000000000 --- a/src/main/java/forge/card/cardfactory/CardFactoryPlaneswalkers.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Forge: Play Magic: the Gathering. - * Copyright (C) 2011 Forge Team - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package forge.card.cardfactory; - -import forge.Card; -import forge.Command; -import forge.CounterType; -import forge.card.replacement.ReplacementHandler; - -/** - *

- * CardFactory_Planeswalkers class. - *

- * - * @author Forge - * @version $Id$ - */ -public class CardFactoryPlaneswalkers { - - /** - *

- * getCard. - *

- * - * @param card - * a {@link forge.Card} object. - * @return a {@link forge.Card} object. - */ - public static void buildCard(final Card card) { - // All Planeswalkers set their loyality in the beginning - if (card.getBaseLoyalty() > 0) { - Command cmd = CardFactoryUtil.entersBattleFieldWithCounters(card, CounterType.LOYALTY, card.getBaseLoyalty()); - card.addComesIntoPlayCommand(cmd); - } - - //Planeswalker damage redirection - card.addReplacementEffect(ReplacementHandler.parseReplacement("Event$ DamageDone | ActiveZones$ Battlefield | IsCombat$ False | ValidSource$ Card.YouDontCtrl" - + " | ValidTarget$ You | Optional$ True | OptionalDecider$ Opponent | ReplaceWith$ DamagePW | Secondary$ True" - + " | AICheckSVar$ DamagePWAI | AISVarCompare$ GT4 | Description$ Redirect damage to " + card.toString(), card)); - card.setSVar("DamagePW", "AB$DealDamage | Cost$ 0 | Defined$ Self | NumDmg$ DamagePWX | DamageSource$ ReplacedSource | References$ DamagePWX,DamagePWAI"); - card.setSVar("DamagePWX", "ReplaceCount$DamageAmount"); - card.setSVar("DamagePWAI", "ReplaceCount$DamageAmount/NMinus.DamagePWY"); - card.setSVar("DamagePWY", "Count$YourLifeTotal"); - } - -} // end class CardFactoryPlaneswalkers diff --git a/src/main/java/forge/card/spellability/Target.java b/src/main/java/forge/card/spellability/Target.java index 4a5727bcb22..c0b835643cd 100644 --- a/src/main/java/forge/card/spellability/Target.java +++ b/src/main/java/forge/card/spellability/Target.java @@ -40,9 +40,22 @@ import forge.game.zone.ZoneType; public class Target { // Target has two things happening: // Targeting restrictions (Creature, Min/Maxm etc) which are true for this - // whole Target + // Target Choices (which is specific for the StackInstance) private Card srcCard; + // What this Object is restricted to targeting + private boolean tgtValid = false; + private String[] validTgts; + private String vtSelection = ""; + private List tgtZone = Arrays.asList(ZoneType.Battlefield); + + //SpellAbility Restrictions + // Comma-separated + private String targetSpellAbilityType = null; + // The target SA of this SA must be targeting a Valid X + private String saValidTargeting = null; + + // Additional restrictions that may not fit into Valid private boolean uniqueTargets = false; private boolean singleZone = false; private boolean differentZone = false; @@ -50,11 +63,108 @@ public class Target { private boolean sameController = false; private boolean withoutSameCreatureType = false; private String definedController = null; + + // How many can be targeted? + private String minTargets; + private String maxTargets; + + // What Choices are actually made for targeting private TargetChoices choice = null; + + // For "Divided" cards. Is this better in TargetChoices? private boolean dividedAsYouChoose = false; private HashMap dividedMap = new HashMap(); private int stillToDivide = 0; + + // Not sure what's up with Mandatory? Why wouldn't targeting be mandatory? + private boolean bMandatory = false; + /** + *

+ * Copy Constructor for Target. + *

+ * + * @param target + * a {@link forge.card.spellability.Target} object. + */ + public Target(final Target target) { + this.tgtValid = true; + this.srcCard = target.getSourceCard(); + this.vtSelection = target.getVTSelection(); + this.validTgts = target.getValidTgts(); + this.minTargets = target.getMinTargets(); + this.maxTargets = target.getMaxTargets(); + this.tgtZone = target.getZone(); + this.targetSpellAbilityType = target.getTargetSpellAbilityType(); + this.saValidTargeting = target.getSAValidTargeting(); + this.dividedAsYouChoose = target.isDividedAsYouChoose(); + this.uniqueTargets = target.isUniqueTargets(); + this.singleZone = target.isSingleZone(); + this.differentControllers = target.isDifferentControllers(); + this.differentZone = target.isDifferentZone(); + this.sameController = target.isSameController(); + this.withoutSameCreatureType = target.isWithoutSameCreatureType(); + this.definedController = target.getDefinedController(); + } + + /** + *

+ * Constructor for Target. + *

+ * + * @param src + * a {@link forge.Card} object. + * @param select + * a {@link java.lang.String} object. + * @param valid + * an array of {@link java.lang.String} objects. + */ + public Target(final Card src, final String select, final String[] valid) { + this(src, select, valid, "1", "1"); + } + + /** + *

+ * Constructor for Target. + *

+ * + * @param src + * a {@link forge.Card} object. + * @param select + * a {@link java.lang.String} object. + * @param valid + * a {@link java.lang.String} object. + */ + public Target(final Card src, final String select, final String valid) { + this(src, select, valid.split(","), "1", "1"); + } + + /** + *

+ * Constructor for Target. + *

+ * + * @param src + * a {@link forge.Card} object. + * @param select + * a {@link java.lang.String} object. + * @param valid + * an array of {@link java.lang.String} objects. + * @param min + * a {@link java.lang.String} object. + * @param max + * a {@link java.lang.String} object. + */ + public Target(final Card src, final String select, final String[] valid, final String min, final String max) { + this.srcCard = src; + this.tgtValid = true; + this.vtSelection = select; + this.validTgts = valid; + + this.minTargets = min; + this.maxTargets = max; + } + /** *

* getSourceCard. @@ -101,8 +211,6 @@ public class Target { this.choice = tc; } - private boolean bMandatory = false; - /** *

* getMandatory. @@ -126,10 +234,6 @@ public class Target { this.bMandatory = m; } - private boolean tgtValid = false; - private String[] validTgts; - private String vtSelection = ""; - /** *

* doesTarget. @@ -163,9 +267,6 @@ public class Target { return this.vtSelection; } - private String minTargets; - private String maxTargets; - /** * Gets the min targets. * @@ -247,8 +348,6 @@ public class Target { return (this.choice != null) && (this.getMinTargets(c, sa) <= this.choice.getNumTargeted()); } - private List tgtZone = Arrays.asList(ZoneType.Battlefield); - /** *

* setZone. @@ -282,10 +381,6 @@ public class Target { return this.tgtZone; } - // Used for Counters. Currently, Spell,Activated,Triggered can be - // Comma-separated - private String targetSpellAbilityType = null; - /** *

* Setter for the field targetSpellAbilityType. @@ -309,9 +404,6 @@ public class Target { return this.targetSpellAbilityType; } - // Used for Counters. The target SA of this SA must be targeting a Valid X - private String saValidTargeting = null; - /** *

* setSAValidTargeting. @@ -448,141 +540,6 @@ public class Target { this.choice = null; } - /** - *

- * Constructor for Target. - *

- * - * @param target - * a {@link forge.card.spellability.Target} object. - */ - public Target(final Target target) { - - this.tgtValid = true; - this.srcCard = target.getSourceCard(); - this.vtSelection = target.getVTSelection(); - this.validTgts = target.getValidTgts(); - this.minTargets = target.getMinTargets(); - this.maxTargets = target.getMaxTargets(); - this.tgtZone = target.getZone(); - this.targetSpellAbilityType = target.getTargetSpellAbilityType(); - } - - /** - *

- * Constructor for Target. - *

- * DEPRECATED!!! This will be removed after 1.3.5 is released - * - * @param src - * a {@link forge.Card} object. - * @param parse - * a {@link java.lang.String} object. - * @param min - * a {@link java.lang.String} object. - * @param max - * a {@link java.lang.String} object. - */ -// @Deprecated -// public Target(final Card src, String parse, final String min, final String max) { -// // parse=Tgt{C}{P} - Primarily used for Pump or Damage -// // C = Creature P=Player/Planeswalker -// // CP = All three -// -// this.tgtValid = true; -// this.srcCard = src; -// -// if (parse.contains("Tgt")) { -// parse = parse.replace("Tgt", ""); -// } -// -// String valid; -// String prompt; -// final StringBuilder sb = new StringBuilder(); -// -// if (parse.equals("CP")) { -// valid = "Creature,Player"; -// prompt = "Select target creature or player"; -// } else if (parse.equals("C")) { -// valid = "Creature"; -// prompt = "Select target creature"; -// } else if (parse.equals("P")) { -// valid = "Player"; -// prompt = "Select player"; -// } else { -// System.out.println("Bad Parsing in Target(parse, min, max): " + parse); -// return; -// } -// -// if (src != null) { -// sb.append(src + " - "); -// } -// sb.append(prompt); -// this.vtSelection = sb.toString(); -// this.validTgts = valid.split(","); -// -// this.minTargets = min; -// this.maxTargets = max; -// } - - /** - *

- * Constructor for Target. - *

- * - * @param src - * a {@link forge.Card} object. - * @param select - * a {@link java.lang.String} object. - * @param valid - * an array of {@link java.lang.String} objects. - */ - public Target(final Card src, final String select, final String[] valid) { - this(src, select, valid, "1", "1"); - } - - /** - *

- * Constructor for Target. - *

- * - * @param src - * a {@link forge.Card} object. - * @param select - * a {@link java.lang.String} object. - * @param valid - * a {@link java.lang.String} object. - */ - public Target(final Card src, final String select, final String valid) { - this(src, select, valid.split(","), "1", "1"); - } - - /** - *

- * Constructor for Target. - *

- * - * @param src - * a {@link forge.Card} object. - * @param select - * a {@link java.lang.String} object. - * @param valid - * an array of {@link java.lang.String} objects. - * @param min - * a {@link java.lang.String} object. - * @param max - * a {@link java.lang.String} object. - */ - public Target(final Card src, final String select, final String[] valid, final String min, final String max) { - this.srcCard = src; - this.tgtValid = true; - this.vtSelection = select; - this.validTgts = valid; - - this.minTargets = min; - this.maxTargets = max; - } - /** *

* getTargetedString.