diff --git a/Mage.Client/release/sample-decks/Planeswalk Decks/Ajani, Valiant Protector.dck b/Mage.Client/release/sample-decks/Planeswalk Decks/Ajani, Valiant Protector.dck new file mode 100644 index 00000000000..2ffcb886d62 --- /dev/null +++ b/Mage.Client/release/sample-decks/Planeswalk Decks/Ajani, Valiant Protector.dck @@ -0,0 +1,27 @@ +3 [AER:173] Renegade Map +2 [KLD:144] Armorcraft Judge +9 [KLD:263] Forest +1 [KLD:181] Engineered Might +1 [AER:149] Daredevil Dragster +1 [AER:105] Aid from the Cowl +3 [AER:7] Audacious Infiltrator +1 [AER:5] Airdrop Aeronauts +4 [AER:189] Tranquil Expanse +1 [AER:22] Solemn Recruit +2 [AER:126] Unbridled Growth +2 [AER:125] Silkweaver Elite +1 [AER:120] Prey Upon +4 [AER:186] Inspiring Roar +1 [AER:185] Ajani, Valiant Protector +2 [AER:188] Ajani's Aid +3 [AER:187] Ajani's Comrade +1 [AER:121] Ridgescale Tusker +9 [KLD:250] Plains +1 [KLD:156] Ghirapur Guide +2 [AER:180] Verdant Automaton +1 [AER:15] Deadeye Harpooner +2 [AER:117] Narnam Renegade +1 [AER:118] Natural Obsolescence +2 [AER:113] Lifecraft Cavalry +LAYOUT MAIN:(1,7)(CMC,false,50)|([KLD:263],[KLD:263],[KLD:263],[KLD:263],[KLD:263],[KLD:263],[KLD:263],[KLD:263],[KLD:263],[KLD:250],[KLD:250],[KLD:250],[KLD:250],[KLD:250],[KLD:250],[KLD:250],[KLD:250],[KLD:250],[AER:189],[AER:189],[AER:189],[AER:189])([AER:117],[AER:117],[AER:120],[AER:173],[AER:173],[AER:173],[AER:126],[AER:126])([AER:187],[AER:187],[AER:187],[AER:7],[AER:7],[AER:7],[AER:118],[AER:180],[AER:180])([AER:149],[AER:15],[KLD:156],[AER:125],[AER:125],[AER:22])([AER:188],[AER:188],[KLD:144],[KLD:144],[AER:186],[AER:186],[AER:186],[AER:186])([AER:105],[AER:5],[KLD:181],[AER:113],[AER:113],[AER:121])([AER:185]) +LAYOUT SIDEBOARD:(0,0)(NONE,false,50)| diff --git a/Mage.Client/release/sample-decks/Planeswalk Decks/Chandra, Pyrogenius.dck b/Mage.Client/release/sample-decks/Planeswalk Decks/Chandra, Pyrogenius.dck new file mode 100644 index 00000000000..29dd1db50a1 --- /dev/null +++ b/Mage.Client/release/sample-decks/Planeswalk Decks/Chandra, Pyrogenius.dck @@ -0,0 +1,27 @@ +11 [KLD:261] Mountain +1 [KLD:265] Chandra, Pyrogenius +2 [KLD:188] Veteran Motorist +4 [KLD:266] Flame Lash +1 [KLD:28] Skyswirl Harrier +1 [KLD:225] Ovalchase Dragster +2 [KLD:267] Liberating Combustion +3 [KLD:268] Renegade Firebrand +4 [AKH:274] Stone Quarry +1 [KLD:109] Cathartic Reunion +1 [KLD:107] Brazen Scourge +10 [KLD:250] Plains +2 [KLD:133] Spireside Infiltrator +2 [KLD:233] Sky Skiff +2 [KLD:230] Renegade Freighter +1 [KLD:132] Speedway Fanatic +2 [KLD:33] Trusty Companion +1 [KLD:198] Bomat Bazaar Barge +1 [KLD:16] Gearshift Ace +2 [KLD:2] Aerial Responder +2 [KLD:7] Built to Last +1 [KLD:236] Snare Thopter +1 [KLD:214] Fleetwheel Cruiser +1 [KLD:114] Fateful Showdown +1 [KLD:238] Weldfast Monitor +LAYOUT MAIN:(1,7)(CMC,false,50)|([KLD:261],[KLD:261],[KLD:261],[KLD:261],[KLD:261],[KLD:261],[KLD:261],[KLD:261],[KLD:261],[KLD:261],[KLD:261],[KLD:250],[KLD:250],[KLD:250],[KLD:250],[KLD:250],[KLD:250],[KLD:250],[KLD:250],[KLD:250],[KLD:250],[AKH:274],[AKH:274],[AKH:274],[AKH:274])([KLD:7],[KLD:7])([KLD:109],[KLD:16],[KLD:233],[KLD:233],[KLD:132],[KLD:33],[KLD:33],[KLD:188],[KLD:188])([KLD:2],[KLD:2],[KLD:107],[KLD:268],[KLD:268],[KLD:268],[KLD:230],[KLD:230],[KLD:133],[KLD:133],[KLD:238])([KLD:198],[KLD:114],[KLD:266],[KLD:266],[KLD:266],[KLD:266],[KLD:214],[KLD:225],[KLD:236])([KLD:267],[KLD:267],[KLD:28])([KLD:265]) +LAYOUT SIDEBOARD:(0,0)(NONE,false,50)| diff --git a/Mage.Client/release/sample-decks/Planeswalk Decks/Gideon, Martial Paragon.dck b/Mage.Client/release/sample-decks/Planeswalk Decks/Gideon, Martial Paragon.dck new file mode 100644 index 00000000000..1b296855a27 --- /dev/null +++ b/Mage.Client/release/sample-decks/Planeswalk Decks/Gideon, Martial Paragon.dck @@ -0,0 +1,24 @@ +1 [AKH:270] Gideon, Martial Paragon +2 [AKH:272] Gideon's Resolve +10 [AKH:250] Plains +3 [AKH:271] Companion of the Trials +1 [AKH:10] Devoted Crop-Mate +1 [AKH:31] Tah-Crop Elite +2 [AKH:29] Sparring Mummy +1 [AKH:18] Impeccable Timing +3 [AKH:17] Gust Walker +1 [AKH:16] Glory-Bound Initiate +3 [AKH:117] Ahn-Crop Crasher +2 [AKH:139] Hyena Pack +2 [AKH:129] Electrify +1 [AKH:146] Pathmaker Initiate +2 [AKH:124] Cartouche of Zeal +2 [AKH:200] Honored Crop-Captain +1 [AKH:137] Hazoret's Favor +4 [AKH:274] Stone Quarry +4 [AKH:273] Graceful Cat +3 [AKH:152] Trial of Zeal +1 [AKH:144] Nef-Crop Entangler +10 [AKH:253] Mountain +LAYOUT MAIN:(1,6)(CMC,false,50)|([AKH:274],[AKH:274],[AKH:274],[AKH:274],[AKH:250],[AKH:250],[AKH:250],[AKH:250],[AKH:250],[AKH:250],[AKH:250],[AKH:250],[AKH:250],[AKH:250],[AKH:253],[AKH:253],[AKH:253],[AKH:253],[AKH:253],[AKH:253],[AKH:253],[AKH:253],[AKH:253],[AKH:253])([AKH:124],[AKH:124])([AKH:16],[AKH:17],[AKH:17],[AKH:17],[AKH:144],[AKH:146],[AKH:200],[AKH:200],[AKH:18])([AKH:271],[AKH:271],[AKH:271],[AKH:10],[AKH:273],[AKH:273],[AKH:273],[AKH:273],[AKH:117],[AKH:117],[AKH:117],[AKH:137],[AKH:152],[AKH:152],[AKH:152])([AKH:29],[AKH:29],[AKH:31],[AKH:139],[AKH:139],[AKH:129],[AKH:129])([AKH:270],[AKH:272],[AKH:272]) +LAYOUT SIDEBOARD:(0,0)(NONE,false,50)| diff --git a/Mage.Client/release/sample-decks/Planeswalk Decks/Liliana, Death Wielder.dck b/Mage.Client/release/sample-decks/Planeswalk Decks/Liliana, Death Wielder.dck new file mode 100644 index 00000000000..a559eca3798 --- /dev/null +++ b/Mage.Client/release/sample-decks/Planeswalk Decks/Liliana, Death Wielder.dck @@ -0,0 +1,26 @@ +1 [AKH:160] Channeler Initiate +1 [AKH:91] Festering Mummy +1 [AKH:162] Crocodile of the Crossing +2 [AKH:89] Dune Beetle +2 [AKH:83] Cartouche of Ambition +2 [AKH:93] Gravedigger +2 [AKH:109] Splendid Agony +1 [AKH:226] Edifice of Authority +2 [AKH:79] Baleful Ammit +4 [AKH:278] Tattered Mummy +1 [AKH:234] Oracle's Vault +2 [AKH:113] Trial of Ambition +2 [AKH:277] Liliana's Influence +1 [AKH:167] Gift of Paradise +1 [AKH:244] Grasping Dunes +2 [AKH:158] Cartouche of Strength +4 [AKH:279] Foul Orchard +2 [AKH:197] Decimator Beetle +11 [AKH:252] Swamp +3 [AKH:276] Desiccated Naga +2 [AKH:166] Giant Spider +1 [AKH:232] Luxa River Shrine +9 [AKH:254] Forest +1 [AKH:275] Liliana, Death Wielder +LAYOUT MAIN:(1,8)(CMC,false,50)|([AKH:254],[AKH:254],[AKH:254],[AKH:254],[AKH:254],[AKH:254],[AKH:254],[AKH:254],[AKH:254],[AKH:279],[AKH:279],[AKH:279],[AKH:279],[AKH:244],[AKH:252],[AKH:252],[AKH:252],[AKH:252],[AKH:252],[AKH:252],[AKH:252],[AKH:252],[AKH:252],[AKH:252],[AKH:252])([AKH:91])([AKH:160],[AKH:89],[AKH:89],[AKH:278],[AKH:278],[AKH:278],[AKH:278],[AKH:113],[AKH:113])([AKH:79],[AKH:79],[AKH:83],[AKH:83],[AKH:158],[AKH:158],[AKH:276],[AKH:276],[AKH:276],[AKH:226],[AKH:167],[AKH:232],[AKH:109],[AKH:109])([AKH:162],[AKH:166],[AKH:166],[AKH:93],[AKH:93],[AKH:234])([AKH:197],[AKH:197])([AKH:277],[AKH:277])([AKH:275]) +LAYOUT SIDEBOARD:(0,0)(NONE,false,50)| diff --git a/Mage.Client/release/sample-decks/Planeswalk Decks/Nissa, Nature's Artisan.dck b/Mage.Client/release/sample-decks/Planeswalk Decks/Nissa, Nature's Artisan.dck new file mode 100644 index 00000000000..e67fcf5bf2a --- /dev/null +++ b/Mage.Client/release/sample-decks/Planeswalk Decks/Nissa, Nature's Artisan.dck @@ -0,0 +1,24 @@ +4 [KLD:272] Terrain Elemental +2 [KLD:273] Verdant Crescendo +2 [KLD:141] Appetite for the Unnatural +1 [KLD:270] Nissa, Nature's Artisan +2 [KLD:171] Thriving Rhino +2 [KLD:161] Longtusk Cub +3 [KLD:271] Guardian of the Great Conduit +2 [KLD:53] Janjeet Sentry +1 [KLD:167] Riparian Tiger +3 [KLD:145] Attune with Aether +2 [KLD:54] Long-Finned Skywhale +2 [KLD:142] Arborback Stomper +4 [KLD:274] Woodland Stream +11 [KLD:263] Forest +2 [KLD:66] Thriving Turtle +2 [KLD:55] Malfunction +8 [KLD:253] Island +2 [KLD:180] Empyreal Voyager +1 [KLD:39] Aethersquall Ancient +1 [KLD:168] Sage of Shaila's Claim +2 [KLD:169] Servant of the Conduit +1 [KLD:147] Bristling Hydra +LAYOUT MAIN:(1,8)(CMC,false,50)|([KLD:263],[KLD:263],[KLD:263],[KLD:263],[KLD:263],[KLD:263],[KLD:263],[KLD:263],[KLD:263],[KLD:263],[KLD:263],[KLD:253],[KLD:253],[KLD:253],[KLD:253],[KLD:253],[KLD:253],[KLD:253],[KLD:253],[KLD:274],[KLD:274],[KLD:274],[KLD:274])([KLD:145],[KLD:145],[KLD:145],[KLD:66],[KLD:66])([KLD:161],[KLD:161],[KLD:168],[KLD:169],[KLD:169],[KLD:272],[KLD:272],[KLD:272],[KLD:272])([KLD:141],[KLD:141],[KLD:180],[KLD:180],[KLD:53],[KLD:53],[KLD:171],[KLD:171])([KLD:147],[KLD:271],[KLD:271],[KLD:271],[KLD:54],[KLD:54],[KLD:55],[KLD:55],[KLD:273],[KLD:273])([KLD:142],[KLD:142],[KLD:167])([KLD:270])([KLD:39]) +LAYOUT SIDEBOARD:(0,0)(NONE,false,50)| diff --git a/Mage.Client/release/sample-decks/Planeswalk Decks/Tezzeret, Master of Metal.dck b/Mage.Client/release/sample-decks/Planeswalk Decks/Tezzeret, Master of Metal.dck new file mode 100644 index 00000000000..48ecec315ff --- /dev/null +++ b/Mage.Client/release/sample-decks/Planeswalk Decks/Tezzeret, Master of Metal.dck @@ -0,0 +1,27 @@ +3 [AER:193] Tezzeret's Simulacrum +4 [AER:192] Pendulum of Patterns +1 [AER:151] Foundry Assembler +4 [AER:194] Submerged Boneyard +2 [AER:191] Tezzeret's Betrayal +1 [AER:190] Tezzeret, Master of Metal +1 [AER:42] Reverse Engineer +1 [AER:167] Ornithopter +1 [AER:65] Ironclad Revolutionary +1 [KLD:207] Dukhara Peafowl +1 [AER:163] Merchant's Dockhand +1 [AER:144] Barricade Breaker +2 [AER:143] Augmenting Automaton +1 [AER:41] Quicksmith Spy +2 [KLD:74] Dhund Operative +1 [AER:58] Fen Hauler +11 [KLD:253] Island +2 [AER:138] Tezzeret's Touch +10 [KLD:258] Swamp +2 [AER:178] Universal Solvent +2 [AER:156] Implement of Examination +2 [AER:50] Wind-Kin Raiders +1 [AER:177] Treasure Keeper +2 [AER:30] Bastion Inventor +1 [KLD:80] Essence Extraction +LAYOUT MAIN:(1,8)(CMC,false,50)|([KLD:253],[KLD:253],[KLD:253],[KLD:253],[KLD:253],[KLD:253],[KLD:253],[KLD:253],[KLD:253],[KLD:253],[KLD:253],[AER:167],[AER:194],[AER:194],[AER:194],[AER:194],[KLD:258],[KLD:258],[KLD:258],[KLD:258],[KLD:258],[KLD:258],[KLD:258],[KLD:258],[KLD:258],[KLD:258])([AER:143],[AER:143],[AER:163],[AER:178],[AER:178])([KLD:74],[KLD:74],[AER:192],[AER:192],[AER:192],[AER:192])([KLD:80],[AER:156],[AER:156],[AER:193],[AER:193],[AER:193],[AER:138],[AER:138])([KLD:207],[AER:41],[AER:177])([AER:151],[AER:42],[AER:191],[AER:191])([AER:30],[AER:30],[AER:65],[AER:190],[AER:50],[AER:50])([AER:144],[AER:58]) +LAYOUT SIDEBOARD:(0,0)(NONE,false,50)| diff --git a/Mage.Client/src/main/resources/image.url.properties b/Mage.Client/src/main/resources/image.url.properties index ef7b0ec9ff1..031ea1e4168 100644 --- a/Mage.Client/src/main/resources/image.url.properties +++ b/Mage.Client/src/main/resources/image.url.properties @@ -74,6 +74,6 @@ dd3evg=ddaevg dd3gvl=ddagvl dd3jvc=ddajvc # Remove setname as soon as the images can be downloaded -ignore.urls=TOK,PCA,ANB,HOU,C17 +ignore.urls=TOK,PCA,ANB,HOU,C17,IMA # sets ordered by release time (newest goes first) -token.lookup.order=C17,ANB,HOU,MM3,DDS,AKH,DD3DVD,DD3EVG,DD3GVL,DD3JVC,H09,AER,PCA,C16,V16,MPS,KLD,DDR,CN2,EMN,EMA,SOI,DDQ,CP,CMA,ARENA,SUS,APAC,EURO,UGIN,C15,OGW,EXP,DDP,BFZ,DRB,V09,V10,V11,V12,V13,V14,V15,TPR,MPRP,DD3,DDO,ORI,MM2,PTC,DTK,FRF,KTK,M15,VMA,CNS,JOU,BNG,THS,DDL,M14,MMA,DGM,GTC,RTR,M13,AVR,DDI,DKA,ISD,M12,NPH,MBS,SOM,M11,ROE,DDE,WWK,ZEN,M10,GVL,ARB,DVD,CFX,JVC,ALA,EVE,SHM,EVG,MOR,LRW,10E,CLS,CHK,GRC \ No newline at end of file +token.lookup.order=IMA,C17,ANB,HOU,MM3,DDS,AKH,DD3DVD,DD3EVG,DD3GVL,DD3JVC,H09,AER,PCA,C16,V16,MPS,KLD,DDR,CN2,EMN,EMA,SOI,DDQ,CP,CMA,ARENA,SUS,APAC,EURO,UGIN,C15,OGW,EXP,DDP,BFZ,DRB,V09,V10,V11,V12,V13,V14,V15,TPR,MPRP,DD3,DDO,ORI,MM2,PTC,DTK,FRF,KTK,M15,VMA,CNS,JOU,BNG,THS,DDL,M14,MMA,DGM,GTC,RTR,M13,AVR,DDI,DKA,ISD,M12,NPH,MBS,SOM,M11,ROE,DDE,WWK,ZEN,M10,GVL,ARB,DVD,CFX,JVC,ALA,EVE,SHM,EVG,MOR,LRW,10E,CLS,CHK,GRC \ No newline at end of file diff --git a/Mage.Common/src/mage/cards/CardBorder.java b/Mage.Common/src/main/java/mage/cards/CardBorder.java similarity index 100% rename from Mage.Common/src/mage/cards/CardBorder.java rename to Mage.Common/src/main/java/mage/cards/CardBorder.java diff --git a/Mage.Common/src/mage/cards/CardDimensions.java b/Mage.Common/src/main/java/mage/cards/CardDimensions.java similarity index 100% rename from Mage.Common/src/mage/cards/CardDimensions.java rename to Mage.Common/src/main/java/mage/cards/CardDimensions.java diff --git a/Mage.Common/src/mage/cards/MageCard.java b/Mage.Common/src/main/java/mage/cards/MageCard.java similarity index 100% rename from Mage.Common/src/mage/cards/MageCard.java rename to Mage.Common/src/main/java/mage/cards/MageCard.java diff --git a/Mage.Common/src/mage/cards/MagePermanent.java b/Mage.Common/src/main/java/mage/cards/MagePermanent.java similarity index 100% rename from Mage.Common/src/mage/cards/MagePermanent.java rename to Mage.Common/src/main/java/mage/cards/MagePermanent.java diff --git a/Mage.Common/src/mage/cards/TextPopup.form b/Mage.Common/src/main/java/mage/cards/TextPopup.form similarity index 100% rename from Mage.Common/src/mage/cards/TextPopup.form rename to Mage.Common/src/main/java/mage/cards/TextPopup.form diff --git a/Mage.Common/src/mage/cards/TextPopup.java b/Mage.Common/src/main/java/mage/cards/TextPopup.java similarity index 100% rename from Mage.Common/src/mage/cards/TextPopup.java rename to Mage.Common/src/main/java/mage/cards/TextPopup.java diff --git a/Mage.Common/src/mage/cards/action/ActionCallback.java b/Mage.Common/src/main/java/mage/cards/action/ActionCallback.java similarity index 100% rename from Mage.Common/src/mage/cards/action/ActionCallback.java rename to Mage.Common/src/main/java/mage/cards/action/ActionCallback.java diff --git a/Mage.Common/src/mage/cards/action/TransferData.java b/Mage.Common/src/main/java/mage/cards/action/TransferData.java similarity index 100% rename from Mage.Common/src/mage/cards/action/TransferData.java rename to Mage.Common/src/main/java/mage/cards/action/TransferData.java diff --git a/Mage.Common/src/mage/cards/action/impl/EmptyCallback.java b/Mage.Common/src/main/java/mage/cards/action/impl/EmptyCallback.java similarity index 100% rename from Mage.Common/src/mage/cards/action/impl/EmptyCallback.java rename to Mage.Common/src/main/java/mage/cards/action/impl/EmptyCallback.java diff --git a/Mage.Common/src/mage/components/CardInfoPane.java b/Mage.Common/src/main/java/mage/components/CardInfoPane.java similarity index 100% rename from Mage.Common/src/mage/components/CardInfoPane.java rename to Mage.Common/src/main/java/mage/components/CardInfoPane.java diff --git a/Mage.Common/src/mage/components/ImagePanel.java b/Mage.Common/src/main/java/mage/components/ImagePanel.java similarity index 100% rename from Mage.Common/src/mage/components/ImagePanel.java rename to Mage.Common/src/main/java/mage/components/ImagePanel.java diff --git a/Mage.Common/src/mage/components/ImagePanelStyle.java b/Mage.Common/src/main/java/mage/components/ImagePanelStyle.java similarity index 100% rename from Mage.Common/src/mage/components/ImagePanelStyle.java rename to Mage.Common/src/main/java/mage/components/ImagePanelStyle.java diff --git a/Mage.Common/src/mage/constants/Constants.java b/Mage.Common/src/main/java/mage/constants/Constants.java similarity index 100% rename from Mage.Common/src/mage/constants/Constants.java rename to Mage.Common/src/main/java/mage/constants/Constants.java diff --git a/Mage.Common/src/mage/db/EntityManager.java b/Mage.Common/src/main/java/mage/db/EntityManager.java similarity index 100% rename from Mage.Common/src/mage/db/EntityManager.java rename to Mage.Common/src/main/java/mage/db/EntityManager.java diff --git a/Mage.Common/src/mage/db/EntityManagerTest.java b/Mage.Common/src/main/java/mage/db/EntityManagerTest.java similarity index 100% rename from Mage.Common/src/mage/db/EntityManagerTest.java rename to Mage.Common/src/main/java/mage/db/EntityManagerTest.java diff --git a/Mage.Common/src/mage/db/Statistics.java b/Mage.Common/src/main/java/mage/db/Statistics.java similarity index 100% rename from Mage.Common/src/mage/db/Statistics.java rename to Mage.Common/src/main/java/mage/db/Statistics.java diff --git a/Mage.Common/src/mage/db/model/Feedback.java b/Mage.Common/src/main/java/mage/db/model/Feedback.java similarity index 100% rename from Mage.Common/src/mage/db/model/Feedback.java rename to Mage.Common/src/main/java/mage/db/model/Feedback.java diff --git a/Mage.Common/src/mage/db/model/Log.java b/Mage.Common/src/main/java/mage/db/model/Log.java similarity index 100% rename from Mage.Common/src/mage/db/model/Log.java rename to Mage.Common/src/main/java/mage/db/model/Log.java diff --git a/Mage.Common/src/mage/filters/MageBufferedImageOp.java b/Mage.Common/src/main/java/mage/filters/MageBufferedImageOp.java similarity index 100% rename from Mage.Common/src/mage/filters/MageBufferedImageOp.java rename to Mage.Common/src/main/java/mage/filters/MageBufferedImageOp.java diff --git a/Mage.Common/src/mage/interfaces/Action.java b/Mage.Common/src/main/java/mage/interfaces/Action.java similarity index 100% rename from Mage.Common/src/mage/interfaces/Action.java rename to Mage.Common/src/main/java/mage/interfaces/Action.java diff --git a/Mage.Common/src/mage/interfaces/ActionWithResult.java b/Mage.Common/src/main/java/mage/interfaces/ActionWithResult.java similarity index 100% rename from Mage.Common/src/mage/interfaces/ActionWithResult.java rename to Mage.Common/src/main/java/mage/interfaces/ActionWithResult.java diff --git a/Mage.Common/src/mage/interfaces/MageClient.java b/Mage.Common/src/main/java/mage/interfaces/MageClient.java similarity index 100% rename from Mage.Common/src/mage/interfaces/MageClient.java rename to Mage.Common/src/main/java/mage/interfaces/MageClient.java diff --git a/Mage.Common/src/mage/interfaces/MageServer.java b/Mage.Common/src/main/java/mage/interfaces/MageServer.java similarity index 100% rename from Mage.Common/src/mage/interfaces/MageServer.java rename to Mage.Common/src/main/java/mage/interfaces/MageServer.java diff --git a/Mage.Common/src/mage/interfaces/PluginException.java b/Mage.Common/src/main/java/mage/interfaces/PluginException.java similarity index 100% rename from Mage.Common/src/mage/interfaces/PluginException.java rename to Mage.Common/src/main/java/mage/interfaces/PluginException.java diff --git a/Mage.Common/src/mage/interfaces/ServerState.java b/Mage.Common/src/main/java/mage/interfaces/ServerState.java similarity index 100% rename from Mage.Common/src/mage/interfaces/ServerState.java rename to Mage.Common/src/main/java/mage/interfaces/ServerState.java diff --git a/Mage.Common/src/mage/interfaces/callback/CallbackClient.java b/Mage.Common/src/main/java/mage/interfaces/callback/CallbackClient.java similarity index 100% rename from Mage.Common/src/mage/interfaces/callback/CallbackClient.java rename to Mage.Common/src/main/java/mage/interfaces/callback/CallbackClient.java diff --git a/Mage.Common/src/mage/interfaces/callback/ClientCallback.java b/Mage.Common/src/main/java/mage/interfaces/callback/ClientCallback.java similarity index 100% rename from Mage.Common/src/mage/interfaces/callback/ClientCallback.java rename to Mage.Common/src/main/java/mage/interfaces/callback/ClientCallback.java diff --git a/Mage.Common/src/mage/interfaces/callback/ClientCallbackMethod.java b/Mage.Common/src/main/java/mage/interfaces/callback/ClientCallbackMethod.java similarity index 100% rename from Mage.Common/src/mage/interfaces/callback/ClientCallbackMethod.java rename to Mage.Common/src/main/java/mage/interfaces/callback/ClientCallbackMethod.java diff --git a/Mage.Common/src/mage/interfaces/plugin/CardPlugin.java b/Mage.Common/src/main/java/mage/interfaces/plugin/CardPlugin.java similarity index 100% rename from Mage.Common/src/mage/interfaces/plugin/CardPlugin.java rename to Mage.Common/src/main/java/mage/interfaces/plugin/CardPlugin.java diff --git a/Mage.Common/src/mage/interfaces/plugin/CounterPlugin.java b/Mage.Common/src/main/java/mage/interfaces/plugin/CounterPlugin.java similarity index 100% rename from Mage.Common/src/mage/interfaces/plugin/CounterPlugin.java rename to Mage.Common/src/main/java/mage/interfaces/plugin/CounterPlugin.java diff --git a/Mage.Common/src/mage/interfaces/plugin/ThemePlugin.java b/Mage.Common/src/main/java/mage/interfaces/plugin/ThemePlugin.java similarity index 100% rename from Mage.Common/src/mage/interfaces/plugin/ThemePlugin.java rename to Mage.Common/src/main/java/mage/interfaces/plugin/ThemePlugin.java diff --git a/Mage.Common/src/mage/interfaces/rate/RateCallback.java b/Mage.Common/src/main/java/mage/interfaces/rate/RateCallback.java similarity index 100% rename from Mage.Common/src/mage/interfaces/rate/RateCallback.java rename to Mage.Common/src/main/java/mage/interfaces/rate/RateCallback.java diff --git a/Mage.Common/src/mage/remote/Connection.java b/Mage.Common/src/main/java/mage/remote/Connection.java similarity index 100% rename from Mage.Common/src/mage/remote/Connection.java rename to Mage.Common/src/main/java/mage/remote/Connection.java diff --git a/Mage.Common/src/mage/remote/MageRemoteException.java b/Mage.Common/src/main/java/mage/remote/MageRemoteException.java similarity index 100% rename from Mage.Common/src/mage/remote/MageRemoteException.java rename to Mage.Common/src/main/java/mage/remote/MageRemoteException.java diff --git a/Mage.Common/src/mage/remote/MageVersionException.java b/Mage.Common/src/main/java/mage/remote/MageVersionException.java similarity index 100% rename from Mage.Common/src/mage/remote/MageVersionException.java rename to Mage.Common/src/main/java/mage/remote/MageVersionException.java diff --git a/Mage.Common/src/mage/remote/Session.java b/Mage.Common/src/main/java/mage/remote/Session.java similarity index 100% rename from Mage.Common/src/mage/remote/Session.java rename to Mage.Common/src/main/java/mage/remote/Session.java diff --git a/Mage.Common/src/mage/remote/SessionImpl.java b/Mage.Common/src/main/java/mage/remote/SessionImpl.java similarity index 100% rename from Mage.Common/src/mage/remote/SessionImpl.java rename to Mage.Common/src/main/java/mage/remote/SessionImpl.java diff --git a/Mage.Common/src/mage/remote/interfaces/ChatSession.java b/Mage.Common/src/main/java/mage/remote/interfaces/ChatSession.java similarity index 100% rename from Mage.Common/src/mage/remote/interfaces/ChatSession.java rename to Mage.Common/src/main/java/mage/remote/interfaces/ChatSession.java diff --git a/Mage.Common/src/mage/remote/interfaces/ClientData.java b/Mage.Common/src/main/java/mage/remote/interfaces/ClientData.java similarity index 100% rename from Mage.Common/src/mage/remote/interfaces/ClientData.java rename to Mage.Common/src/main/java/mage/remote/interfaces/ClientData.java diff --git a/Mage.Common/src/mage/remote/interfaces/Connect.java b/Mage.Common/src/main/java/mage/remote/interfaces/Connect.java similarity index 100% rename from Mage.Common/src/mage/remote/interfaces/Connect.java rename to Mage.Common/src/main/java/mage/remote/interfaces/Connect.java diff --git a/Mage.Common/src/mage/remote/interfaces/Feedback.java b/Mage.Common/src/main/java/mage/remote/interfaces/Feedback.java similarity index 100% rename from Mage.Common/src/mage/remote/interfaces/Feedback.java rename to Mage.Common/src/main/java/mage/remote/interfaces/Feedback.java diff --git a/Mage.Common/src/mage/remote/interfaces/GamePlay.java b/Mage.Common/src/main/java/mage/remote/interfaces/GamePlay.java similarity index 100% rename from Mage.Common/src/mage/remote/interfaces/GamePlay.java rename to Mage.Common/src/main/java/mage/remote/interfaces/GamePlay.java diff --git a/Mage.Common/src/mage/remote/interfaces/GameTypes.java b/Mage.Common/src/main/java/mage/remote/interfaces/GameTypes.java similarity index 100% rename from Mage.Common/src/mage/remote/interfaces/GameTypes.java rename to Mage.Common/src/main/java/mage/remote/interfaces/GameTypes.java diff --git a/Mage.Common/src/mage/remote/interfaces/PlayerActions.java b/Mage.Common/src/main/java/mage/remote/interfaces/PlayerActions.java similarity index 100% rename from Mage.Common/src/mage/remote/interfaces/PlayerActions.java rename to Mage.Common/src/main/java/mage/remote/interfaces/PlayerActions.java diff --git a/Mage.Common/src/mage/remote/interfaces/Replays.java b/Mage.Common/src/main/java/mage/remote/interfaces/Replays.java similarity index 100% rename from Mage.Common/src/mage/remote/interfaces/Replays.java rename to Mage.Common/src/main/java/mage/remote/interfaces/Replays.java diff --git a/Mage.Common/src/mage/remote/interfaces/ServerState.java b/Mage.Common/src/main/java/mage/remote/interfaces/ServerState.java similarity index 100% rename from Mage.Common/src/mage/remote/interfaces/ServerState.java rename to Mage.Common/src/main/java/mage/remote/interfaces/ServerState.java diff --git a/Mage.Common/src/mage/remote/interfaces/Testable.java b/Mage.Common/src/main/java/mage/remote/interfaces/Testable.java similarity index 100% rename from Mage.Common/src/mage/remote/interfaces/Testable.java rename to Mage.Common/src/main/java/mage/remote/interfaces/Testable.java diff --git a/Mage.Common/src/mage/remote/traffic/ZippedObject.java b/Mage.Common/src/main/java/mage/remote/traffic/ZippedObject.java similarity index 100% rename from Mage.Common/src/mage/remote/traffic/ZippedObject.java rename to Mage.Common/src/main/java/mage/remote/traffic/ZippedObject.java diff --git a/Mage.Common/src/mage/remote/traffic/ZippedObjectImpl.java b/Mage.Common/src/main/java/mage/remote/traffic/ZippedObjectImpl.java similarity index 100% rename from Mage.Common/src/mage/remote/traffic/ZippedObjectImpl.java rename to Mage.Common/src/main/java/mage/remote/traffic/ZippedObjectImpl.java diff --git a/Mage.Common/src/mage/utils/ActionWithBooleanResult.java b/Mage.Common/src/main/java/mage/utils/ActionWithBooleanResult.java similarity index 100% rename from Mage.Common/src/mage/utils/ActionWithBooleanResult.java rename to Mage.Common/src/main/java/mage/utils/ActionWithBooleanResult.java diff --git a/Mage.Common/src/mage/utils/ActionWithNullNegativeResult.java b/Mage.Common/src/main/java/mage/utils/ActionWithNullNegativeResult.java similarity index 100% rename from Mage.Common/src/mage/utils/ActionWithNullNegativeResult.java rename to Mage.Common/src/main/java/mage/utils/ActionWithNullNegativeResult.java diff --git a/Mage.Common/src/mage/utils/ActionWithTableViewResult.java b/Mage.Common/src/main/java/mage/utils/ActionWithTableViewResult.java similarity index 100% rename from Mage.Common/src/mage/utils/ActionWithTableViewResult.java rename to Mage.Common/src/main/java/mage/utils/ActionWithTableViewResult.java diff --git a/Mage.Common/src/mage/utils/ActionWithUUIDResult.java b/Mage.Common/src/main/java/mage/utils/ActionWithUUIDResult.java similarity index 100% rename from Mage.Common/src/mage/utils/ActionWithUUIDResult.java rename to Mage.Common/src/main/java/mage/utils/ActionWithUUIDResult.java diff --git a/Mage.Common/src/mage/utils/CardUtil.java b/Mage.Common/src/main/java/mage/utils/CardUtil.java similarity index 100% rename from Mage.Common/src/mage/utils/CardUtil.java rename to Mage.Common/src/main/java/mage/utils/CardUtil.java diff --git a/Mage.Common/src/mage/utils/CompressUtil.java b/Mage.Common/src/main/java/mage/utils/CompressUtil.java similarity index 100% rename from Mage.Common/src/mage/utils/CompressUtil.java rename to Mage.Common/src/main/java/mage/utils/CompressUtil.java diff --git a/Mage.Common/src/mage/utils/DeckBuilder.java b/Mage.Common/src/main/java/mage/utils/DeckBuilder.java similarity index 100% rename from Mage.Common/src/mage/utils/DeckBuilder.java rename to Mage.Common/src/main/java/mage/utils/DeckBuilder.java diff --git a/Mage.Common/src/mage/utils/MageVersion.java b/Mage.Common/src/main/java/mage/utils/MageVersion.java similarity index 100% rename from Mage.Common/src/mage/utils/MageVersion.java rename to Mage.Common/src/main/java/mage/utils/MageVersion.java diff --git a/Mage.Common/src/mage/utils/ThreadUtils.java b/Mage.Common/src/main/java/mage/utils/ThreadUtils.java similarity index 100% rename from Mage.Common/src/mage/utils/ThreadUtils.java rename to Mage.Common/src/main/java/mage/utils/ThreadUtils.java diff --git a/Mage.Common/src/mage/utils/properties/PropertiesUtil.java b/Mage.Common/src/main/java/mage/utils/properties/PropertiesUtil.java similarity index 100% rename from Mage.Common/src/mage/utils/properties/PropertiesUtil.java rename to Mage.Common/src/main/java/mage/utils/properties/PropertiesUtil.java diff --git a/Mage.Common/src/mage/utils/properties/PropertyKeys.java b/Mage.Common/src/main/java/mage/utils/properties/PropertyKeys.java similarity index 100% rename from Mage.Common/src/mage/utils/properties/PropertyKeys.java rename to Mage.Common/src/main/java/mage/utils/properties/PropertyKeys.java diff --git a/Mage.Common/src/mage/utils/timer/PriorityTimer.java b/Mage.Common/src/main/java/mage/utils/timer/PriorityTimer.java similarity index 100% rename from Mage.Common/src/mage/utils/timer/PriorityTimer.java rename to Mage.Common/src/main/java/mage/utils/timer/PriorityTimer.java diff --git a/Mage.Common/src/mage/view/AbilityPickerView.java b/Mage.Common/src/main/java/mage/view/AbilityPickerView.java similarity index 100% rename from Mage.Common/src/mage/view/AbilityPickerView.java rename to Mage.Common/src/main/java/mage/view/AbilityPickerView.java diff --git a/Mage.Common/src/mage/view/AbilityView.java b/Mage.Common/src/main/java/mage/view/AbilityView.java similarity index 100% rename from Mage.Common/src/mage/view/AbilityView.java rename to Mage.Common/src/main/java/mage/view/AbilityView.java diff --git a/Mage.Common/src/mage/view/CardView.java b/Mage.Common/src/main/java/mage/view/CardView.java similarity index 76% rename from Mage.Common/src/mage/view/CardView.java rename to Mage.Common/src/main/java/mage/view/CardView.java index 8b567d89da8..b238047d368 100644 --- a/Mage.Common/src/mage/view/CardView.java +++ b/Mage.Common/src/main/java/mage/view/CardView.java @@ -27,7 +27,6 @@ */ package mage.view; -import java.util.*; import mage.MageObject; import mage.ObjectColor; import mage.abilities.Abilities; @@ -51,6 +50,8 @@ import mage.game.stack.StackAbility; import mage.target.Target; import mage.target.Targets; +import java.util.*; + /** * @author BetaSteward_at_googlemail.com */ @@ -1028,4 +1029,180 @@ public class CardView extends SimpleCardView { public boolean isTribal() { return cardTypes.contains(CardType.TRIBAL); } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final CardView cardView = (CardView) o; + + if (getConvertedManaCost() != cardView.getConvertedManaCost()) return false; + if (isAbility() != cardView.isAbility()) return false; + if (isToken() != cardView.isToken()) return false; + if (getType() != cardView.getType()) return false; + if (transformable != cardView.transformable) return false; + if (isTransformed() != cardView.isTransformed()) return false; + if (isFlipCard() != cardView.isFlipCard()) return false; + if (isFaceDown() != cardView.isFaceDown()) return false; + if (isSplitCard() != cardView.isSplitCard()) return false; + if (isPaid() != cardView.isPaid()) return false; + if (isControlledByOwner() != cardView.isControlledByOwner()) return false; + if (rotate != cardView.rotate) return false; + if (hideInfo != cardView.hideInfo) return false; + if (isPlayable() != cardView.isPlayable()) return false; + if (isChoosable() != cardView.isChoosable()) return false; + if (isSelected() != cardView.isSelected()) return false; + if (isCanAttack() != cardView.isCanAttack()) return false; + if (getParentId() != null ? !getParentId().equals(cardView.getParentId()) : cardView + .getParentId() != null) + return false; + if (getName() != null ? !getName().equals(cardView.getName()) : cardView.getName() != null) + return false; + if (getDisplayName() != null ? !getDisplayName().equals(cardView.getDisplayName()) : + cardView.getDisplayName() != null) + return false; + if (getRules() != null ? !getRules().equals(cardView.getRules()) : cardView.getRules() != + null) + return false; + if (getPower() != null ? !getPower().equals(cardView.getPower()) : cardView.getPower() != + null) + return false; + if (getToughness() != null ? !getToughness().equals(cardView.getToughness()) : cardView + .getToughness() != null) + return false; + if (getLoyalty() != null ? !getLoyalty().equals(cardView.getLoyalty()) : cardView + .getLoyalty() != null) + return false; + if (getStartingLoyalty() != null ? !getStartingLoyalty().equals(cardView + .getStartingLoyalty()) : cardView.getStartingLoyalty() != null) + return false; + if (getCardTypes() != null ? !getCardTypes().equals(cardView.getCardTypes()) : cardView + .getCardTypes() != null) + return false; + if (getSubTypes() != null ? !getSubTypes().equals(cardView.getSubTypes()) : cardView + .getSubTypes() != null) + return false; + if (getSuperTypes() != null ? !getSuperTypes().equals(cardView.getSuperTypes()) : + cardView.getSuperTypes() != null) + return false; + if (getColor() != null ? !getColor().equals(cardView.getColor()) : cardView.getColor() != + null) + return false; + if (getFrameColor() != null ? !getFrameColor().equals(cardView.getFrameColor()) : + cardView.getFrameColor() != null) + return false; + if (getFrameStyle() != cardView.getFrameStyle()) return false; + if (getManaCost() != null ? !getManaCost().equals(cardView.getManaCost()) : cardView + .getManaCost() != null) + return false; + if (getRarity() != cardView.getRarity()) return false; + if (getMageObjectType() != cardView.getMageObjectType()) return false; + if (getAbilityType() != cardView.getAbilityType()) return false; + if (isAbility() != cardView.isAbility()) + return false; + if (getSecondCardFace() != null ? !getSecondCardFace().equals(cardView.getSecondCardFace + ()) : cardView.getSecondCardFace() != null) + return false; + if (getAlternateName() != null ? !getAlternateName().equals(cardView.getAlternateName()) + : cardView.getAlternateName() != null) + return false; + if (getOriginalName() != null ? !getOriginalName().equals(cardView.getOriginalName()) : + cardView.getOriginalName() != null) + return false; + if (getLeftSplitName() != null ? !getLeftSplitName().equals(cardView.getLeftSplitName()) + : cardView.getLeftSplitName() != null) + return false; + if (getLeftSplitCosts() != null ? !getLeftSplitCosts().equals(cardView.getLeftSplitCosts + ()) : cardView.getLeftSplitCosts() != null) + return false; + if (getLeftSplitRules() != null ? !getLeftSplitRules().equals(cardView.getLeftSplitRules + ()) : cardView.getLeftSplitRules() != null) + return false; + if (getLeftSplitTypeLine() != null ? !getLeftSplitTypeLine().equals(cardView + .getLeftSplitTypeLine()) : cardView.getLeftSplitTypeLine() != null) + return false; + if (getRightSplitName() != null ? !getRightSplitName().equals(cardView.getRightSplitName + ()) : cardView.getRightSplitName() != null) + return false; + if (getRightSplitCosts() != null ? !getRightSplitCosts().equals(cardView + .getRightSplitCosts()) : cardView.getRightSplitCosts() != null) + return false; + if (getRightSplitRules() != null ? !getRightSplitRules().equals(cardView + .getRightSplitRules()) : cardView.getRightSplitRules() != null) + return false; + if (getRightSplitTypeLine() != null ? !getRightSplitTypeLine().equals(cardView + .getRightSplitTypeLine()) : cardView.getRightSplitTypeLine() != null) + return false; + if (getArtRect() != cardView.getArtRect()) return false; + if (getTargets() != null ? !getTargets().equals(cardView.getTargets()) : cardView + .getTargets() != null) + return false; + if (getPairedCard() != null ? !getPairedCard().equals(cardView.getPairedCard()) : + cardView.getPairedCard() != null) + return false; + if (getCounters() != null ? !getCounters().equals(cardView.getCounters()) : cardView + .getCounters() != null) + return false; + return getZone() == cardView.getZone(); + + } + + @Override + public int hashCode() { + int result = getParentId() != null ? getParentId().hashCode() : 0; + result = 31 * result + (getName() != null ? getName().hashCode() : 0); + result = 31 * result + (getDisplayName() != null ? getDisplayName().hashCode() : 0); + result = 31 * result + (getRules() != null ? getRules().hashCode() : 0); + result = 31 * result + (getPower() != null ? getPower().hashCode() : 0); + result = 31 * result + (getToughness() != null ? getToughness().hashCode() : 0); + result = 31 * result + (getLoyalty() != null ? getLoyalty().hashCode() : 0); + result = 31 * result + (getStartingLoyalty() != null ? getStartingLoyalty().hashCode() : 0); + result = 31 * result + (getCardTypes() != null ? getCardTypes().hashCode() : 0); + result = 31 * result + (getSubTypes() != null ? getSubTypes().hashCode() : 0); + result = 31 * result + (getSuperTypes() != null ? getSuperTypes().hashCode() : 0); + result = 31 * result + (getColor() != null ? getColor().hashCode() : 0); + result = 31 * result + (getFrameColor() != null ? getFrameColor().hashCode() : 0); + result = 31 * result + (getFrameStyle() != null ? getFrameStyle().hashCode() : 0); + result = 31 * result + (getManaCost() != null ? getManaCost().hashCode() : 0); + result = 31 * result + getConvertedManaCost(); + result = 31 * result + (getRarity() != null ? getRarity().hashCode() : 0); + result = 31 * result + (getMageObjectType() != null ? getMageObjectType().hashCode() : 0); + result = 31 * result + (isAbility() ? 1 : 0); + result = 31 * result + (getAbilityType() != null ? getAbilityType().hashCode() : 0); + result = 31 * result + (isToken() ? 1 : 0); + result = 31 * result + (isAbility() ? 1 : 0); + result = 31 * result + getType(); + result = 31 * result + (transformable ? 1 : 0); + result = 31 * result + (getSecondCardFace() != null ? getSecondCardFace().hashCode() : 0); + result = 31 * result + (isTransformed() ? 1 : 0); + result = 31 * result + (isFlipCard() ? 1 : 0); + result = 31 * result + (isFaceDown() ? 1 : 0); + result = 31 * result + (getAlternateName() != null ? getAlternateName().hashCode() : 0); + result = 31 * result + (getOriginalName() != null ? getOriginalName().hashCode() : 0); + result = 31 * result + (isSplitCard() ? 1 : 0); + result = 31 * result + (getLeftSplitName() != null ? getLeftSplitName().hashCode() : 0); + result = 31 * result + (getLeftSplitCosts() != null ? getLeftSplitCosts().hashCode() : 0); + result = 31 * result + (getLeftSplitRules() != null ? getLeftSplitRules().hashCode() : 0); + result = 31 * result + (getLeftSplitTypeLine() != null ? getLeftSplitTypeLine().hashCode + () : 0); + result = 31 * result + (getRightSplitName() != null ? getRightSplitName().hashCode() : 0); + result = 31 * result + (getRightSplitCosts() != null ? getRightSplitCosts().hashCode() : 0); + result = 31 * result + (getRightSplitRules() != null ? getRightSplitRules().hashCode() : 0); + result = 31 * result + (getRightSplitTypeLine() != null ? getRightSplitTypeLine().hashCode() : 0); + result = 31 * result + (getArtRect() != null ? getArtRect().hashCode() : 0); + result = 31 * result + (getTargets() != null ? getTargets().hashCode() : 0); + result = 31 * result + (getPairedCard() != null ? getPairedCard().hashCode() : 0); + result = 31 * result + (isPaid() ? 1 : 0); + result = 31 * result + (getCounters() != null ? getCounters().hashCode() : 0); + result = 31 * result + (isControlledByOwner() ? 1 : 0); + result = 31 * result + (getZone() != null ? getZone().hashCode() : 0); + result = 31 * result + (rotate ? 1 : 0); + result = 31 * result + (hideInfo ? 1 : 0); + result = 31 * result + (isPlayable() ? 1 : 0); + result = 31 * result + (isChoosable() ? 1 : 0); + result = 31 * result + (isSelected() ? 1 : 0); + result = 31 * result + (isCanAttack() ? 1 : 0); + return result; + } } diff --git a/Mage.Common/src/mage/view/CardsView.java b/Mage.Common/src/main/java/mage/view/CardsView.java similarity index 98% rename from Mage.Common/src/mage/view/CardsView.java rename to Mage.Common/src/main/java/mage/view/CardsView.java index e37b9801a66..f4b7a19d90a 100644 --- a/Mage.Common/src/mage/view/CardsView.java +++ b/Mage.Common/src/main/java/mage/view/CardsView.java @@ -27,11 +27,6 @@ */ package mage.view; -import java.util.ArrayList; -import java.util.Collection; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.Effect; @@ -45,6 +40,8 @@ import mage.game.permanent.PermanentToken; import mage.target.targetpointer.TargetPointer; import mage.util.GameLog; +import java.util.*; + /** * * @author BetaSteward_at_googlemail.com diff --git a/Mage.Common/src/mage/view/ChatMessage.java b/Mage.Common/src/main/java/mage/view/ChatMessage.java similarity index 100% rename from Mage.Common/src/mage/view/ChatMessage.java rename to Mage.Common/src/main/java/mage/view/ChatMessage.java diff --git a/Mage.Common/src/mage/view/CombatGroupView.java b/Mage.Common/src/main/java/mage/view/CombatGroupView.java similarity index 81% rename from Mage.Common/src/mage/view/CombatGroupView.java rename to Mage.Common/src/main/java/mage/view/CombatGroupView.java index 9a1d0bb7481..8201ba0f818 100644 --- a/Mage.Common/src/mage/view/CombatGroupView.java +++ b/Mage.Common/src/main/java/mage/view/CombatGroupView.java @@ -89,4 +89,27 @@ public class CombatGroupView implements Serializable { public UUID getDefenderId() { return defenderId; } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final CombatGroupView that = (CombatGroupView) o; + + if (!getAttackers().equals(that.getAttackers())) return false; + if (!getBlockers().equals(that.getBlockers())) return false; + if (!getDefenderName().equals(that.getDefenderName())) return false; + return getDefenderId().equals(that.getDefenderId()); + + } + + @Override + public int hashCode() { + int result = getAttackers().hashCode(); + result = 31 * result + getBlockers().hashCode(); + result = 31 * result + getDefenderName().hashCode(); + result = 31 * result + getDefenderId().hashCode(); + return result; + } } diff --git a/Mage.Common/src/mage/view/CommandObjectView.java b/Mage.Common/src/main/java/mage/view/CommandObjectView.java similarity index 100% rename from Mage.Common/src/mage/view/CommandObjectView.java rename to Mage.Common/src/main/java/mage/view/CommandObjectView.java diff --git a/Mage.Common/src/mage/view/CommanderView.java b/Mage.Common/src/main/java/mage/view/CommanderView.java similarity index 100% rename from Mage.Common/src/mage/view/CommanderView.java rename to Mage.Common/src/main/java/mage/view/CommanderView.java diff --git a/Mage.Common/src/mage/view/CounterView.java b/Mage.Common/src/main/java/mage/view/CounterView.java similarity index 100% rename from Mage.Common/src/mage/view/CounterView.java rename to Mage.Common/src/main/java/mage/view/CounterView.java diff --git a/Mage.Common/src/mage/view/DeckView.java b/Mage.Common/src/main/java/mage/view/DeckView.java similarity index 100% rename from Mage.Common/src/mage/view/DeckView.java rename to Mage.Common/src/main/java/mage/view/DeckView.java diff --git a/Mage.Common/src/mage/view/DraftClientMessage.java b/Mage.Common/src/main/java/mage/view/DraftClientMessage.java similarity index 100% rename from Mage.Common/src/mage/view/DraftClientMessage.java rename to Mage.Common/src/main/java/mage/view/DraftClientMessage.java diff --git a/Mage.Common/src/mage/view/DraftPickView.java b/Mage.Common/src/main/java/mage/view/DraftPickView.java similarity index 100% rename from Mage.Common/src/mage/view/DraftPickView.java rename to Mage.Common/src/main/java/mage/view/DraftPickView.java diff --git a/Mage.Common/src/mage/view/DraftView.java b/Mage.Common/src/main/java/mage/view/DraftView.java similarity index 100% rename from Mage.Common/src/mage/view/DraftView.java rename to Mage.Common/src/main/java/mage/view/DraftView.java diff --git a/Mage.Common/src/mage/view/EmblemView.java b/Mage.Common/src/main/java/mage/view/EmblemView.java similarity index 56% rename from Mage.Common/src/mage/view/EmblemView.java rename to Mage.Common/src/main/java/mage/view/EmblemView.java index 807bd0c1f52..316f04f71c3 100644 --- a/Mage.Common/src/mage/view/EmblemView.java +++ b/Mage.Common/src/main/java/mage/view/EmblemView.java @@ -1,10 +1,11 @@ package mage.view; +import mage.cards.Card; +import mage.game.command.Emblem; + import java.io.Serializable; import java.util.List; import java.util.UUID; -import mage.cards.Card; -import mage.game.command.Emblem; /** * @author noxx @@ -54,4 +55,31 @@ public class EmblemView implements CommandObjectView, Serializable { public List getRules() { return rules; } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final EmblemView that = (EmblemView) o; + + if (!getId().equals(that.getId())) return false; + if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null) + return false; + if (getExpansionSetCode() != null ? !getExpansionSetCode().equals(that + .getExpansionSetCode()) : that.getExpansionSetCode() != null) + return false; + return getRules() != null ? getRules().equals(that.getRules()) : that.getRules() == null; + + } + + @Override + public int hashCode() { + int result = getId().hashCode(); + result = 31 * result + (getName() != null ? getName().hashCode() : 0); + result = 31 * result + (getExpansionSetCode() != null ? getExpansionSetCode().hashCode() + : 0); + result = 31 * result + (getRules() != null ? getRules().hashCode() : 0); + return result; + } } diff --git a/Mage.Common/src/mage/view/ExileView.java b/Mage.Common/src/main/java/mage/view/ExileView.java similarity index 79% rename from Mage.Common/src/mage/view/ExileView.java rename to Mage.Common/src/main/java/mage/view/ExileView.java index bd0c03752a3..79a39888a12 100644 --- a/Mage.Common/src/mage/view/ExileView.java +++ b/Mage.Common/src/main/java/mage/view/ExileView.java @@ -28,11 +28,12 @@ package mage.view; -import java.util.UUID; import mage.cards.Card; import mage.game.ExileZone; import mage.game.Game; +import java.util.UUID; + /** * * @author BetaSteward_at_googlemail.com @@ -59,4 +60,24 @@ public class ExileView extends CardsView { return id; } + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + + final ExileView exileView = (ExileView) o; + + if (!getName().equals(exileView.getName())) return false; + return getId().equals(exileView.getId()); + + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + getName().hashCode(); + result = 31 * result + getId().hashCode(); + return result; + } } diff --git a/Mage.Common/src/mage/view/GameClientMessage.java b/Mage.Common/src/main/java/mage/view/GameClientMessage.java similarity index 100% rename from Mage.Common/src/mage/view/GameClientMessage.java rename to Mage.Common/src/main/java/mage/view/GameClientMessage.java diff --git a/Mage.Common/src/mage/view/GameEndView.java b/Mage.Common/src/main/java/mage/view/GameEndView.java similarity index 100% rename from Mage.Common/src/mage/view/GameEndView.java rename to Mage.Common/src/main/java/mage/view/GameEndView.java diff --git a/Mage.Common/src/mage/view/GameTypeView.java b/Mage.Common/src/main/java/mage/view/GameTypeView.java similarity index 100% rename from Mage.Common/src/mage/view/GameTypeView.java rename to Mage.Common/src/main/java/mage/view/GameTypeView.java diff --git a/Mage.Common/src/mage/view/GameView.java b/Mage.Common/src/main/java/mage/view/GameView.java similarity index 98% rename from Mage.Common/src/mage/view/GameView.java rename to Mage.Common/src/main/java/mage/view/GameView.java index a9f7bfa9ee9..69fc4dd24dc 100644 --- a/Mage.Common/src/mage/view/GameView.java +++ b/Mage.Common/src/main/java/mage/view/GameView.java @@ -27,12 +27,6 @@ */ package mage.view; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; import mage.MageObject; import mage.abilities.costs.Cost; import mage.cards.Card; @@ -55,6 +49,9 @@ import mage.players.Player; import mage.watchers.common.CastSpellLastTurnWatcher; import org.apache.log4j.Logger; +import java.io.Serializable; +import java.util.*; + /** * * @author BetaSteward_at_googlemail.com @@ -63,7 +60,7 @@ public class GameView implements Serializable { private static final long serialVersionUID = 1L; - private static final Logger LOGGER = Logger.getLogger(GameView.class); + private transient static final Logger LOGGER = Logger.getLogger(GameView.class); private final int priorityTime; private final List players = new ArrayList<>(); diff --git a/Mage.Common/src/mage/view/LookedAtView.java b/Mage.Common/src/main/java/mage/view/LookedAtView.java similarity index 83% rename from Mage.Common/src/mage/view/LookedAtView.java rename to Mage.Common/src/main/java/mage/view/LookedAtView.java index ac965c6e31e..76877517e00 100644 --- a/Mage.Common/src/mage/view/LookedAtView.java +++ b/Mage.Common/src/main/java/mage/view/LookedAtView.java @@ -57,4 +57,23 @@ public class LookedAtView implements Serializable { public SimpleCardsView getCards() { return cards; } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final LookedAtView that = (LookedAtView) o; + + if (!getName().equals(that.getName())) return false; + return getCards().equals(that.getCards()); + + } + + @Override + public int hashCode() { + int result = getName().hashCode(); + result = 31 * result + getCards().hashCode(); + return result; + } } diff --git a/Mage.Common/src/mage/view/ManaPoolView.java b/Mage.Common/src/main/java/mage/view/ManaPoolView.java similarity index 77% rename from Mage.Common/src/mage/view/ManaPoolView.java rename to Mage.Common/src/main/java/mage/view/ManaPoolView.java index 746b87d8b94..ea7c1a10358 100644 --- a/Mage.Common/src/mage/view/ManaPoolView.java +++ b/Mage.Common/src/main/java/mage/view/ManaPoolView.java @@ -27,10 +27,11 @@ */ package mage.view; -import java.io.Serializable; import mage.ConditionalMana; import mage.players.ManaPool; +import java.io.Serializable; + /** * * @author BetaSteward_at_googlemail.com @@ -87,4 +88,30 @@ public class ManaPoolView implements Serializable { return colorless; } + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final ManaPoolView that = (ManaPoolView) o; + + if (getRed() != that.getRed()) return false; + if (getGreen() != that.getGreen()) return false; + if (getBlue() != that.getBlue()) return false; + if (getWhite() != that.getWhite()) return false; + if (getBlack() != that.getBlack()) return false; + return getColorless() == that.getColorless(); + + } + + @Override + public int hashCode() { + int result = getRed(); + result = 31 * result + getGreen(); + result = 31 * result + getBlue(); + result = 31 * result + getWhite(); + result = 31 * result + getBlack(); + result = 31 * result + getColorless(); + return result; + } } diff --git a/Mage.Common/src/mage/view/MatchView.java b/Mage.Common/src/main/java/mage/view/MatchView.java similarity index 100% rename from Mage.Common/src/mage/view/MatchView.java rename to Mage.Common/src/main/java/mage/view/MatchView.java diff --git a/Mage.Common/src/mage/view/PermanentView.java b/Mage.Common/src/main/java/mage/view/PermanentView.java similarity index 77% rename from Mage.Common/src/mage/view/PermanentView.java rename to Mage.Common/src/main/java/mage/view/PermanentView.java index 003af1f6930..284e12d007a 100644 --- a/Mage.Common/src/mage/view/PermanentView.java +++ b/Mage.Common/src/main/java/mage/view/PermanentView.java @@ -27,9 +27,6 @@ */ package mage.view; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.TurnFaceUpAbility; import mage.cards.Card; @@ -38,6 +35,10 @@ import mage.game.permanent.Permanent; import mage.game.permanent.PermanentToken; import mage.players.Player; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + /** * * @author BetaSteward_at_googlemail.com @@ -214,4 +215,55 @@ public class PermanentView extends CardView { public boolean isManifested() { return manifested; } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + + final PermanentView that = (PermanentView) o; + + if (isTapped() != that.isTapped()) return false; + if (isFlipped() != that.isFlipped()) return false; + if (isPhasedIn() != that.isPhasedIn()) return false; + if (summoningSickness != that.summoningSickness) return false; + if (getDamage() != that.getDamage()) return false; + if (isCopy() != that.isCopy()) return false; + if (isControlled() != that.isControlled()) return false; + if (isMorphed() != that.isMorphed()) return false; + if (isManifested() != that.isManifested()) return false; + if (isAttachedToPermanent() != that.isAttachedToPermanent()) return false; + if (getAttachments() != null ? !getAttachments().equals(that.getAttachments()) : that + .getAttachments() != null) + return false; + if (getOriginal() != null ? !getOriginal().equals(that.getOriginal()) : that.getOriginal + () != null) + return false; + if (getNameOwner() != null ? !getNameOwner().equals(that.getNameOwner()) : that + .getNameOwner() != null) + return false; + return isAttachedTo() == that.isAttachedTo(); + + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + (isTapped() ? 1 : 0); + result = 31 * result + (isFlipped() ? 1 : 0); + result = 31 * result + (isPhasedIn() ? 1 : 0); + result = 31 * result + (summoningSickness ? 1 : 0); + result = 31 * result + getDamage(); + result = 31 * result + (getAttachments() != null ? getAttachments().hashCode() : 0); + result = 31 * result + (getOriginal() != null ? getOriginal().hashCode() : 0); + result = 31 * result + (isCopy() ? 1 : 0); + result = 31 * result + (getNameOwner() != null ? getNameOwner().hashCode() : 0); + result = 31 * result + (isControlled() ? 1 : 0); + result = 31 * result + (isAttachedTo() ? 1 : 0); + result = 31 * result + (isMorphed() ? 1 : 0); + result = 31 * result + (isManifested() ? 1 : 0); + result = 31 * result + (isAttachedToPermanent() ? 1 : 0); + return result; + } } diff --git a/Mage.Common/src/mage/view/PlayerView.java b/Mage.Common/src/main/java/mage/view/PlayerView.java similarity index 69% rename from Mage.Common/src/mage/view/PlayerView.java rename to Mage.Common/src/main/java/mage/view/PlayerView.java index 70e4238a1fc..afb791d04ae 100644 --- a/Mage.Common/src/mage/view/PlayerView.java +++ b/Mage.Common/src/main/java/mage/view/PlayerView.java @@ -27,14 +27,6 @@ */ package mage.view; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.ConcurrentModificationException; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; - import mage.cards.Card; import mage.counters.Counters; import mage.game.ExileZone; @@ -47,6 +39,9 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.players.net.UserData; +import java.io.Serializable; +import java.util.*; + /** * @author BetaSteward_at_googlemail.com */ @@ -305,4 +300,88 @@ public class PlayerView implements Serializable { return monarch; } + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final PlayerView that = (PlayerView) o; + + if (getLife() != that.getLife()) return false; + if (getWins() != that.getWins()) return false; + if (getWinsNeeded() != that.getWinsNeeded()) return false; + if (getDeckHashCode() != that.getDeckHashCode()) return false; + if (getLibraryCount() != that.getLibraryCount()) return false; + if (getHandCount() != that.getHandCount()) return false; + if (isActive() != that.isActive()) return false; + if (hasPriority != that.hasPriority) return false; + if (isTimerActive() != that.isTimerActive()) return false; + if (hasLeft != that.hasLeft) return false; + if (getStatesSavedSize() != that.getStatesSavedSize()) return false; + if (getPriorityTimeLeft() != that.getPriorityTimeLeft()) return false; + if (isPassedTurn() != that.isPassedTurn()) return false; + if (isPassedUntilEndOfTurn() != that.isPassedUntilEndOfTurn()) return false; + if (isPassedUntilNextMain() != that.isPassedUntilNextMain()) return false; + if (isPassedUntilStackResolved() != that.isPassedUntilStackResolved()) return false; + if (isPassedAllTurns() != that.isPassedAllTurns()) return false; + if (isPassedUntilEndStepBeforeMyTurn() != that.isPassedUntilEndStepBeforeMyTurn()) + return false; + if (isMonarch() != that.isMonarch()) return false; + if (!getPlayerId().equals(that.getPlayerId())) return false; + if (getName() != null ? !getName().equals(that.getName()) : that.getName() != null) + return false; + if (getCounters() != null ? !getCounters().equals(that.getCounters()) : that.getCounters + () != null) + return false; + if (getManaPool() != null ? !getManaPool().equals(that.getManaPool()) : that.getManaPool + () != null) + return false; + if (!getGraveyard().equals(that.getGraveyard())) return false; + if (!getExile().equals(that.getExile())) return false; + if (!getBattlefield().equals(that.getBattlefield())) return false; + if (getTopCard() != null ? !getTopCard().equals(that.getTopCard()) : that.getTopCard() != + null) + return false; + if (getUserData() != null ? !getUserData().equals(that.getUserData()) : that.getUserData + () != null) + return false; + if (!commandList.equals(that.commandList)) return false; + return getAttachments().equals(that.getAttachments()); + + } + + @Override + public int hashCode() { + int result = getPlayerId().hashCode(); + result = 31 * result + (getName() != null ? getName().hashCode() : 0); + result = 31 * result + getLife(); + result = 31 * result + (getCounters() != null ? getCounters().hashCode() : 0); + result = 31 * result + getWins(); + result = 31 * result + getWinsNeeded(); + result = 31 * result + (int) (getDeckHashCode() ^ (getDeckHashCode() >>> 32)); + result = 31 * result + getLibraryCount(); + result = 31 * result + getHandCount(); + result = 31 * result + (isActive() ? 1 : 0); + result = 31 * result + (hasPriority ? 1 : 0); + result = 31 * result + (isTimerActive() ? 1 : 0); + result = 31 * result + (hasLeft ? 1 : 0); + result = 31 * result + (getManaPool() != null ? getManaPool().hashCode() : 0); + result = 31 * result + getGraveyard().hashCode(); + result = 31 * result + getExile().hashCode(); + result = 31 * result + getBattlefield().hashCode(); + result = 31 * result + (getTopCard() != null ? getTopCard().hashCode() : 0); + result = 31 * result + (getUserData() != null ? getUserData().hashCode() : 0); + result = 31 * result + commandList.hashCode(); + result = 31 * result + getAttachments().hashCode(); + result = 31 * result + getStatesSavedSize(); + result = 31 * result + getPriorityTimeLeft(); + result = 31 * result + (isPassedTurn() ? 1 : 0); + result = 31 * result + (isPassedUntilEndOfTurn() ? 1 : 0); + result = 31 * result + (isPassedUntilNextMain() ? 1 : 0); + result = 31 * result + (isPassedUntilStackResolved() ? 1 : 0); + result = 31 * result + (isPassedAllTurns() ? 1 : 0); + result = 31 * result + (isPassedUntilEndStepBeforeMyTurn() ? 1 : 0); + result = 31 * result + (isMonarch() ? 1 : 0); + return result; + } } diff --git a/Mage.Common/src/mage/view/RevealedView.java b/Mage.Common/src/main/java/mage/view/RevealedView.java similarity index 100% rename from Mage.Common/src/mage/view/RevealedView.java rename to Mage.Common/src/main/java/mage/view/RevealedView.java diff --git a/Mage.Common/src/mage/view/RoomUsersView.java b/Mage.Common/src/main/java/mage/view/RoomUsersView.java similarity index 100% rename from Mage.Common/src/mage/view/RoomUsersView.java rename to Mage.Common/src/main/java/mage/view/RoomUsersView.java diff --git a/Mage.Common/src/mage/view/RoundView.java b/Mage.Common/src/main/java/mage/view/RoundView.java similarity index 100% rename from Mage.Common/src/mage/view/RoundView.java rename to Mage.Common/src/main/java/mage/view/RoundView.java diff --git a/Mage.Common/src/mage/view/SeatView.java b/Mage.Common/src/main/java/mage/view/SeatView.java similarity index 100% rename from Mage.Common/src/mage/view/SeatView.java rename to Mage.Common/src/main/java/mage/view/SeatView.java diff --git a/Mage.Common/src/mage/view/SimpleCardView.java b/Mage.Common/src/main/java/mage/view/SimpleCardView.java similarity index 69% rename from Mage.Common/src/mage/view/SimpleCardView.java rename to Mage.Common/src/main/java/mage/view/SimpleCardView.java index 709e45ad837..64e299ac683 100644 --- a/Mage.Common/src/mage/view/SimpleCardView.java +++ b/Mage.Common/src/main/java/mage/view/SimpleCardView.java @@ -83,5 +83,38 @@ public class SimpleCardView implements Serializable { public boolean isGameObject() { return gameObject; - } + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final SimpleCardView that = (SimpleCardView) o; + + if (getUsesVariousArt() != that.getUsesVariousArt()) return false; + if (isGameObject() != that.isGameObject()) return false; + if (!getId().equals(that.getId())) return false; + if (!getExpansionSetCode().equals(that.getExpansionSetCode())) return false; + if (getTokenSetCode() != null ? !getTokenSetCode().equals(that.getTokenSetCode()) : that + .getTokenSetCode() != null) + return false; + if (getTokenDescriptor() != null ? !getTokenDescriptor().equals(that.getTokenDescriptor() + ) : that.getTokenDescriptor() != null) + return false; + return getCardNumber().equals(that.getCardNumber()); + + } + + @Override + public int hashCode() { + int result = getId().hashCode(); + result = 31 * result + getExpansionSetCode().hashCode(); + result = 31 * result + (getTokenSetCode() != null ? getTokenSetCode().hashCode() : 0); + result = 31 * result + (getTokenDescriptor() != null ? getTokenDescriptor().hashCode() : 0); + result = 31 * result + getCardNumber().hashCode(); + result = 31 * result + (getUsesVariousArt() ? 1 : 0); + result = 31 * result + (isGameObject() ? 1 : 0); + return result; + } } diff --git a/Mage.Common/src/mage/view/SimpleCardsView.java b/Mage.Common/src/main/java/mage/view/SimpleCardsView.java similarity index 100% rename from Mage.Common/src/mage/view/SimpleCardsView.java rename to Mage.Common/src/main/java/mage/view/SimpleCardsView.java diff --git a/Mage.Common/src/mage/view/StackAbilityView.java b/Mage.Common/src/main/java/mage/view/StackAbilityView.java similarity index 100% rename from Mage.Common/src/mage/view/StackAbilityView.java rename to Mage.Common/src/main/java/mage/view/StackAbilityView.java diff --git a/Mage.Common/src/mage/view/TableClientMessage.java b/Mage.Common/src/main/java/mage/view/TableClientMessage.java similarity index 100% rename from Mage.Common/src/mage/view/TableClientMessage.java rename to Mage.Common/src/main/java/mage/view/TableClientMessage.java diff --git a/Mage.Common/src/mage/view/TableView.java b/Mage.Common/src/main/java/mage/view/TableView.java similarity index 100% rename from Mage.Common/src/mage/view/TableView.java rename to Mage.Common/src/main/java/mage/view/TableView.java diff --git a/Mage.Common/src/mage/view/TournamentGameView.java b/Mage.Common/src/main/java/mage/view/TournamentGameView.java similarity index 100% rename from Mage.Common/src/mage/view/TournamentGameView.java rename to Mage.Common/src/main/java/mage/view/TournamentGameView.java diff --git a/Mage.Common/src/mage/view/TournamentPlayerView.java b/Mage.Common/src/main/java/mage/view/TournamentPlayerView.java similarity index 100% rename from Mage.Common/src/mage/view/TournamentPlayerView.java rename to Mage.Common/src/main/java/mage/view/TournamentPlayerView.java diff --git a/Mage.Common/src/mage/view/TournamentTypeView.java b/Mage.Common/src/main/java/mage/view/TournamentTypeView.java similarity index 100% rename from Mage.Common/src/mage/view/TournamentTypeView.java rename to Mage.Common/src/main/java/mage/view/TournamentTypeView.java diff --git a/Mage.Common/src/mage/view/TournamentView.java b/Mage.Common/src/main/java/mage/view/TournamentView.java similarity index 100% rename from Mage.Common/src/mage/view/TournamentView.java rename to Mage.Common/src/main/java/mage/view/TournamentView.java diff --git a/Mage.Common/src/mage/view/UserDataView.java b/Mage.Common/src/main/java/mage/view/UserDataView.java similarity index 100% rename from Mage.Common/src/mage/view/UserDataView.java rename to Mage.Common/src/main/java/mage/view/UserDataView.java diff --git a/Mage.Common/src/mage/view/UserRequestMessage.java b/Mage.Common/src/main/java/mage/view/UserRequestMessage.java similarity index 100% rename from Mage.Common/src/mage/view/UserRequestMessage.java rename to Mage.Common/src/main/java/mage/view/UserRequestMessage.java diff --git a/Mage.Common/src/mage/view/UserView.java b/Mage.Common/src/main/java/mage/view/UserView.java similarity index 100% rename from Mage.Common/src/mage/view/UserView.java rename to Mage.Common/src/main/java/mage/view/UserView.java diff --git a/Mage.Common/src/mage/view/UsersView.java b/Mage.Common/src/main/java/mage/view/UsersView.java similarity index 100% rename from Mage.Common/src/mage/view/UsersView.java rename to Mage.Common/src/main/java/mage/view/UsersView.java diff --git a/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/SamBlacksCube.java b/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/SamBlacksCube.java new file mode 100644 index 00000000000..6b5ddf0ae8d --- /dev/null +++ b/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/SamBlacksCube.java @@ -0,0 +1,627 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package mage.tournament.cubes; + +import mage.game.draft.DraftCube; + +/** + * + * @author fireshoes + */ +public class SamBlacksCube extends DraftCube { + +public SamBlacksCube() { + super("Sam Black's No Search Cube"); // http://www.cubetutor.com/viewcube/69564 + + cubeCards.add(new DraftCube.CardIdentity("Abbot of Keral Keep", "")); + cubeCards.add(new DraftCube.CardIdentity("Abrupt Decay", "")); + cubeCards.add(new DraftCube.CardIdentity("Acidic Slime", "")); + cubeCards.add(new DraftCube.CardIdentity("Aether Vial", "")); + cubeCards.add(new DraftCube.CardIdentity("Aetherling", "")); + cubeCards.add(new DraftCube.CardIdentity("Ajani Vengeant", "")); + cubeCards.add(new DraftCube.CardIdentity("Ajani, Caller of the Pride", "")); + cubeCards.add(new DraftCube.CardIdentity("Always Watching", "")); + cubeCards.add(new DraftCube.CardIdentity("Anafenza, Kin-Tree Spirit", "")); + cubeCards.add(new DraftCube.CardIdentity("Ancestral Recall", "")); + cubeCards.add(new DraftCube.CardIdentity("Ancestral Vision", "")); + cubeCards.add(new DraftCube.CardIdentity("Ancient Grudge", "")); + cubeCards.add(new DraftCube.CardIdentity("Ancient Tomb", "")); + cubeCards.add(new DraftCube.CardIdentity("Angel of Serenity", "")); + cubeCards.add(new DraftCube.CardIdentity("Anger of the Gods", "")); + cubeCards.add(new DraftCube.CardIdentity("Animate Dead", "")); + cubeCards.add(new DraftCube.CardIdentity("Arbor Elf", "")); + cubeCards.add(new DraftCube.CardIdentity("Arcane Sanctum", "")); + cubeCards.add(new DraftCube.CardIdentity("Archangel Avacyn", "")); + cubeCards.add(new DraftCube.CardIdentity("Armageddon", "")); + cubeCards.add(new DraftCube.CardIdentity("Artisan of Kozilek", "")); + cubeCards.add(new DraftCube.CardIdentity("Ashiok, Nightmare Weaver", "")); + cubeCards.add(new DraftCube.CardIdentity("Atarka's Command", "")); + cubeCards.add(new DraftCube.CardIdentity("Avenger of Zendikar", "")); + cubeCards.add(new DraftCube.CardIdentity("Ayli, Eternal Pilgrim", "")); + cubeCards.add(new DraftCube.CardIdentity("Azorius Chancery", "")); + cubeCards.add(new DraftCube.CardIdentity("Badlands", "")); + cubeCards.add(new DraftCube.CardIdentity("Balance", "")); + cubeCards.add(new DraftCube.CardIdentity("Baleful Strix", "")); + cubeCards.add(new DraftCube.CardIdentity("Baneslayer Angel", "")); + cubeCards.add(new DraftCube.CardIdentity("Banisher Priest", "")); + cubeCards.add(new DraftCube.CardIdentity("Banishing Light", "")); + cubeCards.add(new DraftCube.CardIdentity("Barbarian Ring", "")); + cubeCards.add(new DraftCube.CardIdentity("Basalt Monolith", "")); + cubeCards.add(new DraftCube.CardIdentity("Batterskull", "")); + cubeCards.add(new DraftCube.CardIdentity("Bayou", "")); + cubeCards.add(new DraftCube.CardIdentity("Bazaar of Baghdad", "")); + cubeCards.add(new DraftCube.CardIdentity("Beast Within", "")); + cubeCards.add(new DraftCube.CardIdentity("Become Immense", "")); + cubeCards.add(new DraftCube.CardIdentity("Bedlam Reveler", "")); + cubeCards.add(new DraftCube.CardIdentity("Benevolent Bodyguard", "")); + cubeCards.add(new DraftCube.CardIdentity("Birds of Paradise", "")); + cubeCards.add(new DraftCube.CardIdentity("Bitterblossom", "")); + cubeCards.add(new DraftCube.CardIdentity("Black Lotus", "")); + cubeCards.add(new DraftCube.CardIdentity("Black Sun's Zenith", "")); + cubeCards.add(new DraftCube.CardIdentity("Blackcleave Cliffs", "")); + cubeCards.add(new DraftCube.CardIdentity("Blade Splicer", "")); + cubeCards.add(new DraftCube.CardIdentity("Blood Artist", "")); + cubeCards.add(new DraftCube.CardIdentity("Bloodbraid Elf", "")); + cubeCards.add(new DraftCube.CardIdentity("Bloodghast", "")); + cubeCards.add(new DraftCube.CardIdentity("Bloodthrone Vampire", "")); + cubeCards.add(new DraftCube.CardIdentity("Blossoming Defense", "")); + cubeCards.add(new DraftCube.CardIdentity("Bomat Courier", "")); + cubeCards.add(new DraftCube.CardIdentity("Bone Shredder", "")); + cubeCards.add(new DraftCube.CardIdentity("Bonfire of the Damned", "")); + cubeCards.add(new DraftCube.CardIdentity("Boros Charm", "")); + cubeCards.add(new DraftCube.CardIdentity("Boros Garrison", "")); + cubeCards.add(new DraftCube.CardIdentity("Braids, Cabal Minion", "")); + cubeCards.add(new DraftCube.CardIdentity("Brimaz, King of Oreskos", "")); + cubeCards.add(new DraftCube.CardIdentity("Brimstone Volley", "")); + cubeCards.add(new DraftCube.CardIdentity("Broodmate Dragon", "")); + cubeCards.add(new DraftCube.CardIdentity("Burst Lightning", "")); + cubeCards.add(new DraftCube.CardIdentity("Capsize", "")); + cubeCards.add(new DraftCube.CardIdentity("Carrion Feeder", "")); + cubeCards.add(new DraftCube.CardIdentity("Cartel Aristocrat", "")); + cubeCards.add(new DraftCube.CardIdentity("Catastrophe", "")); + cubeCards.add(new DraftCube.CardIdentity("Celestial Colonnade", "")); + cubeCards.add(new DraftCube.CardIdentity("Chain Lightning", "")); + cubeCards.add(new DraftCube.CardIdentity("Champion of the Parish", "")); + cubeCards.add(new DraftCube.CardIdentity("Chandra's Phoenix", "")); + cubeCards.add(new DraftCube.CardIdentity("Chandra, Flamecaller", "")); + cubeCards.add(new DraftCube.CardIdentity("Chandra, Pyromaster", "")); + cubeCards.add(new DraftCube.CardIdentity("Chandra, Torch of Defiance", "")); + cubeCards.add(new DraftCube.CardIdentity("Channel", "")); + cubeCards.add(new DraftCube.CardIdentity("Chaos Orb", "")); + cubeCards.add(new DraftCube.CardIdentity("Chromatic Star", "")); + cubeCards.add(new DraftCube.CardIdentity("Chrome Mox", "")); + cubeCards.add(new DraftCube.CardIdentity("City of Traitors", "")); + cubeCards.add(new DraftCube.CardIdentity("Coalition Relic", "")); + cubeCards.add(new DraftCube.CardIdentity("Coercive Portal", "")); + cubeCards.add(new DraftCube.CardIdentity("Coldsteel Heart", "")); + cubeCards.add(new DraftCube.CardIdentity("Compulsive Research", "")); + cubeCards.add(new DraftCube.CardIdentity("Condemn", "")); + cubeCards.add(new DraftCube.CardIdentity("Condescend", "")); + cubeCards.add(new DraftCube.CardIdentity("Consecrated Sphinx", "")); + cubeCards.add(new DraftCube.CardIdentity("Contraband Kingpin", "")); + cubeCards.add(new DraftCube.CardIdentity("Control Magic", "")); + cubeCards.add(new DraftCube.CardIdentity("Corpse Dance", "")); + cubeCards.add(new DraftCube.CardIdentity("Council's Judgment", "")); + cubeCards.add(new DraftCube.CardIdentity("Counterspell", "")); + cubeCards.add(new DraftCube.CardIdentity("Courser of Kruphix", "")); + cubeCards.add(new DraftCube.CardIdentity("Crackling Doom", "")); + cubeCards.add(new DraftCube.CardIdentity("Craterhoof Behemoth", "")); + cubeCards.add(new DraftCube.CardIdentity("Creeping Tar Pit", "")); + cubeCards.add(new DraftCube.CardIdentity("Crumbling Necropolis", "")); + cubeCards.add(new DraftCube.CardIdentity("Cryptbreaker", "")); + cubeCards.add(new DraftCube.CardIdentity("Cryptic Command", "")); + cubeCards.add(new DraftCube.CardIdentity("Crystal Shard", "")); + cubeCards.add(new DraftCube.CardIdentity("Cultivator's Caravan", "")); + cubeCards.add(new DraftCube.CardIdentity("Dack Fayden", "")); + cubeCards.add(new DraftCube.CardIdentity("Dack's Duplicate", "")); + cubeCards.add(new DraftCube.CardIdentity("Damnation", "")); + cubeCards.add(new DraftCube.CardIdentity("Dark Confidant", "")); + cubeCards.add(new DraftCube.CardIdentity("Dark Ritual", "")); + cubeCards.add(new DraftCube.CardIdentity("Daze", "")); + cubeCards.add(new DraftCube.CardIdentity("Deceiver Exarch", "")); + cubeCards.add(new DraftCube.CardIdentity("Delver of Secrets", "")); + cubeCards.add(new DraftCube.CardIdentity("Den Protector", "")); + cubeCards.add(new DraftCube.CardIdentity("Desecration Demon", "")); + cubeCards.add(new DraftCube.CardIdentity("Desolate Lighthouse", "")); + cubeCards.add(new DraftCube.CardIdentity("Dig Through Time", "")); + cubeCards.add(new DraftCube.CardIdentity("Dimir Aqueduct", "")); + cubeCards.add(new DraftCube.CardIdentity("Disciple of Bolas", "")); + cubeCards.add(new DraftCube.CardIdentity("Disenchant", "")); + cubeCards.add(new DraftCube.CardIdentity("Dismember", "")); + cubeCards.add(new DraftCube.CardIdentity("Distended Mindbender", "")); + cubeCards.add(new DraftCube.CardIdentity("Domri Rade", "")); + cubeCards.add(new DraftCube.CardIdentity("Doom Blade", "")); + cubeCards.add(new DraftCube.CardIdentity("Dragonlord Atarka", "")); + cubeCards.add(new DraftCube.CardIdentity("Dragonlord Dromoka", "")); + cubeCards.add(new DraftCube.CardIdentity("Dragonlord Ojutai", "")); + cubeCards.add(new DraftCube.CardIdentity("Dragonlord Silumgar", "")); + cubeCards.add(new DraftCube.CardIdentity("Dread Return", "")); + cubeCards.add(new DraftCube.CardIdentity("Dromoka's Command", "")); + cubeCards.add(new DraftCube.CardIdentity("Druidic Satchel", "")); + cubeCards.add(new DraftCube.CardIdentity("Duplicant", "")); + cubeCards.add(new DraftCube.CardIdentity("Duskwatch Recruiter", "")); + cubeCards.add(new DraftCube.CardIdentity("Edric, Spymaster of Trest", "")); + cubeCards.add(new DraftCube.CardIdentity("Eidolon of the Great Revel", "")); + cubeCards.add(new DraftCube.CardIdentity("Elder Deep-Fiend", "")); + cubeCards.add(new DraftCube.CardIdentity("Eldrazi Displacer", "")); + cubeCards.add(new DraftCube.CardIdentity("Eldrazi Skyspawner", "")); + cubeCards.add(new DraftCube.CardIdentity("Eldrazi Temple", "")); + cubeCards.add(new DraftCube.CardIdentity("Electrolyze", "")); + cubeCards.add(new DraftCube.CardIdentity("Elesh Norn, Grand Cenobite", "")); + cubeCards.add(new DraftCube.CardIdentity("Elixir of Immortality", "")); + cubeCards.add(new DraftCube.CardIdentity("Elspeth, Sun's Champion", "")); + cubeCards.add(new DraftCube.CardIdentity("Elvish Visionary", "")); + cubeCards.add(new DraftCube.CardIdentity("Emrakul, the Aeons Torn", "")); + cubeCards.add(new DraftCube.CardIdentity("Emrakul, the Promised End", "")); + cubeCards.add(new DraftCube.CardIdentity("Enclave Cryptologist", "")); + cubeCards.add(new DraftCube.CardIdentity("Engineered Explosives", "")); + cubeCards.add(new DraftCube.CardIdentity("Ensnaring Bridge", "")); + cubeCards.add(new DraftCube.CardIdentity("Entomber Exarch", "")); + cubeCards.add(new DraftCube.CardIdentity("Eternal Witness", "")); + cubeCards.add(new DraftCube.CardIdentity("Everflowing Chalice", "")); + cubeCards.add(new DraftCube.CardIdentity("Evolutionary Leap", "")); + cubeCards.add(new DraftCube.CardIdentity("Exhume", "")); + cubeCards.add(new DraftCube.CardIdentity("Explore", "")); + cubeCards.add(new DraftCube.CardIdentity("Fact or Fiction", "")); + cubeCards.add(new DraftCube.CardIdentity("Faith's Fetters", "")); + cubeCards.add(new DraftCube.CardIdentity("Faithless Looting", "")); + cubeCards.add(new DraftCube.CardIdentity("Falkenrath Aristocrat", "")); + cubeCards.add(new DraftCube.CardIdentity("Fastbond", "")); + cubeCards.add(new DraftCube.CardIdentity("Feldon of the Third Path", "")); + cubeCards.add(new DraftCube.CardIdentity("Fellwar Stone", "")); + cubeCards.add(new DraftCube.CardIdentity("Fiend Hunter", "")); + cubeCards.add(new DraftCube.CardIdentity("Fiery Justice", "")); + cubeCards.add(new DraftCube.CardIdentity("Figure of Destiny", "")); + cubeCards.add(new DraftCube.CardIdentity("Fire // Ice", "")); + cubeCards.add(new DraftCube.CardIdentity("Fireblast", "")); + cubeCards.add(new DraftCube.CardIdentity("Firebolt", "")); + cubeCards.add(new DraftCube.CardIdentity("Firedrinker Satyr", "")); + cubeCards.add(new DraftCube.CardIdentity("Flame Slash", "")); + cubeCards.add(new DraftCube.CardIdentity("Flametongue Kavu", "")); + cubeCards.add(new DraftCube.CardIdentity("Fleecemane Lion", "")); + cubeCards.add(new DraftCube.CardIdentity("Fleetwheel Cruiser", "")); + cubeCards.add(new DraftCube.CardIdentity("Flickerwisp", "")); + cubeCards.add(new DraftCube.CardIdentity("Flooded Grove", "")); + cubeCards.add(new DraftCube.CardIdentity("Force of Will", "")); + cubeCards.add(new DraftCube.CardIdentity("Forked Bolt", "")); + cubeCards.add(new DraftCube.CardIdentity("Frantic Search", "")); + cubeCards.add(new DraftCube.CardIdentity("Frontier Bivouac", "")); + cubeCards.add(new DraftCube.CardIdentity("Frost Titan", "")); + cubeCards.add(new DraftCube.CardIdentity("Gaea's Cradle", "")); + cubeCards.add(new DraftCube.CardIdentity("Garruk Wildspeaker", "")); + cubeCards.add(new DraftCube.CardIdentity("Garza's Assassin", "")); + cubeCards.add(new DraftCube.CardIdentity("Gavony Township", "")); + cubeCards.add(new DraftCube.CardIdentity("Geist of Saint Traft", "")); + cubeCards.add(new DraftCube.CardIdentity("Genesis Hydra", "")); + cubeCards.add(new DraftCube.CardIdentity("Genesis Wave", "")); + cubeCards.add(new DraftCube.CardIdentity("Ghor-Clan Rampager", "")); + cubeCards.add(new DraftCube.CardIdentity("Gideon Jura", "")); + cubeCards.add(new DraftCube.CardIdentity("Gideon, Ally of Zendikar", "")); + cubeCards.add(new DraftCube.CardIdentity("Gilded Lotus", "")); + cubeCards.add(new DraftCube.CardIdentity("Gitaxian Probe", "")); + cubeCards.add(new DraftCube.CardIdentity("Glen Elendra Archmage", "")); + cubeCards.add(new DraftCube.CardIdentity("Glint-Nest Crane", "")); + cubeCards.add(new DraftCube.CardIdentity("Go for the Throat", "")); + cubeCards.add(new DraftCube.CardIdentity("Goblin Bombardment", "")); + cubeCards.add(new DraftCube.CardIdentity("Goblin Bushwhacker", "")); + cubeCards.add(new DraftCube.CardIdentity("Goblin Dark-Dwellers", "")); + cubeCards.add(new DraftCube.CardIdentity("Goblin Guide", "")); + cubeCards.add(new DraftCube.CardIdentity("Goblin Rabblemaster", "")); + cubeCards.add(new DraftCube.CardIdentity("Goblin Welder", "")); + cubeCards.add(new DraftCube.CardIdentity("Golgari Rot Farm", "")); + cubeCards.add(new DraftCube.CardIdentity("Gonti, Lord of Luxury", "")); + cubeCards.add(new DraftCube.CardIdentity("Grave Titan", "")); + cubeCards.add(new DraftCube.CardIdentity("Gray Merchant of Asphodel", "")); + cubeCards.add(new DraftCube.CardIdentity("Greater Gargadon", "")); + cubeCards.add(new DraftCube.CardIdentity("Grenzo, Dungeon Warden", "")); + cubeCards.add(new DraftCube.CardIdentity("Grim Lavamancer", "")); + cubeCards.add(new DraftCube.CardIdentity("Grim Monolith", "")); + cubeCards.add(new DraftCube.CardIdentity("Griselbrand", "")); + cubeCards.add(new DraftCube.CardIdentity("Gruul Turf", "")); + cubeCards.add(new DraftCube.CardIdentity("Hangarback Walker", "")); + cubeCards.add(new DraftCube.CardIdentity("Hanweir Militia Captain", "")); + cubeCards.add(new DraftCube.CardIdentity("Harbinger of the Tides", "")); + cubeCards.add(new DraftCube.CardIdentity("Harmonize", "")); + cubeCards.add(new DraftCube.CardIdentity("Hedron Archive", "")); + cubeCards.add(new DraftCube.CardIdentity("Hellrider", "")); + cubeCards.add(new DraftCube.CardIdentity("Hermit Druid", "")); + cubeCards.add(new DraftCube.CardIdentity("Hero of Bladehold", "")); + cubeCards.add(new DraftCube.CardIdentity("Hero's Downfall", "")); + cubeCards.add(new DraftCube.CardIdentity("Hissing Quagmire", "")); + cubeCards.add(new DraftCube.CardIdentity("Honor of the Pure", "")); + cubeCards.add(new DraftCube.CardIdentity("Hooting Mandrills", "")); + cubeCards.add(new DraftCube.CardIdentity("Hordeling Outburst", "")); + cubeCards.add(new DraftCube.CardIdentity("Hornet Queen", "")); + cubeCards.add(new DraftCube.CardIdentity("Huntmaster of the Fells", "")); + cubeCards.add(new DraftCube.CardIdentity("Hymn to Tourach", "")); + cubeCards.add(new DraftCube.CardIdentity("Incinerate", "")); + cubeCards.add(new DraftCube.CardIdentity("Inferno Titan", "")); + cubeCards.add(new DraftCube.CardIdentity("Inquisition of Kozilek", "")); + cubeCards.add(new DraftCube.CardIdentity("Insolent Neonate", "")); + cubeCards.add(new DraftCube.CardIdentity("Ishkanah, Grafwidow", "")); + cubeCards.add(new DraftCube.CardIdentity("Ivory Tower", "")); + cubeCards.add(new DraftCube.CardIdentity("Izzet Boilerworks", "")); + cubeCards.add(new DraftCube.CardIdentity("Izzet Signet", "")); + cubeCards.add(new DraftCube.CardIdentity("Jace Beleren", "")); + cubeCards.add(new DraftCube.CardIdentity("Jace, Vryn's Prodigy", "")); + cubeCards.add(new DraftCube.CardIdentity("Jace, the Mind Sculptor", "")); + cubeCards.add(new DraftCube.CardIdentity("Joraga Treespeaker", "")); + cubeCards.add(new DraftCube.CardIdentity("Journey to Nowhere", "")); + cubeCards.add(new DraftCube.CardIdentity("Jungle Shrine", "")); + cubeCards.add(new DraftCube.CardIdentity("Kalitas, Traitor of Ghet", "")); + cubeCards.add(new DraftCube.CardIdentity("Karakas", "")); + cubeCards.add(new DraftCube.CardIdentity("Kargan Dragonlord", "")); + cubeCards.add(new DraftCube.CardIdentity("Karn Liberated", "")); + cubeCards.add(new DraftCube.CardIdentity("Keranos, God of Storms", "")); + cubeCards.add(new DraftCube.CardIdentity("Kessig Wolf Run", "")); + cubeCards.add(new DraftCube.CardIdentity("Key to the City", "")); + cubeCards.add(new DraftCube.CardIdentity("Kher Keep", "")); + cubeCards.add(new DraftCube.CardIdentity("Kiki-Jiki, Mirror Breaker", "")); + cubeCards.add(new DraftCube.CardIdentity("Kiora's Follower", "")); + cubeCards.add(new DraftCube.CardIdentity("Kiora, the Crashing Wave", "")); + cubeCards.add(new DraftCube.CardIdentity("Kira, Great Glass-Spinner", "")); + cubeCards.add(new DraftCube.CardIdentity("Kitchen Finks", "")); + cubeCards.add(new DraftCube.CardIdentity("Knight of Glory", "")); + cubeCards.add(new DraftCube.CardIdentity("Kokusho, the Evening Star", "")); + cubeCards.add(new DraftCube.CardIdentity("Kolaghan's Command", "")); + cubeCards.add(new DraftCube.CardIdentity("Kozilek's Return", "")); + cubeCards.add(new DraftCube.CardIdentity("Kozilek, Butcher of Truth", "")); + cubeCards.add(new DraftCube.CardIdentity("Krosan Grip", "")); + cubeCards.add(new DraftCube.CardIdentity("Kytheon, Hero of Akros", "")); + cubeCards.add(new DraftCube.CardIdentity("Lavaclaw Reaches", "")); + cubeCards.add(new DraftCube.CardIdentity("Legacy's Allure", "")); + cubeCards.add(new DraftCube.CardIdentity("Legion Loyalist", "")); + cubeCards.add(new DraftCube.CardIdentity("Leovold, Emissary of Trest", "")); + cubeCards.add(new DraftCube.CardIdentity("Library of Alexandria", "")); + cubeCards.add(new DraftCube.CardIdentity("Lifebane Zombie", "")); + cubeCards.add(new DraftCube.CardIdentity("Lightning Berserker", "")); + cubeCards.add(new DraftCube.CardIdentity("Lightning Bolt", "")); + cubeCards.add(new DraftCube.CardIdentity("Lightning Helix", "")); + cubeCards.add(new DraftCube.CardIdentity("Lightning Mauler", "")); + cubeCards.add(new DraftCube.CardIdentity("Liliana of the Veil", "")); + cubeCards.add(new DraftCube.CardIdentity("Liliana, Heretical Healer", "")); + cubeCards.add(new DraftCube.CardIdentity("Liliana, the Last Hope", "")); + cubeCards.add(new DraftCube.CardIdentity("Lingering Souls", "")); + cubeCards.add(new DraftCube.CardIdentity("Linvala, the Preserver", "")); + cubeCards.add(new DraftCube.CardIdentity("Living Death", "")); + cubeCards.add(new DraftCube.CardIdentity("Llanowar Elves", "")); + cubeCards.add(new DraftCube.CardIdentity("Lodestone Golem", "")); + cubeCards.add(new DraftCube.CardIdentity("Looter il-Kor", "")); + cubeCards.add(new DraftCube.CardIdentity("Lotleth Troll", "")); + cubeCards.add(new DraftCube.CardIdentity("Lotus Bloom", "")); + cubeCards.add(new DraftCube.CardIdentity("Lumbering Falls", "")); + cubeCards.add(new DraftCube.CardIdentity("Maelstrom Pulse", "")); + cubeCards.add(new DraftCube.CardIdentity("Maelstrom Wanderer", "")); + cubeCards.add(new DraftCube.CardIdentity("Magma Jet", "")); + cubeCards.add(new DraftCube.CardIdentity("Malicious Affliction", "")); + cubeCards.add(new DraftCube.CardIdentity("Man-o'-War", "")); + cubeCards.add(new DraftCube.CardIdentity("Mana Crypt", "")); + cubeCards.add(new DraftCube.CardIdentity("Mana Drain", "")); + cubeCards.add(new DraftCube.CardIdentity("Mana Leak", "")); + cubeCards.add(new DraftCube.CardIdentity("Mana Tithe", "")); + cubeCards.add(new DraftCube.CardIdentity("Mana Vault", "")); + cubeCards.add(new DraftCube.CardIdentity("Managorger Hydra", "")); + cubeCards.add(new DraftCube.CardIdentity("Mantis Rider", "")); + cubeCards.add(new DraftCube.CardIdentity("Marsh Flitter", "")); + cubeCards.add(new DraftCube.CardIdentity("Martial Coup", "")); + cubeCards.add(new DraftCube.CardIdentity("Master of Waves", "")); + cubeCards.add(new DraftCube.CardIdentity("Master of the Wild Hunt", "")); + cubeCards.add(new DraftCube.CardIdentity("Mastery of the Unseen", "")); + cubeCards.add(new DraftCube.CardIdentity("Masticore", "")); + cubeCards.add(new DraftCube.CardIdentity("Maze of Ith", "")); + cubeCards.add(new DraftCube.CardIdentity("Memory Jar", "")); + cubeCards.add(new DraftCube.CardIdentity("Metalworker", "")); + cubeCards.add(new DraftCube.CardIdentity("Mind Stone", "")); + cubeCards.add(new DraftCube.CardIdentity("Mind Twist", "")); + cubeCards.add(new DraftCube.CardIdentity("Mindslaver", "")); + cubeCards.add(new DraftCube.CardIdentity("Mindwrack Demon", "")); + cubeCards.add(new DraftCube.CardIdentity("Mirari's Wake", "")); + cubeCards.add(new DraftCube.CardIdentity("Mirran Crusader", "")); + cubeCards.add(new DraftCube.CardIdentity("Mirror Entity", "")); + cubeCards.add(new DraftCube.CardIdentity("Mishra's Factory", "")); + cubeCards.add(new DraftCube.CardIdentity("Mishra's Workshop", "")); + cubeCards.add(new DraftCube.CardIdentity("Mogg War Marshal", "")); + cubeCards.add(new DraftCube.CardIdentity("Molten Rain", "")); + cubeCards.add(new DraftCube.CardIdentity("Monastery Mentor", "")); + cubeCards.add(new DraftCube.CardIdentity("Monastery Swiftspear", "")); + cubeCards.add(new DraftCube.CardIdentity("Moorland Haunt", "")); + cubeCards.add(new DraftCube.CardIdentity("Mother of Runes", "")); + cubeCards.add(new DraftCube.CardIdentity("Mox Diamond", "")); + cubeCards.add(new DraftCube.CardIdentity("Mox Emerald", "")); + cubeCards.add(new DraftCube.CardIdentity("Mox Jet", "")); + cubeCards.add(new DraftCube.CardIdentity("Mox Pearl", "")); + cubeCards.add(new DraftCube.CardIdentity("Mox Ruby", "")); + cubeCards.add(new DraftCube.CardIdentity("Mox Sapphire", "")); + cubeCards.add(new DraftCube.CardIdentity("Mulldrifter", "")); + cubeCards.add(new DraftCube.CardIdentity("Murderous Redcap", "")); + cubeCards.add(new DraftCube.CardIdentity("Mutavault", "")); + cubeCards.add(new DraftCube.CardIdentity("Myr Battlesphere", "")); + cubeCards.add(new DraftCube.CardIdentity("Mystic Monastery", "")); + cubeCards.add(new DraftCube.CardIdentity("Nahiri, the Harbinger", "")); + cubeCards.add(new DraftCube.CardIdentity("Nature's Claim", "")); + cubeCards.add(new DraftCube.CardIdentity("Necromancy", "")); + cubeCards.add(new DraftCube.CardIdentity("Necropotence", "")); + cubeCards.add(new DraftCube.CardIdentity("Needle Spires", "")); + cubeCards.add(new DraftCube.CardIdentity("Nephalia Drownyard", "")); + cubeCards.add(new DraftCube.CardIdentity("Nest Invader", "")); + cubeCards.add(new DraftCube.CardIdentity("Nicol Bolas, Planeswalker", "")); + cubeCards.add(new DraftCube.CardIdentity("Night's Whisper", "")); + cubeCards.add(new DraftCube.CardIdentity("Nightveil Specter", "")); + cubeCards.add(new DraftCube.CardIdentity("Nissa, Vital Force", "")); + cubeCards.add(new DraftCube.CardIdentity("Nissa, Voice of Zendikar", "")); + cubeCards.add(new DraftCube.CardIdentity("Noble Hierarch", "")); + cubeCards.add(new DraftCube.CardIdentity("Nomad Outpost", "")); + cubeCards.add(new DraftCube.CardIdentity("Noose Constrictor", "")); + cubeCards.add(new DraftCube.CardIdentity("Noxious Gearhulk", "")); + cubeCards.add(new DraftCube.CardIdentity("Nyx-Fleece Ram", "")); + cubeCards.add(new DraftCube.CardIdentity("Oath of Druids", "")); + cubeCards.add(new DraftCube.CardIdentity("Oath of Nissa", "")); + cubeCards.add(new DraftCube.CardIdentity("Oblivion Ring", "")); + cubeCards.add(new DraftCube.CardIdentity("Oblivion Sower", "")); + cubeCards.add(new DraftCube.CardIdentity("Oblivion Stone", "")); + cubeCards.add(new DraftCube.CardIdentity("Obstinate Baloth", "")); + cubeCards.add(new DraftCube.CardIdentity("Obzedat, Ghost Council", "")); + cubeCards.add(new DraftCube.CardIdentity("Ohran Viper", "")); + cubeCards.add(new DraftCube.CardIdentity("Ophiomancer", "")); + cubeCards.add(new DraftCube.CardIdentity("Opposition", "")); + cubeCards.add(new DraftCube.CardIdentity("Opulent Palace", "")); + cubeCards.add(new DraftCube.CardIdentity("Oracle of Mul Daya", "")); + cubeCards.add(new DraftCube.CardIdentity("Orzhov Basilica", "")); + cubeCards.add(new DraftCube.CardIdentity("Outpost Siege", "")); + cubeCards.add(new DraftCube.CardIdentity("Pack Rat", "")); + cubeCards.add(new DraftCube.CardIdentity("Pact of Negation", "")); + cubeCards.add(new DraftCube.CardIdentity("Painful Truths", "")); + cubeCards.add(new DraftCube.CardIdentity("Paliano, the High City", "")); + cubeCards.add(new DraftCube.CardIdentity("Palinchron", "")); + cubeCards.add(new DraftCube.CardIdentity("Palladium Myr", "")); + cubeCards.add(new DraftCube.CardIdentity("Pelakka Wurm", "")); + cubeCards.add(new DraftCube.CardIdentity("Pentavus", "")); + cubeCards.add(new DraftCube.CardIdentity("Pernicious Deed", "")); + cubeCards.add(new DraftCube.CardIdentity("Pestermite", "")); + cubeCards.add(new DraftCube.CardIdentity("Phantasmal Image", "")); + cubeCards.add(new DraftCube.CardIdentity("Phyrexian Metamorph", "")); + cubeCards.add(new DraftCube.CardIdentity("Phyrexian Revoker", "")); + cubeCards.add(new DraftCube.CardIdentity("Phyrexian Tower", "")); + cubeCards.add(new DraftCube.CardIdentity("Pia Nalaar", "")); + cubeCards.add(new DraftCube.CardIdentity("Pia and Kiran Nalaar", "")); + cubeCards.add(new DraftCube.CardIdentity("Plateau", "")); + cubeCards.add(new DraftCube.CardIdentity("Polukranos, World Eater", "")); + cubeCards.add(new DraftCube.CardIdentity("Ponder", "")); + cubeCards.add(new DraftCube.CardIdentity("Porcelain Legionnaire", "")); + cubeCards.add(new DraftCube.CardIdentity("Precinct Captain", "")); + cubeCards.add(new DraftCube.CardIdentity("Preordain", "")); + cubeCards.add(new DraftCube.CardIdentity("Price of Progress", "")); + cubeCards.add(new DraftCube.CardIdentity("Prime Speaker Zegana", "")); + cubeCards.add(new DraftCube.CardIdentity("Pristine Talisman", "")); + cubeCards.add(new DraftCube.CardIdentity("Prophet of Kruphix", "")); + cubeCards.add(new DraftCube.CardIdentity("Puppeteer Clique", "")); + cubeCards.add(new DraftCube.CardIdentity("Quarantine Field", "")); + cubeCards.add(new DraftCube.CardIdentity("Radiant Flames", "")); + cubeCards.add(new DraftCube.CardIdentity("Raging Ravine", "")); + cubeCards.add(new DraftCube.CardIdentity("Rakdos Carnarium", "")); + cubeCards.add(new DraftCube.CardIdentity("Rakdos's Return", "")); + cubeCards.add(new DraftCube.CardIdentity("Rancor", "")); + cubeCards.add(new DraftCube.CardIdentity("Ratchet Bomb", "")); + cubeCards.add(new DraftCube.CardIdentity("Reality Smasher", "")); + cubeCards.add(new DraftCube.CardIdentity("Reanimate", "")); + cubeCards.add(new DraftCube.CardIdentity("Reassembling Skeleton", "")); + cubeCards.add(new DraftCube.CardIdentity("Reclamation Sage", "")); + cubeCards.add(new DraftCube.CardIdentity("Recurring Nightmare", "")); + cubeCards.add(new DraftCube.CardIdentity("Reflector Mage", "")); + cubeCards.add(new DraftCube.CardIdentity("Regrowth", "")); + cubeCards.add(new DraftCube.CardIdentity("Relic of Progenitus", "")); + cubeCards.add(new DraftCube.CardIdentity("Remand", "")); + cubeCards.add(new DraftCube.CardIdentity("Restoration Angel", "")); + cubeCards.add(new DraftCube.CardIdentity("Reveillark", "")); + cubeCards.add(new DraftCube.CardIdentity("Ribbons of Night", "")); + cubeCards.add(new DraftCube.CardIdentity("Rift Bolt", "")); + cubeCards.add(new DraftCube.CardIdentity("Riftwing Cloudskate", "")); + cubeCards.add(new DraftCube.CardIdentity("Rishadan Port", "")); + cubeCards.add(new DraftCube.CardIdentity("Rofellos, Llanowar Emissary", "")); + cubeCards.add(new DraftCube.CardIdentity("Sandsteppe Citadel", "")); + cubeCards.add(new DraftCube.CardIdentity("Satyr Wayfinder", "")); + cubeCards.add(new DraftCube.CardIdentity("Savage Lands", "")); + cubeCards.add(new DraftCube.CardIdentity("Savannah", "")); + cubeCards.add(new DraftCube.CardIdentity("Scavenging Ooze", "")); + cubeCards.add(new DraftCube.CardIdentity("Scrapheap Scrounger", "")); + cubeCards.add(new DraftCube.CardIdentity("Scrubland", "")); + cubeCards.add(new DraftCube.CardIdentity("Sea Gate Oracle", "")); + cubeCards.add(new DraftCube.CardIdentity("Sea Gate Wreckage", "")); + cubeCards.add(new DraftCube.CardIdentity("Seal of Primordium", "")); + cubeCards.add(new DraftCube.CardIdentity("Searing Blaze", "")); + cubeCards.add(new DraftCube.CardIdentity("Searing Blood", "")); + cubeCards.add(new DraftCube.CardIdentity("Seaside Citadel", "")); + cubeCards.add(new DraftCube.CardIdentity("Seasons Past", "")); + cubeCards.add(new DraftCube.CardIdentity("Secure the Wastes", "")); + cubeCards.add(new DraftCube.CardIdentity("Seeker of the Way", "")); + cubeCards.add(new DraftCube.CardIdentity("Selesnya Sanctuary", "")); + cubeCards.add(new DraftCube.CardIdentity("Selfless Spirit", "")); + cubeCards.add(new DraftCube.CardIdentity("Setessan Tactics", "")); + cubeCards.add(new DraftCube.CardIdentity("Shambling Vent", "")); + cubeCards.add(new DraftCube.CardIdentity("Shardless Agent", "")); + cubeCards.add(new DraftCube.CardIdentity("Shelldock Isle", "")); + cubeCards.add(new DraftCube.CardIdentity("Show and Tell", "")); + cubeCards.add(new DraftCube.CardIdentity("Shriekmaw", "")); + cubeCards.add(new DraftCube.CardIdentity("Shrine of Burning Rage", "")); + cubeCards.add(new DraftCube.CardIdentity("Siege Rhino", "")); + cubeCards.add(new DraftCube.CardIdentity("Siege-Gang Commander", "")); + cubeCards.add(new DraftCube.CardIdentity("Simic Growth Chamber", "")); + cubeCards.add(new DraftCube.CardIdentity("Sinkhole", "")); + cubeCards.add(new DraftCube.CardIdentity("Skirsdag High Priest", "")); + cubeCards.add(new DraftCube.CardIdentity("Skullclamp", "")); + cubeCards.add(new DraftCube.CardIdentity("Skysovereign, Consul Flagship", "")); + cubeCards.add(new DraftCube.CardIdentity("Slaughter Pact", "")); + cubeCards.add(new DraftCube.CardIdentity("Slayers' Stronghold", "")); + cubeCards.add(new DraftCube.CardIdentity("Smash to Smithereens", "")); + cubeCards.add(new DraftCube.CardIdentity("Smokestack", "")); + cubeCards.add(new DraftCube.CardIdentity("Smuggler's Copter", "")); + cubeCards.add(new DraftCube.CardIdentity("Snapcaster Mage", "")); + cubeCards.add(new DraftCube.CardIdentity("Sneak Attack", "")); + cubeCards.add(new DraftCube.CardIdentity("Sol Ring", "")); + cubeCards.add(new DraftCube.CardIdentity("Soldier of the Pantheon", "")); + cubeCards.add(new DraftCube.CardIdentity("Sorin, Grim Nemesis", "")); + cubeCards.add(new DraftCube.CardIdentity("Sorin, Solemn Visitor", "")); + cubeCards.add(new DraftCube.CardIdentity("Soulfire Grand Master", "")); + cubeCards.add(new DraftCube.CardIdentity("Sower of Temptation", "")); + cubeCards.add(new DraftCube.CardIdentity("Spear of Heliod", "")); + cubeCards.add(new DraftCube.CardIdentity("Spectral Procession", "")); + cubeCards.add(new DraftCube.CardIdentity("Spell Pierce", "")); + cubeCards.add(new DraftCube.CardIdentity("Spell Queller", "")); + cubeCards.add(new DraftCube.CardIdentity("Spellskite", "")); + cubeCards.add(new DraftCube.CardIdentity("Sphere of the Suns", "")); + cubeCards.add(new DraftCube.CardIdentity("Sphinx of the Steel Wind", "")); + cubeCards.add(new DraftCube.CardIdentity("Sphinx's Revelation", "")); + cubeCards.add(new DraftCube.CardIdentity("Splinter Twin", "")); + cubeCards.add(new DraftCube.CardIdentity("Stirring Wildwood", "")); + cubeCards.add(new DraftCube.CardIdentity("Stoke the Flames", "")); + cubeCards.add(new DraftCube.CardIdentity("Stormbreath Dragon", "")); + cubeCards.add(new DraftCube.CardIdentity("Stratus Dancer", "")); + cubeCards.add(new DraftCube.CardIdentity("Strip Mine", "")); + cubeCards.add(new DraftCube.CardIdentity("Student of Warfare", "")); + cubeCards.add(new DraftCube.CardIdentity("Sublime Archangel", "")); + cubeCards.add(new DraftCube.CardIdentity("Sulfuric Vortex", "")); + cubeCards.add(new DraftCube.CardIdentity("Sun Titan", "")); + cubeCards.add(new DraftCube.CardIdentity("Sundering Titan", "")); + cubeCards.add(new DraftCube.CardIdentity("Supreme Verdict", "")); + cubeCards.add(new DraftCube.CardIdentity("Sword of Feast and Famine", "")); + cubeCards.add(new DraftCube.CardIdentity("Sword of Fire and Ice", "")); + cubeCards.add(new DraftCube.CardIdentity("Swords to Plowshares", "")); + cubeCards.add(new DraftCube.CardIdentity("Sylvan Advocate", "")); + cubeCards.add(new DraftCube.CardIdentity("Sylvan Caryatid", "")); + cubeCards.add(new DraftCube.CardIdentity("Taiga", "")); + cubeCards.add(new DraftCube.CardIdentity("Tamiyo, Field Researcher", "")); + cubeCards.add(new DraftCube.CardIdentity("Tamiyo, the Moon Sage", "")); + cubeCards.add(new DraftCube.CardIdentity("Tarmogoyf", "")); + cubeCards.add(new DraftCube.CardIdentity("Tasigur, the Golden Fang", "")); + cubeCards.add(new DraftCube.CardIdentity("Temple of Abandon", "")); + cubeCards.add(new DraftCube.CardIdentity("Temple of Deceit", "")); + cubeCards.add(new DraftCube.CardIdentity("Temple of Epiphany", "")); + cubeCards.add(new DraftCube.CardIdentity("Temple of Malady", "")); + cubeCards.add(new DraftCube.CardIdentity("Temple of Malice", "")); + cubeCards.add(new DraftCube.CardIdentity("Temple of Mystery", "")); + cubeCards.add(new DraftCube.CardIdentity("Temple of Mystery", "")); + cubeCards.add(new DraftCube.CardIdentity("Temple of Plenty", "")); + cubeCards.add(new DraftCube.CardIdentity("Temple of Silence", "")); + cubeCards.add(new DraftCube.CardIdentity("Temple of Triumph", "")); + cubeCards.add(new DraftCube.CardIdentity("Tendrils of Corruption", "")); + cubeCards.add(new DraftCube.CardIdentity("Terastodon", "")); + cubeCards.add(new DraftCube.CardIdentity("Terminus", "")); + cubeCards.add(new DraftCube.CardIdentity("Tezzeret, Agent of Bolas", "")); + cubeCards.add(new DraftCube.CardIdentity("Thalia's Lieutenant", "")); + cubeCards.add(new DraftCube.CardIdentity("Thalia, Guardian of Thraben", "")); + cubeCards.add(new DraftCube.CardIdentity("Thalia, Heretic Cathar", "")); + cubeCards.add(new DraftCube.CardIdentity("Thassa, God of the Sea", "")); + cubeCards.add(new DraftCube.CardIdentity("Thing in the Ice", "")); + cubeCards.add(new DraftCube.CardIdentity("Thirst for Knowledge", "")); + cubeCards.add(new DraftCube.CardIdentity("Thopter Engineer", "")); + cubeCards.add(new DraftCube.CardIdentity("Thought-Knot Seer", "")); + cubeCards.add(new DraftCube.CardIdentity("Thoughtseize", "")); + cubeCards.add(new DraftCube.CardIdentity("Thraben Inspector", "")); + cubeCards.add(new DraftCube.CardIdentity("Thragtusk", "")); + cubeCards.add(new DraftCube.CardIdentity("Thran Dynamo", "")); + cubeCards.add(new DraftCube.CardIdentity("Thrun, the Last Troll", "")); + cubeCards.add(new DraftCube.CardIdentity("Thunderbreak Regent", "")); + cubeCards.add(new DraftCube.CardIdentity("Thundermaw Hellkite", "")); + cubeCards.add(new DraftCube.CardIdentity("Tidebinder Mage", "")); + cubeCards.add(new DraftCube.CardIdentity("Time Spiral", "")); + cubeCards.add(new DraftCube.CardIdentity("Time Walk", "")); + cubeCards.add(new DraftCube.CardIdentity("Timely Reinforcements", "")); + cubeCards.add(new DraftCube.CardIdentity("Timetwister", "")); + cubeCards.add(new DraftCube.CardIdentity("Tin Street Hooligan", "")); + cubeCards.add(new DraftCube.CardIdentity("Tireless Tracker", "")); + cubeCards.add(new DraftCube.CardIdentity("Tolarian Academy", "")); + cubeCards.add(new DraftCube.CardIdentity("Tormenting Voice", "")); + cubeCards.add(new DraftCube.CardIdentity("Torrential Gearhulk", "")); + cubeCards.add(new DraftCube.CardIdentity("Toxic Deluge", "")); + cubeCards.add(new DraftCube.CardIdentity("Tradewind Rider", "")); + cubeCards.add(new DraftCube.CardIdentity("Trading Post", "")); + cubeCards.add(new DraftCube.CardIdentity("Treachery", "")); + cubeCards.add(new DraftCube.CardIdentity("Treasure Cruise", "")); + cubeCards.add(new DraftCube.CardIdentity("Treetop Village", "")); + cubeCards.add(new DraftCube.CardIdentity("Triskelion", "")); + cubeCards.add(new DraftCube.CardIdentity("Tropical Island", "")); + cubeCards.add(new DraftCube.CardIdentity("True-Name Nemesis", "")); + cubeCards.add(new DraftCube.CardIdentity("Tundra", "")); + cubeCards.add(new DraftCube.CardIdentity("Twilight Mire", "")); + cubeCards.add(new DraftCube.CardIdentity("Ugin, the Spirit Dragon", "")); + cubeCards.add(new DraftCube.CardIdentity("Ulamog, the Ceaseless Hunger", "")); + cubeCards.add(new DraftCube.CardIdentity("Umezawa's Jitte", "")); + cubeCards.add(new DraftCube.CardIdentity("Unburial Rites", "")); + cubeCards.add(new DraftCube.CardIdentity("Underground Sea", "")); + cubeCards.add(new DraftCube.CardIdentity("Unexpectedly Absent", "")); + cubeCards.add(new DraftCube.CardIdentity("Unlicensed Disintegration", "")); + cubeCards.add(new DraftCube.CardIdentity("Upheaval", "")); + cubeCards.add(new DraftCube.CardIdentity("Utopia Sprawl", "")); + cubeCards.add(new DraftCube.CardIdentity("Valorous Stance", "")); + cubeCards.add(new DraftCube.CardIdentity("Vampire Nighthawk", "")); + cubeCards.add(new DraftCube.CardIdentity("Varolz, the Scar-Striped", "")); + cubeCards.add(new DraftCube.CardIdentity("Vault of the Archangel", "")); + cubeCards.add(new DraftCube.CardIdentity("Vedalken Shackles", "")); + cubeCards.add(new DraftCube.CardIdentity("Vendilion Clique", "")); + cubeCards.add(new DraftCube.CardIdentity("Venser, Shaper Savant", "")); + cubeCards.add(new DraftCube.CardIdentity("Verdurous Gearhulk", "")); + cubeCards.add(new DraftCube.CardIdentity("Vesuvan Shapeshifter", "")); + cubeCards.add(new DraftCube.CardIdentity("Veteran Motorist", "")); + cubeCards.add(new DraftCube.CardIdentity("Vindicate", "")); + cubeCards.add(new DraftCube.CardIdentity("Viscera Seer", "")); + cubeCards.add(new DraftCube.CardIdentity("Voice of Resurgence", "")); + cubeCards.add(new DraftCube.CardIdentity("Volcanic Island", "")); + cubeCards.add(new DraftCube.CardIdentity("Volrath's Stronghold", "")); + cubeCards.add(new DraftCube.CardIdentity("Vraska the Unseen", "")); + cubeCards.add(new DraftCube.CardIdentity("Wall of Blossoms", "")); + cubeCards.add(new DraftCube.CardIdentity("Wall of Omens", "")); + cubeCards.add(new DraftCube.CardIdentity("Wall of Roots", "")); + cubeCards.add(new DraftCube.CardIdentity("Wandering Fumarole", "")); + cubeCards.add(new DraftCube.CardIdentity("Warden of the First Tree", "")); + cubeCards.add(new DraftCube.CardIdentity("Wasteland", "")); + cubeCards.add(new DraftCube.CardIdentity("Westvale Abbey", "")); + cubeCards.add(new DraftCube.CardIdentity("Wheel of Fortune", "")); + cubeCards.add(new DraftCube.CardIdentity("Whip of Erebos", "")); + cubeCards.add(new DraftCube.CardIdentity("Whirler Rogue", "")); + cubeCards.add(new DraftCube.CardIdentity("Whisperwood Elemental", "")); + cubeCards.add(new DraftCube.CardIdentity("Wickerbough Elder", "")); + cubeCards.add(new DraftCube.CardIdentity("Wild Growth", "")); + cubeCards.add(new DraftCube.CardIdentity("Wildest Dreams", "")); + cubeCards.add(new DraftCube.CardIdentity("Wildfire", "")); + cubeCards.add(new DraftCube.CardIdentity("Windbrisk Heights", "")); + cubeCards.add(new DraftCube.CardIdentity("Wingmate Roc", "")); + cubeCards.add(new DraftCube.CardIdentity("Winter Orb", "")); + cubeCards.add(new DraftCube.CardIdentity("Wolfir Silverheart", "")); + cubeCards.add(new DraftCube.CardIdentity("Woodland Wanderer", "")); + cubeCards.add(new DraftCube.CardIdentity("Worn Powerstone", "")); + cubeCards.add(new DraftCube.CardIdentity("Wrath of God", "")); + cubeCards.add(new DraftCube.CardIdentity("Wurmcoil Engine", "")); + cubeCards.add(new DraftCube.CardIdentity("Xathrid Necromancer", "")); + cubeCards.add(new DraftCube.CardIdentity("Yawgmoth's Bargain", "")); + cubeCards.add(new DraftCube.CardIdentity("Yawgmoth's Will", "")); + cubeCards.add(new DraftCube.CardIdentity("Young Pyromancer", "")); + cubeCards.add(new DraftCube.CardIdentity("Zealous Conscripts", "")); + cubeCards.add(new DraftCube.CardIdentity("Zulaport Cutthroat", "")); + cubeCards.add(new DraftCube.CardIdentity("Zurgo Bellstriker", "")); + } +} \ No newline at end of file diff --git a/Mage.Server/config/config.xml b/Mage.Server/config/config.xml index 88b18aa2161..0584d768669 100644 --- a/Mage.Server/config/config.xml +++ b/Mage.Server/config/config.xml @@ -103,6 +103,7 @@ + diff --git a/Mage.Server/release/config/config.xml b/Mage.Server/release/config/config.xml index 03b66244b09..90442aa45ff 100644 --- a/Mage.Server/release/config/config.xml +++ b/Mage.Server/release/config/config.xml @@ -100,6 +100,7 @@ + diff --git a/Mage.Sets/src/mage/cards/c/CruelReality.java b/Mage.Sets/src/mage/cards/c/CruelReality.java index 66be70bbb4f..1a323fc6995 100644 --- a/Mage.Sets/src/mage/cards/c/CruelReality.java +++ b/Mage.Sets/src/mage/cards/c/CruelReality.java @@ -161,6 +161,7 @@ class CruelRealityEffect extends OneShotEffect { } } cursedPlayer.loseLife(5, game, false); + return true; } return false; } diff --git a/Mage.Sets/src/mage/cards/d/DungroveElder.java b/Mage.Sets/src/mage/cards/d/DungroveElder.java index a7833ce80de..25c9ab1f1f1 100644 --- a/Mage.Sets/src/mage/cards/d/DungroveElder.java +++ b/Mage.Sets/src/mage/cards/d/DungroveElder.java @@ -28,6 +28,7 @@ package mage.cards.d; +import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; @@ -41,8 +42,6 @@ import mage.constants.Zone; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.SubtypePredicate; -import java.util.UUID; - /** * * @author Loki @@ -62,7 +61,10 @@ public class DungroveElder extends CardImpl { this.power = new MageInt(0); this.toughness = new MageInt(0); - this.addAbility(HexproofAbility.getInstance()); + // Hexproof (This creature can't be the target of spells or abilities your opponents control.) + this.addAbility(HexproofAbility.getInstance()); + + // Dungrove Elder's power and toughness are each equal to the number of Forests you control. this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(new PermanentsOnBattlefieldCount(filterLands), Duration.EndOfGame))); } diff --git a/Mage.Sets/src/mage/cards/g/GlyphKeeper.java b/Mage.Sets/src/mage/cards/g/GlyphKeeper.java index 2d5d1a3bf7a..fff800de406 100644 --- a/Mage.Sets/src/mage/cards/g/GlyphKeeper.java +++ b/Mage.Sets/src/mage/cards/g/GlyphKeeper.java @@ -32,6 +32,7 @@ import mage.MageInt; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.keyword.FlyingAbility; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.CounterTargetEffect; import mage.abilities.keyword.EmbalmAbility; import mage.cards.CardImpl; @@ -40,7 +41,9 @@ import mage.constants.CardType; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; -import mage.target.TargetStackObject; +import mage.game.permanent.Permanent; +import mage.target.targetpointer.FixedTarget; +import mage.watchers.common.NumberOfTimesPermanentTargetedATurnWatcher; /** * @@ -59,7 +62,7 @@ public class GlyphKeeper extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Whenever Glyph Keeper becomes the target of a spell or ability for the first time in a turn, counter that spell or ability. - this.addAbility(new GlyphKeeperAbility()); + this.addAbility(new GlyphKeeperAbility(), new NumberOfTimesPermanentTargetedATurnWatcher()); // Embalm {5}{U}{U} this.addAbility(new EmbalmAbility(new ManaCostsImpl("{5}{U}{U}"), this)); @@ -78,15 +81,12 @@ public class GlyphKeeper extends CardImpl { class GlyphKeeperAbility extends TriggeredAbilityImpl { - protected int turnUsed; - public GlyphKeeperAbility() { super(Zone.BATTLEFIELD, new CounterTargetEffect(), false); } public GlyphKeeperAbility(final GlyphKeeperAbility ability) { super(ability); - turnUsed = ability.turnUsed; } @Override @@ -101,13 +101,18 @@ class GlyphKeeperAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - if (event.getTargetId().equals(this.getSourceId()) && game.getTurnNum() > turnUsed) { - this.getTargets().clear(); - TargetStackObject target = new TargetStackObject(); - target.add(event.getSourceId(), game); - this.addTarget(target); - turnUsed = game.getTurnNum(); - return true; + if (event.getTargetId().equals(this.getSourceId())) { + Permanent permanent = game.getPermanent(event.getTargetId()); + if (permanent != null && permanent.isCreature()) { + NumberOfTimesPermanentTargetedATurnWatcher watcher = (NumberOfTimesPermanentTargetedATurnWatcher) game.getState().getWatchers().get(NumberOfTimesPermanentTargetedATurnWatcher.class.getName()); + if (watcher != null + && watcher.notMoreThanOnceTargetedThisTurn(permanent, game)) { + for (Effect effect : getEffects()) { + effect.setTargetPointer(new FixedTarget(event.getSourceId())); + } + return true; + } + } } return false; } @@ -117,4 +122,4 @@ class GlyphKeeperAbility extends TriggeredAbilityImpl { return "Whenever {this} becomes the target of a spell or ability for the first time in a turn, counter that spell or ability."; } -} +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/k/KiraGreatGlassSpinner.java b/Mage.Sets/src/mage/cards/k/KiraGreatGlassSpinner.java index 1ac7af667b3..0c1bf2bdb86 100644 --- a/Mage.Sets/src/mage/cards/k/KiraGreatGlassSpinner.java +++ b/Mage.Sets/src/mage/cards/k/KiraGreatGlassSpinner.java @@ -27,11 +27,8 @@ */ package mage.cards.k; -import java.util.HashMap; -import java.util.Map; import java.util.UUID; import mage.MageInt; -import mage.MageObjectReference; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.Effect; @@ -47,7 +44,7 @@ import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.target.targetpointer.FixedTarget; -import mage.watchers.Watcher; +import mage.watchers.common.NumberOfTimesPermanentTargetedATurnWatcher; /** * @@ -72,7 +69,7 @@ public class KiraGreatGlassSpinner extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(new KiraGreatGlassSpinnerAbility(effect), Duration.WhileOnBattlefield, new FilterCreaturePermanent("creatures"))), - new KiraGreatGlassSpinnerWatcher()); + new NumberOfTimesPermanentTargetedATurnWatcher()); } @@ -111,7 +108,7 @@ class KiraGreatGlassSpinnerAbility extends TriggeredAbilityImpl { if (event.getTargetId().equals(this.getSourceId())) { Permanent permanent = game.getPermanent(event.getTargetId()); if (permanent != null && permanent.isCreature()) { - KiraGreatGlassSpinnerWatcher watcher = (KiraGreatGlassSpinnerWatcher) game.getState().getWatchers().get(KiraGreatGlassSpinnerWatcher.class.getName()); + NumberOfTimesPermanentTargetedATurnWatcher watcher = (NumberOfTimesPermanentTargetedATurnWatcher) game.getState().getWatchers().get(NumberOfTimesPermanentTargetedATurnWatcher.class.getName()); if (watcher != null && watcher.notMoreThanOnceTargetedThisTurn(permanent, game)) { for (Effect effect : getEffects()) { effect.setTargetPointer(new FixedTarget(event.getSourceId())); @@ -128,51 +125,4 @@ class KiraGreatGlassSpinnerAbility extends TriggeredAbilityImpl { return "Whenever this creature becomes the target of a spell or ability for the first time in a turn, counter that spell or ability."; } -} - -class KiraGreatGlassSpinnerWatcher extends Watcher { - - private final Map creaturesTargeted = new HashMap<>(); - - public KiraGreatGlassSpinnerWatcher() { - super(KiraGreatGlassSpinnerWatcher.class.getName(), WatcherScope.GAME); - } - - public KiraGreatGlassSpinnerWatcher(final KiraGreatGlassSpinnerWatcher watcher) { - super(watcher); - this.creaturesTargeted.putAll(creaturesTargeted); - } - - @Override - public void watch(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.TARGETED) { - Permanent permanent = game.getPermanent(event.getTargetId()); - if (permanent != null) { - MageObjectReference mor = new MageObjectReference(permanent, game); - int amount = 0; - if (creaturesTargeted.containsKey(mor)) { - amount = creaturesTargeted.get(mor); - } - creaturesTargeted.put(mor, ++amount); - } - } - } - - public boolean notMoreThanOnceTargetedThisTurn(Permanent creature, Game game) { - if (creaturesTargeted.containsKey(new MageObjectReference(creature, game))) { - return creaturesTargeted.get(new MageObjectReference(creature, game)) < 2; - } - return true; - } - - @Override - public void reset() { - super.reset(); - creaturesTargeted.clear(); - } - - @Override - public KiraGreatGlassSpinnerWatcher copy() { - return new KiraGreatGlassSpinnerWatcher(this); - } -} +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/l/LilianaDeathsMajesty.java b/Mage.Sets/src/mage/cards/l/LilianaDeathsMajesty.java index d8d044b6d4b..ab62477845b 100644 --- a/Mage.Sets/src/mage/cards/l/LilianaDeathsMajesty.java +++ b/Mage.Sets/src/mage/cards/l/LilianaDeathsMajesty.java @@ -28,10 +28,8 @@ package mage.cards.l; import java.util.UUID; - import mage.abilities.LoyaltyAbility; import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DestroyAllEffect; import mage.abilities.effects.common.PutTopCardOfLibraryIntoGraveControllerEffect; @@ -40,8 +38,6 @@ import mage.abilities.effects.common.continuous.BecomesBlackZombieAdditionEffect import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; import mage.filter.common.FilterCreatureCard; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; @@ -75,9 +71,11 @@ public class LilianaDeathsMajesty extends CardImpl { this.addAbility(ability); // -3: Return target creature card from your graveyard to the battlefield. That creature is a black Zombie in addition to its other colors and types. - ability = new LoyaltyAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(), -3); + ability = new LoyaltyAbility(new BecomesBlackZombieAdditionEffect() // because the effect has to be active for triggered effects that e.g. check if the creature entering is a Zombie, the continuous effect needs to be added before the card moving effect is applied + .setText(""), -3); ability.addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card from your graveyard"))); - ability.addEffect(new BecomesBlackZombieAdditionEffect()); + ability.addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect() + .setText("Return target creature card from your graveyard to the battlefield. That creature is a black Zombie in addition to its other colors and types")); this.addAbility(ability); // -7: Destroy all non-Zombie creatures. diff --git a/Mage.Sets/src/mage/cards/s/SigardaHostOfHerons.java b/Mage.Sets/src/mage/cards/s/SigardaHostOfHerons.java index 441e6cec3e1..0acbbc4a77f 100644 --- a/Mage.Sets/src/mage/cards/s/SigardaHostOfHerons.java +++ b/Mage.Sets/src/mage/cards/s/SigardaHostOfHerons.java @@ -44,6 +44,7 @@ import mage.game.permanent.PermanentCard; import mage.game.stack.Spell; import java.util.UUID; +import mage.game.stack.StackAbility; /** * @author noxx @@ -51,7 +52,7 @@ import java.util.UUID; public class SigardaHostOfHerons extends CardImpl { public SigardaHostOfHerons(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{W}{W}"); addSuperType(SuperType.LEGENDARY); this.subtype.add("Angel"); @@ -115,6 +116,11 @@ class SigardaHostOfHeronsEffect extends ContinuousRuleModifyingEffectImpl { return true; } } + if (object instanceof StackAbility) { + if (game.getOpponents(source.getControllerId()).contains(((StackAbility) object).getControllerId())) { + return true; + } + } } return false; } diff --git a/Mage.Sets/src/mage/cards/s/SoulScarMage.java b/Mage.Sets/src/mage/cards/s/SoulScarMage.java index 4f12aa3ba96..90c4c3d0dd4 100644 --- a/Mage.Sets/src/mage/cards/s/SoulScarMage.java +++ b/Mage.Sets/src/mage/cards/s/SoulScarMage.java @@ -56,7 +56,7 @@ public class SoulScarMage extends CardImpl { public SoulScarMage(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}"); - + this.subtype.add("Human"); this.subtype.add("Wizard"); this.power = new MageInt(1); @@ -114,8 +114,14 @@ class SoulScarMageDamageReplacementEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - boolean weControlSource = game.getControllerId(event.getSourceId()).equals(source.getControllerId()); - boolean isNoncombatDamage = !((DamageCreatureEvent)event).isCombatDamage(); - return weControlSource && isNoncombatDamage; + UUID sourceControllerId = game.getControllerId(event.getSourceId()); + UUID targetControllerId = game.getControllerId(event.getTargetId()); + UUID controllerId = source.getControllerId(); + boolean weControlSource = controllerId.equals(sourceControllerId); + boolean opponentControlsTarget = game.getOpponents(sourceControllerId).contains(targetControllerId); + boolean isNoncombatDamage = !((DamageCreatureEvent) event).isCombatDamage(); + return weControlSource + && isNoncombatDamage + && opponentControlsTarget; } } diff --git a/Mage.Sets/src/mage/cards/w/WanderingFumarole.java b/Mage.Sets/src/mage/cards/w/WanderingFumarole.java index 3aae09c7ae1..fa8d76ffbf7 100644 --- a/Mage.Sets/src/mage/cards/w/WanderingFumarole.java +++ b/Mage.Sets/src/mage/cards/w/WanderingFumarole.java @@ -27,7 +27,6 @@ */ package mage.cards.w; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTappedAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -44,6 +43,8 @@ import mage.constants.Duration; import mage.constants.Zone; import mage.game.permanent.token.Token; +import java.util.UUID; + /** * * @author fireshoes @@ -84,7 +85,7 @@ class WanderingFumaroleToken extends Token { cardType.add(CardType.CREATURE); subtype.add("Elemental"); color.setRed(true); - color.setWhite(true); + color.setBlue(true); power = new MageInt(1); toughness = new MageInt(4); addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new SwitchPowerToughnessSourceEffect(Duration.EndOfTurn), new ManaCostsImpl("{0}"))); diff --git a/Mage.Sets/src/mage/sets/IconicMasters.java b/Mage.Sets/src/mage/sets/IconicMasters.java new file mode 100644 index 00000000000..ec12aaa6fee --- /dev/null +++ b/Mage.Sets/src/mage/sets/IconicMasters.java @@ -0,0 +1,58 @@ +/* +* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are +* permitted provided that the following conditions are met: +* +* 1. Redistributions of source code must retain the above copyright notice, this list of +* conditions and the following disclaimer. +* +* 2. Redistributions in binary form must reproduce the above copyright notice, this list +* of conditions and the following disclaimer in the documentation and/or other materials +* provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR +* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +* The views and conclusions contained in the software and documentation are those of the +* authors and should not be interpreted as representing official policies, either expressed +* or implied, of BetaSteward_at_googlemail.com. +*/ + +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.SetType; + +/** + * + * @author fireshoes + */ +public class IconicMasters extends ExpansionSet { + + private static final IconicMasters instance = new IconicMasters(); + + public static IconicMasters getInstance() { + return instance; + } + + private IconicMasters() { + super("Iconic Masters", "IMA", ExpansionSet.buildDate(2017, 11, 17), SetType.SUPPLEMENTAL); + this.blockName = "Reprint"; + this.hasBasicLands = false; + this.hasBoosters = true; + this.numBoosterLands = 0; + this.numBoosterCommon = 11; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 8; + + } +} \ No newline at end of file diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/curses/CursesTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/curses/CursesTest.java index 48e4bbd1d9b..99407f099b2 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/curses/CursesTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/curses/CursesTest.java @@ -289,6 +289,197 @@ public class CursesTest extends CardTestPlayerBase { assertGraveyardCount(playerA, 2); assertPowerToughness(playerB, "Silvercoat Lion", 1, 1); - } - + } + + + + @Test + public void cruelRealityHasBothCreatureAndPwChoosePw() { + + /* + Cruel Reality {5}{B}{B} + Enchantment - Aura Curse + Enchant player + At the beginning of enchanted player's upkeep, that player sacrifices a creature or planeswalker. If the player can't, he or she loses 5 life. + */ + String cReality = "Cruel Reality"; + + /* + Ugin, the Spirit Dragon {8} + Planeswalker — Ugin + +2: Ugin, the Spirit Dragon deals 3 damage to target creature or player. + −X: Exile each permanent with converted mana cost X or less that's one or more colors. + −10: You gain 7 life, draw seven cards, then put up to seven permanent cards from your hand onto the battlefield. + */ + String ugin = "Ugin, the Spirit Dragon"; + String memnite = "Memnite"; // {0} 1/1 + + addCard(Zone.HAND, playerA, cReality); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 7); + addCard(Zone.BATTLEFIELD, playerB, ugin); + addCard(Zone.BATTLEFIELD, playerB, memnite); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, cReality, playerB); + setChoice(playerB, ugin); + + setStopAt(2, PhaseStep.PRECOMBAT_MAIN); + execute(); + + assertGraveyardCount(playerB, ugin, 1); + assertPermanentCount(playerB, memnite, 1); + assertPermanentCount(playerA, cReality, 1); + assertLife(playerB, 20); + } + + @Test + public void cruelRealityHasBothCreatureAndPwChooseCreature() { + + /* + Cruel Reality {5}{B}{B} + Enchantment - Aura Curse + Enchant player + At the beginning of enchanted player's upkeep, that player sacrifices a creature or planeswalker. If the player can't, he or she loses 5 life. + */ + String cReality = "Cruel Reality"; + + /* + Ugin, the Spirit Dragon {8} + Planeswalker — Ugin + +2: Ugin, the Spirit Dragon deals 3 damage to target creature or player. + −X: Exile each permanent with converted mana cost X or less that's one or more colors. + −10: You gain 7 life, draw seven cards, then put up to seven permanent cards from your hand onto the battlefield. + */ + String ugin = "Ugin, the Spirit Dragon"; + String memnite = "Memnite"; // {0} 1/1 + + addCard(Zone.HAND, playerA, cReality); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 7); + addCard(Zone.BATTLEFIELD, playerB, ugin); + addCard(Zone.BATTLEFIELD, playerB, memnite); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, cReality, playerB); + setChoice(playerB, memnite); + + setStopAt(2, PhaseStep.PRECOMBAT_MAIN); + execute(); + + assertGraveyardCount(playerB, memnite, 1); + assertPermanentCount(playerB, ugin, 1); + assertPermanentCount(playerA, cReality, 1); + assertLife(playerB, 20); + } + + @Test + public void cruelRealityOnlyHasCreatureNoChoiceMade() { + + /* + Cruel Reality {5}{B}{B} + Enchantment - Aura Curse + Enchant player + At the beginning of enchanted player's upkeep, that player sacrifices a creature or planeswalker. If the player can't, he or she loses 5 life. + */ + String cReality = "Cruel Reality"; + String memnite = "Memnite"; // {0} 1/1 + + addCard(Zone.HAND, playerA, cReality); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 7); + addCard(Zone.BATTLEFIELD, playerB, memnite); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, cReality, playerB); + + setStopAt(2, PhaseStep.PRECOMBAT_MAIN); + execute(); + + assertGraveyardCount(playerB, memnite, 1); + assertPermanentCount(playerA, cReality, 1); + assertLife(playerB, 20); + } + + @Test + public void cruelRealityOnlyHasPwNoChoiceMade() { + + /* + Cruel Reality {5}{B}{B} + Enchantment - Aura Curse + Enchant player + At the beginning of enchanted player's upkeep, that player sacrifices a creature or planeswalker. If the player can't, he or she loses 5 life. + */ + String cReality = "Cruel Reality"; + + /* + Ugin, the Spirit Dragon {8} + Planeswalker — Ugin + +2: Ugin, the Spirit Dragon deals 3 damage to target creature or player. + −X: Exile each permanent with converted mana cost X or less that's one or more colors. + −10: You gain 7 life, draw seven cards, then put up to seven permanent cards from your hand onto the battlefield. + */ + String ugin = "Ugin, the Spirit Dragon"; + + addCard(Zone.HAND, playerA, cReality); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 7); + addCard(Zone.BATTLEFIELD, playerB, ugin); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, cReality, playerB); + + setStopAt(2, PhaseStep.PRECOMBAT_MAIN); + execute(); + + assertGraveyardCount(playerB, ugin, 1); + assertPermanentCount(playerA, cReality, 1); + assertLife(playerB, 20); + } + + @Test + public void cruelRealityOnlyHasCreatureTryToChooseNotToSac() { + + /* + Cruel Reality {5}{B}{B} + Enchantment - Aura Curse + Enchant player + At the beginning of enchanted player's upkeep, that player sacrifices a creature or planeswalker. If the player can't, he or she loses 5 life. + */ + String cReality = "Cruel Reality"; + String memnite = "Memnite"; // {0} 1/1 + + addCard(Zone.HAND, playerA, cReality); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 7); + addCard(Zone.BATTLEFIELD, playerB, memnite); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, cReality, playerB); + setChoice(playerB, "No"); + + setStopAt(2, PhaseStep.PRECOMBAT_MAIN); + execute(); + + assertGraveyardCount(playerB, memnite, 1); + assertPermanentCount(playerA, cReality, 1); + assertLife(playerB, 20); + } + + @Test + public void cruelRealityNoCreatureOrPwForcesLifeLoss() { + + /* + Cruel Reality {5}{B}{B} + Enchantment - Aura Curse + Enchant player + At the beginning of enchanted player's upkeep, that player sacrifices a creature or planeswalker. If the player can't, he or she loses 5 life. + */ + String cReality = "Cruel Reality"; + String gPrison = "Ghostly Prison"; // {2}{W} enchantment - doesnt matter text for this + + addCard(Zone.HAND, playerA, cReality); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 7); + addCard(Zone.BATTLEFIELD, playerB, gPrison); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, cReality, playerB); + setChoice(playerB, gPrison); // try to set choice to enchantment + + setStopAt(2, PhaseStep.PRECOMBAT_MAIN); + execute(); + + assertPermanentCount(playerB, gPrison, 1); + assertPermanentCount(playerA, cReality, 1); + assertLife(playerB, 15); + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ExertTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ExertTest.java new file mode 100644 index 00000000000..dccfcf70044 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ExertTest.java @@ -0,0 +1,91 @@ +package org.mage.test.cards.abilities.keywords; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author escplan9 + */ +public class ExertTest extends CardTestPlayerBase { + + @Test + public void exertUsedDoesNotUntapNextUntapStep() { + + /* + Glory-Bound Initiate {1}{W} + Creature - Human Warrior 3/1 + You may exert Glory-Bound Intiate as it attacks. When you do, it gets +1/+3 and gains lifelink until end of turn. + */ + String gbInitiate = "Glory-Bound Initiate"; + + addCard(Zone.BATTLEFIELD, playerA, gbInitiate); + attack(1, playerA, gbInitiate); + setChoice(playerA, "Yes"); + + setStopAt(3, PhaseStep.PRECOMBAT_MAIN); + execute(); + + assertTapped(gbInitiate, true); // does not untap due to exert + assertLife(playerA, 24); // exerted 4/4 lifelink + assertLife(playerB, 16); + } + + @Test + public void exertNotUsedRegularAttack() { + + /* + Glory-Bound Initiate {1}{W} + Creature - Human Warrior 3/1 + You may exert Glory-Bound Intiate as it attacks. When you do, it gets +1/+3 and gains lifelink until end of turn. + */ + String gbInitiate = "Glory-Bound Initiate"; + + addCard(Zone.BATTLEFIELD, playerA, gbInitiate); + attack(1, playerA, gbInitiate); + setChoice(playerA, "No"); + + setStopAt(3, PhaseStep.PRECOMBAT_MAIN); + execute(); + + assertTapped(gbInitiate, false); // untaps as normal + assertLife(playerA, 20); + assertLife(playerB, 17); + } + + /* + "If you gain control of another player's creature until end of turn and exert it, it will untap during that player's untap step." + See issue #3183 + */ + @Test + public void stolenExertCreatureShouldUntapDuringOwnersUntapStep() { + + /* + Glory-Bound Initiate {1}{W} + Creature - Human Warrior 3/1 + You may exert Glory-Bound Intiate as it attacks. When you do, it gets +1/+3 and gains lifelink until end of turn. + */ + String gbInitiate = "Glory-Bound Initiate"; + String aTreason = "Act of Treason"; // {2}{R} sorcery gain control target creature, untap, gains haste until end of turn + + addCard(Zone.HAND, playerA, gbInitiate); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + addCard(Zone.HAND, playerB, aTreason); + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 3); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, gbInitiate); + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, aTreason, gbInitiate); + attack(2, playerB, gbInitiate); + setChoice(playerB, "Yes"); + + setStopAt(3, PhaseStep.PRECOMBAT_MAIN); + execute(); + + assertGraveyardCount(playerB, aTreason, 1); + assertLife(playerA, 16); + assertLife(playerB, 24); + assertTapped(gbInitiate, false); // stolen creature exerted does untap during owner's untap step + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/TransmuteTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/TransmuteTest.java index d275bc45a60..ebaf77092ef 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/TransmuteTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/TransmuteTest.java @@ -73,18 +73,48 @@ public class TransmuteTest extends CardTestPlayerBase { @Test public void searchSplittedCardOneManaCmcSpell() { addCard(Zone.BATTLEFIELD, playerA, "Island", 3); - addCard(Zone.HAND, playerA, "Dizzy Spell"); + // Target creature gets -3/-0 until end of turn. + // Transmute {1}{U}{U} ({1}{U}{U}, Discard this card: Search your library for a card with the same converted mana cost as this card, reveal it, and put it into your hand. Then shuffle your library. Transmute only as a sorcery.) + addCard(Zone.HAND, playerA, "Dizzy Spell"); // Instant {U} + // Wear {1}{R} + // Destroy target artifact. + // Tear {W} + // Destroy target enchantment. addCard(Zone.LIBRARY, playerA, "Wear // Tear"); activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Transmute {1}{U}{U}"); + setChoice(playerA, "Wear // Tear"); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); assertGraveyardCount(playerA, "Dizzy Spell", 1); - assertHandCount(playerA, "Wear", 1); // Filter search can only search for one side of a split card - assertHandCount(playerA, "Tear", 1); // Filter search can only search for one side of a split card + assertHandCount(playerA, "Wear // Tear", 0); + } + + @Test + public void searchSplittedCardThreeManaCmcSpell() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 2); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); + // Counter target spell unless its controller discards his or her hand. + // Transmute {1}{U}{B} + addCard(Zone.HAND, playerA, "Perplex"); // Instant {1}{U}{B} + + // Wear {1}{R} + // Destroy target artifact. + // Tear {W} + // Destroy target enchantment. + addCard(Zone.LIBRARY, playerA, "Wear // Tear"); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Transmute {1}{U}{B}"); + setChoice(playerA, "Wear // Tear"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, "Perplex", 1); + assertHandCount(playerA, "Wear // Tear", 1); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/TwoHeadedSliverTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/TwoHeadedSliverTest.java index 98f1e49237d..0d56a0d4b4d 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/TwoHeadedSliverTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/TwoHeadedSliverTest.java @@ -5,6 +5,9 @@ import mage.constants.Zone; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; +import static junit.framework.TestCase.assertEquals; +import static org.junit.Assert.fail; + /** * @author LevelX2 */ @@ -26,9 +29,47 @@ public class TwoHeadedSliverTest extends CardTestPlayerBase { block(3, playerB, "Silvercoat Lion", "Two-Headed Sliver"); setStopAt(3, PhaseStep.END_TURN); + + try { + execute(); + fail("Expected exception not thrown"); + } catch (UnsupportedOperationException e) { + assertEquals("Two-Headed Sliver is blocked by 1 creature(s). It has to be blocked by 2 or more.", e.getMessage()); + } + + } + + @Test + public void testCanBeBlockedByTwoEffectAbility() { + + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2); + // Two-Headed Sliver {1}{R} 1/1 + // All Sliver creatures have "This creature can't be blocked except by two or more creatures." + addCard(Zone.HAND, playerA, "Two-Headed Sliver"); + + // Silvercoat Lion {1}{W} 2/2 + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion"); + // Coral Barrier {2}{U} 1/3 + addCard(Zone.BATTLEFIELD, playerB, "Coral Barrier"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Two-Headed Sliver"); + + attack(3, playerA, "Two-Headed Sliver"); + // Two blocks will succeed + block(3, playerB, "Silvercoat Lion", "Two-Headed Sliver"); + block(3, playerB, "Coral Barrier", "Two-Headed Sliver"); + + setStopAt(3, PhaseStep.END_TURN); + execute(); - assertPermanentCount(playerA, "Two-Headed Sliver", 1); - assertLife(playerB, 19); + assertLife(playerA, 20); + assertLife(playerB, 20); + + // Two-Headed Sliver died from the block + assertPermanentCount(playerA, "Two-Headed Sliver", 0); + assertPermanentCount(playerB, "Silvercoat Lion", 1); + assertPermanentCount(playerB, "Coral Barrier", 1); + assertGraveyardCount(playerA, "Two-Headed Sliver", 1); } -} +} \ No newline at end of file diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/cost/modification/FluctuatorTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/cost/modification/FluctuatorTest.java index 197a7c56295..3cc45a8ae62 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/cost/modification/FluctuatorTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/cost/modification/FluctuatorTest.java @@ -38,6 +38,8 @@ import org.mage.test.serverside.base.CardTestPlayerBase; public class FluctuatorTest extends CardTestPlayerBase { /** + * NOTE: As of 4/19/2017 this test is failing due to a bug in code. See issue #3148 + * * Fluctuator makes 'Akroma's Vengeance' cyclic cost reduced to {1} * Test it with one Plains on battlefield. */ @@ -88,8 +90,9 @@ public class FluctuatorTest extends CardTestPlayerBase { } /** + * NOTE: As of 4/19/2017 this test is failing due to a bug in code. See issue #3148 + * * Test 2 Fluctuators reduce cycling cost up to 4. - * */ @Test public void testTwoFluctuatorsReduceBy4() { diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/cost/splitcards/SplitCardCmcTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/cost/splitcards/SplitCardCmcTest.java index 6c7a4e80e4b..0d18400e618 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/cost/splitcards/SplitCardCmcTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/cost/splitcards/SplitCardCmcTest.java @@ -28,6 +28,8 @@ public class SplitCardCmcTest extends CardTestPlayerBase { public void testSplitCardCmcInHand() { // Total CMC of Failure // Comply is 3, so should be exiled by Transgress the Mind. addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2); + // Devoid + // Target player reveals his or her hand. You may choose a card from it with converted mana cost 3 or greater and exile that card. addCard(Zone.HAND, playerA, "Transgress the Mind"); addCard(Zone.HAND, playerB, "Failure // Comply"); @@ -42,11 +44,17 @@ public class SplitCardCmcTest extends CardTestPlayerBase { public void testSplitCardCmcOnStack() { // Counterbalance revealing Wear // Tear counters a spell with converted mana cost 3, but not 1 or 2. addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); - addCard(Zone.HAND, playerA, "Typhoid Rats"); + addCard(Zone.HAND, playerA, "Typhoid Rats"); // Creature 1/1 {B} + // Whenever an opponent casts a spell, you may reveal the top card of your library. If you do, counter that spell + // if it has the same converted mana cost as the revealed card. addCard(Zone.BATTLEFIELD, playerB, "Counterbalance"); addCard(Zone.BATTLEFIELD, playerB, "Island", 2); + // Wear {1}{R} + // Destroy target artifact. + // Tear {W} + // Destroy target enchantment. addCard(Zone.LIBRARY, playerB, "Wear // Tear"); // CMC now 3 skipInitShuffling(); // so the set to top card stays at top diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/LilianaTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/LilianaTest.java index ce6452da542..bc1e5de6a20 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/LilianaTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/LilianaTest.java @@ -14,7 +14,7 @@ import org.mage.test.serverside.base.CardTestPlayerBase; public class LilianaTest extends CardTestPlayerBase { @Test - public void testMe() { + public void testCreatureGainsZombieAsAdditionalType() { /* Binding Mummy {1}{W} Creature - Zombie 2/2 diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/requirement/BlockRequirementTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/requirement/BlockRequirementTest.java index 4305b94d51a..e15a8bc72ea 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/requirement/BlockRequirementTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/requirement/BlockRequirementTest.java @@ -32,6 +32,9 @@ import mage.constants.Zone; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; +import static junit.framework.TestCase.assertEquals; +import static org.junit.Assert.fail; + /** * * @author LevelX2, icetc @@ -212,12 +215,13 @@ public class BlockRequirementTest extends CardTestPlayerBase { block(1, playerB, "Hill Giant", "Breaker of Armies"); setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); - execute(); - // Hill giant is still alive - assertPermanentCount(playerB, "Hill Giant", 1); - // Player B was unable to block, so goes down to 10 life - assertLife(playerB, 8); + try { + execute(); + fail("Expected exception not thrown"); + } catch (UnsupportedOperationException e) { + assertEquals("Breaker of Armies is blocked by 1 creature(s). It has to be blocked by 2 or more.", e.getMessage()); + } } /* @@ -230,17 +234,17 @@ public class BlockRequirementTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Slayer's Cleaver"); addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4); addCard(Zone.BATTLEFIELD, playerA, "Memnite"); // {1} 1/1 - + addCard(Zone.BATTLEFIELD, playerB, "Dimensional Infiltrator"); // 2/1 - Eldrazi addCard(Zone.BATTLEFIELD, playerB, "Llanowar Elves"); // 1/1 - + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Equip", "Memnite"); // pumps to 4/2 attack(1, playerA, "Memnite"); // must be blocked by Dimensional Infiltrator block(1, playerB, "Llanowar Elves", "Memnite"); // should not be allowed as only blocker - + setStopAt(1, PhaseStep.END_COMBAT); execute(); - + assertPermanentCount(playerA, "Slayer's Cleaver", 1); assertLife(playerB, 20); assertGraveyardCount(playerA, "Memnite", 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/akh/DuskDawnTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/akh/DuskDawnTest.java index 6dd662ff135..067f5c040d5 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/akh/DuskDawnTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/akh/DuskDawnTest.java @@ -65,12 +65,16 @@ public class DuskDawnTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Dusk // Dawn", 0); } + // Fail to cast Dawn (Aftermath part) from hand @Test public void testCastDawnFail() { - // Fail to cast dawn from hand + // Dusk {2}{W}{W} + // Destroy all creatures with power 3 or greater. + // Dawn {3}{W}{W} + // Return all creature cards with power less than or equal to 2 from your graveyard to your hand. addCard(Zone.HAND, playerA, "Dusk // Dawn"); addCard(Zone.BATTLEFIELD, playerA, "Plains", 5); - addCard(Zone.GRAVEYARD, playerA, "Devoted Hero"); + addCard(Zone.GRAVEYARD, playerA, "Devoted Hero"); // Creature 1/2 {W} castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Dawn"); setStopAt(1, PhaseStep.END_TURN); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/emn/PermeatingMassTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/emn/PermeatingMassTest.java index da14227d555..4c7038c7e71 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/emn/PermeatingMassTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/emn/PermeatingMassTest.java @@ -36,6 +36,9 @@ public class PermeatingMassTest extends CardTestPlayerBase { assertPowerToughness(playerA, "Permeating Mass", 1, 3); } + /* + * NOTE: As of 04/19/2017 this test is failing due to a bug in code. See issue #3167 + */ @Test public void damagedCreatureWithVaryingPTbecomesCopyOfPermeatingMass() { /* diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/TargetedTriggeredTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/TargetedTriggeredTest.java index 1e4ecf5f987..d96ebf4d758 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/TargetedTriggeredTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/TargetedTriggeredTest.java @@ -29,7 +29,8 @@ package org.mage.test.cards.triggers; import mage.constants.PhaseStep; import mage.constants.Zone; -import org.junit.Ignore; +import mage.counters.CounterType; +import mage.filter.Filter; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -45,9 +46,10 @@ public class TargetedTriggeredTest extends CardTestPlayerBase { * */ @Test - @Ignore - // this does not currently work in test, because the target event will be fired earlier during tests, + //@Ignore + // this does not currently work in test (????), because the target event will be fired earlier during tests, // so the zone change counter for the fixed target of the counterspell will not work + // UPDATE: seems to work fine now? 04/19/2017 escplan9 public void testKiraGreatGlassSpinnerFirstSpellTurn() { addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); addCard(Zone.HAND, playerA, "Lightning Bolt"); @@ -89,4 +91,115 @@ public class TargetedTriggeredTest extends CardTestPlayerBase { assertPowerToughness(playerB, "Ashenmoor Liege", 4, 1); } + @Test + public void testGlyphKeeperCountersFirstSpell() { + + /* + Glyph Keeper {3}{U}{U} + Creature - Sphinx + Flying 5/3 + Whenever this creature becomes the target of a spell or ability for the first time in a turn, counter that spell or ability." + */ + String gKeeper = "Glyph Keeper"; + String bolt = "Lightning Bolt"; // {R} instant deal 3 dmg + + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); + addCard(Zone.HAND, playerA, bolt); + + addCard(Zone.BATTLEFIELD, playerB, gKeeper); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bolt, gKeeper); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, bolt, 1); + assertPermanentCount(playerB, gKeeper, 1); + } + + @Test + public void testGlyphKeeperCountersFirstSpellButNotSecondSpell() { + + /* + Glyph Keeper {3}{U}{U} + Creature - Sphinx + Flying 5/3 + Whenever this creature becomes the target of a spell or ability for the first time in a turn, counter that spell or ability." + */ + String gKeeper = "Glyph Keeper"; + String bolt = "Lightning Bolt"; // {R} instant deal 3 dmg + + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2); + addCard(Zone.HAND, playerA, bolt, 2); + + addCard(Zone.BATTLEFIELD, playerB, gKeeper); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bolt, gKeeper); + castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, bolt, gKeeper); + + setStopAt(1, PhaseStep.DECLARE_ATTACKERS); + execute(); + + assertGraveyardCount(playerA, bolt, 2); + assertPermanentCount(playerB, gKeeper, 0); + } + + /* + NOTE: test is failing due to card bug as of 04/20/2017. See issue #3180 + I had a Glyph Keeper on board (cloned with Vizier of many faces). -- note this test is a simplified version, next test will test on the Clone if needed + First I played a Soulstinger and targeted the Glyph Keeper, the ability was countered. Then on the same main phase I played a Cartouche of Strength targeting the Glyph Keeper, that was also countered. + Only the first should have been countered. + */ + @Test + public void testGlyphKeeperCountersFirstAbilityButNotSecondOne() { + + /* + Glyph Keeper {3}{U}{U} + Creature - Sphinx + Flying 5/3 + Whenever this creature becomes the target of a spell or ability for the first time in a turn, counter that spell or ability." + */ + String gKeeper = "Glyph Keeper"; + + /* + Soulstinger {3}{B} + Creature - Scorpion Demon 4/5 + When Soulstinger enters the battlefield, put two -1/-1 counter on target creature you control. + When Soulstinger dies, you may put a -1/-1 counter on target creature for each -1/-1 counter on Soulstinger. + */ + String sStinger = "Soulstinger"; + + /* + Cartouche of Strength {2}{G} + Enchantment - Aura Cartouche + Enchant creature you control + When Cartouche of Strength enters the battlefield, you may have enchanted creature fight target creature an opponent controls. + Enchanted creature gets +1/+1 and has trample. + */ + String cStrength = "Cartouche of Strength"; + String memnite = "Memnite"; // {0} 1/1 + + addCard(Zone.BATTLEFIELD, playerA, gKeeper); + addCard(Zone.HAND, playerA, sStinger); + addCard(Zone.HAND, playerA, cStrength); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 6); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 6); + addCard(Zone.BATTLEFIELD, playerB, memnite); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, sStinger); + addTarget(playerA, gKeeper); // should be countered by Glyph Keeper clause as first ability targetting it + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, cStrength, gKeeper); // should not be countered anymore + addTarget(playerA, memnite); // Cartouche of Strength fight + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, gKeeper, 1); + assertGraveyardCount(playerA, sStinger, 0); // countered + assertGraveyardCount(playerA, cStrength, 0); // should not be countered + assertPermanentCount(playerA, cStrength, 1); + assertGraveyardCount(playerB, memnite, 1); // dies from fight + assertPowerToughness(playerA, gKeeper, 5, 3, Filter.ComparisonScope.All); // Soul Stinger should never have given it two -1/-1 counters + assertCounterCount(playerA, gKeeper, CounterType.M1M1, 0); + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/watchers/KiraGreatGlassSpinnerTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/watchers/KiraGreatGlassSpinnerTest.java index 4c9ffeefc61..ade57ada5a5 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/watchers/KiraGreatGlassSpinnerTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/watchers/KiraGreatGlassSpinnerTest.java @@ -2,8 +2,7 @@ package org.mage.test.cards.watchers; import mage.constants.PhaseStep; import mage.constants.Zone; -import mage.game.permanent.Permanent; -import org.junit.Assert; +import mage.counters.CounterType; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -11,27 +10,28 @@ import org.mage.test.serverside.base.CardTestPlayerBase; * Created by IGOUDT on 30-3-2017. */ public class KiraGreatGlassSpinnerTest extends CardTestPlayerBase { + private final String kira = "Kira, Great Glass-Spinner"; - private final String shock = "Shock"; @Test - public void counterFirst(){ - addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4); - addCard(Zone.BATTLEFIELD, playerA, "Swamp", 4); - addCard(Zone.BATTLEFIELD, playerA, "Ugin, the Spirit Dragon"); // starts with 7 Loyality counters + public void counterFirst() { + + String ugin = "Ugin, the Spirit Dragon"; + addCard(Zone.BATTLEFIELD, playerA, ugin); // starts with 7 Loyality counters + /* + Kira, Great Glass-Spinner {1}{U}{U} + Legendary Creature - Spirit 2/2 + Flying + Creatures you control have "Whenever this creature becomes the target of a spell or ability for the first time each turn, counter that spell or ability." + */ addCard(Zone.BATTLEFIELD, playerA, kira); - addCard(Zone.HAND, playerA, shock); - addCard(Zone.HAND, playerA, shock); - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+2: {source} deals 3 damage to target creature or player.", kira); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+2: {source} deals 3 damage to target creature or player.", kira); // Ugin ability setStopAt(1, PhaseStep.BEGIN_COMBAT); - execute(); - Permanent _kira = getPermanent(kira, playerA.getId()); - Assert.assertNotNull(_kira); - - + assertPermanentCount(playerA, kira, 1); + assertCounterCount(playerA, ugin, CounterType.LOYALTY, 9); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/combat/AttackBlockRestrictionsTest.java b/Mage.Tests/src/test/java/org/mage/test/combat/AttackBlockRestrictionsTest.java index 530a9cbb144..363c68c6a25 100644 --- a/Mage.Tests/src/test/java/org/mage/test/combat/AttackBlockRestrictionsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/combat/AttackBlockRestrictionsTest.java @@ -8,6 +8,9 @@ import org.junit.Assert; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + /** * Test restrictions for choosing attackers and blockers. * @@ -38,7 +41,7 @@ public class AttackBlockRestrictionsTest extends CardTestPlayerBase { * Frost */ @Test - public void testWallofWrost() { + public void testWallofFrost() { // Whenever Wall of Frost blocks a creature, that creature doesn't untap during its controller's next untap step. addCard(Zone.BATTLEFIELD, playerA, "Wall of Frost"); // 0/7 addCard(Zone.BATTLEFIELD, playerB, "Craw Wurm"); @@ -338,36 +341,36 @@ public class AttackBlockRestrictionsTest extends CardTestPlayerBase { */ @Test public void testMustAttackButCannotAttackAlone() - { + { /* Mogg Flunkies {1}{R} 3/3 Creature — Goblin Mogg Flunkies can't attack or block alone. */ String flunkies = "Mogg Flunkies"; - + /* Goblin Assault {2}{R} - * Enchantment + * Enchantment At the beginning of your upkeep, create a 1/1 red Goblin creature token with haste. Goblin creatures attack each turn if able. */ String gAssault = "Goblin Assault"; - + addCard(Zone.BATTLEFIELD, playerA, flunkies); addCard(Zone.BATTLEFIELD, playerB, gAssault); - + setStopAt(3, PhaseStep.POSTCOMBAT_MAIN); execute(); - + assertTapped(flunkies, false); assertLife(playerB, 20); } - + /* Reported bug: Tromokratis is unable to be blocked. */ @Test public void tromokratisBlockedByAll() { - /* + /* Tromokratis {5}{U}{U} Legendary Creature — Kraken 8/8 Tromokratis has hexproof unless it's attacking or blocking. @@ -376,30 +379,30 @@ public class AttackBlockRestrictionsTest extends CardTestPlayerBase { String tromokratis = "Tromokratis"; String gBears = "Grizzly Bears"; // {1}{G} 2/2 String memnite = "Memnite"; // {0} 1/1 - + addCard(Zone.BATTLEFIELD, playerA, tromokratis); addCard(Zone.BATTLEFIELD, playerB, gBears); addCard(Zone.BATTLEFIELD, playerB, memnite); - + attack(1, playerA, tromokratis); block(1, playerB, gBears, tromokratis); block(1, playerB, memnite, tromokratis); - + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); execute(); - + assertLife(playerB, 20); assertGraveyardCount(playerB, gBears, 1); assertGraveyardCount(playerB, memnite, 1); assertTapped(tromokratis, true); } - + /* Reported bug: Tromokratis is unable to be blocked. */ @Test public void tromokratisNotBlockedByAll() { - /* + /* Tromokratis {5}{U}{U} Legendary Creature — Kraken 8/8 Tromokratis has hexproof unless it's attacking or blocking. @@ -409,24 +412,138 @@ public class AttackBlockRestrictionsTest extends CardTestPlayerBase { String gBears = "Grizzly Bears"; // {1}{G} 2/2 String memnite = "Memnite"; // {0} 1/1 String hGiant = "Hill Giant"; // {3}{R} 3/3 - + addCard(Zone.BATTLEFIELD, playerA, tromokratis); addCard(Zone.BATTLEFIELD, playerB, gBears); addCard(Zone.BATTLEFIELD, playerB, memnite); addCard(Zone.BATTLEFIELD, playerB, hGiant); - + attack(2, playerB, hGiant); // forces a creature to be tapped so unable to block Tromokratis, which means it cannot be blocked at all attack(3, playerA, tromokratis); block(3, playerB, gBears, tromokratis); block(3, playerB, memnite, tromokratis); - + setStopAt(3, PhaseStep.POSTCOMBAT_MAIN); execute(); - + assertLife(playerB, 12); // Hill Giant could not block it, so no other creature could block Tromokratis either assertPermanentCount(playerB, gBears, 1); assertPermanentCount(playerB, memnite, 1); assertTapped(tromokratis, true); assertTapped(hGiant, true); } + + @Test + public void underworldCerberusBlockedByOneTest() { + /* Underworld Cerberus {3}{B}{3} 6/6 + * Underworld Cerberus can't be blocked except by three or more creatures. + * Cards in graveyards can't be the targets of spells or abilities. + * When Underworld Cerberus dies, exile it and each player returns all creature cards from his or her graveyard to his or her hand. + */ + addCard(Zone.BATTLEFIELD, playerA, "Underworld Cerberus"); + addCard(Zone.BATTLEFIELD, playerB, "Memnite"); // 1/1 + + attack(3, playerA, "Underworld Cerberus"); + block(3, playerB, "Memnite", "Underworld Cerberus"); + + setStopAt(3, PhaseStep.POSTCOMBAT_MAIN); + + try { + execute(); + fail("Expected exception not thrown"); + } catch(UnsupportedOperationException e) { + assertEquals("Underworld Cerberus is blocked by 1 creature(s). It has to be blocked by 3 or more.", e.getMessage()); + } + + } + + @Test + public void underworldCerberusBlockedByTwoTest() { + /* Underworld Cerberus {3}{B}{3} 6/6 + * Underworld Cerberus can't be blocked except by three or more creatures. + * Cards in graveyards can't be the targets of spells or abilities. + * When Underworld Cerberus dies, exile it and each player returns all creature cards from his or her graveyard to his or her hand. + */ + addCard(Zone.BATTLEFIELD, playerA, "Underworld Cerberus"); + addCard(Zone.BATTLEFIELD, playerB, "Memnite", 2); // 1/1 + + attack(3, playerA, "Underworld Cerberus"); + block(3, playerB, "Memnite", "Underworld Cerberus"); + block(3, playerB, "Memnite", "Underworld Cerberus"); + + setStopAt(3, PhaseStep.POSTCOMBAT_MAIN); + + try { + execute(); + fail("Expected exception not thrown"); + } catch(UnsupportedOperationException e) { + assertEquals("Underworld Cerberus is blocked by 2 creature(s). It has to be blocked by 3 or more.", e.getMessage()); + } + } + + @Test + public void underworldCerberusBlockedByThreeTest() { + + /* Underworld Cerberus {3}{B}{3} 6/6 + * Underworld Cerberus can't be blocked except by three or more creatures. + * Cards in graveyards can't be the targets of spells or abilities. + * When Underworld Cerberus dies, exile it and each player returns all creature cards from his or her graveyard to his or her hand. + */ + addCard(Zone.BATTLEFIELD, playerA, "Underworld Cerberus"); + addCard(Zone.BATTLEFIELD, playerB, "Memnite", 3); // 1/1 + + + // Blocked by 3 creatures - this is acceptable + attack(3, playerA, "Underworld Cerberus"); + block(3, playerB, "Memnite", "Underworld Cerberus"); + block(3, playerB, "Memnite", "Underworld Cerberus"); + block(3, playerB, "Memnite", "Underworld Cerberus"); + + setStopAt(3, PhaseStep.POSTCOMBAT_MAIN); + + execute(); + + assertPermanentCount(playerA, "Underworld Cerberus", 1); + assertPermanentCount(playerB, "Memnite", 0); + assertGraveyardCount(playerB, "Memnite", 3); + + assertLife(playerA, 20); + assertLife(playerB, 20); + } + + @Test + public void underworldCerberusBlockedByTenTest() { + /* Underworld Cerberus {3}{B}{3} 6/6 + * Underworld Cerberus can't be blocked except by three or more creatures. + * Cards in graveyards can't be the targets of spells or abilities. + * When Underworld Cerberus dies, exile it and each player returns all creature cards from his or her graveyard to his or her hand. + */ + addCard(Zone.BATTLEFIELD, playerA, "Underworld Cerberus"); + addCard(Zone.BATTLEFIELD, playerB, "Memnite", 10); // 1/1 + + // Blocked by 10 creatures - this is acceptable as it's >3 + attack(3, playerA, "Underworld Cerberus"); + for(int i = 0; i < 10; i++) { + block(3, playerB, "Memnite", "Underworld Cerberus"); + } + + setStopAt(3, PhaseStep.POSTCOMBAT_MAIN); + + execute(); + + assertPermanentCount(playerA, "Underworld Cerberus", 0); + assertPermanentCount(playerB, "Memnite", 4); + // Actually exiled when it dies + assertGraveyardCount(playerA, "Underworld Cerberus", 0); + assertExileCount(playerA, "Underworld Cerberus", 1); + // Cards are returned to their owner's hand when Underworld Cerberus dies + assertGraveyardCount(playerB, "Memnite", 0); + assertHandCount(playerB, "Memnite", 6); + + assertLife(playerA, 20); + assertLife(playerB, 20); + } + + + } diff --git a/Mage.Tests/src/test/java/org/mage/test/combat/CanBlockMultipleCreatures.java b/Mage.Tests/src/test/java/org/mage/test/combat/CanBlockMultipleCreatures.java deleted file mode 100644 index abb44c24a2c..00000000000 --- a/Mage.Tests/src/test/java/org/mage/test/combat/CanBlockMultipleCreatures.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are - * permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * The views and conclusions contained in the software and documentation are those of the - * authors and should not be interpreted as representing official policies, either expressed - * or implied, of BetaSteward_at_googlemail.com. - */ -package org.mage.test.combat; - -import mage.constants.PhaseStep; -import mage.constants.Zone; -import org.junit.Ignore; -import org.junit.Test; -import org.mage.test.serverside.base.CardTestPlayerBase; - -/** - * - * @author jeffwadsworth - */ -public class CanBlockMultipleCreatures extends CardTestPlayerBase { - - // test must be ignored until creature blocking multiple supported by test framework - @Ignore - @Test - public void testCombat() { - addCard(Zone.BATTLEFIELD, playerA, "Watcher in the Web", 1); - - addCard(Zone.BATTLEFIELD, playerB, "Ulrich, Uncontested Alpha", 1); // 6/6 - addCard(Zone.BATTLEFIELD, playerB, "Kessig Dire Swine", 1); // 6/6 (trample if delirium) - addCard(Zone.BATTLEFIELD, playerB, "Howlpack Wolf", 1); // 3/3 - addCard(Zone.BATTLEFIELD, playerB, "Incorrigible Youths", 1); // 4/3 - - // Trample requirement for Kessig Dire Swine - addCard(Zone.GRAVEYARD, playerB, "Forest", 1); - addCard(Zone.GRAVEYARD, playerB, "Memnite", 1); - addCard(Zone.GRAVEYARD, playerB, "Flight", 1); - addCard(Zone.GRAVEYARD, playerB, "Drain Life", 1); - - // Attack with all 4 creatures and block all with the Watcher in the Web - attack(2, playerB, "Ulrich, Uncontested Alpha"); - attack(2, playerB, "Kessig Dire Swine"); - attack(2, playerB, "Howlpack Wolf"); - attack(2, playerB, "Incorrigible Youths"); - - block(2, playerA, "Watcher in the Web", "Ulrich, Uncontested Alpha"); - block(2, playerA, "Watcher in the Web", "Kessig Dire Swine"); - block(2, playerA, "Watcher in the Web", "Howlpack Wolf"); - block(2, playerA, "Watcher in the Web", "Incorrigible Youths"); - - setStopAt(2, PhaseStep.COMBAT_DAMAGE); - execute(); - - assertLife(playerA, 19); - - } - - /* - * Reported bug: Night Market Guard was able to block a creature with Menace - */ - @Test - public void testNightMarketGuardShouldNotBlockCreatureWithMenace() - { - /* - Night Market Guard {3} 3/1 - Artifact Creature — Construct - Night Market Guard can block an additional creature each combat. - */ - String nMarketGuard = "Night Market Guard"; - - /* - Embraal Bruiser {1}{B} - Creature - Human Warrior - Embraal Bruiser enters the battlefield tapped. - Embraal Bruiser has menace as long as you control an artifact. - */ - String eBruiser = "Embraal Bruiser"; - - /* - {0} 1/1 - * Artifact Creature — Construct - */ - String memnite = "Memnite"; - - addCard(Zone.BATTLEFIELD, playerA, nMarketGuard); - addCard(Zone.BATTLEFIELD, playerB, eBruiser); - addCard(Zone.BATTLEFIELD, playerB, memnite); // only here to grant Embraal Menace - - attack(4, playerB, eBruiser); - block(4, playerA, nMarketGuard, eBruiser); - - setStopAt(4, PhaseStep.POSTCOMBAT_MAIN); - execute(); - - assertTapped(eBruiser, true); - assertLife(playerA, 17); // could not block, so 3 damage goes through - assertPermanentCount(playerA, nMarketGuard, 1); - assertPermanentCount(playerB, eBruiser, 1); - } -} \ No newline at end of file diff --git a/Mage.Tests/src/test/java/org/mage/test/combat/CanBlockMultipleCreaturesTest.java b/Mage.Tests/src/test/java/org/mage/test/combat/CanBlockMultipleCreaturesTest.java new file mode 100644 index 00000000000..d74ac7ad270 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/combat/CanBlockMultipleCreaturesTest.java @@ -0,0 +1,226 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ +package org.mage.test.combat; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Ignore; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +/** + * + * @author jeffwadsworth + * @author Simown + */ +public class CanBlockMultipleCreaturesTest extends CardTestPlayerBase { + + @Test + public void testMultipleBlockWithTrample() { + + addCard(Zone.BATTLEFIELD, playerA, "Watcher in the Web", 1); + + addCard(Zone.BATTLEFIELD, playerB, "Ulrich, Uncontested Alpha", 1); // 6/6 + addCard(Zone.BATTLEFIELD, playerB, "Kessig Dire Swine", 1); // 6/6 (trample if delirium) + addCard(Zone.BATTLEFIELD, playerB, "Howlpack Wolf", 1); // 3/3 + addCard(Zone.BATTLEFIELD, playerB, "Incorrigible Youths", 1); // 4/3 + + // Trample requirement for Kessig Dire Swine + addCard(Zone.GRAVEYARD, playerB, "Forest", 1); + addCard(Zone.GRAVEYARD, playerB, "Memnite", 1); + addCard(Zone.GRAVEYARD, playerB, "Flight", 1); + addCard(Zone.GRAVEYARD, playerB, "Drain Life", 1); + + // Attack with all 4 creatures and block all with the Watcher in the Web + attack(2, playerB, "Kessig Dire Swine"); + attack(2, playerB, "Ulrich, Uncontested Alpha"); + attack(2, playerB, "Howlpack Wolf"); + attack(2, playerB, "Incorrigible Youths"); + + // BLOCKING ORDER MATTERS - the trampling creature must be selected to block first + // You can manually change the blocking order but it's easier to assign them in order + block(2, playerA, "Watcher in the Web", "Kessig Dire Swine"); + block(2, playerA, "Watcher in the Web", "Ulrich, Uncontested Alpha"); + block(2, playerA, "Watcher in the Web", "Howlpack Wolf"); + block(2, playerA, "Watcher in the Web", "Incorrigible Youths"); + + setStopAt(2, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertLife(playerA, 19); + + } + + @Test + public void testMultipleBlockWithTrample2() { + + addCard(Zone.BATTLEFIELD, playerA, "Watcher in the Web", 1); + + addCard(Zone.BATTLEFIELD, playerB, "Ulrich, Uncontested Alpha", 1); // 6/6 + addCard(Zone.BATTLEFIELD, playerB, "Kessig Dire Swine", 1); // 6/6 (trample if delirium) + addCard(Zone.BATTLEFIELD, playerB, "Howlpack Wolf", 1); // 3/3 + addCard(Zone.BATTLEFIELD, playerB, "Incorrigible Youths", 1); // 4/3 + + // Trample requirement for Kessig Dire Swine + addCard(Zone.GRAVEYARD, playerB, "Forest", 1); + addCard(Zone.GRAVEYARD, playerB, "Memnite", 1); + addCard(Zone.GRAVEYARD, playerB, "Flight", 1); + addCard(Zone.GRAVEYARD, playerB, "Drain Life", 1); + + // Attack with all 4 creatures and block all with the Watcher in the Web + attack(2, playerB, "Kessig Dire Swine"); + attack(2, playerB, "Ulrich, Uncontested Alpha"); + attack(2, playerB, "Howlpack Wolf"); + attack(2, playerB, "Incorrigible Youths"); + + // BLOCKING ORDER MATTERS - the trampling creature must be selected to block first + block(2, playerA, "Watcher in the Web", "Kessig Dire Swine"); + block(2, playerA, "Watcher in the Web", "Ulrich, Uncontested Alpha"); + block(2, playerA, "Watcher in the Web", "Howlpack Wolf"); + // Don't block Incorrigible Youths + + setStopAt(2, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + // Damage 1 from Kessig Dire Swine + 4 from Incorrigible Youths + assertLife(playerA, 15); + } + + @Test + public void testCanOnlyBlockSingle() { + + // Hundred-Handed One {2}{W}{W} + // Monstrosity 3. {3}{W}{W}{W} (If this creature isn’t monstrous, put three +1/+1 counters on it and it becomes monstrous.) + //As long as Hundred-Handed One is monstrous, it has reach and can block an additional ninety-nine creatures each combat. + addCard(Zone.BATTLEFIELD, playerA, "Hundred-Handed One", 1); + + addCard(Zone.BATTLEFIELD, playerB, "Bronze Sable", 1); // 2/1 + addCard(Zone.BATTLEFIELD, playerB, "Fabled Hero", 1); // 2/2 double strike + + // Attack with all 4 creatures and try and block both with hundred-handed one + attack(2, playerB, "Bronze Sable"); + attack(2, playerB, "Fabled Hero"); + + block(2, playerA, "Hundred-Handed One", "Bronze Sable"); + block(2, playerA, "Hundred-Handed One", "Fabled Hero"); + + setStopAt(2, PhaseStep.POSTCOMBAT_MAIN); + + // Will fail on purpose - we are trying to block too many creatures! + try { + execute(); + fail("Expected exception not thrown"); + } catch(UnsupportedOperationException e) { + assertEquals("Hundred-Handed One cannot block Fabled Hero", e.getMessage()); + } + } + + @Test + public void testCanBlockMultiple() { + + // Hundred-Handed One {2}{W}{W} + // Monstrosity 3. {3}{W}{W}{W} (If this creature isn’t monstrous, put three +1/+1 counters on it and it becomes monstrous.) + // As long as Hundred-Handed One is monstrous, it has reach and can block an additional ninety-nine creatures each combat. + addCard(Zone.BATTLEFIELD, playerA, "Hundred-Handed One", 1); + // For monstrosity + addCard(Zone.BATTLEFIELD, playerA, "Plains", 6); + + addCard(Zone.BATTLEFIELD, playerB, "Bronze Sable", 1); // 2/1 + addCard(Zone.BATTLEFIELD, playerB, "Fabled Hero", 1); // 2/2 double strike + + // Make hundred-handed one monstrous + activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerA, "{3}{W}{W}{W}: Monstrosity 3."); + + // Attack with all 4 creatures and try and block both with hundred-handed one + attack(2, playerB, "Bronze Sable"); + attack(2, playerB, "Fabled Hero"); + + block(2, playerA, "Hundred-Handed One", "Bronze Sable"); + block(2, playerA, "Hundred-Handed One", "Fabled Hero"); + + setStopAt(2, PhaseStep.POSTCOMBAT_MAIN); + + // Will not fail this time as hundred-handed one is monstrous and can block up to 100 creatures + execute(); + + // Was a 3/5 but monstrosity 3 + assertPowerToughness(playerA, "Hundred-Handed One", 6, 8); + // No one has been hit + assertLife(playerA, 20); + assertLife(playerB, 20); + } + + /* + * Reported bug: Night Market Guard was able to block a creature with Menace + */ + @Test + public void testNightMarketGuardShouldNotBlockCreatureWithMenace() + { + /* + Night Market Guard {3} 3/1 + Artifact Creature — Construct + Night Market Guard can block an additional creature each combat. + */ + String nMarketGuard = "Night Market Guard"; + + /* + Embraal Bruiser {1}{B} + Creature - Human Warrior + Embraal Bruiser enters the battlefield tapped. + Embraal Bruiser has menace as long as you control an artifact. + */ + String eBruiser = "Embraal Bruiser"; + + /* + {0} 1/1 + * Artifact Creature — Construct + */ + String memnite = "Memnite"; + + addCard(Zone.BATTLEFIELD, playerA, nMarketGuard); + addCard(Zone.BATTLEFIELD, playerB, eBruiser); + addCard(Zone.BATTLEFIELD, playerB, memnite); // only here to grant Embraal Menace + + attack(4, playerB, eBruiser); + block(4, playerA, nMarketGuard, eBruiser); + + setStopAt(4, PhaseStep.POSTCOMBAT_MAIN); + + // Catch the illegal block + try { + execute(); + fail("Expected exception not thrown"); + } catch(UnsupportedOperationException e) { + assertEquals("Embraal Bruiser is blocked by 1 creature(s). It has to be blocked by 2 or more.", e.getMessage()); + } + + } +} \ No newline at end of file diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java index e58a4f17cb8..da10ded0a55 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java @@ -28,13 +28,10 @@ package org.mage.test.player; import java.io.Serializable; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; +import java.util.*; + import mage.MageObject; +import mage.MageObjectReference; import mage.abilities.Abilities; import mage.abilities.Ability; import mage.abilities.ActivatedAbility; @@ -65,15 +62,10 @@ import mage.counters.Counter; import mage.counters.Counters; import mage.filter.Filter; import mage.filter.FilterPermanent; -import mage.filter.common.FilterAttackingCreature; -import mage.filter.common.FilterCreatureForCombat; -import mage.filter.common.FilterCreatureForCombatBlock; -import mage.filter.common.FilterCreatureOrPlayer; -import mage.filter.common.FilterPlaneswalkerPermanent; +import mage.filter.common.*; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.NamePredicate; import mage.filter.predicate.permanent.AttackingPredicate; -import mage.filter.predicate.permanent.BlockingPredicate; import mage.filter.predicate.permanent.SummoningSicknessPredicate; import mage.game.Game; import mage.game.Graveyard; @@ -181,6 +173,11 @@ public class TestPlayer implements Player { return null; } + // Gets all permanents that match the filter + protected List findPermanents(FilterPermanent filter, UUID controllerId, Game game) { + return game.getBattlefield().getAllActivePermanents(filter, controllerId, game); + } + private boolean checkExecuteCondition(String[] groups, Game game) { if (groups[2].startsWith("spellOnStack=")) { String spellOnStack = groups[2].substring(13); @@ -289,7 +286,7 @@ public class TestPlayer implements Player { int index = 0; int targetsSet = 0; for (String targetName : targetList) { - Mode selectedMode = null; + Mode selectedMode; if (targetName.startsWith("mode=")) { int modeNr = Integer.parseInt(targetName.substring(5, 6)); if (modeNr == 0 || modeNr > (ability.getModes().isEachModeMoreThanOnce() ? ability.getModes().getSelectedModes().size() : ability.getModes().size())) { @@ -561,25 +558,86 @@ public class TestPlayer implements Player { @Override public void selectBlockers(Game game, UUID defendingPlayerId) { UUID opponentId = game.getOpponents(computerPlayer.getId()).iterator().next(); + // Map of Blocker reference -> list of creatures blocked + Map> blockedCreaturesByCreature = new HashMap<>(); for (PlayerAction action : actions) { if (action.getTurnNum() == game.getTurnNum() && action.getAction().startsWith("block:")) { String command = action.getAction(); command = command.substring(command.indexOf("block:") + 6); String[] groups = command.split("\\$"); - FilterCreatureForCombatBlock filterBlocker = new FilterCreatureForCombatBlock(); - filterBlocker.add(new NamePredicate(groups[0])); - filterBlocker.add(Predicates.not(new BlockingPredicate())); - Permanent blocker = findPermanent(filterBlocker, computerPlayer.getId(), game); - if (blocker != null) { - FilterAttackingCreature filterAttacker = new FilterAttackingCreature(); - filterAttacker.add(new NamePredicate(groups[1])); - Permanent attacker = findPermanent(filterAttacker, opponentId, game); - if (attacker != null) { - computerPlayer.declareBlocker(defendingPlayerId, blocker.getId(), attacker.getId(), game); + FilterAttackingCreature filterAttacker = new FilterAttackingCreature(); + filterAttacker.add(new NamePredicate(groups[1])); + Permanent attacker = findPermanent(filterAttacker, opponentId, game); + FilterControlledPermanent filterPermanent = new FilterControlledPermanent(); + filterPermanent.add(new NamePredicate(groups[0])); + // Get all possible blockers - those with the same name on the battlefield + List possibleBlockers = findPermanents(filterPermanent, computerPlayer.getId(), game); + if (!possibleBlockers.isEmpty() && attacker != null) { + boolean blockerFound = false; + for(Permanent blocker: possibleBlockers) { + // See if it can block this creature + if(canBlockAnother(game, blocker, attacker, blockedCreaturesByCreature)) { + computerPlayer.declareBlocker(defendingPlayerId, blocker.getId(), attacker.getId(), game); + blockerFound = true; + break; + } + } + // If we haven't found a blocker then an illegal block has been made in the test + if(!blockerFound) { + throw new UnsupportedOperationException(groups[0] + " cannot block " + groups[1]); } } } } + checkMultipleBlockers(game, blockedCreaturesByCreature); + } + + // Checks if a creature can block at least one more creature + private boolean canBlockAnother(Game game, Permanent blocker, Permanent attacker, Map> blockedCreaturesByCreature) { + MageObjectReference blockerRef = new MageObjectReference(blocker, game); + // See if we already reference this blocker + for(MageObjectReference r: blockedCreaturesByCreature.keySet()) { + if(r.equals(blockerRef)) { + // Use the existing reference if we do + blockerRef = r; + } + } + List blocked = blockedCreaturesByCreature.getOrDefault(blockerRef, new ArrayList<>()); + int numBlocked = blocked.size(); + // Can't block any more creatures + if(++numBlocked > blocker.getMaxBlocks()) { + return false; + } + // Add the attacker reference to the list of creatures this creature is blocking + blocked.add(new MageObjectReference(attacker, game)); + blockedCreaturesByCreature.put(blockerRef, blocked); + return true; + } + + // Check for Menace type abilities - if creatures can be blocked by >X or > blockedCreaturesByCreature) { + // Stores the total number of blockers for each attacker + Map blockersForAttacker = new HashMap<>(); + // Calculate the number of blockers each attacker has + for(List attackers : blockedCreaturesByCreature.values()) { + for(MageObjectReference mr: attackers) { + Integer blockers = blockersForAttacker.getOrDefault(mr, 0); + blockersForAttacker.put(mr, blockers+1); + } + } + // Check each attacker is blocked by an allowed amount of creatures + for(Map.Entry entry: blockersForAttacker.entrySet()) { + Permanent attacker = entry.getKey().getPermanent(game); + Integer blockers = entry.getValue(); + // If getMaxBlockedBy() == 0 it means any number of creatures can block this creature + if(attacker.getMaxBlockedBy() != 0 && blockers > attacker.getMaxBlockedBy()) { + throw new UnsupportedOperationException(attacker.getName() + " is blocked by " + blockers + " creature(s). It can only be blocked by " + attacker.getMaxBlockedBy() + " or less."); + } + else if(blockers < attacker.getMinBlockedBy()) { + throw new UnsupportedOperationException(attacker.getName() + " is blocked by " + blockers + " creature(s). It has to be blocked by " + attacker.getMinBlockedBy() + " or more."); + } + } + // No errors raised - all the blockers pass the test! } @Override diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java index cabd79c4598..0d3b5adf835 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java @@ -805,9 +805,19 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param count Expected count. */ public void assertHandCount(Player player, String cardName, int count) throws AssertionError { - FilterCard filter = new FilterCard(); - filter.add(new NamePredicate(cardName)); - int actual = currentGame.getPlayer(player.getId()).getHand().count(filter, player.getId(), currentGame); + int actual; + if (cardName.contains("//")) { // special logic for cheched split cards, because in game logic of card name filtering is different than for test + actual = 0; + for (Card card : currentGame.getPlayer(player.getId()).getHand().getCards(currentGame)) { + if (card.getName().equals(cardName)) { + actual++; + } + } + } else { + FilterCard filter = new FilterCard(); + filter.add(new NamePredicate(cardName)); + actual = currentGame.getPlayer(player.getId()).getHand().count(filter, player.getId(), currentGame); + } Assert.assertEquals("(Hand) Card counts for card " + cardName + " for " + player.getName() + " are not equal ", count, actual); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/DontUntapInControllersNextUntapStepTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DontUntapInControllersNextUntapStepTargetEffect.java index 8f0989f7cbe..f0de6583bdb 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DontUntapInControllersNextUntapStepTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DontUntapInControllersNextUntapStepTargetEffect.java @@ -120,7 +120,7 @@ public class DontUntapInControllersNextUntapStepTargetEffect extends ContinuousR Permanent permanent = game.getPermanent(targetId); if (permanent != null) { if (game.getActivePlayerId().equals(permanent.getControllerId()) - || (game.getActivePlayerId().equals(onlyIfControlledByPlayer))) { // if effect works only for specific player, all permanents have to be set to handled in that players untap step + && ((onlyIfControlledByPlayer == null) || (game.getActivePlayerId().equals(onlyIfControlledByPlayer)))) { // if effect works only for specific player, all permanents have to be set to handled in that players untap step if (!handledTargetsDuringTurn.containsKey(targetId)) { // it's the untep step of the current controller and the effect was not handled for this target yet, so do it now handledTargetsDuringTurn.put(targetId, false); @@ -145,8 +145,10 @@ public class DontUntapInControllersNextUntapStepTargetEffect extends ContinuousR && getTargetPointer().getTargets(game, source).contains(event.getTargetId())) { Permanent permanent = game.getPermanent(event.getTargetId()); if (permanent != null && game.getActivePlayerId().equals(permanent.getControllerId())) { - handledTargetsDuringTurn.put(event.getTargetId(), true); - return true; + if ((onlyIfControlledByPlayer == null) || game.getActivePlayerId().equals(onlyIfControlledByPlayer)) { // If onlyIfControlledByPlayer is set, then don't apply unless we're currently controlled by the specified player. + handledTargetsDuringTurn.put(event.getTargetId(), true); + return true; + } } } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesBlackZombieAdditionEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesBlackZombieAdditionEffect.java index c78390b2998..0030052e48a 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesBlackZombieAdditionEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesBlackZombieAdditionEffect.java @@ -58,7 +58,10 @@ public class BecomesBlackZombieAdditionEffect extends ContinuousEffectImpl { @Override public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { - Permanent creature = game.getPermanent(targetPointer.getFirst(game, source)); + Permanent creature = game.getPermanent(source.getTargets().getFirstTarget()); + if (creature == null) { + creature = game.getPermanentEntering(source.getTargets().getFirstTarget()); + } if (creature != null) { switch (layer) { case TypeChangingEffects_4: diff --git a/Mage/src/main/java/mage/abilities/keyword/ExertAbility.java b/Mage/src/main/java/mage/abilities/keyword/ExertAbility.java index 2034b96fa9b..93c6e696e67 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ExertAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ExertAbility.java @@ -147,7 +147,7 @@ class ExertReplacementEffect extends ReplacementEffectImpl { game.informPlayers(controller.getLogName() + " exerted " + creature.getName()); } game.fireEvent(GameEvent.getEvent(GameEvent.EventType.BECOMES_EXERTED, creature.getId(), creature.getId(), creature.getControllerId())); - ContinuousEffect effect = new DontUntapInControllersNextUntapStepTargetEffect(); + ContinuousEffect effect = new DontUntapInControllersNextUntapStepTargetEffect("", creature.getControllerId()); effect.setTargetPointer(new FixedTarget(creature, game)); game.addEffect(effect, source); } diff --git a/Mage/src/main/java/mage/filter/FilterCard.java b/Mage/src/main/java/mage/filter/FilterCard.java index b1d25603e8c..ceff64ce941 100644 --- a/Mage/src/main/java/mage/filter/FilterCard.java +++ b/Mage/src/main/java/mage/filter/FilterCard.java @@ -28,14 +28,11 @@ package mage.filter; import java.util.ArrayList; -import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.UUID; import java.util.stream.Collectors; - import mage.cards.Card; -import mage.cards.SplitCard; import mage.filter.predicate.ObjectPlayer; import mage.filter.predicate.ObjectPlayerPredicate; import mage.filter.predicate.ObjectSourcePlayer; @@ -78,12 +75,7 @@ public class FilterCard extends FilterObject { if (card == null) { return false; } - if (card.isSplitCard()) { - return super.match(((SplitCard) card).getLeftHalfCard(), game) - || super.match(((SplitCard) card).getRightHalfCard(), game); - } else { - return super.match(card, game); - } + return super.match(card, game); } public boolean match(Card card, UUID playerId, Game game) { diff --git a/Mage/src/main/java/mage/filter/predicate/Predicates.java b/Mage/src/main/java/mage/filter/predicate/Predicates.java index 30ad5956a49..c37eaa16276 100644 --- a/Mage/src/main/java/mage/filter/predicate/Predicates.java +++ b/Mage/src/main/java/mage/filter/predicate/Predicates.java @@ -52,7 +52,7 @@ public final class Predicates { * @return */ public static Predicate not(Predicate predicate) { - return new NotPredicate<>(predicate); + return new NotPredicate(predicate); } /** @@ -65,7 +65,7 @@ public final class Predicates { * @return */ public static Predicate and(Iterable> components) { - return new AndPredicate<>(defensiveCopy(components)); + return new AndPredicate(defensiveCopy(components)); } /** @@ -78,7 +78,7 @@ public final class Predicates { * @return */ public static Predicate and(Predicate... components) { - return new AndPredicate<>(defensiveCopy(components)); + return new AndPredicate(defensiveCopy(components)); } /** @@ -91,7 +91,7 @@ public final class Predicates { * @return */ public static Predicate and(Predicate first, Predicate second) { - return new AndPredicate<>(Predicates.asList(checkNotNull(first), checkNotNull(second))); + return new AndPredicate(Predicates.asList(checkNotNull(first), checkNotNull(second))); } /** @@ -104,7 +104,7 @@ public final class Predicates { * @return */ public static Predicate or(Iterable> components) { - return new OrPredicate<>(defensiveCopy(components)); + return new OrPredicate(defensiveCopy(components)); } /** @@ -117,7 +117,7 @@ public final class Predicates { * @return */ public static Predicate or(Predicate... components) { - return new OrPredicate<>(defensiveCopy(components)); + return new OrPredicate(defensiveCopy(components)); } /** @@ -129,7 +129,7 @@ public final class Predicates { * @return */ public static Predicate or(Predicate first, Predicate second) { - return new OrPredicate<>(Predicates.asList(first, second)); + return new OrPredicate(Predicates.asList(first, second)); } /** @@ -221,7 +221,7 @@ public final class Predicates { } static List defensiveCopy(Iterable iterable) { - ArrayList list = new ArrayList<>(); + ArrayList list = new ArrayList(); for (T element : iterable) { list.add(checkNotNull(element)); } diff --git a/Mage/src/main/java/mage/players/net/SkipPrioritySteps.java b/Mage/src/main/java/mage/players/net/SkipPrioritySteps.java index c5c5e13a3ce..809c23f8f79 100644 --- a/Mage/src/main/java/mage/players/net/SkipPrioritySteps.java +++ b/Mage/src/main/java/mage/players/net/SkipPrioritySteps.java @@ -27,9 +27,10 @@ */ package mage.players.net; -import java.io.Serializable; import mage.constants.PhaseStep; +import java.io.Serializable; + /** * * @author LevelX2 @@ -119,5 +120,33 @@ public class SkipPrioritySteps implements Serializable { return true; } } - + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final SkipPrioritySteps that = (SkipPrioritySteps) o; + + if (isUpkeep() != that.isUpkeep()) return false; + if (isDraw() != that.isDraw()) return false; + if (isMain1() != that.isMain1()) return false; + if (isBeforeCombat() != that.isBeforeCombat()) return false; + if (isEndOfCombat() != that.isEndOfCombat()) return false; + if (isMain2() != that.isMain2()) return false; + return isEndOfTurn() == that.isEndOfTurn(); + + } + + @Override + public int hashCode() { + int result = (isUpkeep() ? 1 : 0); + result = 31 * result + (isDraw() ? 1 : 0); + result = 31 * result + (isMain1() ? 1 : 0); + result = 31 * result + (isBeforeCombat() ? 1 : 0); + result = 31 * result + (isEndOfCombat() ? 1 : 0); + result = 31 * result + (isMain2() ? 1 : 0); + result = 31 * result + (isEndOfTurn() ? 1 : 0); + return result; + } } diff --git a/Mage/src/main/java/mage/players/net/UserData.java b/Mage/src/main/java/mage/players/net/UserData.java index b6bb290d8f2..742540c433a 100644 --- a/Mage/src/main/java/mage/players/net/UserData.java +++ b/Mage/src/main/java/mage/players/net/UserData.java @@ -263,4 +263,73 @@ public class UserData implements Serializable { public static String getDefaultFlagName() { return "world.png"; } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final UserData userData = (UserData) o; + + if (getGroupId() != userData.getGroupId()) return false; + if (getAvatarId() != userData.getAvatarId()) return false; + if (isShowAbilityPickerForced() != userData.isShowAbilityPickerForced()) return false; + if (isAllowRequestShowHandCards() != userData.isAllowRequestShowHandCards()) return false; + if (confirmEmptyManaPool != userData.confirmEmptyManaPool) return false; + if (askMoveToGraveOrder != userData.askMoveToGraveOrder) return false; + if (isManaPoolAutomatic() != userData.isManaPoolAutomatic()) return false; + if (isManaPoolAutomaticRestricted() != userData.isManaPoolAutomaticRestricted()) + return false; + if (isPassPriorityCast() != userData.isPassPriorityCast()) return false; + if (isPassPriorityActivation() != userData.isPassPriorityActivation()) return false; + if (isAutoOrderTrigger() != userData.isAutoOrderTrigger()) return false; + if (isUseFirstManaAbility() != userData.isUseFirstManaAbility()) return false; + if (getMatchQuitRatio() != userData.getMatchQuitRatio()) return false; + if (getTourneyQuitRatio() != userData.getTourneyQuitRatio()) return false; + if (getGeneralRating() != userData.getGeneralRating()) return false; + if (getConstructedRating() != userData.getConstructedRating()) return false; + if (getLimitedRating() != userData.getLimitedRating()) return false; + if (getUserSkipPrioritySteps() != null ? !getUserSkipPrioritySteps().equals(userData + .getUserSkipPrioritySteps()) : userData.getUserSkipPrioritySteps() != null) + return false; + if (getFlagName() != null ? !getFlagName().equals(userData.getFlagName()) : userData + .getFlagName() != null) + return false; + if (userIdStr != null ? !userIdStr.equals(userData.userIdStr) : userData.userIdStr != null) + return false; + if (getMatchHistory() != null ? !getMatchHistory().equals(userData.getMatchHistory()) : + userData.getMatchHistory() != null) + return false; + return getTourneyHistory() != null ? getTourneyHistory().equals(userData + .getTourneyHistory()) : userData.getTourneyHistory() == null; + + } + + @Override + public int hashCode() { + int result = getGroupId(); + result = 31 * result + getAvatarId(); + result = 31 * result + (isShowAbilityPickerForced() ? 1 : 0); + result = 31 * result + (isAllowRequestShowHandCards() ? 1 : 0); + result = 31 * result + (confirmEmptyManaPool ? 1 : 0); + result = 31 * result + (getUserSkipPrioritySteps() != null ? getUserSkipPrioritySteps() + .hashCode() : 0); + result = 31 * result + (getFlagName() != null ? getFlagName().hashCode() : 0); + result = 31 * result + (askMoveToGraveOrder ? 1 : 0); + result = 31 * result + (isManaPoolAutomatic() ? 1 : 0); + result = 31 * result + (isManaPoolAutomaticRestricted() ? 1 : 0); + result = 31 * result + (isPassPriorityCast() ? 1 : 0); + result = 31 * result + (isPassPriorityActivation() ? 1 : 0); + result = 31 * result + (isAutoOrderTrigger() ? 1 : 0); + result = 31 * result + (isUseFirstManaAbility() ? 1 : 0); + result = 31 * result + (userIdStr != null ? userIdStr.hashCode() : 0); + result = 31 * result + (getMatchHistory() != null ? getMatchHistory().hashCode() : 0); + result = 31 * result + getMatchQuitRatio(); + result = 31 * result + (getTourneyHistory() != null ? getTourneyHistory().hashCode() : 0); + result = 31 * result + getTourneyQuitRatio(); + result = 31 * result + getGeneralRating(); + result = 31 * result + getConstructedRating(); + result = 31 * result + getLimitedRating(); + return result; + } } diff --git a/Mage/src/main/java/mage/players/net/UserSkipPrioritySteps.java b/Mage/src/main/java/mage/players/net/UserSkipPrioritySteps.java index 9e405cc6033..f3b43e7d778 100644 --- a/Mage/src/main/java/mage/players/net/UserSkipPrioritySteps.java +++ b/Mage/src/main/java/mage/players/net/UserSkipPrioritySteps.java @@ -88,4 +88,36 @@ public class UserSkipPrioritySteps implements Serializable { this.stopOnAllEndPhases = stopOnAllEndPhases; } + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final UserSkipPrioritySteps that = (UserSkipPrioritySteps) o; + + if (isStopOnDeclareAttackersDuringSkipAction() != that + .isStopOnDeclareAttackersDuringSkipAction()) + return false; + if (isStopOnDeclareBlockerIfNoneAvailable() != that.isStopOnDeclareBlockerIfNoneAvailable()) + return false; + if (isStopOnAllMainPhases() != that.isStopOnAllMainPhases()) return false; + if (isStopOnAllEndPhases() != that.isStopOnAllEndPhases()) return false; + if (getYourTurn() != null ? !getYourTurn().equals(that.getYourTurn()) : that.getYourTurn + () != null) + return false; + return getOpponentTurn() != null ? getOpponentTurn().equals(that.getOpponentTurn()) : + that.getOpponentTurn() == null; + + } + + @Override + public int hashCode() { + int result = getYourTurn() != null ? getYourTurn().hashCode() : 0; + result = 31 * result + (getOpponentTurn() != null ? getOpponentTurn().hashCode() : 0); + result = 31 * result + (isStopOnDeclareAttackersDuringSkipAction() ? 1 : 0); + result = 31 * result + (isStopOnDeclareBlockerIfNoneAvailable() ? 1 : 0); + result = 31 * result + (isStopOnAllMainPhases() ? 1 : 0); + result = 31 * result + (isStopOnAllEndPhases() ? 1 : 0); + return result; + } } diff --git a/Mage/src/main/java/mage/util/CardUtil.java b/Mage/src/main/java/mage/util/CardUtil.java index a431a616f6c..2a89380ec71 100644 --- a/Mage/src/main/java/mage/util/CardUtil.java +++ b/Mage/src/main/java/mage/util/CardUtil.java @@ -27,6 +27,10 @@ */ package mage.util; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; import mage.MageObject; import mage.Mana; import mage.ObjectColor; @@ -36,7 +40,6 @@ import mage.abilities.SpellAbility; import mage.abilities.costs.VariableCost; import mage.abilities.costs.mana.*; import mage.cards.Card; -import mage.cards.SplitCard; import mage.filter.FilterMana; import mage.game.Game; import mage.game.permanent.Permanent; @@ -44,11 +47,6 @@ import mage.game.permanent.token.Token; import mage.game.stack.Spell; import mage.util.functions.CopyTokenFunction; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; - /** * @author nantuko */ @@ -540,13 +538,7 @@ public final class CardUtil { cmcObject.add(object.getConvertedManaCost()); } else if (object instanceof Card) { Card card = (Card) object; - if (card instanceof SplitCard) { - SplitCard splitCard = (SplitCard) card; - cmcObject.add(splitCard.getLeftHalfCard().getConvertedManaCost()); - cmcObject.add(splitCard.getRightHalfCard().getConvertedManaCost()); - } else { - cmcObject.add(card.getConvertedManaCost()); - } + cmcObject.add(card.getConvertedManaCost()); } return cmcObject; } diff --git a/Mage/src/main/java/mage/watchers/common/NumberOfTimesPermanentTargetedATurnWatcher.java b/Mage/src/main/java/mage/watchers/common/NumberOfTimesPermanentTargetedATurnWatcher.java new file mode 100644 index 00000000000..b2ba609b062 --- /dev/null +++ b/Mage/src/main/java/mage/watchers/common/NumberOfTimesPermanentTargetedATurnWatcher.java @@ -0,0 +1,89 @@ +/* + * Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of BetaSteward_at_googlemail.com. + */ + +package mage.watchers.common; + +import java.util.HashMap; +import java.util.Map; +import mage.MageObjectReference; +import mage.constants.WatcherScope; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.watchers.Watcher; + +/** + * + * @author LevelX2 + */ +public class NumberOfTimesPermanentTargetedATurnWatcher extends Watcher { + + private final Map permanentsTargeted = new HashMap<>(); + + public NumberOfTimesPermanentTargetedATurnWatcher() { + super(NumberOfTimesPermanentTargetedATurnWatcher.class.getName(), WatcherScope.GAME); + } + + public NumberOfTimesPermanentTargetedATurnWatcher(final NumberOfTimesPermanentTargetedATurnWatcher watcher) { + super(watcher); + this.permanentsTargeted.putAll(permanentsTargeted); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.TARGETED) { + Permanent permanent = game.getPermanent(event.getTargetId()); + if (permanent != null) { + MageObjectReference mor = new MageObjectReference(permanent, game); + int amount = 0; + if (permanentsTargeted.containsKey(mor)) { + amount = permanentsTargeted.get(mor); + } + permanentsTargeted.put(mor, ++amount); + } + } + } + + public boolean notMoreThanOnceTargetedThisTurn(Permanent creature, Game game) { + if (permanentsTargeted.containsKey(new MageObjectReference(creature, game))) { + return permanentsTargeted.get(new MageObjectReference(creature, game)) < 2; + } + return true; + } + + @Override + public void reset() { + super.reset(); + permanentsTargeted.clear(); + } + + @Override + public NumberOfTimesPermanentTargetedATurnWatcher copy() { + return new NumberOfTimesPermanentTargetedATurnWatcher(this); + } +} diff --git a/Utils/known-sets.txt b/Utils/known-sets.txt index 3732a92345d..9838560168f 100644 --- a/Utils/known-sets.txt +++ b/Utils/known-sets.txt @@ -87,6 +87,7 @@ Guru|Guru| Homelands|Homelands| Hour of Devastation|HourOfDevastation| Ice Age|IceAge| +IconicMasters|IconicMasters| Innistrad|Innistrad| Invasion|Invasion| Ixalan|Ixalan| diff --git a/Utils/mtg-sets-data.txt b/Utils/mtg-sets-data.txt index e7e2d3ee2d9..0285f451dd2 100644 --- a/Utils/mtg-sets-data.txt +++ b/Utils/mtg-sets-data.txt @@ -93,6 +93,7 @@ Homelands|HML| Planechase|HOP| Hour of Devastation|HOU| Ice Age|ICE| +Iconic Masters|IMA| Invasion|INV| Innistrad|ISD| Journey into Nyx|JOU|