Compare commits

...

547 commits

Author SHA1 Message Date
Johannes Wolf
2a3b4aff7a
GUI: fixed error with miss tray icon in some linux systems like gnome (#14130) 2025-12-19 19:15:01 +04:00
theelk801
a3e155918b [SLD] Implement Nathan Drake, Treasure Hunter 2025-12-19 09:29:32 -05:00
theelk801
89f2efd7a9 [SLD] Implement Jin Sakai, Ghost of Tsushima 2025-12-19 09:29:32 -05:00
theelk801
e2df6dff19 [ECL] use common class for Perfect Intimidation 2025-12-19 09:29:32 -05:00
xenohedron
3343f93723 fix #14113 (Gornog, the Red Reaper) 2025-12-18 00:54:52 -05:00
xenohedron
0967f05721 fix NPE in Evendo Brushrazer (PermanentsSacrificedWatcher) 2025-12-18 00:44:52 -05:00
theelk801
acc180d1d4 [ECL] Implement Dose of Dawnglow 2025-12-16 15:30:53 -05:00
theelk801
0ef4695e29 [ECL] Implement Kirol, Attentive First-Year 2025-12-12 12:36:20 -05:00
theelk801
16e3b25024 fix verify failure 2025-12-11 15:57:40 -05:00
theelk801
5ca153507e [MSC] Implement Invisible Woman 2025-12-11 15:02:40 -05:00
theelk801
d133bb09e7 [MSC] Implement The Thing 2025-12-11 14:58:26 -05:00
theelk801
bd1627cf5e [MSC] Implement Human Torch 2025-12-11 14:52:07 -05:00
theelk801
986a198708 [ECL] Implement High Perfect Morcant 2025-12-11 11:45:24 -05:00
theelk801
efe7372449 [ECL] Implement Unexpected Assistance 2025-12-11 11:36:07 -05:00
theelk801
3d4338bf8e [ECL] Implement Perfect Intimidation 2025-12-11 11:35:28 -05:00
theelk801
ed79a8e91f [ECL] update spoiler 2025-12-11 11:29:56 -05:00
theelk801
6fe5a80c60 [MSH] Implement Namor the Sub-Mariner 2025-12-10 11:36:47 -05:00
theelk801
0a2fea6684 [MSH] Implement Doctor Doom 2025-12-10 11:26:53 -05:00
theelk801
5927828965 [MSH] Implement The Sentry, Golden Guardian 2025-12-10 11:20:00 -05:00
theelk801
48631a3487 [MSH] Implement Bruce Banner / The Incredible Hulk 2025-12-10 11:12:37 -05:00
xenohedron
27066e008d fix Shay Cormac 2025-12-09 19:36:18 -05:00
theelk801
b50b14ba96 [MSC] Implement Mister Fantastic 2025-12-09 17:20:19 -05:00
theelk801
ff4470e681 [MSH] Implement The Coming of Galactus 2025-12-09 17:05:26 -05:00
theelk801
71412c36c8 [MSH] Implement Attuma, Atlantean Warlord 2025-12-09 17:01:13 -05:00
theelk801
908cee28d5 [MSH] Implement Captain America, Super-Soldier 2025-12-09 16:55:22 -05:00
theelk801
892214dc5c [MSH] Implement Moon Girl and Devil Dinosaur 2025-12-09 16:41:08 -05:00
theelk801
3c1cbad441 [MSH] Implement Super-Skrull 2025-12-09 16:37:46 -05:00
theelk801
c1c1e94f70 [MSH] Implement Quicksilver, Brash Blur 2025-12-09 16:27:57 -05:00
theelk801
7bae541245 [MSC] add set 2025-12-09 16:06:36 -05:00
theelk801
4939fc5816 [MSH] add set 2025-12-09 15:59:58 -05:00
theelk801
6f17fe597a [DSK] Implement Rampaging Soulrager 2025-12-08 10:24:27 -05:00
theelk801
9563714dcb [DSK] Implement Ghostly Keybearer 2025-12-08 10:18:54 -05:00
theelk801
91f61f3f66 [DSC] Implement Spiked Corridor // Torture Pit 2025-12-08 10:03:29 -05:00
theelk801
bee3614f65 [DSC] Implement Experimental Lab // Staff Room 2025-12-08 09:54:09 -05:00
theelk801
98f7613d20 [DSK] Implement Mirror Room // Fractured Realm 2025-12-07 15:05:31 -05:00
theelk801
cfc28b188e [DSK] Implement Roaring Furnace // Steaming Sauna 2025-12-07 14:58:52 -05:00
theelk801
387d882f1c [DSK] Implement Painter's Studio // Defaced Gallery 2025-12-07 14:55:47 -05:00
theelk801
565520d1d8 [DSK] Implement Derelict Attic // Widow's Walk 2025-12-07 14:55:29 -05:00
theelk801
1901058a73 [DSK] Implement Defiled Crypt // Cadaver Lab 2025-12-07 14:47:32 -05:00
theelk801
520c3a36e5 [DSK] Implement Moldering Gym // Weight Room 2025-12-07 14:16:30 -05:00
theelk801
42bde03b2a [DSK] Implement Restricted Office // Lecture Hall 2025-12-07 14:04:07 -05:00
theelk801
9c854d1bdb [DSK] Implement Meat Locker // Drowned Diner 2025-12-07 14:00:17 -05:00
theelk801
c28f06fd89 [DSK] Implement Glassworks // Shattered Yard 2025-12-07 13:57:53 -05:00
theelk801
3b121df7e2 [WHO] small update to Truth or Consequences 2025-12-07 13:56:45 -05:00
theelk801
83ab56c8a4 simplify room constructor/generation 2025-12-07 12:32:27 -05:00
theelk801
7d2e95cddd fix verify failure 2025-12-07 12:21:16 -05:00
theelk801
f0d83d3de9 [DSK] Implement Underwater Tunnel // Slimy Aquarium 2025-12-07 12:01:32 -05:00
theelk801
f61289b297 [DSK] Implement Ticket Booth // Tunnel of Hate 2025-12-07 11:57:48 -05:00
theelk801
50c7c6aa5b [DSC] update spoiler and reprints 2025-12-07 11:55:31 -05:00
theelk801
6cc187962c [DSK] update spoiler 2025-12-07 11:54:56 -05:00
theelk801
b9052103bb [DSK] Implement Greenhouse / Rickety Gazebo 2025-12-07 11:51:26 -05:00
theelk801
caba72094e [DSK] Implement Grand Entryway // Elegant Rotunda 2025-12-07 11:40:43 -05:00
theelk801
a5483496f8 [WHO] fix Truth or Consequences not correctly picking an opponent at random (fixes #14110) 2025-12-07 11:23:45 -05:00
theelk801
fa1dfb8a42 fix error 2025-12-07 11:11:41 -05:00
theelk801
ce972d294d [FIC] Implement Chocobo Camp 2025-12-07 10:53:46 -05:00
theelk801
147ac2fef2 [FIC] Implement Noctis, Heir Apparent 2025-12-07 10:40:04 -05:00
theelk801
c6f977d02b [FIC] Implement Squall, Gunblade Duelist 2025-12-07 10:22:41 -05:00
theelk801
928a851d79 [FIC] Implement Garland, Royal Kidnapper 2025-12-06 14:34:48 -05:00
Grath
4b146dec7e
Merge pull request #14106 from Grath/grath/fix-dfc-commander-damage
Fix tracking Commander in play when your commander is a (M)DFC.

Fixes #7530, #7637, #7699, #7773
2025-12-06 10:56:38 -05:00
jmlundeen
c2b642632b actual last TDFC conversions
* Casal, Lurkwood Pathfinder // Casal, Pathbreaker Owlbear
* Docent of Perfection // Final Iteration
* Grist, Voracious Larva // Grist, the Plague Swarm
* Ore-Rich Stalactite // Cosmium Catalyst
* Ral, Monsoon Mage // Ral, Leyline Prodigy
* orin of House Markov // Sorin, Ravenous Neonate

part of #14099
2025-12-06 09:44:42 -06:00
jmlundeen
b32ff6abe8 convert final transform card Zenos Yae Galvus
part of #14099
2025-12-06 09:14:06 -06:00
jmlundeen
0f5716d28e convert transforming "W" cards to single class file
part of #14099
2025-12-06 08:57:39 -06:00
jmlundeen
9a26221048 fix TDFC not loading as commander 2025-12-06 08:41:49 -06:00
Grath
8cc31b1a74 Null check. 2025-12-05 22:29:51 -05:00
Grath
ce36e5dec0 Use getCard.getMainCard() instead. 2025-12-05 18:06:00 -05:00
Grath
531768491c Fix tracking Commander in play when your commander is a (M)DFC.
Fixes #7530, #7637, #7699, #7773
2025-12-05 17:43:33 -05:00
jmlundeen
e39c0b8852 convert transforming "V" cards to single class file
part of #14099
2025-12-05 13:48:37 -06:00
jmlundeen
59cf680abc convert transforming "U" cards to single class file
part of #14099
2025-12-05 11:52:47 -06:00
jmlundeen
84933f5802 Locus of Enlightenment - update exile zone and add test 2025-12-05 11:32:44 -06:00
jmlundeen
4f88266893 DayNightTest - fix testCopy null secondCardFace
* pulling directly from game cards is grabbing a card half and not the main card
2025-12-05 10:45:22 -06:00
jmlundeen
5b2629f0dc convert transforming "T" cards to single class file
part of #14099
2025-12-05 09:49:07 -06:00
jmlundeen
7cd68d9620 convert transforming "S" cards to single class file
part of #14099
2025-12-04 10:58:39 -06:00
jmlundeen
99bb467bdc update exile zone for CraftAbility to share between card sides
* updated and added test coverage for previously converted cards Altar of the Wretched and Eye of Ojer Taq
2025-12-04 10:44:19 -06:00
jmlundeen
ae97f8944d ExileAndReturnSourceEffect - update post move zone check 2025-12-04 10:44:19 -06:00
theelk801
a73c3ce553 [ECL] Implement Ashling, Rekindled / Ashling, Rimebound 2025-12-04 11:02:10 -05:00
jmlundeen
6906072ec4 convert transforming "R" cards to single class file
part of #14099
2025-12-03 11:57:21 -06:00
jmlundeen
23dc279b9b convert transforming "P" cards to single class file
part of #14099
2025-12-03 11:57:13 -06:00
jmlundeen
39f62a1c02 convert transforming "O" cards to single class file
part of #14099
2025-12-03 11:57:03 -06:00
jmlundeen
60e2d4d89f convert transforming "N" cards to single class file
part of #14099
2025-12-03 11:56:53 -06:00
jmlundeen
3484e58944 convert transforming "M" cards to single class file
part of #14099
2025-12-03 11:56:45 -06:00
jmlundeen
78ca8e6be7 convert transforming "L" cards to single class file
part of #14099
2025-12-03 08:39:21 -06:00
jmlundeen
1bcbdd520e ExileAndReturnSourceEffect - check for other face being returned
* possible for transform using PutCards
2025-12-03 08:39:01 -06:00
jmlundeen
b43ab76d60 convert transforming "K" cards to single class file
part of #14099
2025-12-03 08:39:00 -06:00
jmlundeen
e0770c8aa5 convert transforming "J" cards to single class file
part of #14099
2025-12-03 08:38:38 -06:00
jmlundeen
ba32691556 convert transforming "I" cards to single class file
part of #14099
2025-12-03 08:38:21 -06:00
jmlundeen
41075fef39 convert transforming "H" cards to single class file 2025-12-01 08:47:55 -06:00
jmlundeen
06f54e5df1 convert transforming "G" cards to single class file 2025-12-01 08:47:55 -06:00
jmlundeen
f550f077d0 convert transforming "F" cards to single class file 2025-12-01 08:47:55 -06:00
jmlundeen
7da85577ef fix Disturb targets for back face auras 2025-12-01 08:47:55 -06:00
jmlundeen
822fb8711a re-add Ambitious Farmhand // Seasoned Cathar 2025-12-01 08:47:55 -06:00
theelk801
7f4f6eab62 [FIC] fix Bugenhagen, Wise Elder condition 2025-11-30 18:49:19 -05:00
jmlundeen
9d9896bd4c convert transforming "E" cards to single class file 2025-11-28 22:35:31 -06:00
jmlundeen
bb69fe2595 convert transforming "D" cards to single class file 2025-11-28 12:59:54 -06:00
jmlundeen
a5d14f91f6 convert transforming "C" cards to single class file 2025-11-28 12:59:52 -06:00
jmlundeen
436ac5bbbd VerifyCardDataTest - update showCardInfo to check reference for both sides of the card 2025-11-28 12:59:49 -06:00
jmlundeen
97738afb9e revert card scanner changes 2025-11-28 12:59:48 -06:00
jmlundeen
0fc8d0871c convert transforming "B" cards to single class file 2025-11-28 12:59:36 -06:00
theelk801
f1d86a569f [TLA] Implement Koh, the Face Stealer 2025-11-28 13:41:52 -05:00
theelk801
bbb9a8f656 [TLE] Implement Tale of Katara and Toph 2025-11-28 10:47:52 -05:00
Grath
95f1e00fee [TLA] Fix Iroh, Grand Lotus
Was applying full-cost flashback to Lessons, which is not a benefit to anyone but should still be fixed.
2025-11-27 18:00:08 -05:00
jmlundeen
c5c42abb59 convert transforming "A" cards to single class file 2025-11-27 10:12:33 -06:00
jmlundeen
395a327cd3 fix verify 2025-11-27 09:42:47 -06:00
jmlundeen
b32a786236 add verify checks for Double Faced Cards having abilities on main card
* add booleans to card scanner, restricting to checking cards by name and set. Reduces duplication of verify checks across sets.
2025-11-27 09:39:46 -06:00
Jmlundeen
69e20b1061
Merge pull request #14061
* move setPT to Card

* Create DoubleFacedCard and DoubleFacedCardHalf to share code between …

* Create Transforming Double Face Card class

* allow putting either permanent side of a double faced card to the bat…

* refactor exile and return transforming card

* update ModalDoubleFacedCard references to DoubleFacedCard where relev…

* update for GUI

* refactor a disturb card

* refactor more disturb cards for test coverage

* refactor a transform card

* refactor more transform cards for test coverage

* fix Archangel Avacyn

* fix cantPlayTDFCBackSide inconsistency

* fix Double Faced Cards having triggers and static abilities when tran…

* fix Double Faced Cards card view erroring when flipping in client

* fix test_Copy_AsSpell_Backside inconsistency

* enable Spider-Man MDFC

* convert TDFC with saga as the front and add card references to Transf…

* refactor More Than Meets the Eye Card

* refactor a battle

* refactor a craft card

* update comment on PeterParkerTest

* Merge branch 'master' into rework-dfc

* fix Saga TDFC Azusa's Many Journeys

* fix double faced cards adding permanent triggers / effects to game

* move permanents entering map into Battlefield

* convert Room cards for new Permanent structure

* fix disturb not exiling

* Merge branch 'master' into rework-dfc

* fix Eddie Brock Power/Toughness

* fix Miles Morales ability on main card

* fix verify conditions for siege and day/night cards

* change room characteristics to text effect to match game rules

* update verify test to skip DoubleFacedCard in missing card test

* accidentally removed transform condition

* Merge branch 'master' into rework-dfc

* fix verify

* CardUtil - remove unnecessary line from castSingle method
2025-11-27 09:24:03 -06:00
theelk801
29557f4334 fix verify failure 2025-11-25 21:22:05 -05:00
theelk801
1700a06b00 [SLP] update and rename set 2025-11-25 21:06:56 -05:00
theelk801
b15e8b314a [TLE] Implement Fire Nation Salvagers 2025-11-25 19:52:11 -05:00
theelk801
a3dea879f0 [TLE] Implement Fire Lord Ozai 2025-11-25 19:42:58 -05:00
theelk801
210f93a7cc [TLA] fix Zuko, Conflicted not limiting modes 2025-11-25 18:57:42 -05:00
theelk801
1f21d6e716 [TLA] Implement Foggy Swamp Visions 2025-11-25 15:02:40 -05:00
theelk801
edbb5b0209 [TLA] Implement Hama, the Bloodbender 2025-11-25 14:55:18 -05:00
theelk801
10c5351b60 [TLE] Implement Nyla, Shirshu Sleuth 2025-11-25 12:56:52 -05:00
theelk801
54e23ac3f4 [TLE] Implement Storm of Memories 2025-11-25 12:42:35 -05:00
theelk801
9d46ecaf7f [TLE] Implement Momo's Heist 2025-11-25 12:37:47 -05:00
theelk801
bb0cc796f1 [TLE] Implement Waterbender's Restoration 2025-11-25 12:33:31 -05:00
theelk801
252707f947 [TLA] Implement Crashing Wave 2025-11-25 12:30:32 -05:00
theelk801
83e99022e1 [TLA] Implement Sandbender Scavengers 2025-11-25 12:23:37 -05:00
theelk801
04af8e94ab [TLA] Implement Obsessive Pursuit 2025-11-25 12:10:30 -05:00
theelk801
26488bf6e2 [TLA] Implement Zuko, Conflicted 2025-11-25 11:54:11 -05:00
Steven Knipe
bb5536b458 Fix Sokka and Sukki target 2025-11-24 18:08:42 -08:00
xenohedron
074f58d341
cleanup DamageTargetEffect (closes #11111) (#14096) 2025-11-23 01:00:34 -05:00
xenohedron
934d8e13f5 various text fixes 2025-11-22 20:44:33 -05:00
xenohedron
9c5e4b0698 fix The Destined Thief 2025-11-22 20:44:14 -05:00
xenohedron
153cac5587 fix Emptiness 2025-11-22 20:40:35 -05:00
xenohedron
d744b347f2 fix Bitterbloom Bearer token 2025-11-22 20:40:05 -05:00
xenohedron
4f8cc385fd fix Urban Retreat 2025-11-22 20:36:41 -05:00
xenohedron
d1b3dd3877 fix Iron Spider, Stark Upgrade 2025-11-22 20:31:37 -05:00
xenohedron
823ba6d849 fix Tectonic Split 2025-11-22 20:25:38 -05:00
xenohedron
3dfc836f14 fix Hermetic Herbalist 2025-11-22 20:23:20 -05:00
xenohedron
589a02ae85 fix verify 2025-11-22 20:17:57 -05:00
Grath
e8d5fb8c59 [TLA] Fix Earthbending with creature counter replacement
Did not work with effects that apply replacement effects to counters being added to creatures (but not to lands). Fixed by processing action between turning the land into a creature and putting the counters on it.
2025-11-21 11:47:15 -05:00
Grath
b715043d4a [FIN] Fix Summon: Brynhildr
1. Was looking for STUN counters being added rather than LORE counters.
2. Was not accounting for if Summon: Brynhildr was entering with a counter, such as on the first turn it was played.
2025-11-21 11:42:01 -05:00
Grath
b33ecac6bd Fix Cradle of Vitality. 2025-11-21 11:36:05 -05:00
theelk801
74305ee3fb [TLE] Implement Desperate Plea 2025-11-20 13:16:26 -05:00
theelk801
898e3a37d1 [TLE] Implement That's Rough Buddy 2025-11-20 13:11:22 -05:00
theelk801
36c6210cee [TLE] Implement Tale of Momo 2025-11-20 13:09:38 -05:00
theelk801
ebf82309fc [TLE] Implement Swampbenders 2025-11-20 12:57:39 -05:00
theelk801
e38c199177 fix verify failure again 2025-11-19 20:52:56 -05:00
theelk801
b8062c4131 fix verify failure 2025-11-19 20:32:35 -05:00
theelk801
440ece463a fix test failure 2025-11-19 19:50:10 -05:00
theelk801
6b4acfe5ce [TLA] Implement Jasmine Dragon Tea Shop 2025-11-19 16:00:17 -05:00
theelk801
4772658527 [TLA] Implement The Last Agni Kai 2025-11-19 13:19:11 -05:00
theelk801
80d58a35f7 [TLA] Implement The Earth King 2025-11-19 12:59:59 -05:00
theelk801
a656f0292a [TLA] Implement Trusty Boomerang 2025-11-19 12:46:35 -05:00
theelk801
85b5f91936 [TLE] fix Dutiful Knowledge Seeker ability 2025-11-19 12:32:23 -05:00
theelk801
832ebf0096 [TLE] Implement Wan Shi Tong, All-Knowing 2025-11-19 09:31:53 -05:00
theelk801
9b0f09ce91 [TLE] Implement Stand United 2025-11-19 09:25:28 -05:00
theelk801
6ba8c6fb90 [TLE] Implement Katara's Reversal 2025-11-19 09:11:05 -05:00
theelk801
3b978aa258 [TLE] Implement Hermitic Herbalist 2025-11-19 09:06:30 -05:00
theelk801
d6cc23ff95 [TLA] Implement Hermitic Herbalist 2025-11-19 08:55:54 -05:00
theelk801
7f06b7e3f7 [TLA] Implement White Lotus Hideout 2025-11-19 08:54:07 -05:00
theelk801
603ad33d0e [TLA] Implement Avatar Destiny 2025-11-19 08:50:47 -05:00
theelk801
e97718c6a8 [TLA] Implement Unlucky Cabbage Merchant 2025-11-19 08:30:06 -05:00
Steven Knipe
965bf8bea3 Fix Earthbend target for verify check 2025-11-18 23:01:41 -08:00
xenohedron
e7e6623ec9 fix #14079 (Fumble) 2025-11-18 22:47:01 -05:00
xenohedron
a2a4af7981 fix #14084 (The Darkness Crystal) 2025-11-18 22:41:47 -05:00
xenohedron
46452b252e verify fix 2025-11-18 21:14:39 -05:00
xenohedron
bc3240e94d some text fixes 2025-11-18 21:10:58 -05:00
xenohedron
4dcf37e007 fix text generation in new damage effect classes 2025-11-18 20:50:21 -05:00
xenohedron
2893fb43fc remove unneeded methods from DamageTargetEffect
minor cleanup to Sentinel Tower, Tephraderm

(see #11111)
2025-11-18 20:47:26 -05:00
xenohedron
aa1e2342e4 small fix Mournwillow 2025-11-18 20:47:26 -05:00
theelk801
426583ce83 [TLE] Implement Tectonic Split 2025-11-18 12:27:54 -05:00
theelk801
5bf14e2add [TLE] Implement Princess Yue 2025-11-18 11:55:25 -05:00
theelk801
07a1875561 [TLE] Implement Hog-Monkey Rampage 2025-11-18 11:46:53 -05:00
theelk801
1f0b829522 [TLE] Implement Hei Bai, Forest Guardian 2025-11-18 11:44:11 -05:00
theelk801
761818c90f [TLE] various text fixes 2025-11-18 11:30:24 -05:00
theelk801
790361f59f [TLA] various text fixes 2025-11-18 09:21:40 -05:00
theelk801
00c5daa5ea [TLA] Implement Ty Lee, Chi Blocker 2025-11-18 08:21:22 -05:00
theelk801
7aa91ab43e [TLA] Implement Toph, Hardheaded Teacher 2025-11-18 08:19:51 -05:00
theelk801
0ecd425069 [TLA] Implement Iroh, Tea Master 2025-11-18 08:15:02 -05:00
theelk801
f81b0645f5 [TLA] Implement Azula, Cunning Usurper 2025-11-18 07:59:12 -05:00
theelk801
08a0fa285e [TLA] Implement The Blue Spirit 2025-11-17 09:38:59 -05:00
theelk801
aa2fd2534e [TLA] Implement Uncle's Musings 2025-11-17 09:31:56 -05:00
theelk801
f0370c4759 [TLA] Implement Sokka, Swordmaster 2025-11-17 09:27:49 -05:00
theelk801
0445d65777 [TLA] Implement Wartime Protestors 2025-11-17 09:17:19 -05:00
theelk801
9cfbcf6f84 [TLA] Implement Wan Shi Tong, Librarian 2025-11-17 09:14:56 -05:00
theelk801
31b682644a [TLE] Implement Katara, Seeking Revenge 2025-11-17 09:09:10 -05:00
theelk801
abb348ac1c [TLA] Implement Ruinous Waterbending 2025-11-17 09:05:33 -05:00
theelk801
5c8a185411 [TLA] Implement Spirit Water Revival 2025-11-17 09:00:58 -05:00
theelk801
1ae2ba93a7 [TLE] Implement The Duke, Rebel Sentry 2025-11-17 08:36:00 -05:00
theelk801
cb2e37c6a7 [TLE] Implement Reckless Blaze 2025-11-17 08:30:25 -05:00
theelk801
1abee5d86b [TLE] Implement Sokka and Suki 2025-11-17 08:20:11 -05:00
theelk801
f82f465c00 [UNF] add test for Embiggen 2025-11-17 08:10:50 -05:00
theelk801
6fbdc86ed8 [TLE] Implement Dutiful Knowledge Seeker 2025-11-16 17:31:41 -05:00
theelk801
3f0b37ea99 [TLA] Implement The Legend of Yangchen / Avatar Yangchen 2025-11-16 17:22:07 -05:00
theelk801
0c9ce259bd [TLA] Implement The Fire Nation Drill 2025-11-16 17:09:40 -05:00
theelk801
fad886d48b [TLA] Implement Team Avatar 2025-11-16 17:00:32 -05:00
theelk801
037e30f802 [TLA] Implement Honest Work 2025-11-16 16:56:47 -05:00
theelk801
b16fba2ceb [TLA] Implement The Legend of Kyoshi / Avatar Kyoshi 2025-11-15 10:38:02 -05:00
theelk801
886dd1f0b2 [TLA] Implement Lost Days 2025-11-15 10:24:28 -05:00
theelk801
7f85e6ef3f [TLA] Implement Combustion Man 2025-11-15 10:08:26 -05:00
theelk801
6b4b938713 [TLA] Implement Bumi, King of Three Trials 2025-11-15 10:03:06 -05:00
ReSech
49442b7caf
Slimefoot And Squee - fixed that it can't be activated without another target (#14089, #14088) 2025-11-15 13:10:31 +04:00
theelk801
25cd45c8b8 [TLE] Implement Toph, Greatest Earthbender 2025-11-14 15:58:20 -05:00
theelk801
be04d9b28f [TLE] Implement Suki, Kyoshi Captain 2025-11-14 15:55:22 -05:00
theelk801
a4adf6f844 [TLE] Implement Nightmares and Daydreams 2025-11-14 15:51:15 -05:00
theelk801
c193ff994b [TLE] Implement Monk Gyatso 2025-11-14 15:41:37 -05:00
theelk801
1447f467c3 [TLE] Implement Master's Guidance 2025-11-14 15:39:22 -05:00
theelk801
dc458681cc [TLE] Implement Lost in Memories 2025-11-14 15:35:54 -05:00
theelk801
ad61edd559 [TLE] Implement Kyoshi Warrior Exemplars 2025-11-14 15:30:52 -05:00
theelk801
6c45ec6004 [TLE] Implement Chong and Lily, Nomads 2025-11-14 15:30:39 -05:00
theelk801
7322bf784f [TLA] Implement Sparring Dummy 2025-11-14 15:13:55 -05:00
theelk801
2fd0065e7e [TLA] Implement Price of Freedom 2025-11-14 15:07:44 -05:00
theelk801
a59d57ae93 [TLA] Implement Phoenix Fleet Airship 2025-11-14 15:04:56 -05:00
theelk801
6b5fb2d4c2 [TLA] Implement Destined Confrontation 2025-11-14 14:56:57 -05:00
theelk801
4e2c4ec1f0 [TLE] Implement Lo and Li, Royal Advisors 2025-11-14 11:09:22 -05:00
theelk801
79afaa0fbb [TLE] Implement Hook Swords 2025-11-14 10:59:44 -05:00
theelk801
67dc571224 [TLE] Implement Giant Fly 2025-11-14 10:56:51 -05:00
theelk801
76605e2a9d [TLE] Implement Freedom Fighter Recruit 2025-11-14 10:56:03 -05:00
theelk801
80f604943d [TLE] Implement Elephant-Mandrill 2025-11-14 10:54:22 -05:00
theelk801
d10863b844 [TLE] Implement Bumi's Feast Lecture 2025-11-14 10:54:22 -05:00
theelk801
88fc3b9045 [TLE] Implement Appa the Vigilant 2025-11-14 10:54:22 -05:00
theelk801
b5954c90a5 [TLE] Implement Aang and Katara 2025-11-14 10:54:22 -05:00
theelk801
31b023a003 [TLA] Implement Raven Eagle 2025-11-14 10:32:19 -05:00
theelk801
70ffc77a5b [TLA] Implement Elemental Teachings 2025-11-14 10:27:59 -05:00
theelk801
7d482d7a44 [TLA] Implement The Legend of Roku / Avatar Roku 2025-11-14 10:03:02 -05:00
theelk801
cc330ac3b8 [TLA] Implement The Legend of Kurruk / Avatar Kurruk 2025-11-14 09:54:33 -05:00
Grath
5bfd0ae796 Syr Vondam's second ability needs to function from the graveyard and/or exile zones. 2025-11-13 16:21:40 -05:00
theelk801
62ad2a1545 [TLE] Implement Bosco, Just a Bear 2025-11-13 10:23:44 -05:00
theelk801
c76ffbb3f5 [TLE] Implement Bison Whistle 2025-11-13 10:20:13 -05:00
theelk801
3d4454c7da [TLE] Implement Baboon Spirit 2025-11-13 10:03:52 -05:00
theelk801
5c62f53b08 [TLE] Implement Air Nomad Student 2025-11-13 10:00:12 -05:00
theelk801
7a0142867a [TLA] Implement Iroh, Grand Lotus 2025-11-13 09:56:03 -05:00
theelk801
ab2980116d [TLA] Implement Fatal Fissure 2025-11-13 09:48:59 -05:00
theelk801
5ce393f617 [TLA] Implement Energybending 2025-11-13 09:44:59 -05:00
theelk801
998b737ab5 [TLA] Implement Earth Kingdom General 2025-11-13 09:35:04 -05:00
theelk801
09d3d89045 [TLA] Implement Avatar's Wrath 2025-11-13 09:28:13 -05:00
theelk801
694f5332cc [TLA] Implement Aang, Swift Savior / Aang and La, Ocean's Fury 2025-11-13 09:22:25 -05:00
theelk801
13f4a314a7 [TLA] Implement Allies at Last 2025-11-13 09:11:56 -05:00
theelk801
ee77746db8 [TLA] Implement Secret Tunnel 2025-11-13 09:08:50 -05:00
xenohedron
1cb72d0efb
Merge pull request #14078 from xenohedron/damagemulti
Rework effects that deal damage to multiple specific objects
2025-11-13 00:35:06 -05:00
theelk801
ac71e5d5d8 [TLA] Implement Vengeful Villagers 2025-11-12 10:53:02 -05:00
theelk801
d7b5c21894 [TLA] Implement Zhao, the Moon Slayer 2025-11-12 10:50:21 -05:00
theelk801
70444ba7de [TLA] Implement Waterbending Scroll 2025-11-12 10:41:23 -05:00
theelk801
74f7a4fcbe [TLA] Implement Waterbender Ascension 2025-11-12 10:37:58 -05:00
theelk801
3c3b6b4353 [TLA] Implement Walltop Sentries 2025-11-12 10:33:48 -05:00
theelk801
d63b816a5f [TLA] Implement Teo, Spirited Glider 2025-11-12 10:31:11 -05:00
theelk801
096795be00 [TLA] Implement Pirate Peddlers 2025-11-12 10:25:39 -05:00
theelk801
f5ce27f6c8 [TLA] Implement Messenger Hawk 2025-11-12 10:18:47 -05:00
theelk801
c0e10f0569 [TLA] Implement Lo and Li, Twin Tutors 2025-11-12 10:17:13 -05:00
theelk801
c602edeca3 [TLA] Implement Kyoshi Island Plaza 2025-11-12 10:10:03 -05:00
theelk801
6efb4e5df4 [TLA] Implement Foggy Swamp Spirit Keeper 2025-11-12 09:22:04 -05:00
theelk801
d83e1f1e4e [TLA] Implement Foggy Swamp Hunters 2025-11-12 09:21:11 -05:00
theelk801
473df7ac12 [TLA] Implement Fire Navy Trebuchet 2025-11-12 09:06:29 -05:00
theelk801
626317cf68 [TLA] Implement Ember Island Production 2025-11-12 09:01:52 -05:00
theelk801
4c3af32a50 [TLA] Implement Combustion Technique 2025-11-12 08:55:11 -05:00
theelk801
c76dd063f2 [TLA] Implement Beifong's Bounty Hunters 2025-11-12 08:52:03 -05:00
theelk801
e338f5c3f2 [TLA] Implement Aang, at the Crossroads / Aang, Destined Savior 2025-11-12 08:46:31 -05:00
theelk801
7bd6c157a8 [SLD] Implement Kratos, Stoic Father 2025-11-11 18:11:38 -05:00
theelk801
e6cb3fe68e [TLA] Implement Jet, Freedom Fighter 2025-11-11 18:11:38 -05:00
theelk801
b87735aa49 [TLA] Implement June, Bounty Hunter 2025-11-11 18:11:38 -05:00
theelk801
ad063f7874 [TLA] Implement Jeong Jeong, the Deserter 2025-11-11 18:11:37 -05:00
theelk801
e562c20f1d [TLA] Implement Earthen Ally 2025-11-11 18:11:37 -05:00
theelk801
d88f7c68d4 [TLA] Implement Day of Black Sun 2025-11-11 18:11:37 -05:00
theelk801
6cdc989c04 [TLA] Implement Bitter Work 2025-11-11 18:11:37 -05:00
theelk801
019e3ecf1c [TLA] Implement Boiling Rock Rioter 2025-11-11 18:11:37 -05:00
theelk801
4eaf1233c9 [TLA] Implement Realm of Koh 2025-11-11 18:11:37 -05:00
theelk801
522e54e215 [TLA] Implement Accumulate Wisdom 2025-11-11 18:11:37 -05:00
ReSech
6fc4a5fbba
Add TLA and TLE Tokens (#14083)
* Add copy tokens

* TLE Tokens

* Add TLA Tokens
2025-11-11 17:07:57 -06:00
theelk801
0ff60c91c1 fix test failure 2025-11-11 13:03:50 -05:00
theelk801
43e7d31cc5 [TLE] Implement Solid Ground 2025-11-11 12:47:03 -05:00
theelk801
697a914892 [TLE] Implement Scarring Memories 2025-11-11 12:45:23 -05:00
theelk801
c9af0467b9 [TLE] Implement Zuko, Seeking Honor 2025-11-11 12:41:47 -05:00
theelk801
9057461c29 [TLE] Implement Whirlwind Technique 2025-11-11 12:40:22 -05:00
theelk801
32d9c6887c [TLE] Implement Unagi's Spray 2025-11-11 12:38:06 -05:00
theelk801
47246ee381 [TLE] Implement Tui and La, Moon and Ocean 2025-11-11 12:35:34 -05:00
theelk801
9bdda9c5fd [TLE] Implement The Art of Tea 2025-11-11 12:32:36 -05:00
theelk801
654a29cba9 [TLE] Implement Sokka's Charge 2025-11-11 12:28:55 -05:00
theelk801
4c3a48b5f9 [TLE] Implement Smellerbee, Rebel Fighter 2025-11-11 12:24:30 -05:00
theelk801
6cd0c9d500 [TLE] Implement Ruthless Waterbender 2025-11-11 12:21:04 -05:00
theelk801
58206f24d5 [TLE] Implement Pipsqueak, Rebel Strongarm 2025-11-11 12:17:57 -05:00
theelk801
b412b9dd9a [TLE] Implement Overwhelming Victory 2025-11-11 12:15:55 -05:00
theelk801
04bd66b638 [TLE] Implement Moku, Meandering Drummer 2025-11-11 12:09:27 -05:00
theelk801
81592ac710 [TLE] Implement Mai and Zuko 2025-11-11 12:04:12 -05:00
theelk801
4742d414eb [TLE] Implement Longshot, Rebel Bowman 2025-11-11 12:02:17 -05:00
theelk801
defa5e20f5 [TLE] Implement Koala-Sheep 2025-11-11 11:40:11 -05:00
theelk801
ee99f7b094 [TLE] Implement Jet, Rebel Leader 2025-11-11 11:39:22 -05:00
theelk801
97f57fc0e0 [TLE] Implement Inspired Insurgent 2025-11-11 11:31:34 -05:00
theelk801
25e010ee01 [TLE] Implement Frantic Confrontation 2025-11-11 11:30:08 -05:00
theelk801
eafc6600da [TLE] Implement Founding of Omashu 2025-11-11 11:28:13 -05:00
theelk801
4cc7a079ec [TLE] Implement Fire Nation Turret 2025-11-11 11:26:05 -05:00
theelk801
d64e8b9194 [TLE] Implement Fire Nation Occupation 2025-11-11 11:23:23 -05:00
theelk801
f5802be133 [TLE] Implement Earthshape 2025-11-11 11:21:37 -05:00
theelk801
6fb84830b3 [TLE] Implement Deer-Dog 2025-11-11 11:13:45 -05:00
theelk801
bea75d55af [TLE] Implement Dai Li Censor 2025-11-11 11:13:24 -05:00
theelk801
8794545c9f [TLE] Implement Crystalline Armor 2025-11-11 11:12:08 -05:00
theelk801
7bb5e54eec [TLE] Implement Creeping Crystal Coating 2025-11-11 11:10:46 -05:00
theelk801
bfed992bf8 [TLE] Implement Cracked Earth Technique 2025-11-11 11:09:03 -05:00
theelk801
3bca2e4eab [TLE] Implement Chakra Meditation 2025-11-11 11:05:31 -05:00
theelk801
9d49f601c2 [TLE] Implement Aang, A Lot to Learn 2025-11-11 10:59:32 -05:00
xenohedron
f2bf831e61 improve verify checks for target tag usage 2025-11-11 00:20:32 -05:00
xenohedron
646d34a90e fix oversight for real this time 2025-11-10 22:35:55 -05:00
xenohedron
97fd15d7a6 fix oversight 2025-11-10 22:06:41 -05:00
theelk801
2799c3f1c0 update ban lists 2025-11-10 11:17:55 -05:00
xenohedron
71269f972e add failing tests using lifelink 2025-11-10 02:02:59 -05:00
xenohedron
1fb0d26db9 cleanup to common class 2025-11-10 02:01:58 -05:00
xenohedron
0ae2c2b86e remove custom multitarget handling from DamageTargetEffect 2025-11-10 01:53:27 -05:00
xenohedron
1a1f7ec588 update all cards that deal damage to two or more specific things simultaneously 2025-11-10 01:38:25 -05:00
xenohedron
b8394f99e2 new DamageTargetAndAllControlledEffect 2025-11-09 23:59:57 -05:00
xenohedron
03100a932e new DamageTargetAndTargetControllerEffect 2025-11-09 23:59:56 -05:00
xenohedron
24785b6d81 new DamageTargetAndSelfEffect 2025-11-09 23:59:56 -05:00
xenohedron
9f663f2a23 new DamageTargetAndYouEffect 2025-11-09 23:59:56 -05:00
xenohedron
7a6dfb7a2f new DamageTargetAndTargetEffect 2025-11-09 23:59:56 -05:00
xenohedron
06c51bd829 update to check damage batch by source 2025-11-09 23:59:55 -05:00
xenohedron
cd1f3985fd add test cases (not depending on lifelink) 2025-11-09 23:59:55 -05:00
xenohedron
f7855dda8b fix Awaken the Maelstrom 2025-11-09 20:55:51 -05:00
Steven Knipe
00ff663c40 implement Orcish Conscripts, rework can't block alone ability 2025-11-09 20:48:13 -05:00
Steven Knipe
d785193b97 implement Orcish Farmer 2025-11-09 20:48:13 -05:00
Steven Knipe
066fb6dd46 implement Sacred Boon and Scars of the Veteran 2025-11-09 20:48:13 -05:00
ssk97
f0e551dafb
Update damage prevention effects to use preventDamageAction (#14071) 2025-11-09 20:47:59 -05:00
xenohedron
caf7a2b8a9 fix verify 2025-11-09 20:47:27 -05:00
xenohedron
865b05781e fix Zuko's Conviction missing target 2025-11-09 14:26:06 -05:00
Grath
784bea734f Better fix with text generation. 2025-11-08 23:42:11 -05:00
ReSech
df20c64c58
Update reprints and tokens [SLC] [SLD] [PW25] [PSPL] (#14074)
* Add Mutagen Token

* Add missing SLC

* Add missing SLD

* Add missing PW25

* Add missing PSPL

* fix verify errors
2025-11-08 23:03:57 -05:00
Grath
86d0910e1e Update OptionalOneShotEffect with possibly better text generation. 2025-11-08 23:01:44 -05:00
ReSech
eb69df1623
FULL_ART Card and Check Fixes (#14004)
* Fix SLD Lands and SLC Full Art

* Update FULL_ART cards in SPM

* Update FULL_ART in SLD

* More SLD FULL_ART

* update test_checkWrongFullArtAndRetro
2025-11-08 15:26:13 -05:00
theelk801
70327c70c7 [TLA] Implement Zuko's Conviction 2025-11-08 15:24:22 -05:00
theelk801
f0d1fb8fa4 [TLA] Implement Water Tribe Rallier 2025-11-08 15:22:26 -05:00
theelk801
1bd3963079 [TLA] Implement Water Tribe Captain 2025-11-08 15:20:47 -05:00
theelk801
3c75bd4889 [TLA] Implement Wandering Musicians 2025-11-08 15:19:53 -05:00
theelk801
67004140ff [TLA] Implement South Pole Voyager 2025-11-08 15:19:15 -05:00
theelk801
a986cdf31e [TLA] Implement Rumble Arena 2025-11-08 15:16:10 -05:00
theelk801
cff73aa9f8 [TLA] Implement Meteor Sword 2025-11-08 15:13:47 -05:00
theelk801
6a2bc8f2ee [TLA] Implement Joo Dee, One of Many 2025-11-08 15:13:47 -05:00
theelk801
f744712d92 [TLA] Implement Foggy Swamp Vinebender 2025-11-08 15:13:47 -05:00
theelk801
da4c97acbe [TLA] Implement Firebending Lesson 2025-11-08 15:13:47 -05:00
theelk801
b69a4c1616 [TLA] Implement Earth Kingdom Protectors 2025-11-08 15:13:47 -05:00
theelk801
504d8d375f [TLA] Implement Curious Farm Animals 2025-11-08 15:13:47 -05:00
theelk801
71f642acc4 [TLA] Implement Canyon Crawler 2025-11-08 15:13:47 -05:00
theelk801
6a5fb5dd51 [TLA] Implement Boar-q-pine 2025-11-08 15:13:47 -05:00
theelk801
e996131ea9 [TLA] Implement Air Nomad Legacy 2025-11-08 15:13:47 -05:00
theelk801
401b70e616 [TLA] Implement Ba Sing Se 2025-11-08 15:13:46 -05:00
theelk801
7a71bf70aa [TLA] Implement Agna Qel'a 2025-11-08 15:13:46 -05:00
theelk801
80fdc8f88b [TLA] Implement Abandoned Air Temple 2025-11-08 15:13:46 -05:00
xenohedron
1c95a93af2 fix Carnage, Crimson Chaos (closes #14056) 2025-11-08 14:59:52 -05:00
xenohedron
a03e971090 fix Spider-Punk 2025-11-08 14:59:52 -05:00
xenohedron
8ac800b08b fix Shadow of the Goblin 2025-11-08 14:59:52 -05:00
xenohedron
39a8945589 fix Sandman, Shifting Scoundrel 2025-11-08 14:59:52 -05:00
xenohedron
d2559333e8 fix Koth of the Hammer 2025-11-08 14:59:52 -05:00
Tuomas-Matti Soikkeli
1327fe2b99
gui: cover scale style option for background images (#14049) 2025-11-08 14:59:45 -05:00
ReSech
7e34363954
Move cards from PMEI to LMAR and add missing PURL Reprints (#14008)
* Add new PURL reprints

* Move LMAR cards to dedicated set, remove from PMEI
2025-11-08 14:58:25 -05:00
ReSech
67660374cb Fix 2214 Back Image Download 2025-11-08 14:58:04 -05:00
ReSech
2b288cfd00 Add SLD Reprint and Tokens 2025-11-08 14:58:04 -05:00
theelk801
aac1aa55cc fix verify errors 2025-11-08 09:54:48 -05:00
theelk801
6e68121897 [TLE] update spoiler and reprints 2025-11-08 09:34:11 -05:00
theelk801
0d21b67057 [TLA] update spoiler 2025-11-08 09:33:53 -05:00
Grath
90815541f9 [TLA] Implement Ozai, the Phoenix King 2025-11-07 22:22:33 -05:00
Grath
a17635564a [TLE] Implement Iroh, Dragon of the West 2025-11-07 21:50:20 -05:00
Grath
3a92c32e48 [TLE] Implement Azula, Ruthless Firebender 2025-11-07 21:34:48 -05:00
Grath
b69fb2f4cd [TLE] Implement Zuko, Firebending Master 2025-11-07 20:48:57 -05:00
Grath
9c4bd210d7 [EOE] Fix Planetary Annihilation
It was never allowing people with 6 or fewer lands to save their lands.
2025-11-07 20:19:19 -05:00
Grath
a502ee94d5 [TLA] Implement Firebender Ascension
Also implemented an OptionalOneShotEffect for ease of stapling together a mandatory effect and an optional effect on the same ability.
2025-11-07 18:40:45 -05:00
Grath
4494bdddbb [TLA] Fix Fire Lord Azula. 2025-11-07 16:38:14 -05:00
Steven Knipe
93ebabf443 Fix IntPlusDynamicValue not modifying getMessage as well 2025-11-05 21:30:05 -08:00
Steven Knipe
d41d9693b4 Fix AzorsElocutors missing first ability 2025-11-05 21:25:19 -08:00
theelk801
cc9a7bafc3 [TLA] Implement Airbender's Reversal 2025-11-05 19:12:20 -05:00
theelk801
69c018fd3f [TLA] Implement The Walls of Ba Sing Se 2025-11-05 19:11:01 -05:00
theelk801
b77d6cd8fd [TLA] Implement Kyoshi Battle Fan 2025-11-05 19:10:01 -05:00
theelk801
fbf6fe6ae6 [TLA] update spoiler 2025-11-05 19:08:18 -05:00
theelk801
b05f749be4 [TLE] update spoiler and reprints 2025-11-05 19:07:58 -05:00
theelk801
e43cef514b [TLE] Implement Kindly Customer 2025-11-05 12:53:03 -05:00
theelk801
6e3d278fc8 [TLE] Implement Sokka's Sword Training 2025-11-05 12:52:23 -05:00
theelk801
52dbd96147 [TLE] Implement Toucan-Puffin 2025-11-05 12:51:23 -05:00
theelk801
49aab3a855 [TLE] update spoiler and reprints 2025-11-05 12:49:13 -05:00
theelk801
08130d98b1 fix verify failure 2025-11-05 12:42:35 -05:00
theelk801
1c56342485 [TLA] Implement Knowledge Seeker 2025-11-05 12:23:51 -05:00
theelk801
a50095e784 [TLA] Implement Wolfbat 2025-11-05 12:22:35 -05:00
theelk801
e4fcca82dd [TLA] Implement Benevolent River Spirit 2025-11-05 12:20:15 -05:00
theelk801
9c630578f1 [TLA] Implement Rockalanche 2025-11-05 12:19:24 -05:00
theelk801
6e0dc4f5f6 [TLA] Implement Professor Zei, Anthropologist 2025-11-05 12:17:45 -05:00
theelk801
835d4ae465 [TLA] Implement Great Divide Guide 2025-11-05 12:14:18 -05:00
theelk801
c9e4b33e4c [TLA] Implement Invasion Reinforcements 2025-11-05 12:12:00 -05:00
theelk801
d8b32308e8 [TLA] Implement Kyoshi Warriors 2025-11-05 12:11:20 -05:00
theelk801
35eeb2cb2d [TLA] Implement Swampsnare Trap 2025-11-05 12:10:10 -05:00
theelk801
9d1d27c9a5 [TLA] update spoiler 2025-11-05 12:08:16 -05:00
theelk801
d4635eb060 [TLA] Implement Sandbenders' Storm 2025-11-04 13:01:09 -05:00
theelk801
6b482f2afc [TLA] Implement Earthbender Ascension 2025-11-04 12:52:02 -05:00
theelk801
dc07b24ed3 [TLA] Implement Fire Nation Raider 2025-11-04 12:40:16 -05:00
theelk801
143efd64cb [TLA] update spoiler 2025-11-04 12:38:56 -05:00
theelk801
d968fb9f70 [TLA] Implement Boomerang Basics 2025-11-04 12:38:20 -05:00
theelk801
c3f359c5e8 [TLA] Implement Jet's Brainwashing 2025-11-04 10:08:03 -05:00
theelk801
dcf1ab14d7 [TLA] Implement Yip Yip! 2025-11-04 09:58:53 -05:00
theelk801
4c0270a5d5 [TLA] Implement Dai Li Agents 2025-11-04 09:53:44 -05:00
theelk801
34ddd612b3 [TLA] Implement Airbender Ascension 2025-11-04 09:45:00 -05:00
theelk801
ac7f33a156 [TLA] Implement Earth Rumble Wrestlers 2025-11-04 09:36:28 -05:00
theelk801
a13c339df2 [TLA] Implement Appa, Loyal Sky Bison 2025-11-04 09:27:28 -05:00
theelk801
ddb7e133c6 [TLA] Implement Sold Out 2025-11-04 09:27:28 -05:00
theelk801
f880a683f9 [TLA] Implement The Boulder, Ready to Rumble 2025-11-04 09:27:28 -05:00
theelk801
63b01b10d7 [TLE] Implement Iroh's Demonstration 2025-11-04 09:27:28 -05:00
theelk801
c473b7a189 [TLE] Implement Avatar Roku, Firebender 2025-11-04 09:27:28 -05:00
theelk801
f0ba075d56 [TLA] update spoiler 2025-11-04 09:27:18 -05:00
theelk801
6e5116b673 [TLA] Implement Enter the Avatar State 2025-11-04 08:47:08 -05:00
theelk801
da6ba92ba2 [TLA] Implement Earth Kingdom Jailer 2025-11-04 08:44:08 -05:00
theelk801
171ea63bc0 [TLA] Implement Cruel Administrator 2025-11-04 08:40:52 -05:00
theelk801
793c8d1daa [TLA] Implement Fire Nation Palace 2025-11-04 08:38:42 -05:00
theelk801
a0f0c0f6be [TLA] update spoiler 2025-11-04 08:33:54 -05:00
theelk801
10db510c35 [TLE] update spoiler and reprints 2025-11-04 08:33:38 -05:00
theelk801
0168db7a57 temporary verify fix 2025-11-03 20:30:22 -05:00
theelk801
269162bf32 [TLA] Implement Invasion Submersible 2025-11-03 19:54:16 -05:00
theelk801
64cde5ec17 [TLA] Implement Guru Pathik 2025-11-03 19:50:09 -05:00
theelk801
5ff8881d19 [TLA] Implement The Lion Turtle 2025-11-03 19:10:52 -05:00
theelk801
cbd6d11087 [TLA] Implement Earth King's Lieutenant 2025-11-03 19:04:48 -05:00
theelk801
1ec0897101 [TLA] Implement The Spirit Oasis 2025-11-03 19:00:18 -05:00
theelk801
777bb176bf [TLA] Implement Platypus-Bear 2025-11-03 18:52:34 -05:00
theelk801
6e0d6dfc36 [TLA] Implement Callous Inspector 2025-11-03 18:45:22 -05:00
theelk801
698f1d4668 [TLA] Implement The Unagi of Kyoshi Island 2025-11-03 18:41:42 -05:00
theelk801
a205bba849 [TLA] Implement Zhao, Ruthless Admiral 2025-11-03 18:39:43 -05:00
theelk801
ff79d9503e [SLC] update set 2025-11-03 18:38:02 -05:00
theelk801
48ee8eefc3 [TLE] update reprints 2025-11-03 18:37:25 -05:00
theelk801
5bf5bda8e5 [TLA] Implement Gather the White Lotus 2025-11-03 18:35:52 -05:00
theelk801
7caf775696 [TLA] Implement Tiger-Dillo 2025-11-03 18:32:36 -05:00
theelk801
3d6d30561d [TLA] Implement Twin Blades 2025-11-03 18:29:20 -05:00
theelk801
6a36947e65 [TLA] Implement Shared Roots 2025-11-03 18:27:23 -05:00
theelk801
08fc3bbdc1 [TLA] Implement Tolls of War 2025-11-03 18:26:37 -05:00
theelk801
44e6cf999e [TLA] Implement Mai, Scornful Striker 2025-11-03 18:24:31 -05:00
theelk801
0fc84fca38 [TLA] Implement Meditation Pools 2025-11-03 18:23:03 -05:00
theelk801
dfc91bf8cf [TLA] Implement Kyoshi Village 2025-11-03 18:22:53 -05:00
theelk801
19274aa8f0 [TLA] Implement Sun-Blessed Peak 2025-11-03 18:21:10 -05:00
theelk801
fffead4da5 [TLA] Implement Omashu City 2025-11-03 18:20:02 -05:00
theelk801
f4d4e80ed1 [TLA] Implement Foggy Bottom Swamp 2025-11-03 18:19:16 -05:00
theelk801
d2918e69f4 [TLA] Implement Boiling Rock Prison 2025-11-03 18:18:30 -05:00
theelk801
717baabdc3 [TLA] Implement Airship Engine Room 2025-11-03 18:17:30 -05:00
theelk801
46fa105b7e [TLA] Implement Serpent's Pass 2025-11-03 18:16:43 -05:00
theelk801
6766c7b45d [TLA] Implement Misty Palms Oasis 2025-11-03 18:15:35 -05:00
theelk801
76c6f4e2ec [TLA] Implement North Pole Gates 2025-11-03 18:14:43 -05:00
theelk801
852d1d4351 [TLA] update spoiler 2025-11-03 18:13:30 -05:00
Grath
ffb270eac7 [TLA] Implement Bumi, Unleashed 2025-11-02 17:58:37 -05:00
Grath
9ba96ddf11 Make Bebop and Rocksteady's discard optional. 2025-11-01 20:00:03 -04:00
Oleg Agafonov
a0bdfda912 cheats: fixed AI naming, improved cheat commands compatibility:
- added additional aliases for Human (me) and Computer (opponent, ai);
- now same cheat command will be work in real, test, duel or multiplayer games (Computer/Human);
- now same cheat command will be work in human only games;
- fixed wrong/random AI opponent selection in multiplayer games;
- fixed wrong opponent selection after first opponent's loose in multiplayer games;
2025-11-02 01:11:01 +04:00
Oleg Agafonov
064c102590 GUI, game: improved stack's hint with targets list (added player name and sorted by it); 2025-11-02 01:11:01 +04:00
theelk801
654dda8f74 [TLA] Implement Suki, Courageous Rescuer 2025-11-01 17:03:12 -04:00
theelk801
5e5b28151a [TLA] Implement Treetop Freedom Fighters 2025-11-01 17:00:19 -04:00
theelk801
621e7cd454 [TLA] Implement United Front 2025-11-01 16:59:32 -04:00
theelk801
639944d796 [TLA] Implement Mai, Jaded Edge 2025-11-01 16:58:11 -04:00
theelk801
b915d63787 [TLE] update reprints 2025-11-01 16:56:59 -04:00
theelk801
379cd5b7b7 [TLA] update spoiler 2025-11-01 16:56:29 -04:00
Steven Knipe
99bdfe3a1a Convert UnsealTheNecropolis and AnotherChance to use OneShotNonTargetEffect 2025-11-01 00:17:21 -07:00
theelk801
bcba45652f [TLA] Implement The Mechanist, Aerial Artisan 2025-10-31 12:33:46 -04:00
theelk801
d4b8c75619 [TLA] Implement Planetarium of Wan Shi Tong 2025-10-31 12:29:05 -04:00
theelk801
b7416356aa [TLA] Implement Northern Air Temple 2025-10-31 12:16:22 -04:00
theelk801
48fa39256e [TLA] Implement Origin of Metalbending 2025-10-31 12:01:37 -04:00
theelk801
0b796ea276 [TLA] Implement Toph, Earthbending Master 2025-10-31 09:15:10 -04:00
theelk801
55cc7dc36d [TLA] Implement Fire Nation Warship 2025-10-31 08:59:10 -04:00
theelk801
42a9cd8497 [TLA] Implement Fire Nation Cadets 2025-10-31 08:58:26 -04:00
theelk801
411eeab868 [TLA] Implement Bumi Bash 2025-10-31 08:53:36 -04:00
theelk801
c7fb5fd495 [TLA] Implement Octopus Form 2025-10-31 08:50:21 -04:00
theelk801
5d051f02ea [TLA] Implement Deadly Precision 2025-10-31 08:46:03 -04:00
theelk801
a19dbf129b [TLE] update spoiler and reprints 2025-10-31 08:44:29 -04:00
theelk801
531f2e3c38 [TLA] update spoiler 2025-10-31 08:44:11 -04:00
theelk801
8425601562 [TLA] Implement Diligent Zookeeper 2025-10-30 16:46:44 -04:00
theelk801
9f214bf0a3 [TLA] Implement Crescent Island Temple 2025-10-30 16:35:09 -04:00
theelk801
1551492939 [TLA] Implement Tundra Tank 2025-10-30 16:29:09 -04:00
theelk801
0e21b91fd3 [TLA] Implement Seismic Sense 2025-10-30 16:27:21 -04:00
theelk801
4b5b2e191e [TLA] Implement Glider Staff 2025-10-30 16:25:24 -04:00
theelk801
5c1c402fbf [TLA] Implement Fire Lord Azula 2025-10-30 16:23:43 -04:00
theelk801
75f26e3453 [TLA] Implement Dragonfly Swarm 2025-10-30 16:21:25 -04:00
theelk801
3ebe6ec782 [TLA] Implement Compassionate Healer 2025-10-30 16:16:38 -04:00
theelk801
4e46920b50 [TLA] Implement Sun Warriors 2025-10-30 13:26:38 -04:00
theelk801
2218ec0ae4 [TLA] Implement Uncle Iroh 2025-10-30 13:25:32 -04:00
theelk801
955fe40172 [TLA] Implement War Balloon 2025-10-30 13:24:14 -04:00
theelk801
87b040b86f [TLA] Implement Momo, Playful Pet 2025-10-30 13:21:53 -04:00
theelk801
ed34fa4061 [TLA] Implement Ty Lee, Artful Acrobat 2025-10-30 13:20:13 -04:00
theelk801
ba4c030009 [TLA] Implement Fancy Footwork 2025-10-30 13:18:33 -04:00
theelk801
fb4317a988 [TLA] Implement Forecasting Fortune Teller 2025-10-30 13:17:06 -04:00
theelk801
b1ca3804cc [TLA] Implement True Ancestry 2025-10-30 13:16:14 -04:00
theelk801
6db11cc000 [TLA] update spoiler 2025-10-30 13:14:35 -04:00
Grath
3c0593a7fa Update Duel Commander ban list. 2025-10-30 09:37:17 -04:00
jmlundeen
d98d59cc55 rework MayhemLandAbility to work properly 2025-10-29 21:00:11 -05:00
PurpleCrowbar
37ade28c31 Fix preference menu tooltip, minor preference menu clarity improvements 2025-10-29 20:29:49 +00:00
theelk801
13bf2126d3 fix error 2025-10-29 16:28:37 -04:00
theelk801
b489efa05c [TLE] update spoiler and reprints 2025-10-29 16:08:39 -04:00
theelk801
4b3cacbf2b [TLA] Implement Sokka, Tenacious Tactician 2025-10-29 16:02:17 -04:00
theelk801
d3b0531777 [TLA] Implement Solstice Revelations 2025-10-29 15:59:43 -04:00
theelk801
9d2d7827ef [TLA] Implement Ran and Shaw 2025-10-29 15:49:21 -04:00
theelk801
3188c157df [TLA] Implement Leaves from the Vine 2025-10-29 15:40:40 -04:00
theelk801
8cd27af5a5 [TLA] Implement Invasion Tactics 2025-10-29 15:35:03 -04:00
theelk801
085fe11160 [TLA] Implement Cycle of Renewal 2025-10-29 15:31:48 -04:00
theelk801
459fe81ee4 [TLA] Implement Badgermole Cub 2025-10-29 15:29:40 -04:00
theelk801
9c799b432d [TLA] Implement Gran-Gran 2025-10-29 10:17:39 -04:00
theelk801
4ad97ef48c [TLA] Implement Avatar Kyoshi, Earthbender 2025-10-29 08:58:53 -04:00
theelk801
ac055bb808 [TLA] Implement The Cave of Two Lovers 2025-10-29 08:53:44 -04:00
theelk801
e47b17828b [TLA] Implement Zuko's Exile 2025-10-29 08:49:16 -04:00
theelk801
f5893a5c05 [TLA] Implement White Lotus Tile 2025-10-29 08:45:39 -04:00
theelk801
df68b4b4b1 [TLA] Implement White Lotus Reinforcements 2025-10-29 08:42:31 -04:00
theelk801
67dfb64b01 [TLA] Implement Tiger-Seal 2025-10-29 08:41:21 -04:00
theelk801
051440784f [TLA] Implement Sozin's Comet 2025-10-29 08:39:35 -04:00
theelk801
566bb511a6 [TLA] Implement North Pole Patrol 2025-10-29 08:38:09 -04:00
theelk801
a32a5caaa7 [TLA] Implement Firebending Student 2025-10-29 08:36:26 -04:00
theelk801
8778088016 [TLA] Implement Cunning Maneuver 2025-10-29 08:33:29 -04:00
theelk801
f43e0a72f4 [TLA] Implement Azula, On the Hunt 2025-10-29 08:31:59 -04:00
theelk801
774a3553fd [TLE] update spoiler and reprints 2025-10-29 08:24:23 -04:00
theelk801
0e589914de [TLA] update spoiler 2025-10-29 08:23:53 -04:00
xenohedron
09a423ae65 fix Aloy, Savior of Meridian ability 2025-10-26 19:02:34 -04:00
xenohedron
4bcb17a40e fix Devastating Onslaught number of token copies 2025-10-26 18:48:41 -04:00
xenohedron
6718c744e5 fix #14032 (Lizard, Connors's Curse) 2025-10-26 18:48:31 -04:00
xenohedron
313651cfc8 fix #14045 (Ultima, Origin of Oblivion)
rename method to correct typo
2025-10-26 18:33:13 -04:00
jmlundeen
ef4d48a654 Fix Knowledge Pool exile target 2025-10-26 16:25:45 -05:00
jmlundeen
5bbcda3d4e Update card test generation and card info templating
* now accepts lower case name matching
* partial matching also works with confirmation with multiple matches
2025-10-26 16:25:45 -05:00
jmlundeen
45e43fabd4 Fix Tandem Takedown damage target
fixes #14053
2025-10-26 12:57:22 -05:00
PurpleCrowbar
b839c7bf87
Fix AI crashing server on too many target calculations. Closes #9539, #14031 (#14044) 2025-10-24 16:02:44 +01:00
Steven Knipe
4a458800aa Fix AerithRescueMission stunning all targets 2025-10-23 14:48:26 -07:00
Steven Knipe
b235e5e99d The Final Days' tokens should be tapped 2025-10-21 14:36:07 -07:00
Grath
496f147c15 Update brackets, label for "2-card combos" which are not stated as "infinite" in the bracket explainer chart. Fixes #14003 2025-10-21 14:19:06 -04:00
Grath
2092f3857e
Fix Saga first chapter ZCC
I've given JayDi enough opportunity to find his own fix, I'm merging this with a TODO to consider fixing it another way that JayDi's happy with.
2025-10-21 12:30:47 -04:00
Grath
9e475fccd1
Update AbilityImpl.java 2025-10-21 12:27:38 -04:00
PurpleCrowbar
b5118f2a5b Remove ward ability hint from Strong, the Brutish Thespian 2025-10-21 13:19:15 +01:00
Jeff Wadsworth
78281dbe69 A real fix for Glamer Spinners 2025-10-18 22:13:26 -05:00
PurpleCrowbar
94471f3126 [DSK] Implement Unholy Annex // Ritual Chamber 2025-10-17 21:17:00 +01:00
PurpleCrowbar
d63cfa56f8 [DSK] Implement Dollmaker's Shop // Porcelain Gallery 2025-10-17 20:28:16 +01:00
PurpleCrowbar
7e0fdcbe64 [DSK] Implement Dazzling Theater // Prop Room 2025-10-17 19:41:56 +01:00
PurpleCrowbar
cbf70893a8 [DSK] Implement Funeral Room // Awakening Hall 2025-10-17 19:25:16 +01:00
PurpleCrowbar
967e8e6bcb
[DSK] Implement Walk-In Closet // Forgotten Cellar (#14027) 2025-10-17 18:56:43 +01:00
oscscull
f7be842008
feature: implement Rooms (#13786)
- Adds Room + Room half card types
- Adds Room unlock ability
- Adds Room special functionality (locking halves, unlocking, changing names, changing mana values)
- Adjusts name predicate handling for Room name handling (Rooms have between 0 and 2 names on the battlefield depending on their state. They have 1 name on the stack as a normal split card does). Allows cards to match these names properly
- Adds Room game events (Unlock, Fully Unlock) and unlock triggers
- Updates Split card constructor to allow a single type line as with Rooms
- Adds empty name constant for fully unlocked rooms
- Updates Permanent to include the door unlock states (that all permanents have) that are relevant when a permanent is or becomes a Room.
- Updates ZonesHandler to properly move Room card parts onto and off of the battlefield.
- Updated Eerie ability to function properly with Rooms
- Implemented Bottomless Pool // Locker Room
- Implemented Surgical Suite // Hospital Room
- Added Room card tests
2025-10-16 01:36:31 -04:00
xenohedron
cb900eb799 fix Glamer Spinners, add test (fix #14022) 2025-10-16 01:07:21 -04:00
xenohedron
a8aef445fd dev: mark new script as executable 2025-10-16 00:57:31 -04:00
xenohedron
003fe945a2 fix Faller's Faithful 2025-10-16 00:45:02 -04:00
xenohedron
b8a65a31f4 fix filters on Bloodmark Mentor, Roughshod Mentor 2025-10-16 00:42:33 -04:00
PurpleCrowbar
98fbbb25b6 Remove menace hint from Agent Venom 2025-10-15 14:24:43 +01:00
Riley
4a41b0415a
Bugfixes for Kratos, God of War (#14001) 2025-10-14 18:53:31 -04:00
Steven Knipe
e8c8b72a07 Card fixes: MuYanlingCelestialWind "up to" target, RampagingGrowthEffect trying to put player onto battlefield instead of card 2025-10-12 20:14:23 -07:00
theelk801
8a3c6e1523 [TMC] Implement Donnie and April, Adorkable Duo 2025-10-12 10:02:03 -04:00
theelk801
3cf6da1735 [TMC] Implement Heroes in a Half Shell 2025-10-12 10:02:03 -04:00
theelk801
102b5b519d [TMC] Implement Raphael, the Muscle 2025-10-12 10:02:03 -04:00
theelk801
f012b18d8d [TMC] Implement Michelangelo, the Heart 2025-10-12 10:02:03 -04:00
theelk801
e9a115fca0 [TMC] Implement Leonardo, Worldly Warrior 2025-10-12 10:02:03 -04:00
theelk801
7cad86e90f [TMC] Implement Donatello, the Brains 2025-10-12 10:02:03 -04:00
jmlundeen
89f5e84ba7 Fix Electro, Assaulting Battery spell filter
closes #14010
2025-10-12 08:50:12 -05:00
theelk801
41c5076755 [TMC] Implement Splinter, the Mentor 2025-10-10 17:08:41 -04:00
theelk801
60addceff9 [TMC] Implement Donatello, Rad Scientist 2025-10-10 16:57:47 -04:00
theelk801
ad1866e4f0 [TMT] Implement April O'Neil, Hacktivist 2025-10-10 16:55:34 -04:00
theelk801
8bb8eba43d [TMT] Implement Krang, Master Mind 2025-10-10 16:47:23 -04:00
theelk801
747730568e [TMT] Implement Bebop & Rocksteady 2025-10-10 16:43:08 -04:00
theelk801
159933cc8a [TMT] Implement Raphael's Technique 2025-10-10 16:30:48 -04:00
theelk801
1c134ac2c2 fix verify error (the rest will be fixed once mtgjson updates) 2025-10-10 15:33:28 -04:00
theelk801
89c5b54d32 [TMC] Implement Leonardo, the Balance 2025-10-10 14:24:06 -04:00
theelk801
c2b22aba4a [TMT] Implement Super Shredder 2025-10-10 14:15:36 -04:00
theelk801
b9f003ab8c [TMT] Implement Casey Jones, Jury-Rig Justiciar 2025-10-10 14:13:46 -04:00
theelk801
891be73d87 [TMC] add set 2025-10-10 14:11:15 -04:00
theelk801
27f9105c9f [TMT] add set 2025-10-10 14:02:04 -04:00
theelk801
8375d6b606 rework partner variants, add tests 2025-10-10 13:56:39 -04:00
Steven Knipe
fec3599b73 Fix Spider Sense WebSlinging not have the target 2025-10-07 16:04:18 -07:00
theelk801
14fe52124c [FIC] Implement Mega Flare 2025-10-07 12:39:12 -04:00
theelk801
35bed32770 [FIC] Implement Vivi's Persistence 2025-10-07 12:32:17 -04:00
theelk801
085b450e62 [FIC] Implement Seifer, Balamb Rival 2025-10-07 12:28:34 -04:00
theelk801
b4cc09a7a0 [FIC] Implement Fishing Gear 2025-10-07 11:38:42 -04:00
Steven Knipe
2552dcf633 Fix and test token saga zcc tracking 2025-08-10 18:19:41 -07:00
ssk97
4683e5c05a Fix saga first chapter zcc (#13710)
* Enable disabled tests

* Enable zcc Saga fix

* Remove existing zcc hacks

(cherry picked from commit 19f980c2ce)
2025-07-07 10:15:21 +04:00
1715 changed files with 52360 additions and 36446 deletions

View file

@ -39,10 +39,9 @@ public class BracketLegalityLabel extends LegalityLabel {
private static final Logger logger = Logger.getLogger(BracketLegalityLabel.class); private static final Logger logger = Logger.getLogger(BracketLegalityLabel.class);
private static final String GROUP_GAME_CHANGES = "Game Changers"; private static final String GROUP_GAME_CHANGES = "Game Changers";
private static final String GROUP_INFINITE_COMBOS = "Infinite Combos"; private static final String GROUP_INFINITE_COMBOS = "Early-game 2-Card Combos";
private static final String GROUP_MASS_LAND_DESTRUCTION = "Mass Land Destruction"; private static final String GROUP_MASS_LAND_DESTRUCTION = "Mass Land Destruction";
private static final String GROUP_EXTRA_TURN = "Extra Turns"; private static final String GROUP_EXTRA_TURN = "Extra Turns";
private static final String GROUP_TUTORS = "Tutors";
private static final Map<String, List<Integer>> MAX_GROUP_LIMITS = new LinkedHashMap<>(); private static final Map<String, List<Integer>> MAX_GROUP_LIMITS = new LinkedHashMap<>();
@ -78,8 +77,6 @@ public class BracketLegalityLabel extends LegalityLabel {
Arrays.asList(0, 0, 0, 0, 99, 99)); Arrays.asList(0, 0, 0, 0, 99, 99));
MAX_GROUP_LIMITS.put(GROUP_EXTRA_TURN, MAX_GROUP_LIMITS.put(GROUP_EXTRA_TURN,
Arrays.asList(0, 0, 0, 3, 99, 99)); Arrays.asList(0, 0, 0, 3, 99, 99));
MAX_GROUP_LIMITS.put(GROUP_TUTORS,
Arrays.asList(0, 3, 3, 99, 99, 99));
} }
private static final String RESOURCE_INFINITE_COMBOS = "brackets/infinite-combos.txt"; private static final String RESOURCE_INFINITE_COMBOS = "brackets/infinite-combos.txt";
@ -92,7 +89,6 @@ public class BracketLegalityLabel extends LegalityLabel {
private final List<String> foundInfiniteCombos = new ArrayList<>(); private final List<String> foundInfiniteCombos = new ArrayList<>();
private final List<String> foundMassLandDestruction = new ArrayList<>(); private final List<String> foundMassLandDestruction = new ArrayList<>();
private final List<String> foundExtraTurn = new ArrayList<>(); private final List<String> foundExtraTurn = new ArrayList<>();
private final List<String> foundTutors = new ArrayList<>();
private final List<String> badCards = new ArrayList<>(); private final List<String> badCards = new ArrayList<>();
private final List<String> fullGameChanges = new ArrayList<>(); private final List<String> fullGameChanges = new ArrayList<>();
@ -126,9 +122,6 @@ public class BracketLegalityLabel extends LegalityLabel {
if (this.foundExtraTurn.size() > getMaxCardsLimit(GROUP_EXTRA_TURN)) { if (this.foundExtraTurn.size() > getMaxCardsLimit(GROUP_EXTRA_TURN)) {
this.badCards.addAll(this.foundExtraTurn); this.badCards.addAll(this.foundExtraTurn);
} }
if (this.foundTutors.size() > getMaxCardsLimit(GROUP_TUTORS)) {
this.badCards.addAll(this.foundTutors);
}
} }
private Integer getMaxCardsLimit(String groupName) { private Integer getMaxCardsLimit(String groupName) {
@ -165,7 +158,6 @@ public class BracketLegalityLabel extends LegalityLabel {
groups.put(GROUP_INFINITE_COMBOS + getStats(GROUP_INFINITE_COMBOS), this.foundInfiniteCombos); groups.put(GROUP_INFINITE_COMBOS + getStats(GROUP_INFINITE_COMBOS), this.foundInfiniteCombos);
groups.put(GROUP_MASS_LAND_DESTRUCTION + getStats(GROUP_MASS_LAND_DESTRUCTION), this.foundMassLandDestruction); groups.put(GROUP_MASS_LAND_DESTRUCTION + getStats(GROUP_MASS_LAND_DESTRUCTION), this.foundMassLandDestruction);
groups.put(GROUP_EXTRA_TURN + getStats(GROUP_EXTRA_TURN), this.foundExtraTurn); groups.put(GROUP_EXTRA_TURN + getStats(GROUP_EXTRA_TURN), this.foundExtraTurn);
groups.put(GROUP_TUTORS + getStats(GROUP_TUTORS), this.foundTutors);
groups.forEach((group, cards) -> { groups.forEach((group, cards) -> {
showInfo.add("<br>"); showInfo.add("<br>");
showInfo.add("<span style='font-weight:bold;font-size: " + infoFontTextSize + "px;'>" + group + "</span>"); showInfo.add("<span style='font-weight:bold;font-size: " + infoFontTextSize + "px;'>" + group + "</span>");
@ -199,9 +191,6 @@ public class BracketLegalityLabel extends LegalityLabel {
case GROUP_EXTRA_TURN: case GROUP_EXTRA_TURN:
currentAmount = this.foundExtraTurn.size(); currentAmount = this.foundExtraTurn.size();
break; break;
case GROUP_TUTORS:
currentAmount = this.foundTutors.size();
break;
default: default:
throw new IllegalArgumentException("Unknown group " + groupName); throw new IllegalArgumentException("Unknown group " + groupName);
} }
@ -222,7 +211,6 @@ public class BracketLegalityLabel extends LegalityLabel {
collectInfiniteCombos(deck); collectInfiniteCombos(deck);
collectMassLandDestruction(deck); collectMassLandDestruction(deck);
collectExtraTurn(deck); collectExtraTurn(deck);
collectTutors(deck);
} }
private void collectGameChangers(Deck deck) { private void collectGameChangers(Deck deck) {
@ -244,12 +232,9 @@ public class BracketLegalityLabel extends LegalityLabel {
"Consecrated Sphinx", "Consecrated Sphinx",
"Crop Rotation", "Crop Rotation",
"Cyclonic Rift", "Cyclonic Rift",
"Deflecting Swat",
"Enlightened Tutor", "Enlightened Tutor",
"Expropriate",
"Field of the Dead", "Field of the Dead",
"Fierce Guardianship", "Fierce Guardianship",
"Food Chain",
"Force of Will", "Force of Will",
"Gaea's Cradle", "Gaea's Cradle",
"Gamble", "Gamble",
@ -261,8 +246,6 @@ public class BracketLegalityLabel extends LegalityLabel {
"Imperial Seal", "Imperial Seal",
"Intuition", "Intuition",
"Jeska's Will", "Jeska's Will",
"Jin-Gitaxias, Core Augur",
"Kinnan, Bonder Prodigy",
"Lion's Eye Diamond", "Lion's Eye Diamond",
"Mana Vault", "Mana Vault",
"Mishra's Workshop", "Mishra's Workshop",
@ -280,18 +263,13 @@ public class BracketLegalityLabel extends LegalityLabel {
"Serra's Sanctum", "Serra's Sanctum",
"Smothering Tithe", "Smothering Tithe",
"Survival of the Fittest", "Survival of the Fittest",
"Sway of the Stars",
"Teferi's Protection", "Teferi's Protection",
"Tergrid, God of Fright", "Tergrid, God of Fright",
"Thassa's Oracle", "Thassa's Oracle",
"The One Ring", "The One Ring",
"The Tabernacle at Pendrell Vale", "The Tabernacle at Pendrell Vale",
"Underworld Breach", "Underworld Breach",
"Urza, Lord High Artificer",
"Vampiric Tutor", "Vampiric Tutor",
"Vorinclex, Voice of Hunger",
"Yuriko, the Tiger's Shadow",
"Winota, Joiner of Forces",
"Worldly Tutor" "Worldly Tutor"
)); ));
} }
@ -393,19 +371,6 @@ public class BracketLegalityLabel extends LegalityLabel {
.forEach(this.foundExtraTurn::add); .forEach(this.foundExtraTurn::add);
} }
private void collectTutors(Deck deck) {
// edh power level uses search for land and non-land card, but bracket need only non-land cards searching
this.foundTutors.clear();
Stream.concat(deck.getCards().stream(), deck.getSideboard().stream())
.filter(card -> card.getRules().stream()
.map(s -> s.toLowerCase(Locale.ENGLISH))
.anyMatch(s -> s.contains("search your library") && !isTextContainsLandCard(s))
)
.map(Card::getName)
.sorted()
.forEach(this.foundTutors::add);
}
private boolean isTextContainsLandCard(String lowerText) { private boolean isTextContainsLandCard(String lowerText) {
// TODO: share code with AbstractCommander and edh power level // TODO: share code with AbstractCommander and edh power level
// TODO: add tests // TODO: add tests

View file

@ -79,13 +79,15 @@ public enum MageTray {
} catch (AWTException e) { } catch (AWTException e) {
log.error("TrayIcon could not be added: ", e); log.error("TrayIcon could not be added: ", e);
} }
} catch (Exception e) { } catch (Exception e) {
log.error(e); log.error(e);
} }
} }
public synchronized void blink() { public synchronized void blink() {
if (trayIcon == null)
return;
if (state == 0) { if (state == 0) {
synchronized (MageTray.class) { synchronized (MageTray.class) {
if (state == 0) { if (state == 0) {

View file

@ -2115,6 +2115,9 @@
</Events> </Events>
</Component> </Component>
<Component class="javax.swing.JTextField" name="txtBackgroundImagePath"> <Component class="javax.swing.JTextField" name="txtBackgroundImagePath">
<Properties>
<Property name="toolTipText" type="java.lang.String" value="The selected image will be used as the background picture. Requires client restart to see changes."/>
</Properties>
</Component> </Component>
<Component class="javax.swing.JButton" name="btnBrowseBackgroundImage"> <Component class="javax.swing.JButton" name="btnBrowseBackgroundImage">
<Properties> <Properties>
@ -2254,16 +2257,13 @@
<SubComponents> <SubComponents>
<Component class="javax.swing.JCheckBox" name="cbUseDefaultImageFolder"> <Component class="javax.swing.JCheckBox" name="cbUseDefaultImageFolder">
<Properties> <Properties>
<Property name="text" type="java.lang.String" value="Use default location to save images"/> <Property name="text" type="java.lang.String" value="Use default location to save card images"/>
</Properties> </Properties>
<Events> <Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbUseDefaultImageFolderActionPerformed"/> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="cbUseDefaultImageFolderActionPerformed"/>
</Events> </Events>
</Component> </Component>
<Component class="javax.swing.JTextField" name="txtImageFolderPath"> <Component class="javax.swing.JTextField" name="txtImageFolderPath">
<Properties>
<Property name="toolTipText" type="java.lang.String" value="The selected image will be used as background picture. You have to restart MAGE to view a changed background image."/>
</Properties>
</Component> </Component>
<Component class="javax.swing.JButton" name="btnBrowseImageLocation"> <Component class="javax.swing.JButton" name="btnBrowseImageLocation">
<Properties> <Properties>

View file

@ -2155,6 +2155,8 @@ public class PreferencesDialog extends javax.swing.JDialog {
} }
}); });
txtBackgroundImagePath.setToolTipText("The selected image will be used as the background picture. Requires client restart to see changes.");
btnBrowseBackgroundImage.setText("Browse..."); btnBrowseBackgroundImage.setText("Browse...");
btnBrowseBackgroundImage.addActionListener(new java.awt.event.ActionListener() { btnBrowseBackgroundImage.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) { public void actionPerformed(java.awt.event.ActionEvent evt) {
@ -2254,15 +2256,13 @@ public class PreferencesDialog extends javax.swing.JDialog {
panelCardImages.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), "Card images")); panelCardImages.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), "Card images"));
cbUseDefaultImageFolder.setText("Use default location to save images"); cbUseDefaultImageFolder.setText("Use default location to save card images");
cbUseDefaultImageFolder.addActionListener(new java.awt.event.ActionListener() { cbUseDefaultImageFolder.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) { public void actionPerformed(java.awt.event.ActionEvent evt) {
cbUseDefaultImageFolderActionPerformed(evt); cbUseDefaultImageFolderActionPerformed(evt);
} }
}); });
txtImageFolderPath.setToolTipText("The selected image will be used as background picture. You have to restart MAGE to view a changed background image.");
btnBrowseImageLocation.setText("Browse..."); btnBrowseImageLocation.setText("Browse...");
btnBrowseImageLocation.addActionListener(new java.awt.event.ActionListener() { btnBrowseImageLocation.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) { public void actionPerformed(java.awt.event.ActionEvent evt) {

View file

@ -1700,7 +1700,7 @@ public class TablesPanel extends javax.swing.JPanel {
MatchOptions options = new MatchOptions(gameName, gameType, multiPlayer); MatchOptions options = new MatchOptions(gameName, gameType, multiPlayer);
options.getPlayerTypes().add(PlayerType.HUMAN); options.getPlayerTypes().add(PlayerType.HUMAN);
options.getPlayerTypes().add(aiType); options.getPlayerTypes().add(aiType);
for (int i=2 ; i < numPlayers ; i++) { for (int i = 2; i < numPlayers; i++) {
options.getPlayerTypes().add(aiType); options.getPlayerTypes().add(aiType);
} }
options.setDeckType("Variant Magic - Freeform Commander"); options.setDeckType("Variant Magic - Freeform Commander");
@ -1719,9 +1719,9 @@ public class TablesPanel extends javax.swing.JPanel {
table = SessionHandler.createTable(roomId, options); table = SessionHandler.createTable(roomId, options);
SessionHandler.joinTable(roomId, table.getTableId(), "Human", PlayerType.HUMAN, 1, testDeck, ""); SessionHandler.joinTable(roomId, table.getTableId(), "Human", PlayerType.HUMAN, 1, testDeck, "");
SessionHandler.joinTable(roomId, table.getTableId(), "Computer", aiType, 1, testDeck, ""); SessionHandler.joinTable(roomId, table.getTableId(), "Computer" + (multiPlayer ? " 2" : ""), aiType, 1, testDeck, "");
for (int i=2 ; i < numPlayers ; i++) { for (int i = 2; i < numPlayers; i++) {
SessionHandler.joinTable(roomId, table.getTableId(), "Computer" + i, aiType, 1, testDeck, ""); SessionHandler.joinTable(roomId, table.getTableId(), "Computer " + (i + 1), aiType, 1, testDeck, "");
} }
SessionHandler.startMatch(roomId, table.getTableId()); SessionHandler.startMatch(roomId, table.getTableId());
} catch (HeadlessException ex) { } catch (HeadlessException ex) {

View file

@ -940,8 +940,13 @@ public abstract class CardPanel extends MagePermanent implements ComponentListen
private void setGameCardSides(CardView gameCard) { private void setGameCardSides(CardView gameCard) {
if (this.cardSideMain == null) { if (this.cardSideMain == null) {
// new card // new card
this.cardSideMain = gameCard; if (gameCard instanceof PermanentView) {
this.cardSideOther = gameCard.getSecondCardFace(); this.cardSideMain = gameCard;
this.cardSideOther = gameCard.isTransformed() ? ((PermanentView) gameCard).getOriginal() : gameCard.getSecondCardFace();
} else {
this.cardSideMain = gameCard;
this.cardSideOther = gameCard.getSecondCardFace();
}
} else { } else {
// updated card // updated card
if (this.cardSideMain.getName().equals(gameCard.getName())) { if (this.cardSideMain.getName().equals(gameCard.getName())) {

View file

@ -611,10 +611,15 @@ public class ScryfallImageSupportCards {
add("EOS"); // Edge of Eternities: Stellar Sights add("EOS"); // Edge of Eternities: Stellar Sights
add("SPM"); // Marvel's Spider-Man add("SPM"); // Marvel's Spider-Man
add("SPE"); // Marvel's Spider-Man Eternal add("SPE"); // Marvel's Spider-Man Eternal
add("LMAR"); // Marvel Legends Series Inserts
add("MAR"); // Marvel Universe add("MAR"); // Marvel Universe
add("TLA"); // Avatar: The Last Airbender add("TLA"); // Avatar: The Last Airbender
add("TLE"); // Avatar: The Last Airbender Eternal add("TLE"); // Avatar: The Last Airbender Eternal
add("ECL"); // Lorwyn Eclipsed add("ECL"); // Lorwyn Eclipsed
add("TMT"); // Teenage Mutant Ninja Turtles
add("TMC"); // Teenage Mutant Ninja Turtles Eternal
add("MSH"); // Marvel Super Heroes
add("MSC"); // Marvel Super Heroes Commander
// Custom sets using Scryfall images - must provide a direct link for each card in directDownloadLinks // Custom sets using Scryfall images - must provide a direct link for each card in directDownloadLinks
add("CALC"); // Custom Alchemized versions of existing cards add("CALC"); // Custom Alchemized versions of existing cards
@ -715,6 +720,7 @@ public class ScryfallImageSupportCards {
put("SLD/Sol Ring/1512b", "https://api.scryfall.com/cards/sld/1512/en?format=image&face=back"); put("SLD/Sol Ring/1512b", "https://api.scryfall.com/cards/sld/1512/en?format=image&face=back");
put("SLD/Steely Resolve/1326b", "https://api.scryfall.com/cards/sld/1326/en?format=image&face=back"); put("SLD/Steely Resolve/1326b", "https://api.scryfall.com/cards/sld/1326/en?format=image&face=back");
put("SLD/Stitch in Time/382b", "https://api.scryfall.com/cards/sld/382/en?format=image&face=back"); put("SLD/Stitch in Time/382b", "https://api.scryfall.com/cards/sld/382/en?format=image&face=back");
put("SLD/Teferi's Ageless Insight/2214b", "https://api.scryfall.com/cards/sld/2214/en?format=image&face=back");
put("SLD/Terror/750b", "https://api.scryfall.com/cards/sld/750/en?format=image&face=back"); put("SLD/Terror/750b", "https://api.scryfall.com/cards/sld/750/en?format=image&face=back");
put("SLD/Tuvasa the Sunlit/1328b", "https://api.scryfall.com/cards/sld/1328/en?format=image&face=back"); put("SLD/Tuvasa the Sunlit/1328b", "https://api.scryfall.com/cards/sld/1328/en?format=image&face=back");
put("SLD/Ulamog, the Ceaseless Hunger/1122b", "https://api.scryfall.com/cards/sld/1122/en?format=image&face=back"); put("SLD/Ulamog, the Ceaseless Hunger/1122b", "https://api.scryfall.com/cards/sld/1122/en?format=image&face=back");

View file

@ -1,10 +1,10 @@
package org.mage.plugins.card.dl.sources; package org.mage.plugins.card.dl.sources;
import mage.cards.repository.TokenRepository;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import mage.cards.repository.TokenRepository;
/** /**
* @author JayDi85 * @author JayDi85
*/ */
@ -817,10 +817,13 @@ public class ScryfallImageSupportTokens {
// SLD // SLD
put("SLD/Angel", "https://api.scryfall.com/cards/sld/1340?format=image"); put("SLD/Angel", "https://api.scryfall.com/cards/sld/1340?format=image");
put("SLD/Blood", "https://api.scryfall.com/cards/sld/2180?format=image");
put("SLD/Cat/1", "https://api.scryfall.com/cards/sld/1517?format=image"); put("SLD/Cat/1", "https://api.scryfall.com/cards/sld/1517?format=image");
put("SLD/Cat/2", "https://api.scryfall.com/cards/sld/27?format=image"); put("SLD/Cat/2", "https://api.scryfall.com/cards/sld/27?format=image");
put("SLD/Cat/3", "https://api.scryfall.com/cards/sld/28?format=image"); put("SLD/Cat/3", "https://api.scryfall.com/cards/sld/28?format=image");
put("SLD/Clue", "https://api.scryfall.com/cards/sld/348/en?format=image"); put("SLD/Clue", "https://api.scryfall.com/cards/sld/348/en?format=image");
put("SLD/Cordyceps Infected/1", "https://api.scryfall.com/cards/sld/2201?format=image");
put("SLD/Cordyceps Infected/2", "https://api.scryfall.com/cards/sld/2206?format=image");
put("SLD/Dog", "https://api.scryfall.com/cards/sld/1516?format=image"); put("SLD/Dog", "https://api.scryfall.com/cards/sld/1516?format=image");
put("SLD/Egg", "https://api.scryfall.com/cards/sld/1398?format=image"); put("SLD/Egg", "https://api.scryfall.com/cards/sld/1398?format=image");
put("SLD/Faerie Rogue/1", "https://api.scryfall.com/cards/sld/13/en?format=image"); put("SLD/Faerie Rogue/1", "https://api.scryfall.com/cards/sld/13/en?format=image");
@ -2221,7 +2224,7 @@ public class ScryfallImageSupportTokens {
put("WHO/Treasure/2", "https://api.scryfall.com/cards/twho/29?format=image"); put("WHO/Treasure/2", "https://api.scryfall.com/cards/twho/29?format=image");
put("WHO/Treasure/3", "https://api.scryfall.com/cards/twho/30?format=image"); put("WHO/Treasure/3", "https://api.scryfall.com/cards/twho/30?format=image");
put("WHO/Treasure/4", "https://api.scryfall.com/cards/twho/31?format=image"); put("WHO/Treasure/4", "https://api.scryfall.com/cards/twho/31?format=image");
put("WHO/Warrior", "https://api.scryfall.com/cards/twho/9?format=image"); put("WHO/Warrior", "https://api.scryfall.com/cards/twho/9?format=image");
// 8ED // 8ED
put("8ED/Bird", "https://api.scryfall.com/cards/p03/7/en?format=image"); put("8ED/Bird", "https://api.scryfall.com/cards/p03/7/en?format=image");
@ -2398,7 +2401,7 @@ public class ScryfallImageSupportTokens {
put("OTP/Human Warrior", "https://api.scryfall.com/cards/totp/3/en?format=image"); put("OTP/Human Warrior", "https://api.scryfall.com/cards/totp/3/en?format=image");
put("OTP/Pest", "https://api.scryfall.com/cards/totp/4/en?format=image"); put("OTP/Pest", "https://api.scryfall.com/cards/totp/4/en?format=image");
// SCD // SCD
put("SCD/Beast", "https://api.scryfall.com/cards/tscd/19/en?format=image"); put("SCD/Beast", "https://api.scryfall.com/cards/tscd/19/en?format=image");
put("SCD/Bird", "https://api.scryfall.com/cards/tscd/2/en?format=image"); put("SCD/Bird", "https://api.scryfall.com/cards/tscd/2/en?format=image");
put("SCD/Cat", "https://api.scryfall.com/cards/tscd/3/en?format=image"); put("SCD/Cat", "https://api.scryfall.com/cards/tscd/3/en?format=image");
@ -2546,6 +2549,7 @@ public class ScryfallImageSupportTokens {
// DSK // DSK
put("DSK/Beast", "https://api.scryfall.com/cards/tdsk/3?format=image"); put("DSK/Beast", "https://api.scryfall.com/cards/tdsk/3?format=image");
put("DSK/Demon", "https://api.scryfall.com/cards/tdsk/9?format=image");
put("DSK/Emblem Kaito", "https://api.scryfall.com/cards/tdsk/17/en?format=image"); put("DSK/Emblem Kaito", "https://api.scryfall.com/cards/tdsk/17/en?format=image");
put("DSK/Everywhere", "https://api.scryfall.com/cards/tdsk/16?format=image"); put("DSK/Everywhere", "https://api.scryfall.com/cards/tdsk/16?format=image");
put("DSK/Glimmer", "https://api.scryfall.com/cards/tdsk/4?format=image"); put("DSK/Glimmer", "https://api.scryfall.com/cards/tdsk/4?format=image");
@ -2558,6 +2562,7 @@ public class ScryfallImageSupportTokens {
put("DSK/Spider", "https://api.scryfall.com/cards/tdsk/12?format=image"); put("DSK/Spider", "https://api.scryfall.com/cards/tdsk/12?format=image");
put("DSK/Spirit/1", "https://api.scryfall.com/cards/tdsk/6?format=image"); put("DSK/Spirit/1", "https://api.scryfall.com/cards/tdsk/6?format=image");
put("DSK/Spirit/2", "https://api.scryfall.com/cards/tdsk/8?format=image"); put("DSK/Spirit/2", "https://api.scryfall.com/cards/tdsk/8?format=image");
put("DSK/Toy", "https://api.scryfall.com/cards/tdsk/7?format=image");
put("DSK/Treasure", "https://api.scryfall.com/cards/tdsk/15?format=image"); put("DSK/Treasure", "https://api.scryfall.com/cards/tdsk/15?format=image");
// DSC // DSC
@ -2738,7 +2743,7 @@ public class ScryfallImageSupportTokens {
put("ACR/Treasure", "https://api.scryfall.com/cards/tacr/6?format=image"); put("ACR/Treasure", "https://api.scryfall.com/cards/tacr/6?format=image");
// DD2 // DD2
put("DD2/Elemental Shaman", "https://api.scryfall.com/cards/tdd2/1?format=image"); put("DD2/Elemental Shaman", "https://api.scryfall.com/cards/tdd2/1?format=image");
// FIN // FIN
put("FIN/Hero/1", "https://api.scryfall.com/cards/tfin/2/en?format=image"); put("FIN/Hero/1", "https://api.scryfall.com/cards/tfin/2/en?format=image");
@ -2826,6 +2831,35 @@ public class ScryfallImageSupportTokens {
put("SPM/Spider", "https://api.scryfall.com/cards/tspm/3?format=image"); put("SPM/Spider", "https://api.scryfall.com/cards/tspm/3?format=image");
put("SPM/Treasure", "https://api.scryfall.com/cards/tspm/7?format=image"); put("SPM/Treasure", "https://api.scryfall.com/cards/tspm/7?format=image");
// TLA
put("TLA/Ally/1", "https://api.scryfall.com/cards/ttla/4/?format=image");
put("TLA/Ally/2", "https://api.scryfall.com/cards/ttla/5/?format=image");
put("TLA/Ally/3", "https://api.scryfall.com/cards/ttla/6/?format=image");
put("TLA/Ally/4", "https://api.scryfall.com/cards/ttla/7/?format=image");
put("TLA/Ally/5", "https://api.scryfall.com/cards/ttla/8/?format=image");
put("TLA/Ballistic Boulder", "https://api.scryfall.com/cards/ttla/13/?format=image");
put("TLA/Bear", "https://api.scryfall.com/cards/ttla/12/?format=image");
put("TLA/Clue/1", "https://api.scryfall.com/cards/ttla/14/?format=image");
put("TLA/Clue/2", "https://api.scryfall.com/cards/ttla/15/?format=image");
put("TLA/Clue/3", "https://api.scryfall.com/cards/ttla/16/?format=image");
put("TLA/Clue/4", "https://api.scryfall.com/cards/ttla/17/?format=image");
put("TLA/Clue/5", "https://api.scryfall.com/cards/ttla/18/?format=image");
put("TLA/Dragon", "https://api.scryfall.com/cards/ttla/9/?format=image");
put("TLA/Food/1", "https://api.scryfall.com/cards/ttla/19/?format=image");
put("TLA/Food/2", "https://api.scryfall.com/cards/ttla/20/?format=image");
put("TLA/Food/3", "https://api.scryfall.com/cards/ttla/21/?format=image");
put("TLA/Monk", "https://api.scryfall.com/cards/ttla/10/?format=image");
put("TLA/Soldier", "https://api.scryfall.com/cards/ttla/11/?format=image");
put("TLA/Spirit", "https://api.scryfall.com/cards/ttla/3/?format=image");
put("TLA/Treasure", "https://api.scryfall.com/cards/ttla/22?format=image");
// TLE
put("TLE/Marit Lage", "https://api.scryfall.com/cards/ttle/1/?format=image");
put("TLE/Soldier", "https://api.scryfall.com/cards/ttle/2?format=image");
// TMT
put("TMT/Mutagen", "https://api.scryfall.com/cards/ttmt/9?format=image");
// JVC // JVC
put("JVC/Elemental Shaman", "https://api.scryfall.com/cards/tjvc/4?format=image"); put("JVC/Elemental Shaman", "https://api.scryfall.com/cards/tjvc/4?format=image");

View file

@ -558,12 +558,12 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
); );
allCardsUrls.add(url); allCardsUrls.add(url);
} }
if (card.isModalDoubleFacedCard()) { if (card.isDoubleFacedCard()) {
if (card.getModalDoubleFacedSecondSideName() == null || card.getModalDoubleFacedSecondSideName().trim().isEmpty()) { if (card.getDoubleFacedSecondSideName() == null || card.getDoubleFacedSecondSideName().trim().isEmpty()) {
throw new IllegalStateException("MDF card can't have empty name."); throw new IllegalStateException("MDF card can't have empty name.");
} }
CardDownloadData cardDownloadData = new CardDownloadData( CardDownloadData cardDownloadData = new CardDownloadData(
card.getModalDoubleFacedSecondSideName(), card.getDoubleFacedSecondSideName(),
card.getSetCode(), card.getSetCode(),
card.getCardNumber(), card.getCardNumber(),
card.usesVariousArt(), card.usesVariousArt(),

View file

@ -82,7 +82,7 @@ public class ThemePluginImpl implements ThemePlugin {
} }
if (ui.containsKey("gamePanel") && ui.containsKey("jLayeredPane")) { if (ui.containsKey("gamePanel") && ui.containsKey("jLayeredPane")) {
ImagePanel bgPanel = new ImagePanel(backgroundImage, ImagePanelStyle.TILED); ImagePanel bgPanel = new ImagePanel(backgroundImage, ImagePanelStyle.COVER);
// TODO: research - is all components used? And why it make transparent? // TODO: research - is all components used? And why it make transparent?
unsetOpaque(ui.get("splitChatAndLogs")); unsetOpaque(ui.get("splitChatAndLogs"));

View file

@ -78,6 +78,9 @@ public class ImagePanel extends JPanel {
case ACTUAL: case ACTUAL:
drawActual(g); drawActual(g);
break; break;
case COVER:
drawCover(g);
break;
} }
} }
@ -99,4 +102,25 @@ public class ImagePanel extends JPanel {
float y = (d.height - image.getHeight(null)) * alignmentY; float y = (d.height - image.getHeight(null)) * alignmentY;
g.drawImage(image, (int) x, (int) y, this); g.drawImage(image, (int) x, (int) y, this);
} }
private void drawCover(Graphics g) {
Dimension d = getSize();
int imageWidth = image.getWidth(null);
int imageHeight = image.getHeight(null);
// Calculate scale to cover the entire panel while maintaining aspect ratio
double scaleX = (double) d.width / imageWidth;
double scaleY = (double) d.height / imageHeight;
double scale = Math.max(scaleX, scaleY);
// Calculate the scaled dimensions
int scaledWidth = (int) (imageWidth * scale);
int scaledHeight = (int) (imageHeight * scale);
// Center the image
int x = (d.width - scaledWidth) / 2;
int y = (d.height - scaledHeight) / 2;
g.drawImage(image, x, y, scaledWidth, scaledHeight, null);
}
} }

View file

@ -4,5 +4,5 @@ package mage.components;
* Created by IGOUDT on 7-3-2017. * Created by IGOUDT on 7-3-2017.
*/ */
public enum ImagePanelStyle { public enum ImagePanelStyle {
TILED, SCALED, ACTUAL TILED, SCALED, ACTUAL, COVER
} }

View file

@ -601,14 +601,13 @@ public final class SystemUtil {
continue; continue;
} }
Optional<Player> playerOptional = findPlayer(game, command.player); Player player = findPlayer(game, command.player, feedbackPlayer);
if (!playerOptional.isPresent()) { if (player == null) {
String mes = String.format("Unknown player: %s", line); String mes = String.format("Unknown player: %s", line);
errorsList.add(mes); errorsList.add(mes);
logger.warn(mes); logger.warn(mes);
continue; continue;
} }
Player player = playerOptional.get();
// SPECIAL token/emblem call (without SET name) // SPECIAL token/emblem call (without SET name)
if ("token".equalsIgnoreCase(command.zone)) { if ("token".equalsIgnoreCase(command.zone)) {
@ -860,17 +859,54 @@ public final class SystemUtil {
return false; return false;
} }
/** private static Player findPlayer(Game game, String needName, Player feedbackPlayer) {
* Find player by name. // real names
* Player res = game.getPlayerList().stream()
* @param game .map(game::getPlayer)
* @param name .filter(Objects::nonNull)
* @return .filter(player -> player.getName().equals(needName))
*/ .findFirst()
private static Optional<Player> findPlayer(Game game, String name) { .orElse(null);
return game.getPlayers().values().stream()
.filter(player -> player.getName().equals(name)).findFirst();
// test names - cheat commands will be compatible in both modes (quick test and normal)
if (res == null) {
switch (needName.toLowerCase(Locale.ENGLISH)) {
case "me":
case "human":
case "human 1":
res = feedbackPlayer;
break;
case "opponent":
case "opponent 1":
case "computer":
case "computer 1": // multiplayer game uses Computer 2+ naming
case "ai":
case "ai 1":
// try AI
res = game.getPlayerList().stream()
.map(game::getPlayer)
.filter(Objects::nonNull)
.filter(Player::isInGame)
.filter(Player::isComputer)
.findFirst()
.orElse(null);
if (res == null) {
// try opponent (human only games)
res = game.getOpponents(feedbackPlayer.getId(), true).stream()
.map(game::getPlayer)
.filter(Objects::nonNull)
.filter(Player::isInGame)
.findFirst()
.orElse(null);
}
break;
default:
// raise error message due unknown player name
break;
}
}
return res;
} }
public static String sanitize(String input) { public static String sanitize(String input) {

View file

@ -27,11 +27,13 @@ import mage.counters.Counter;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.designations.Designation; import mage.designations.Designation;
import mage.filter.FilterMana; import mage.filter.FilterMana;
import mage.game.ControllableOrOwnerable;
import mage.game.Game; import mage.game.Game;
import mage.game.command.Dungeon; import mage.game.command.Dungeon;
import mage.game.command.Emblem; import mage.game.command.Emblem;
import mage.game.command.Plane; import mage.game.command.Plane;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.game.permanent.PermanentCard;
import mage.game.permanent.PermanentToken; import mage.game.permanent.PermanentToken;
import mage.game.permanent.token.Token; import mage.game.permanent.token.Token;
import mage.game.stack.Spell; import mage.game.stack.Spell;
@ -115,7 +117,7 @@ public class CardView extends SimpleCardView {
protected List<String> rightSplitRules; protected List<String> rightSplitRules;
protected String rightSplitTypeLine; protected String rightSplitTypeLine;
protected boolean isModalDoubleFacedCard; protected boolean isDoubleFacedCard;
protected ArtRect artRect = ArtRect.NORMAL; protected ArtRect artRect = ArtRect.NORMAL;
@ -237,7 +239,7 @@ public class CardView extends SimpleCardView {
this.rightSplitRules = cardView.rightSplitRules == null ? null : new ArrayList<>(cardView.rightSplitRules); this.rightSplitRules = cardView.rightSplitRules == null ? null : new ArrayList<>(cardView.rightSplitRules);
this.rightSplitTypeLine = cardView.rightSplitTypeLine; this.rightSplitTypeLine = cardView.rightSplitTypeLine;
this.isModalDoubleFacedCard = cardView.isModalDoubleFacedCard; this.isDoubleFacedCard = cardView.isDoubleFacedCard;
this.artRect = cardView.artRect; this.artRect = cardView.artRect;
this.targets = cardView.targets == null ? null : new ArrayList<>(cardView.targets); this.targets = cardView.targets == null ? null : new ArrayList<>(cardView.targets);
@ -427,12 +429,18 @@ public class CardView extends SimpleCardView {
this.manaCostLeftStr = splitCard.getLeftHalfCard().getManaCostSymbols(); this.manaCostLeftStr = splitCard.getLeftHalfCard().getManaCostSymbols();
this.manaCostRightStr = splitCard.getRightHalfCard().getManaCostSymbols(); this.manaCostRightStr = splitCard.getRightHalfCard().getManaCostSymbols();
} else if (card instanceof ModalDoubleFacedCard) { } else if (card instanceof ModalDoubleFacedCard) {
this.isModalDoubleFacedCard = true; this.isDoubleFacedCard = true;
ModalDoubleFacedCard mainCard = ((ModalDoubleFacedCard) card); DoubleFacedCard mainCard = ((DoubleFacedCard) card);
fullCardName = mainCard.getLeftHalfCard().getName() + MockCard.MODAL_DOUBLE_FACES_NAME_SEPARATOR + mainCard.getRightHalfCard().getName(); fullCardName = mainCard.getLeftHalfCard().getName() + MockCard.MODAL_DOUBLE_FACES_NAME_SEPARATOR + mainCard.getRightHalfCard().getName();
this.manaCostLeftStr = mainCard.getLeftHalfCard().getManaCostSymbols(); this.manaCostLeftStr = mainCard.getLeftHalfCard().getManaCostSymbols();
this.manaCostRightStr = mainCard.getRightHalfCard().getManaCostSymbols(); this.manaCostRightStr = mainCard.getRightHalfCard().getManaCostSymbols();
} else if (card instanceof CardWithSpellOption) { } else if (card instanceof TransformingDoubleFacedCard) {
this.isDoubleFacedCard = true;
DoubleFacedCard mainCard = ((DoubleFacedCard) card);
fullCardName = mainCard.getLeftHalfCard().getName() + MockCard.MODAL_DOUBLE_FACES_NAME_SEPARATOR + mainCard.getRightHalfCard().getName();
this.manaCostLeftStr = mainCard.getLeftHalfCard().getManaCostSymbols();
this.manaCostRightStr = new ArrayList<>();
} else if (card instanceof CardWithSpellOption) {
this.isSplitCard = true; this.isSplitCard = true;
CardWithSpellOption mainCard = ((CardWithSpellOption) card); CardWithSpellOption mainCard = ((CardWithSpellOption) card);
leftSplitName = mainCard.getName(); leftSplitName = mainCard.getName();
@ -530,13 +538,21 @@ public class CardView extends SimpleCardView {
this.extraDeckCard = card.isExtraDeckCard(); this.extraDeckCard = card.isExtraDeckCard();
// TODO: can probably remove this after tdfc rework
// transformable, double faces cards // transformable, double faces cards
this.transformable = card.isTransformable(); if (!(sourceCard.getMainCard() instanceof DoubleFacedCard)) {
this.transformable = card.isTransformable();
Card secondSideCard = card.getSecondCardFace(); Card secondSideCard = card.getSecondCardFace();
if (secondSideCard != null) { if (secondSideCard != null) {
this.secondCardFace = new CardView(secondSideCard, game);
this.alternateName = secondCardFace.getName();
}
} else if (card instanceof PermanentCard && card.isTransformable()) {
this.transformable = card.isTransformable();
Card secondSideCard = (Card) ((PermanentCard) card).getOtherFace();
this.secondCardFace = new CardView(secondSideCard, game); this.secondCardFace = new CardView(secondSideCard, game);
this.alternateName = secondCardFace.getName(); this.alternateName = secondSideCard.getName();
} }
this.flipCard = card.isFlipCard(); this.flipCard = card.isFlipCard();
@ -544,11 +560,11 @@ public class CardView extends SimpleCardView {
this.alternateName = card.getFlipCardName(); this.alternateName = card.getFlipCardName();
} }
if (card instanceof ModalDoubleFacedCard) { if (card instanceof DoubleFacedCard) {
this.transformable = true; // enable GUI day/night button this.transformable = true; // enable GUI day/night button
ModalDoubleFacedCard mdfCard = (ModalDoubleFacedCard) card; DoubleFacedCard doubleFacedCard = (DoubleFacedCard) card;
this.secondCardFace = new CardView(mdfCard.getRightHalfCard(), game); this.secondCardFace = new CardView(doubleFacedCard.getRightHalfCard(), game);
this.alternateName = mdfCard.getRightHalfCard().getName(); this.alternateName = doubleFacedCard.getRightHalfCard().getName();
} }
Card meldsToCard = card.getMeldsToCard(); Card meldsToCard = card.getMeldsToCard();
@ -764,7 +780,11 @@ public class CardView extends SimpleCardView {
String info; String info;
MageObject targetObject = game.getObject(t); MageObject targetObject = game.getObject(t);
if (targetObject != null) { if (targetObject != null) {
info = targetObject.getIdName(); Player player = null;
if (targetObject instanceof ControllableOrOwnerable) {
player = game.getPlayer(((ControllableOrOwnerable) targetObject).getControllerOrOwnerId());
}
info = (player == null ? "" : player.getName() + ": ") + targetObject.getIdName();
} else { } else {
Player targetPlayer = game.getPlayer(t); Player targetPlayer = game.getPlayer(t);
if (targetPlayer != null) { if (targetPlayer != null) {

View file

@ -27,8 +27,7 @@ public abstract class AbstractCommander extends Constructed {
private static List<CommanderValidator> validators = Arrays.asList( private static List<CommanderValidator> validators = Arrays.asList(
PartnerValidator.instance, PartnerValidator.instance,
PartnerSurvivorsValidator.instance, PartnerVariantValidator.instance,
PartnerFatherAndSonValidator.instance,
FriendsForeverValidator.instance, FriendsForeverValidator.instance,
PartnerWithValidator.instance, PartnerWithValidator.instance,
ChooseABackgroundValidator.instance, ChooseABackgroundValidator.instance,

View file

@ -44,7 +44,6 @@ public class DuelCommander extends Commander {
banned.add("Library of Alexandria"); banned.add("Library of Alexandria");
banned.add("Lion's Eye Diamond"); banned.add("Lion's Eye Diamond");
banned.add("Lotus Petal"); banned.add("Lotus Petal");
banned.add("Loyal Retainers");
banned.add("Lutri, the Spellchaser"); banned.add("Lutri, the Spellchaser");
banned.add("Maddening Hex"); banned.add("Maddening Hex");
banned.add("Mana Crypt"); banned.add("Mana Crypt");
@ -93,8 +92,6 @@ public class DuelCommander extends Commander {
bannedCommander.add("Ajani, Nacatl Pariah"); bannedCommander.add("Ajani, Nacatl Pariah");
bannedCommander.add("Arahbo, Roar of the World"); bannedCommander.add("Arahbo, Roar of the World");
bannedCommander.add("Asmoranomardicadaistinaculdacar");
bannedCommander.add("Baral, Chief of Compliance");
bannedCommander.add("Breya, Etherium Shaper"); bannedCommander.add("Breya, Etherium Shaper");
bannedCommander.add("Derevi, Empyrial Tactician"); bannedCommander.add("Derevi, Empyrial Tactician");
bannedCommander.add("Dihada, Binder of Wills"); bannedCommander.add("Dihada, Binder of Wills");
@ -102,7 +99,6 @@ public class DuelCommander extends Commander {
bannedCommander.add("Edric, Spymaster of Trest"); bannedCommander.add("Edric, Spymaster of Trest");
bannedCommander.add("Emry, Lurker of the Loch"); bannedCommander.add("Emry, Lurker of the Loch");
bannedCommander.add("Eris, Roar of the Storm"); bannedCommander.add("Eris, Roar of the Storm");
bannedCommander.add("Esior, Wardwing Familiar");
bannedCommander.add("Ezio Auditore da Firenze"); bannedCommander.add("Ezio Auditore da Firenze");
bannedCommander.add("Geist of Saint Traft"); bannedCommander.add("Geist of Saint Traft");
bannedCommander.add("Inalla, Archmage Ritualist"); bannedCommander.add("Inalla, Archmage Ritualist");
@ -116,7 +112,6 @@ public class DuelCommander extends Commander {
bannedCommander.add("Omnath, Locus of Creation"); bannedCommander.add("Omnath, Locus of Creation");
bannedCommander.add("Prime Speaker Vannifar"); bannedCommander.add("Prime Speaker Vannifar");
bannedCommander.add("Raffine, Scheming Seer"); bannedCommander.add("Raffine, Scheming Seer");
bannedCommander.add("Rofellos, Llanowar Emissary");
bannedCommander.add("Shorikai, Genesis Engine"); bannedCommander.add("Shorikai, Genesis Engine");
bannedCommander.add("Tamiyo, Inquisitive Student"); bannedCommander.add("Tamiyo, Inquisitive Student");
bannedCommander.add("Tasigur, the Golden Fang"); bannedCommander.add("Tasigur, the Golden Fang");

View file

@ -32,6 +32,7 @@ public class Legacy extends Constructed {
banned.add("Dig Through Time"); banned.add("Dig Through Time");
banned.add("Dreadhorde Arcanist"); banned.add("Dreadhorde Arcanist");
banned.add("Earthcraft"); banned.add("Earthcraft");
banned.add("Entomb");
banned.add("Fastbond"); banned.add("Fastbond");
banned.add("Flash"); banned.add("Flash");
banned.add("Frantic Search"); banned.add("Frantic Search");
@ -56,6 +57,7 @@ public class Legacy extends Constructed {
banned.add("Mox Ruby"); banned.add("Mox Ruby");
banned.add("Mox Sapphire"); banned.add("Mox Sapphire");
banned.add("Mystical Tutor"); banned.add("Mystical Tutor");
banned.add("Nadu, Winged Wisdom");
banned.add("Necropotence"); banned.add("Necropotence");
banned.add("Oath of Druids"); banned.add("Oath of Druids");
banned.add("Oko, Thief of Crowns"); banned.add("Oko, Thief of Crowns");

View file

@ -46,6 +46,7 @@ public class Pauper extends Constructed {
banned.add("Gitaxian Probe"); banned.add("Gitaxian Probe");
banned.add("Grapeshot"); banned.add("Grapeshot");
banned.add("Gush"); banned.add("Gush");
banned.add("High Tide");
banned.add("Hymn to Tourach"); banned.add("Hymn to Tourach");
banned.add("Invigorate"); banned.add("Invigorate");
banned.add("Kuldotha Rebirth"); banned.add("Kuldotha Rebirth");

View file

@ -30,6 +30,7 @@ public class Pioneer extends Constructed {
banned.add("Field of the Dead"); banned.add("Field of the Dead");
banned.add("Flooded Strand"); banned.add("Flooded Strand");
banned.add("Geological Appraiser"); banned.add("Geological Appraiser");
banned.add("Heartfire Hero");
banned.add("Inverter of Truth"); banned.add("Inverter of Truth");
banned.add("Jegantha, the Wellspring"); banned.add("Jegantha, the Wellspring");
banned.add("Karn, the Great Creator"); banned.add("Karn, the Great Creator");

View file

@ -24,8 +24,11 @@ public class Standard extends Constructed {
banned.add("Heartfire Hero"); banned.add("Heartfire Hero");
banned.add("Hopeless Nightmare"); banned.add("Hopeless Nightmare");
banned.add("Monstrous Rage"); banned.add("Monstrous Rage");
banned.add("Proft's Eidetic Memory");
banned.add("Screaming Nemesis");
banned.add("This Town Ain't Big Enough"); banned.add("This Town Ain't Big Enough");
banned.add("Up the Beanstalk"); banned.add("Up the Beanstalk");
banned.add("Vivi Ornitier");
} }
static List<String> makeLegalSets() { static List<String> makeLegalSets() {

View file

@ -206,9 +206,9 @@ public class TinyLeaders extends Constructed {
if (card instanceof SplitCard) { if (card instanceof SplitCard) {
costs.add(((SplitCard) card).getLeftHalfCard().getManaValue()); costs.add(((SplitCard) card).getLeftHalfCard().getManaValue());
costs.add(((SplitCard) card).getRightHalfCard().getManaValue()); costs.add(((SplitCard) card).getRightHalfCard().getManaValue());
} else if (card instanceof ModalDoubleFacedCard) { } else if (card instanceof DoubleFacedCard) {
costs.add(((ModalDoubleFacedCard) card).getLeftHalfCard().getManaValue()); costs.add(((DoubleFacedCard) card).getLeftHalfCard().getManaValue());
costs.add(((ModalDoubleFacedCard) card).getRightHalfCard().getManaValue()); costs.add(((DoubleFacedCard) card).getRightHalfCard().getManaValue());
} else { } else {
costs.add(card.getManaValue()); costs.add(card.getManaValue());
} }

View file

@ -0,0 +1,58 @@
package mage.cards.a;
import mage.MageInt;
import mage.abilities.common.DiesCreatureTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.LessonsInGraveCondition;
import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.common.continuous.GainAbilitySourceEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.keyword.VigilanceAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.counters.CounterType;
import mage.filter.StaticFilters;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class AangALotToLearn extends CardImpl {
public AangALotToLearn(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G/W}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.AVATAR);
this.subtype.add(SubType.ALLY);
this.power = new MageInt(3);
this.toughness = new MageInt(2);
// Aang has vigilance as long as there's a Lesson card in your graveyard.
this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect(
new GainAbilitySourceEffect(VigilanceAbility.getInstance(), Duration.WhileOnBattlefield),
LessonsInGraveCondition.ONE, "{this} has vigilance as long as there's a Lesson card in your graveyard"
)).addHint(LessonsInGraveCondition.getHint()));
// Whenever another creature you control dies, put a +1/+1 counter on Aang.
this.addAbility(new DiesCreatureTriggeredAbility(
new AddCountersSourceEffect(CounterType.P1P1.createInstance()),
false, StaticFilters.FILTER_ANOTHER_CREATURE_YOU_CONTROL
));
}
private AangALotToLearn(final AangALotToLearn card) {
super(card);
}
@Override
public AangALotToLearn copy() {
return new AangALotToLearn(this);
}
}

View file

@ -0,0 +1,64 @@
package mage.cards.a;
import mage.MageInt;
import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.hint.Hint;
import mage.abilities.hint.ValueHint;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledPermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.permanent.TappedPredicate;
import mage.game.permanent.token.AllyToken;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class AangAndKatara extends CardImpl {
private static final FilterPermanent filter = new FilterControlledPermanent("tapped artifacts and/or creatures you control");
static {
filter.add(TappedPredicate.TAPPED);
filter.add(Predicates.or(
CardType.ARTIFACT.getPredicate(),
CardType.CREATURE.getPredicate()
));
}
private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter, null);
private static final Hint hint = new ValueHint("Tapped artifacts and creatures you control", xValue);
public AangAndKatara(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{W}{U}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.AVATAR);
this.subtype.add(SubType.ALLY);
this.power = new MageInt(5);
this.toughness = new MageInt(5);
// Whenever Aang and Katara enter or attack, create X 1/1 white Ally creature tokens, where X is the number of tapped artifacts and/or creatures you control.
this.addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility(new CreateTokenEffect(new AllyToken(), xValue))
.setTriggerPhrase("Whenever {this} enter or attack, ").addHint(hint));
}
private AangAndKatara(final AangAndKatara card) {
super(card);
}
@Override
public AangAndKatara copy() {
return new AangAndKatara(this);
}
}

View file

@ -0,0 +1,89 @@
package mage.cards.a;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.LeavesBattlefieldAllTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.common.delayed.AtTheBeginOfNextUpkeepDelayedTriggeredAbility;
import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
import mage.abilities.effects.common.LookLibraryAndPickControllerEffect;
import mage.abilities.effects.common.TransformSourceEffect;
import mage.abilities.effects.common.continuous.GainAbilityControlledEffect;
import mage.abilities.effects.keyword.EarthbendTargetEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.VigilanceAbility;
import mage.abilities.triggers.BeginningOfCombatTriggeredAbility;
import mage.cards.CardSetInfo;
import mage.cards.TransformingDoubleFacedCard;
import mage.constants.*;
import mage.filter.FilterCard;
import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
import mage.filter.common.FilterCreatureCard;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.target.common.TargetControlledLandPermanent;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class AangAtTheCrossroads extends TransformingDoubleFacedCard {
private static final FilterCard filter = new FilterCreatureCard("creature card with mana value 4 or less");
private static final FilterPermanent saviorFilter = new FilterPermanent("land creatures");
static {
filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 5));
saviorFilter.add(CardType.LAND.getPredicate());
saviorFilter.add(CardType.CREATURE.getPredicate());
}
public AangAtTheCrossroads(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo,
new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.AVATAR, SubType.ALLY}, "{2}{G}{W}{U}",
"Aang, Destined Savior",
new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.AVATAR, SubType.ALLY}, "");
this.getLeftHalfCard().setPT(3, 3);
this.getRightHalfCard().setPT(4, 4);
// Flying
this.getLeftHalfCard().addAbility(FlyingAbility.getInstance());
// When Aang enters, look at the top five cards of your library. You may put a creature card with mana value 4 or less from among them onto the battlefield. Put the rest on the bottom of your library in a random order.
this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect(
5, 1, filter, PutCards.BATTLEFIELD, PutCards.BOTTOM_RANDOM
)));
// When another creature you control leaves the battlefield, transform Aang at the beginning of the next upkeep.
this.getLeftHalfCard().addAbility(new LeavesBattlefieldAllTriggeredAbility(new CreateDelayedTriggeredAbilityEffect(
new AtTheBeginOfNextUpkeepDelayedTriggeredAbility(new TransformSourceEffect())
).setText("transform {this} at the beginning of the next upkeep"), StaticFilters.FILTER_ANOTHER_CREATURE_YOU_CONTROL)
.setTriggerPhrase("When another creature you control leaves the battlefield, "));
// Aang, Destined Savior
// Flying
this.getRightHalfCard().addAbility(FlyingAbility.getInstance());
// Land creatures you control have vigilance.
this.getRightHalfCard().addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect(
VigilanceAbility.getInstance(), Duration.WhileOnBattlefield, saviorFilter
)));
// At the beginning of combat on your turn, earthbend 2.
Ability ability = new BeginningOfCombatTriggeredAbility(new EarthbendTargetEffect(2));
ability.addTarget(new TargetControlledLandPermanent());
this.getRightHalfCard().addAbility(ability);
}
private AangAtTheCrossroads(final AangAtTheCrossroads card) {
super(card);
}
@Override
public AangAtTheCrossroads copy() {
return new AangAtTheCrossroads(this);
}
}

View file

@ -1,112 +0,0 @@
package mage.cards.a;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.Cost;
import mage.abilities.costs.CostImpl;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.common.DamagePlayersEffect;
import mage.abilities.effects.common.DoIfCostPaid;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.GainLifeEffect;
import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.constants.TargetController;
import mage.counters.CounterType;
import mage.filter.FilterCard;
import mage.game.Game;
import java.util.Optional;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class AangMasterOfElements extends CardImpl {
private static final FilterCard filter = new FilterCard("spells");
public AangMasterOfElements(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.AVATAR);
this.subtype.add(SubType.ALLY);
this.power = new MageInt(6);
this.toughness = new MageInt(6);
this.nightCard = true;
// Flying
this.addAbility(FlyingAbility.getInstance());
// Spells you cast cost {W}{U}{B}{R}{G} less to cast.
this.addAbility(new SimpleStaticAbility(new SpellsCostReductionControllerEffect(
filter, new ManaCostsImpl<>("{W}{U}{B}{R}{G}"), StaticValue.get(1), true
)));
// At the beginning of each upkeep, you may transform Aang, Master of Elements. If you do, you gain 4 life, draw four cards, put four +1/+1 counters on him, and he deals 4 damage to each opponent.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(
TargetController.ANY,
new DoIfCostPaid(new GainLifeEffect(4), new AangMasterOfElementsCost())
.addEffect(new DrawCardSourceControllerEffect(4).concatBy(","))
.addEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance(4))
.setText(", put four +1/+1 counters on him"))
.addEffect(new DamagePlayersEffect(4, TargetController.OPPONENT)
.setText(", and he deals 4 damage to each opponent")),
false
));
}
private AangMasterOfElements(final AangMasterOfElements card) {
super(card);
}
@Override
public AangMasterOfElements copy() {
return new AangMasterOfElements(this);
}
}
class AangMasterOfElementsCost extends CostImpl {
AangMasterOfElementsCost() {
super();
text = "transform {this}";
}
private AangMasterOfElementsCost(final AangMasterOfElementsCost cost) {
super(cost);
}
@Override
public AangMasterOfElementsCost copy() {
return new AangMasterOfElementsCost(this);
}
@Override
public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) {
return Optional
.ofNullable(source.getSourcePermanentIfItStillExists(game))
.filter(Card::isTransformable)
.isPresent();
}
@Override
public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) {
paid = Optional
.ofNullable(source.getSourcePermanentIfItStillExists(game))
.filter(permanent -> permanent.transform(source, game))
.isPresent();
return paid;
}
}

View file

@ -0,0 +1,89 @@
package mage.cards.a;
import mage.abilities.Ability;
import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.WaterbendCost;
import mage.abilities.effects.common.TransformSourceEffect;
import mage.abilities.effects.common.counter.AddCountersAllEffect;
import mage.abilities.effects.keyword.AirbendTargetEffect;
import mage.abilities.keyword.FlashAbility;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.ReachAbility;
import mage.abilities.keyword.TrampleAbility;
import mage.cards.CardSetInfo;
import mage.cards.TransformingDoubleFacedCard;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.counters.CounterType;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.common.FilterSpellOrPermanent;
import mage.filter.predicate.mageobject.AnotherPredicate;
import mage.filter.predicate.permanent.TappedPredicate;
import mage.target.common.TargetSpellOrPermanent;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class AangSwiftSavior extends TransformingDoubleFacedCard {
private static final FilterSpellOrPermanent filter = new FilterSpellOrPermanent("other target creature or spell");
private static final FilterPermanent laFilter = new FilterControlledCreaturePermanent("tapped creature you control");
static {
}
static {
filter.getPermanentFilter().add(CardType.CREATURE.getPredicate());
filter.getPermanentFilter().add(AnotherPredicate.instance);
laFilter.add(TappedPredicate.TAPPED);
}
public AangSwiftSavior(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo,
new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.AVATAR, SubType.ALLY}, "{1}{W}{U}",
"Aang and La, Ocean's Fury",
new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.AVATAR, SubType.SPIRIT, SubType.ALLY}, "");
this.getLeftHalfCard().setPT(2, 3);
this.getRightHalfCard().setPT(5, 5);
// Flash
this.getLeftHalfCard().addAbility(FlashAbility.getInstance());
// Flying
this.getLeftHalfCard().addAbility(FlyingAbility.getInstance());
// When Aang enters, airbend up to one other target creature or spell.
Ability ability = new EntersBattlefieldTriggeredAbility(new AirbendTargetEffect());
ability.addTarget(new TargetSpellOrPermanent(0, 1, filter, false));
this.getLeftHalfCard().addAbility(ability);
// Waterbend {8}: Transform Aang.
this.getLeftHalfCard().addAbility(new SimpleActivatedAbility(new TransformSourceEffect(), new WaterbendCost(8)));
// Aang and La, Ocean's Fury
// Reach
this.getRightHalfCard().addAbility(ReachAbility.getInstance());
// Trample
this.getRightHalfCard().addAbility(TrampleAbility.getInstance());
// Whenever Aang and La attack, put a +1/+1 counter on each tapped creature you control.
this.getRightHalfCard().addAbility(new AttacksTriggeredAbility(new AddCountersAllEffect(CounterType.P1P1.createInstance(), laFilter)).setTriggerPhrase("Whenever {this} attack, "));
}
private AangSwiftSavior(final AangSwiftSavior card) {
super(card);
}
@Override
public AangSwiftSavior copy() {
return new AangSwiftSavior(this);
}
}

View file

@ -0,0 +1,50 @@
package mage.cards.a;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTappedUnlessAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.condition.common.YouControlABasicLandCondition;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.counter.AddCountersAllEffect;
import mage.abilities.mana.WhiteManaAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.counters.CounterType;
import mage.filter.StaticFilters;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class AbandonedAirTemple extends CardImpl {
public AbandonedAirTemple(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.LAND}, "");
// This land enters tapped unless you control a basic land.
this.addAbility(new EntersBattlefieldTappedUnlessAbility(YouControlABasicLandCondition.instance)
.addHint(YouControlABasicLandCondition.getHint()));
// {T}: Add {W}.
this.addAbility(new WhiteManaAbility());
// {3}{W}, {T}: Put a +1/+1 counter on each creature you control.
Ability ability = new SimpleActivatedAbility(new AddCountersAllEffect(
CounterType.P1P1.createInstance(), StaticFilters.FILTER_CONTROLLED_CREATURE
), new ManaCostsImpl<>("{3}{W}"));
ability.addCost(new TapSourceCost());
this.addAbility(ability);
}
private AbandonedAirTemple(final AbandonedAirTemple card) {
super(card);
}
@Override
public AbandonedAirTemple copy() {
return new AbandonedAirTemple(this);
}
}

View file

@ -6,10 +6,10 @@ import mage.abilities.dynamicvalue.common.ManaSpentToCastCount;
import mage.abilities.effects.common.CastSourceTriggeredAbility; import mage.abilities.effects.common.CastSourceTriggeredAbility;
import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.effects.common.EntersBattlefieldUnderControlOfOpponentOfChoiceEffect; import mage.abilities.effects.common.EntersBattlefieldUnderControlOfOpponentOfChoiceEffect;
import mage.abilities.keyword.PartnerSurvivorsAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.PartnerVariantType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.SuperType; import mage.constants.SuperType;
import mage.game.permanent.token.CordycepsInfectedToken; import mage.game.permanent.token.CordycepsInfectedToken;
@ -41,7 +41,7 @@ public final class AbbyMercilessSoldier extends CardImpl {
this.addAbility(new EntersBattlefieldAbility(new EntersBattlefieldUnderControlOfOpponentOfChoiceEffect())); this.addAbility(new EntersBattlefieldAbility(new EntersBattlefieldUnderControlOfOpponentOfChoiceEffect()));
// Partner--Survivors // Partner--Survivors
this.addAbility(PartnerSurvivorsAbility.getInstance()); this.addAbility(PartnerVariantType.SURVIVORS.makeAbility());
} }
private AbbyMercilessSoldier(final AbbyMercilessSoldier card) { private AbbyMercilessSoldier(final AbbyMercilessSoldier card) {

View file

@ -1,16 +1,16 @@
package mage.cards.a; package mage.cards.a;
import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.TransformSourceEffect;
import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.TransformAbility; import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.*; import mage.cards.TransformingDoubleFacedCard;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.players.Player;
@ -19,23 +19,26 @@ import java.util.UUID;
/** /**
* @author fireshoes * @author fireshoes
*/ */
public final class AberrantResearcher extends CardImpl { public final class AberrantResearcher extends TransformingDoubleFacedCard {
public AberrantResearcher(UUID ownerId, CardSetInfo setInfo) { public AberrantResearcher(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); super(ownerId, setInfo,
this.subtype.add(SubType.HUMAN); new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.INSECT}, "{3}{U}",
this.subtype.add(SubType.INSECT); "Perfected Form",
this.power = new MageInt(3); new CardType[]{CardType.CREATURE}, new SubType[]{SubType.INSECT, SubType.HORROR}, "U");
this.toughness = new MageInt(2);
this.secondSideCardClazz = mage.cards.p.PerfectedForm.class; this.getLeftHalfCard().setPT(3, 2);
this.getRightHalfCard().setPT(5, 4);
// Flying // Flying
this.addAbility(FlyingAbility.getInstance()); this.getLeftHalfCard().addAbility(FlyingAbility.getInstance());
// At the beginning of your upkeep, put the top card of your library into your graveyard. If it's an instant or sorcery card, transform Aberrant Researcher. // At the beginning of your upkeep, put the top card of your library into your graveyard. If it's an instant or sorcery card, transform Aberrant Researcher.
this.addAbility(new TransformAbility()); this.getLeftHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility(new AberrantResearcherEffect()));
this.addAbility(new BeginningOfUpkeepTriggeredAbility(new AberrantResearcherEffect()));
// Perfected Form
// Flying
this.getRightHalfCard().addAbility(FlyingAbility.getInstance());
} }
private AberrantResearcher(final AberrantResearcher card) { private AberrantResearcher(final AberrantResearcher card) {

View file

@ -1,51 +0,0 @@
package mage.cards.a;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.TransformIntoSourceTriggeredAbility;
import mage.abilities.effects.common.SacrificeEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.filter.StaticFilters;
import mage.target.common.TargetOpponent;
import java.util.UUID;
/**
* @author fireshoes
*/
public final class AbolisherOfBloodlines extends CardImpl {
public AbolisherOfBloodlines(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "");
this.subtype.add(SubType.ELDRAZI);
this.subtype.add(SubType.VAMPIRE);
this.power = new MageInt(6);
this.toughness = new MageInt(5);
// this card is the second face of double-faced card
this.nightCard = true;
// Flying
this.addAbility(FlyingAbility.getInstance());
// When this creature transforms into Abolisher of Bloodlines, target opponent sacrifices three creatures.
Ability ability = new TransformIntoSourceTriggeredAbility(new SacrificeEffect(
StaticFilters.FILTER_PERMANENT_CREATURES, 3, "target opponent"
));
ability.addTarget(new TargetOpponent());
this.addAbility(ability);
}
private AbolisherOfBloodlines(final AbolisherOfBloodlines card) {
super(card);
}
@Override
public AbolisherOfBloodlines copy() {
return new AbolisherOfBloodlines(this);
}
}

View file

@ -0,0 +1,43 @@
package mage.cards.a;
import mage.abilities.condition.common.LessonsInGraveCondition;
import mage.abilities.decorator.ConditionalOneShotEffect;
import mage.abilities.effects.common.LookLibraryAndPickControllerEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.PutCards;
import mage.constants.SubType;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class AccumulateWisdom extends CardImpl {
public AccumulateWisdom(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}");
this.subtype.add(SubType.LESSON);
// Look at the top three cards of your library. Put one of those cards into your hand and the rest on the bottom of your library in any order. Put each of those cards into your hand instead if there are three or more Lesson cards in your graveyard.
this.getSpellAbility().addEffect(new ConditionalOneShotEffect(
new LookLibraryAndPickControllerEffect(3, 3, PutCards.HAND, PutCards.BOTTOM_ANY),
new LookLibraryAndPickControllerEffect(3, 1, PutCards.HAND, PutCards.BOTTOM_ANY),
LessonsInGraveCondition.THREE, "look at the top three cards of your library. " +
"Put one of those cards into your hand and the rest on the bottom of your library in any order. " +
"Put each of those cards into your hand instead if there are three or more Lesson cards in your graveyard"
));
this.getSpellAbility().addHint(LessonsInGraveCondition.getHint());
}
private AccumulateWisdom(final AccumulateWisdom card) {
super(card);
}
@Override
public AccumulateWisdom copy() {
return new AccumulateWisdom(this);
}
}

View file

@ -1,49 +1,76 @@
package mage.cards.a; package mage.cards.a;
import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.SpellAbility;
import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.common.DiesSourceTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.AttachEffect;
import mage.abilities.effects.common.GainLifeEffect;
import mage.abilities.effects.common.LoseLifeTargetEffect;
import mage.abilities.effects.common.cost.CostModificationEffectImpl;
import mage.abilities.effects.common.cost.SpellsCostModificationThatTargetSourceEffect; import mage.abilities.effects.common.cost.SpellsCostModificationThatTargetSourceEffect;
import mage.abilities.keyword.EnchantAbility;
import mage.abilities.keyword.TransformAbility; import mage.abilities.keyword.TransformAbility;
import mage.cards.Card; import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.cards.DoubleFacedCardHalf;
import mage.cards.TransformingDoubleFacedCard;
import mage.constants.*; import mage.constants.*;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.game.stack.Spell;
import mage.players.Player; import mage.players.Player;
import mage.target.TargetPlayer;
import mage.target.common.TargetOpponent; import mage.target.common.TargetOpponent;
import mage.util.CardUtil;
import java.util.Objects;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
/** /**
* @author halljared * @author halljared
*/ */
public final class AccursedWitch extends CardImpl { public final class AccursedWitch extends TransformingDoubleFacedCard {
private static final FilterCard filter = new FilterCard("spells"); private static final FilterCard filter = new FilterCard("spells");
public AccursedWitch(UUID ownerId, CardSetInfo setInfo) { public AccursedWitch(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); super(ownerId, setInfo,
this.subtype.add(SubType.HUMAN); new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.SHAMAN}, "{3}{B}",
this.subtype.add(SubType.SHAMAN); "Infectious Curse",
this.power = new MageInt(4); new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.AURA, SubType.CURSE}, "B");
this.toughness = new MageInt(2); this.getLeftHalfCard().setPT(4, 2);
this.secondSideCardClazz = mage.cards.i.InfectiousCurse.class;
// Spells your opponents cast that target Accursed Witch cost {1} less to cast. // Spells your opponents cast that target Accursed Witch cost {1} less to cast.
this.addAbility(new SimpleStaticAbility( this.getLeftHalfCard().addAbility(new SimpleStaticAbility(
new SpellsCostModificationThatTargetSourceEffect(-1, filter, TargetController.OPPONENT)) new SpellsCostModificationThatTargetSourceEffect(-1, filter, TargetController.OPPONENT))
); );
// When Accursed Witch dies, return it to the battlefield transformed under your control attached to target opponent. // When Accursed Witch dies, return it to the battlefield transformed under your control attached to target opponent.
this.addAbility(new TransformAbility());
Ability ability = new DiesSourceTriggeredAbility(new AccursedWitchReturnTransformedEffect()); Ability ability = new DiesSourceTriggeredAbility(new AccursedWitchReturnTransformedEffect());
ability.addTarget(new TargetOpponent()); ability.addTarget(new TargetOpponent());
this.addAbility(ability); this.getLeftHalfCard().addAbility(ability);
// Infectious Curse
// Enchant player
TargetPlayer auraTarget = new TargetPlayer();
this.getRightHalfCard().getSpellAbility().addTarget(auraTarget);
this.getRightHalfCard().getSpellAbility().addEffect(new AttachEffect(Outcome.Damage));
this.getRightHalfCard().addAbility(new EnchantAbility(auraTarget));
// Spells you cast that target enchanted player cost {1} less to cast.
this.getRightHalfCard().addAbility(new SimpleStaticAbility(new InfectiousCurseCostReductionEffect()));
// At the beginning of enchanted player's upkeep, that player loses 1 life and you gain 1 life.
Ability upkeepAbility = new BeginningOfUpkeepTriggeredAbility(
TargetController.ENCHANTED, new LoseLifeTargetEffect(1).setText("that player loses 1 life"),
false
);
upkeepAbility.addEffect(new GainLifeEffect(1).concatBy("and"));
this.getRightHalfCard().addAbility(upkeepAbility);
} }
private AccursedWitch(final AccursedWitch card) { private AccursedWitch(final AccursedWitch card) {
@ -80,16 +107,67 @@ class AccursedWitchReturnTransformedEffect extends OneShotEffect {
return false; return false;
} }
Card card = game.getCard(source.getSourceId()); DoubleFacedCardHalf card = (DoubleFacedCardHalf) game.getCard(source.getSourceId());
if (card == null) { if (card == null) {
return false; return false;
} }
game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + source.getSourceId(), Boolean.TRUE); game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + source.getSourceId(), Boolean.TRUE);
game.getState().setValue("attachTo:" + source.getSourceId(), attachTo.getId()); game.getState().setValue("attachTo:" + card.getOtherSide().getId(), attachTo.getId());
if (controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { if (controller.moveCards(card, Zone.BATTLEFIELD, source, game)) {
attachTo.addAttachment(card.getId(), source, game); attachTo.addAttachment(card.getOtherSide().getId(), source, game);
} }
return true; return true;
} }
} }
class InfectiousCurseCostReductionEffect extends CostModificationEffectImpl {
InfectiousCurseCostReductionEffect() {
super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.REDUCE_COST);
this.staticText = "Spells you cast that target enchanted player cost {1} less to cast";
}
private InfectiousCurseCostReductionEffect(InfectiousCurseCostReductionEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source, Ability abilityToModify) {
CardUtil.reduceCost(abilityToModify, 1);
return true;
}
@Override
public boolean applies(Ability abilityToModify, Ability source, Game game) {
if (!(abilityToModify instanceof SpellAbility)) {
return false;
}
if (!source.isControlledBy(abilityToModify.getControllerId())) {
return false;
}
Permanent enchantment = game.getPermanent(source.getSourceId());
if (enchantment == null || enchantment.getAttachedTo() == null) {
return false;
}
Spell spell = (Spell) game.getStack().getStackObject(abilityToModify.getId());
Set<UUID> allTargets;
if (spell != null) {
// real cast
allTargets = CardUtil.getAllSelectedTargets(abilityToModify, game);
} else {
// playable
allTargets = CardUtil.getAllPossibleTargets(abilityToModify, game);
}
// try to reduce all the time (if it possible to target)
return allTargets.stream().anyMatch(target -> Objects.equals(target, enchantment.getAttachedTo()));
}
@Override
public InfectiousCurseCostReductionEffect copy() {
return new InfectiousCurseCostReductionEffect(this);
}
}

View file

@ -1,16 +1,23 @@
package mage.cards.a; package mage.cards.a;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl; import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.ActivateIfConditionActivatedAbility;
import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.common.DiesSourceTriggeredAbility;
import mage.abilities.condition.Condition;
import mage.abilities.condition.common.CardsInHandCondition;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.effects.common.TransformSourceEffect;
import mage.abilities.hint.ConditionHint;
import mage.abilities.hint.Hint;
import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.LifelinkAbility; import mage.abilities.keyword.LifelinkAbility;
import mage.abilities.keyword.TransformAbility; import mage.abilities.keyword.TransformAbility;
import mage.abilities.mana.BlackManaAbility;
import mage.cards.*; import mage.cards.*;
import mage.constants.*; import mage.constants.*;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
@ -28,33 +35,43 @@ import java.util.UUID;
/** /**
* @author Susucr * @author Susucr
*/ */
public final class AclazotzDeepestBetrayal extends CardImpl { public final class AclazotzDeepestBetrayal extends TransformingDoubleFacedCard {
private static final Condition condition = new CardsInHandCondition(ComparisonType.FEWER_THAN, 2, TargetController.ANY);
private static final Hint hint = new ConditionHint(condition);
public AclazotzDeepestBetrayal(UUID ownerId, CardSetInfo setInfo) { public AclazotzDeepestBetrayal(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); super(ownerId, setInfo,
this.secondSideCardClazz = mage.cards.t.TempleOfTheDead.class; new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.BAT, SubType.GOD}, "{3}{B}{B}",
"Temple of the Dead",
new SuperType[]{}, new CardType[]{CardType.LAND}, new SubType[]{}, "");
this.supertype.add(SuperType.LEGENDARY); this.getLeftHalfCard().setPT(4, 4);
this.subtype.add(SubType.BAT);
this.subtype.add(SubType.GOD);
this.power = new MageInt(4);
this.toughness = new MageInt(4);
// Flying // Flying
this.addAbility(FlyingAbility.getInstance()); this.getLeftHalfCard().addAbility(FlyingAbility.getInstance());
// Lifelink // Lifelink
this.addAbility(LifelinkAbility.getInstance()); this.getLeftHalfCard().addAbility(LifelinkAbility.getInstance());
// Whenever Aclazotz attacks, each opponent discards a card. For each opponent who can't, you draw a card. // Whenever Aclazotz attacks, each opponent discards a card. For each opponent who can't, you draw a card.
this.addAbility(new AttacksTriggeredAbility(new AclazotzDeepestBetrayalEffect())); this.getLeftHalfCard().addAbility(new AttacksTriggeredAbility(new AclazotzDeepestBetrayalEffect()));
// Whenever an opponent discards a land card, create a 1/1 black Bat creature token with flying. // Whenever an opponent discards a land card, create a 1/1 black Bat creature token with flying.
this.addAbility(new AclazotzDeepestBetrayalTriggeredAbility()); this.getLeftHalfCard().addAbility(new AclazotzDeepestBetrayalTriggeredAbility());
// When Aclazotz dies, return it to the battlefield tapped and transformed under its owner's control. // When Aclazotz dies, return it to the battlefield tapped and transformed under its owner's control.
this.addAbility(new TransformAbility()); this.getLeftHalfCard().addAbility(new DiesSourceTriggeredAbility(new AclazotzDeepestBetrayalTransformEffect()));
this.addAbility(new DiesSourceTriggeredAbility(new AclazotzDeepestBetrayalTransformEffect()));
// Temple of the Dead
// {T}: Add {B}.
this.getRightHalfCard().addAbility(new BlackManaAbility());
// {2}{B}, {T}: Transform Temple of the Dead. Activate only if a player has one or fewer cards in hand and only as a sorcery.
Ability ability = new ActivateIfConditionActivatedAbility(
new TransformSourceEffect(), new ManaCostsImpl<>("{2}{B}"), condition
).setTiming(TimingRule.SORCERY);
ability.addCost(new TapSourceCost());
this.getRightHalfCard().addAbility(ability.addHint(hint));
} }
private AclazotzDeepestBetrayal(final AclazotzDeepestBetrayal card) { private AclazotzDeepestBetrayal(final AclazotzDeepestBetrayal card) {

View file

@ -1,4 +1,3 @@
package mage.cards.a; package mage.cards.a;
import java.util.UUID; import java.util.UUID;
@ -28,7 +27,9 @@ public final class AcolyteOfTheInferno extends CardImpl {
this.addAbility(new RenownAbility(1)); this.addAbility(new RenownAbility(1));
// Whenever Acolyte of the Inferno becomes blocked by a creature, it deals 2 damage to that creature // Whenever Acolyte of the Inferno becomes blocked by a creature, it deals 2 damage to that creature
this.addAbility(new BecomesBlockedByCreatureTriggeredAbility(new DamageTargetEffect(2, true, "that creature", "it"), false)); this.addAbility(new BecomesBlockedByCreatureTriggeredAbility(
new DamageTargetEffect(2, "it")
.withTargetDescription("that creature"), false));
} }
private AcolyteOfTheInferno(final AcolyteOfTheInferno card) { private AcolyteOfTheInferno(final AcolyteOfTheInferno card) {

View file

@ -2,16 +2,14 @@ package mage.cards.a;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.dynamicvalue.common.DevotionCount; import mage.abilities.dynamicvalue.common.DevotionCount;
import mage.abilities.effects.PreventionEffectData;
import mage.abilities.effects.PreventionEffectImpl; import mage.abilities.effects.PreventionEffectImpl;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Duration; import mage.constants.Duration;
import mage.game.Game; import mage.game.Game;
import mage.game.events.DamageEvent;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
import mage.game.events.PreventDamageEvent;
import mage.game.events.PreventedDamageEvent;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import mage.target.common.TargetAnyTarget; import mage.target.common.TargetAnyTarget;
@ -46,16 +44,14 @@ public final class AcolytesReward extends CardImpl {
class AcolytesRewardEffect extends PreventionEffectImpl { class AcolytesRewardEffect extends PreventionEffectImpl {
protected int amount = 0;
AcolytesRewardEffect() { AcolytesRewardEffect() {
super(Duration.EndOfTurn); super(Duration.EndOfTurn, 0, false, true, DevotionCount.W);
staticText = "Prevent the next X damage that would be dealt to target creature this turn, where X is your devotion to white. If damage is prevented this way, {this} deals that much damage to any target"; staticText = "Prevent the next X damage that would be dealt to target creature this turn, where X is your devotion to white. If damage is prevented this way, {this} deals that much damage to any target";
} }
private AcolytesRewardEffect(final AcolytesRewardEffect effect) { private AcolytesRewardEffect(final AcolytesRewardEffect effect) {
super(effect); super(effect);
this.amount = effect.amount;
} }
@Override @Override
@ -63,64 +59,25 @@ class AcolytesRewardEffect extends PreventionEffectImpl {
return new AcolytesRewardEffect(this); return new AcolytesRewardEffect(this);
} }
@Override
public void init(Ability source, Game game) {
super.init(source, game);
amount = DevotionCount.W.calculate(game, source, this);
}
@Override @Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) { public boolean replaceEvent(GameEvent event, Ability source, Game game) {
boolean result = false; PreventionEffectData preventionData = preventDamageAction(event, source, game);
int toPrevent = amount; if (preventionData.getPreventedDamage() > 0) {
if (event.getAmount() < this.amount) { Permanent targetCreature = game.getPermanent(source.getFirstTarget());
toPrevent = event.getAmount(); if (targetCreature != null) {
amount -= event.getAmount(); targetCreature.damage(preventionData.getPreventedDamage(), source.getSourceId(), source, game, false, true);
} else { }
amount = 0; Player targetPlayer = game.getPlayer(source.getFirstTarget());
if (targetCreature != null) {
targetPlayer.damage(preventionData.getPreventedDamage(), source.getSourceId(), source, game, false, true);
}
} }
GameEvent preventEvent = new PreventDamageEvent(event.getTargetId(), source.getSourceId(), source, source.getControllerId(), toPrevent, ((DamageEvent) event).isCombatDamage()); return false;
if (game.replaceEvent(preventEvent)) {
return result;
}
Permanent targetCreature = game.getPermanent(event.getTargetId());
if (targetCreature == null) {
return result;
}
if (amount == 0) {
this.used = true;
this.discard();
}
if (event.getAmount() >= toPrevent) {
event.setAmount(event.getAmount() - toPrevent);
} else {
event.setAmount(0);
result = true;
}
if (toPrevent == 0) {
return result;
}
game.informPlayers("Acolyte's Reward prevented " + toPrevent + " to " + targetCreature.getName());
game.fireEvent(new PreventedDamageEvent(event.getTargetId(), source.getSourceId(), source, source.getControllerId(), toPrevent));
Player targetPlayer = game.getPlayer(source.getTargets().get(1).getFirstTarget());
if (targetPlayer != null) {
targetPlayer.damage(toPrevent, source.getSourceId(), source, game);
game.informPlayers("Acolyte's Reward deals " + toPrevent + " damage to " + targetPlayer.getLogName());
return result;
}
Permanent targetDamageCreature = game.getPermanent(source.getTargets().get(1).getFirstTarget());
if (targetDamageCreature == null) {
return result;
}
targetDamageCreature.damage(toPrevent, source.getSourceId(), source, game, false, true);
game.informPlayers("Acolyte's Reward deals " + toPrevent + " damage to " + targetDamageCreature.getName());
return result;
} }
@Override @Override
public boolean applies(GameEvent event, Ability source, Game game) { public boolean applies(GameEvent event, Ability source, Game game) {
return !this.used && super.applies(event, source, game) && event.getTargetId().equals(source.getFirstTarget()); return super.applies(event, source, game) && event.getTargetId().equals(source.getFirstTarget());
} }
} }

View file

@ -1,48 +0,0 @@
package mage.cards.a;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.mana.WhiteManaAbility;
import mage.constants.SuperType;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Zone;
import mage.game.permanent.token.IxalanVampireToken;
/**
*
* @author TheElk801
*/
public final class AdantoTheFirstFort extends CardImpl {
public AdantoTheFirstFort(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.LAND}, "");
this.supertype.add(SuperType.LEGENDARY);
this.nightCard = true;
// T: Add W.
this.addAbility(new WhiteManaAbility());
// 2W, T: Create a 1/1 white Vampire creature token with lifelink.
Ability ability = new SimpleActivatedAbility(new CreateTokenEffect(new IxalanVampireToken()), new ManaCostsImpl<>("{2}{W}"));
ability.addCost(new TapSourceCost());
this.addAbility(ability);
}
private AdantoTheFirstFort(final AdantoTheFirstFort card) {
super(card);
}
@Override
public AdantoTheFirstFort copy() {
return new AdantoTheFirstFort(this);
}
}

View file

@ -41,7 +41,7 @@ public final class AdrenalineJockey extends CardImpl {
// Whenever a player casts a spell, if it's not their turn, this creature deals 4 damage to them. // Whenever a player casts a spell, if it's not their turn, this creature deals 4 damage to them.
this.addAbility(new SpellCastAllTriggeredAbility( this.addAbility(new SpellCastAllTriggeredAbility(
new DamageTargetEffect(4, true, "them"), new DamageTargetEffect(4).withTargetDescription("them"),
filter, false, SetTargetPointer.PLAYER filter, false, SetTargetPointer.PLAYER
)); ));

View file

@ -1,17 +1,28 @@
package mage.cards.a; package mage.cards.a;
import mage.abilities.Ability;
import mage.abilities.Mode; import mage.abilities.Mode;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.effects.common.TapTargetEffect; import mage.abilities.effects.common.TapTargetEffect;
import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.filter.FilterPermanent;
import mage.filter.predicate.permanent.PermanentReferenceInCollectionPredicate;
import mage.game.Game;
import mage.game.permanent.token.HeroToken; import mage.game.permanent.token.HeroToken;
import mage.target.Target;
import mage.target.TargetPermanent;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
import mage.target.targetpointer.FixedTarget;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors;
/** /**
* @author TheElk801 * @author TheElk801
@ -28,8 +39,7 @@ public final class AerithRescueMission extends CardImpl {
// * Take 59 Flights of Stairs -- Tap up to three target creatures. Put a stun counter on one of them. // * Take 59 Flights of Stairs -- Tap up to three target creatures. Put a stun counter on one of them.
this.getSpellAbility().addMode(new Mode(new TapTargetEffect()) this.getSpellAbility().addMode(new Mode(new TapTargetEffect())
.addEffect(new AddCountersTargetEffect(CounterType.STUN.createInstance()) .addEffect(new AerithRescueMissionStunEffect())
.setText("Put a stun counter on one of them"))
.addTarget(new TargetCreaturePermanent(0, 3)) .addTarget(new TargetCreaturePermanent(0, 3))
.withFlavorWord("Take 59 Flights of Stairs")); .withFlavorWord("Take 59 Flights of Stairs"));
} }
@ -43,3 +53,34 @@ public final class AerithRescueMission extends CardImpl {
return new AerithRescueMission(this); return new AerithRescueMission(this);
} }
} }
class AerithRescueMissionStunEffect extends OneShotEffect {
AerithRescueMissionStunEffect() {
super(Outcome.Detriment);
staticText = "Put a stun counter on one of them";
}
private AerithRescueMissionStunEffect(final AerithRescueMissionStunEffect effect) {
super(effect);
}
@Override
public AerithRescueMissionStunEffect copy() {
return new AerithRescueMissionStunEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
FilterPermanent filter = new FilterPermanent("creature to put a stun counter on");
filter.add(new PermanentReferenceInCollectionPredicate(this.getTargetPointer().getTargets(game, source).stream()
.map(game::getPermanent).collect(Collectors.toList()), game));
Target target = new TargetPermanent(filter).withNotTarget(true);
if (target.choose(Outcome.UnboostCreature, source.getControllerId(), source, game)) {
Effect eff = new AddCountersTargetEffect(CounterType.STUN.createInstance());
eff.setTargetPointer(new FixedTarget(target.getFirstTarget(), game));
return eff.apply(game, source);
}
return false;
}
}

View file

@ -1,13 +1,13 @@
package mage.cards.a; package mage.cards.a;
import mage.MageInt;
import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.common.ActivateAsSorceryActivatedAbility;
import mage.abilities.common.DealsCombatDamageToAPlayerOrBattleTriggeredAbility;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.TransformSourceEffect;
import mage.abilities.keyword.DeathtouchAbility; import mage.abilities.keyword.DeathtouchAbility;
import mage.abilities.keyword.TransformAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.cards.TransformingDoubleFacedCard;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
@ -16,23 +16,28 @@ import java.util.UUID;
/** /**
* @author TheElk801 * @author TheElk801
*/ */
public final class AetherbladeAgent extends CardImpl { public final class AetherbladeAgent extends TransformingDoubleFacedCard {
public AetherbladeAgent(UUID ownerId, CardSetInfo setInfo) { public AetherbladeAgent(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); super(ownerId, setInfo,
new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.ROGUE}, "{1}{B}",
this.subtype.add(SubType.HUMAN); "Gitaxian Mindstinger",
this.subtype.add(SubType.ROGUE); new CardType[]{CardType.CREATURE}, new SubType[]{SubType.PHYREXIAN, SubType.ROGUE}, "UB");
this.power = new MageInt(1); this.getLeftHalfCard().setPT(1, 1);
this.toughness = new MageInt(1); this.getRightHalfCard().setPT(3, 3);
this.secondSideCardClazz = mage.cards.g.GitaxianMindstinger.class;
// Deathtouch // Deathtouch
this.addAbility(DeathtouchAbility.getInstance()); this.getLeftHalfCard().addAbility(DeathtouchAbility.getInstance());
// {4}{U/P}: Transform Aetherblade Agent. Activate only as a sorcery. // {4}{U/P}: Transform Aetherblade Agent. Activate only as a sorcery.
this.addAbility(new TransformAbility()); this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{4}{U/P}")));
this.addAbility(new ActivateAsSorceryActivatedAbility(new TransformSourceEffect(), new ManaCostsImpl<>("{4}{U/P}")));
// Gitaxian Mindstinger
// Deathtouch
this.getRightHalfCard().addAbility(DeathtouchAbility.getInstance());
// Whenever Gitaxian Mindstinger deals combat damage to a player or battle, draw a card.
this.getRightHalfCard().addAbility(new DealsCombatDamageToAPlayerOrBattleTriggeredAbility(new DrawCardSourceControllerEffect(1),false));
} }
private AetherbladeAgent(final AetherbladeAgent card) { private AetherbladeAgent(final AetherbladeAgent card) {

View file

@ -1,53 +0,0 @@
package mage.cards.a;
import mage.MageInt;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.dynamicvalue.common.ArtifactYouControlCount;
import mage.abilities.effects.common.continuous.SetBasePowerSourceEffect;
import mage.abilities.keyword.CrewAbility;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class AetherwingGoldenScaleFlagship extends CardImpl {
public AetherwingGoldenScaleFlagship(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.VEHICLE);
this.power = new MageInt(0);
this.toughness = new MageInt(4);
this.color.setBlue(true);
this.color.setRed(true);
this.nightCard = true;
// Flying
this.addAbility(FlyingAbility.getInstance());
// Aetherwing, Golden-Scale Flagship's power is equal to the number of artifacts you control.
this.addAbility(new SimpleStaticAbility(
Zone.ALL,
new SetBasePowerSourceEffect(ArtifactYouControlCount.instance)
.setText("{this}'s power is equal to the number of artifacts you control")
));
// Crew 1
this.addAbility(new CrewAbility(1));
}
private AetherwingGoldenScaleFlagship(final AetherwingGoldenScaleFlagship card) {
super(card);
}
@Override
public AetherwingGoldenScaleFlagship copy() {
return new AetherwingGoldenScaleFlagship(this);
}
}

View file

@ -1,33 +1,49 @@
package mage.cards.a; package mage.cards.a;
import mage.MageInt; import mage.abilities.Ability;
import mage.abilities.common.TransformIntoSourceTriggeredAbility;
import mage.abilities.common.WerewolfBackTriggeredAbility;
import mage.abilities.common.WerewolfFrontTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility;
import mage.abilities.keyword.TransformAbility; import mage.abilities.effects.OneShotEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.cards.TransformingDoubleFacedCard;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.Zone;
import mage.game.Controllable;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.common.TargetArtifactPermanent;
import java.util.Optional;
import java.util.UUID; import java.util.UUID;
/** /**
* @author BetaSteward * @author BetaSteward
*/ */
public final class AfflictedDeserter extends CardImpl { public final class AfflictedDeserter extends TransformingDoubleFacedCard {
public AfflictedDeserter(UUID ownerId, CardSetInfo setInfo) { public AfflictedDeserter(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); super(ownerId, setInfo,
this.subtype.add(SubType.HUMAN); new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{3}{R}",
this.subtype.add(SubType.WEREWOLF); "Werewolf Ransacker",
new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "R");
this.secondSideCardClazz = mage.cards.w.WerewolfRansacker.class; this.getLeftHalfCard().setPT(3, 2);
this.getRightHalfCard().setPT(5, 4);
this.power = new MageInt(3);
this.toughness = new MageInt(2);
// At the beginning of each upkeep, if no spells were cast last turn, transform Afflicted Deserter. // At the beginning of each upkeep, if no spells were cast last turn, transform Afflicted Deserter.
this.addAbility(new TransformAbility()); this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility());
this.addAbility(new WerewolfFrontTriggeredAbility());
// Werewolf Ransacker
// Whenever this creature transforms into Werewolf Ransacker, you may destroy target artifact. If that artifact is put into a graveyard this way, Werewolf Ransacker deals 3 damage to that artifact's controller.
Ability ability = new TransformIntoSourceTriggeredAbility(new WerewolfRansackerEffect(), true, true);
ability.addTarget(new TargetArtifactPermanent());
this.getRightHalfCard().addAbility(ability);
// At the beginning of each upkeep, if a player cast two or more spells last turn, transform Werewolf Ransacker.
this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility());
} }
private AfflictedDeserter(final AfflictedDeserter card) { private AfflictedDeserter(final AfflictedDeserter card) {
@ -39,3 +55,39 @@ public final class AfflictedDeserter extends CardImpl {
return new AfflictedDeserter(this); return new AfflictedDeserter(this);
} }
} }
class WerewolfRansackerEffect extends OneShotEffect {
WerewolfRansackerEffect() {
super(Outcome.DestroyPermanent);
staticText = "destroy target artifact. If that artifact is put into a graveyard this way, " +
"{this} deals 3 damage to that artifact's controller";
}
private WerewolfRansackerEffect(final WerewolfRansackerEffect effect) {
super(effect);
}
@Override
public WerewolfRansackerEffect copy() {
return new WerewolfRansackerEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (permanent == null) {
return false;
}
permanent.destroy(source, game);
if (game.getState().getZone(permanent.getId()) != Zone.GRAVEYARD) {
return true;
}
Optional.of(permanent)
.map(Controllable::getControllerId)
.map(game::getPlayer)
.ifPresent(player -> player.damage(3, source, game));
return true;
}
}

View file

@ -45,7 +45,7 @@ public final class AgentVenom extends CardImpl {
this.addAbility(FlashAbility.getInstance()); this.addAbility(FlashAbility.getInstance());
// Menace // Menace
this.addAbility(new MenaceAbility()); this.addAbility(new MenaceAbility(false));
// Whenever another nontoken creature you control dies, you draw a card and lose 1 life. // Whenever another nontoken creature you control dies, you draw a card and lose 1 life.
Ability ability = new DiesCreatureTriggeredAbility( Ability ability = new DiesCreatureTriggeredAbility(

View file

@ -0,0 +1,48 @@
package mage.cards.a;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTappedUnlessAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.condition.common.YouControlABasicLandCondition;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.DrawDiscardControllerEffect;
import mage.abilities.mana.BlueManaAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class AgnaQela extends CardImpl {
public AgnaQela(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.LAND}, "");
// This land enters tapped unless you control a basic land.
this.addAbility(new EntersBattlefieldTappedUnlessAbility(YouControlABasicLandCondition.instance)
.addHint(YouControlABasicLandCondition.getHint()));
// {T}: Add {U}.
this.addAbility(new BlueManaAbility());
// {2}{U}, {T}: Draw a card, then discard a card.
Ability ability = new SimpleActivatedAbility(
new DrawDiscardControllerEffect(1, 1), new ManaCostsImpl<>("{2}{U}")
);
ability.addCost(new TapSourceCost());
this.addAbility(ability);
}
private AgnaQela(final AgnaQela card) {
super(card);
}
@Override
public AgnaQela copy() {
return new AgnaQela(this);
}
}

View file

@ -0,0 +1,41 @@
package mage.cards.a;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.effects.common.continuous.BoostControlledEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.filter.StaticFilters;
import mage.game.permanent.token.ClueArtifactToken;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class AirNomadLegacy extends CardImpl {
public AirNomadLegacy(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{W}{U}");
// When this enchantment enters, create a Clue token.
this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new ClueArtifactToken())));
// Creatures you control with flying get +1/+1.
this.addAbility(new SimpleStaticAbility(new BoostControlledEffect(
1, 1, Duration.WhileOnBattlefield, StaticFilters.FILTER_CREATURE_FLYING
).setText("creatures you control with flying get +1/+1")));
}
private AirNomadLegacy(final AirNomadLegacy card) {
super(card);
}
@Override
public AirNomadLegacy copy() {
return new AirNomadLegacy(this);
}
}

View file

@ -0,0 +1,51 @@
package mage.cards.a;
import mage.MageInt;
import mage.abilities.condition.Condition;
import mage.abilities.condition.InvertCondition;
import mage.abilities.condition.common.AttackedThisTurnSourceCondition;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.counters.CounterType;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class AirNomadStudent extends CardImpl {
private static final Condition condition = new InvertCondition(
AttackedThisTurnSourceCondition.instance, "{this} didn't attack this turn"
);
public AirNomadStudent(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}");
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.MONK);
this.power = new MageInt(2);
this.toughness = new MageInt(2);
// Flying
this.addAbility(FlyingAbility.getInstance());
// At the beginning of your end step, if this creature didn't attack this turn, put a +1/+1 counter on it.
this.addAbility(new BeginningOfEndStepTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance())
.setText("put a +1/+1 counter on it")).withInterveningIf(condition));
}
private AirNomadStudent(final AirNomadStudent card) {
super(card);
}
@Override
public AirNomadStudent copy() {
return new AirNomadStudent(this);
}
}

View file

@ -0,0 +1,59 @@
package mage.cards.a;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldAllTriggeredAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.condition.Condition;
import mage.abilities.condition.common.SourceHasCounterCondition;
import mage.abilities.effects.common.ExileThenReturnTargetEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.effects.keyword.AirbendTargetEffect;
import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.counters.CounterType;
import mage.filter.StaticFilters;
import mage.target.common.TargetControlledCreaturePermanent;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class AirbenderAscension extends CardImpl {
private static final Condition condition = new SourceHasCounterCondition(CounterType.QUEST, 4);
public AirbenderAscension(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}");
// When this enchantment enters, airbend up to one target creature.
Ability ability = new EntersBattlefieldTriggeredAbility(new AirbendTargetEffect());
ability.addTarget(new TargetCreaturePermanent(0, 1));
this.addAbility(ability);
// Whenever a creature you control enters, put a quest counter on this enchantment.
this.addAbility(new EntersBattlefieldAllTriggeredAbility(
new AddCountersSourceEffect(CounterType.QUEST.createInstance()),
StaticFilters.FILTER_CONTROLLED_CREATURE
));
// At the beginning of your end step, if this enchantment has four or more quest counters on it, exile up to one target creature you control, then return it to the battlefield under its owner's control.
ability = new BeginningOfEndStepTriggeredAbility(
new ExileThenReturnTargetEffect(false, false)
).withInterveningIf(condition);
ability.addTarget(new TargetControlledCreaturePermanent(0, 1));
this.addAbility(ability);
}
private AirbenderAscension(final AirbenderAscension card) {
super(card);
}
@Override
public AirbenderAscension copy() {
return new AirbenderAscension(this);
}
}

View file

@ -0,0 +1,43 @@
package mage.cards.a;
import mage.abilities.Mode;
import mage.abilities.effects.common.DestroyTargetEffect;
import mage.abilities.effects.keyword.AirbendTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.target.common.TargetAttackingCreature;
import mage.target.common.TargetControlledCreaturePermanent;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class AirbendersReversal extends CardImpl {
public AirbendersReversal(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}");
this.subtype.add(SubType.LESSON);
// Choose one --
// * Destroy target attacking creature.
this.getSpellAbility().addEffect(new DestroyTargetEffect());
this.getSpellAbility().addTarget(new TargetAttackingCreature());
// * Airbend target creature you control.
this.getSpellAbility().addMode(new Mode(new AirbendTargetEffect())
.addTarget(new TargetControlledCreaturePermanent()));
}
private AirbendersReversal(final AirbendersReversal card) {
super(card);
}
@Override
public AirbendersReversal copy() {
return new AirbendersReversal(this);
}
}

View file

@ -0,0 +1,48 @@
package mage.cards.a;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTappedAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.SacrificeSourceCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.mana.BlueManaAbility;
import mage.abilities.mana.RedManaAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class AirshipEngineRoom extends CardImpl {
public AirshipEngineRoom(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.LAND}, "");
// This land enters tapped.
this.addAbility(new EntersBattlefieldTappedAbility());
// {T}: Add {U} or {R}.
this.addAbility(new BlueManaAbility());
this.addAbility(new RedManaAbility());
// {4}, {T}, Sacrifice this land: Draw a card.
Ability ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new GenericManaCost(4));
ability.addCost(new TapSourceCost());
ability.addCost(new SacrificeSourceCost());
this.addAbility(ability);
}
private AirshipEngineRoom(final AirshipEngineRoom card) {
super(card);
}
@Override
public AirshipEngineRoom copy() {
return new AirshipEngineRoom(this);
}
}

View file

@ -1,190 +0,0 @@
package mage.cards.a;
import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.LoyaltyAbility;
import mage.abilities.common.delayed.ReflexiveTriggeredAbility;
import mage.abilities.condition.Condition;
import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition;
import mage.abilities.dynamicvalue.common.CreaturesYouControlCount;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.effects.common.counter.AddCountersAllEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.counters.CounterType;
import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.common.FilterNonlandPermanent;
import mage.filter.predicate.mageobject.AnotherPredicate;
import mage.filter.predicate.mageobject.ColorPredicate;
import mage.filter.predicate.permanent.ControllerIdPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.game.permanent.token.CatWarrior21Token;
import mage.players.Player;
import mage.target.TargetPermanent;
import mage.target.common.TargetAnyTarget;
import mage.util.CardUtil;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author Susucr
*/
public final class AjaniNacatlAvenger extends CardImpl {
private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(SubType.CAT, "Cat you control");
public AjaniNacatlAvenger(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.AJANI);
this.setStartingLoyalty(3);
this.color.setRed(true);
this.color.setWhite(true);
this.nightCard = true;
// +2: Put a +1/+1 counter on each Cat you control.
this.addAbility(new LoyaltyAbility(
new AddCountersAllEffect(CounterType.P1P1.createInstance(), filter), 2
));
// 0: Create a 2/1 white Car Warrior creature token. When you do, if you control a red permanent other than Ajani, Nacatl Avenger, he deals damage equal to the number of creatures you control to any target.
this.addAbility(new LoyaltyAbility(new AjaniNacatlAvengerZeroEffect(), 0));
// -4: Each opponent chooses an artifact, a creature, an enchantment and a planeswalker from among the nonland permanents they control, then sacrifices the rest.
this.addAbility(new LoyaltyAbility(new AjaniNacatlAvengerMinusFourEffect(), -4));
}
private AjaniNacatlAvenger(final AjaniNacatlAvenger card) {
super(card);
}
@Override
public AjaniNacatlAvenger copy() {
return new AjaniNacatlAvenger(this);
}
}
class AjaniNacatlAvengerZeroEffect extends OneShotEffect {
private static final FilterPermanent filter = new FilterPermanent("red permanent other than {this}");
static {
filter.add(new ColorPredicate(ObjectColor.RED));
filter.add(AnotherPredicate.instance);
}
private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, true);
AjaniNacatlAvengerZeroEffect() {
super(Outcome.PutCreatureInPlay);
staticText = "Create a 2/1 white Cat Warrior creature token. "
+ "When you do, if you control a red permanent other than {this}, "
+ "he deals damage equal to the number of creatures you control to any target.";
}
private AjaniNacatlAvengerZeroEffect(final AjaniNacatlAvengerZeroEffect effect) {
super(effect);
}
@Override
public AjaniNacatlAvengerZeroEffect copy() {
return new AjaniNacatlAvengerZeroEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
if (!new CreateTokenEffect(new CatWarrior21Token()).apply(game, source)) {
return false;
}
ReflexiveTriggeredAbility reflexive = new ReflexiveTriggeredAbility(
new DamageTargetEffect(CreaturesYouControlCount.PLURAL),
false,
"When you do, if you control a red permanent other than {this}, "
+ "he deals damage equal to the number of creatures you control to any target.",
condition
);
reflexive.addTarget(new TargetAnyTarget());
game.fireReflexiveTriggeredAbility(reflexive, source);
return true;
}
}
// Inspired by Mythos of Snapdax
class AjaniNacatlAvengerMinusFourEffect extends OneShotEffect {
private static final List<CardType> cardTypes = Arrays.asList(
CardType.ARTIFACT,
CardType.CREATURE,
CardType.ENCHANTMENT,
CardType.PLANESWALKER
);
AjaniNacatlAvengerMinusFourEffect() {
super(Outcome.Benefit);
staticText = "Each opponent chooses an artifact, a creature, an enchantment and a planeswalker "
+ "from among the nonland permanents they control, then sacrifices the rest.";
}
private AjaniNacatlAvengerMinusFourEffect(final AjaniNacatlAvengerMinusFourEffect effect) {
super(effect);
}
@Override
public AjaniNacatlAvengerMinusFourEffect copy() {
return new AjaniNacatlAvengerMinusFourEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return false;
}
List<Player> playerList = game
.getOpponents(controller.getId())
.stream()
.map(game::getPlayer)
.filter(Objects::nonNull)
.collect(Collectors.toList());
Set<UUID> toKeep = new HashSet<>();
for (Player player : playerList) {
for (CardType cardType : cardTypes) {
String message = CardUtil.addArticle(cardType.toString());
FilterPermanent filter = new FilterNonlandPermanent(message);
filter.add(cardType.getPredicate());
filter.add(new ControllerIdPredicate(player.getId()));
if (game.getBattlefield().count(filter, source.getControllerId(), source, game) == 0) {
continue;
}
TargetPermanent target = new TargetPermanent(filter);
target.withNotTarget(true);
player.choose(outcome, target, source, game);
toKeep.add(target.getFirstTarget());
}
}
for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_NON_LAND, source.getControllerId(), game)) {
if (permanent == null || toKeep.contains(permanent.getId()) || !controller.hasOpponent(permanent.getControllerId(), game)) {
continue;
}
permanent.sacrifice(source, game);
}
return true;
}
}

View file

@ -1,27 +1,49 @@
package mage.cards.a; package mage.cards.a;
import mage.MageInt; import mage.ObjectColor;
import mage.constants.Pronoun; import mage.abilities.Ability;
import mage.abilities.LoyaltyAbility;
import mage.abilities.common.DiesOneOrMoreTriggeredAbility; import mage.abilities.common.DiesOneOrMoreTriggeredAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.delayed.ReflexiveTriggeredAbility;
import mage.abilities.condition.Condition;
import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition;
import mage.abilities.dynamicvalue.common.CreaturesYouControlCount;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.effects.common.ExileAndReturnSourceEffect; import mage.abilities.effects.common.ExileAndReturnSourceEffect;
import mage.abilities.keyword.TransformAbility; import mage.abilities.effects.common.counter.AddCountersAllEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.cards.TransformingDoubleFacedCard;
import mage.constants.*; import mage.constants.*;
import mage.counters.CounterType;
import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterCreaturePermanent;
import mage.filter.common.FilterNonlandPermanent;
import mage.filter.predicate.mageobject.AnotherPredicate; import mage.filter.predicate.mageobject.AnotherPredicate;
import mage.filter.predicate.mageobject.ColorPredicate;
import mage.filter.predicate.permanent.ControllerIdPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.game.permanent.token.CatWarrior21Token; import mage.game.permanent.token.CatWarrior21Token;
import mage.players.Player;
import mage.target.TargetPermanent;
import mage.target.common.TargetAnyTarget;
import mage.util.CardUtil;
import java.util.UUID; import java.util.*;
import java.util.stream.Collectors;
/** /**
* @author Susucr * @author Susucr
*/ */
public final class AjaniNacatlPariah extends CardImpl { public final class AjaniNacatlPariah extends TransformingDoubleFacedCard {
public static final FilterCreaturePermanent filter = new FilterCreaturePermanent(SubType.CAT, "other Cats you control"); public static final FilterCreaturePermanent filter = new FilterCreaturePermanent(SubType.CAT, "other Cats you control");
private static final FilterControlledCreaturePermanent nacatlAvengerFilter = new FilterControlledCreaturePermanent(SubType.CAT, "Cat you control");
static { static {
filter.add(AnotherPredicate.instance); filter.add(AnotherPredicate.instance);
@ -29,25 +51,34 @@ public final class AjaniNacatlPariah extends CardImpl {
} }
public AjaniNacatlPariah(UUID ownerId, CardSetInfo setInfo) { public AjaniNacatlPariah(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); super(ownerId, setInfo,
new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.CAT, SubType.WARRIOR}, "{1}{W}",
"Ajani, Nacatl Avenger",
new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.PLANESWALKER}, new SubType[]{SubType.AJANI}, "RW");
this.supertype.add(SuperType.LEGENDARY); this.getLeftHalfCard().setPT(1, 2);
this.subtype.add(SubType.CAT); this.getRightHalfCard().setStartingLoyalty(3);
this.subtype.add(SubType.WARRIOR);
this.power = new MageInt(1);
this.toughness = new MageInt(2);
this.secondSideCardClazz = mage.cards.a.AjaniNacatlAvenger.class;
// When Ajani, Nacatl Pariah enters the battlefield, create a 2/1 white Cat Warrior creature token. // When Ajani, Nacatl Pariah enters the battlefield, create a 2/1 white Cat Warrior creature token.
this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new CatWarrior21Token()))); this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new CatWarrior21Token())));
// Whenever one or more other Cats you control die, you may exile Ajani, then return him to the battlefield transformed under his owner's control. // Whenever one or more other Cats you control die, you may exile Ajani, then return him to the battlefield transformed under his owner's control.
this.addAbility(new TransformAbility()); this.getLeftHalfCard().addAbility(new DiesOneOrMoreTriggeredAbility(
this.addAbility(new DiesOneOrMoreTriggeredAbility(
new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED, Pronoun.HE), new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED, Pronoun.HE),
filter, filter,
true)); true));
// Ajani, Nacatl Avenger
// +2: Put a +1/+1 counter on each Cat you control.
this.getRightHalfCard().addAbility(new LoyaltyAbility(
new AddCountersAllEffect(CounterType.P1P1.createInstance(), nacatlAvengerFilter), 2
));
// 0: Create a 2/1 white Car Warrior creature token. When you do, if you control a red permanent other than Ajani, Nacatl Avenger, he deals damage equal to the number of creatures you control to any target.
this.getRightHalfCard().addAbility(new LoyaltyAbility(new AjaniNacatlAvengerZeroEffect(), 0));
// -4: Each opponent chooses an artifact, a creature, an enchantment and a planeswalker from among the nonland permanents they control, then sacrifices the rest.
this.getRightHalfCard().addAbility(new LoyaltyAbility(new AjaniNacatlAvengerMinusFourEffect(), -4));
} }
private AjaniNacatlPariah(final AjaniNacatlPariah card) { private AjaniNacatlPariah(final AjaniNacatlPariah card) {
@ -59,3 +90,116 @@ public final class AjaniNacatlPariah extends CardImpl {
return new AjaniNacatlPariah(this); return new AjaniNacatlPariah(this);
} }
} }
class AjaniNacatlAvengerZeroEffect extends OneShotEffect {
private static final FilterPermanent filter = new FilterPermanent("red permanent other than {this}");
static {
filter.add(new ColorPredicate(ObjectColor.RED));
filter.add(AnotherPredicate.instance);
}
private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, true);
AjaniNacatlAvengerZeroEffect() {
super(Outcome.PutCreatureInPlay);
staticText = "Create a 2/1 white Cat Warrior creature token. "
+ "When you do, if you control a red permanent other than {this}, "
+ "he deals damage equal to the number of creatures you control to any target.";
}
private AjaniNacatlAvengerZeroEffect(final AjaniNacatlAvengerZeroEffect effect) {
super(effect);
}
@Override
public AjaniNacatlAvengerZeroEffect copy() {
return new AjaniNacatlAvengerZeroEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
if (!new CreateTokenEffect(new CatWarrior21Token()).apply(game, source)) {
return false;
}
ReflexiveTriggeredAbility reflexive = new ReflexiveTriggeredAbility(
new DamageTargetEffect(CreaturesYouControlCount.PLURAL),
false,
"When you do, if you control a red permanent other than {this}, "
+ "he deals damage equal to the number of creatures you control to any target.",
condition
);
reflexive.addTarget(new TargetAnyTarget());
game.fireReflexiveTriggeredAbility(reflexive, source);
return true;
}
}
// Inspired by Mythos of Snapdax
class AjaniNacatlAvengerMinusFourEffect extends OneShotEffect {
private static final List<CardType> cardTypes = Arrays.asList(
CardType.ARTIFACT,
CardType.CREATURE,
CardType.ENCHANTMENT,
CardType.PLANESWALKER
);
AjaniNacatlAvengerMinusFourEffect() {
super(Outcome.Benefit);
staticText = "Each opponent chooses an artifact, a creature, an enchantment and a planeswalker "
+ "from among the nonland permanents they control, then sacrifices the rest.";
}
private AjaniNacatlAvengerMinusFourEffect(final AjaniNacatlAvengerMinusFourEffect effect) {
super(effect);
}
@Override
public AjaniNacatlAvengerMinusFourEffect copy() {
return new AjaniNacatlAvengerMinusFourEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return false;
}
List<Player> playerList = game
.getOpponents(controller.getId())
.stream()
.map(game::getPlayer)
.filter(Objects::nonNull)
.collect(Collectors.toList());
Set<UUID> toKeep = new HashSet<>();
for (Player player : playerList) {
for (CardType cardType : cardTypes) {
String message = CardUtil.addArticle(cardType.toString());
FilterPermanent filter = new FilterNonlandPermanent(message);
filter.add(cardType.getPredicate());
filter.add(new ControllerIdPredicate(player.getId()));
if (game.getBattlefield().count(filter, source.getControllerId(), source, game) == 0) {
continue;
}
TargetPermanent target = new TargetPermanent(filter);
target.withNotTarget(true);
player.choose(outcome, target, source, game);
toKeep.add(target.getFirstTarget());
}
}
for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_NON_LAND, source.getControllerId(), game)) {
if (permanent == null || toKeep.contains(permanent.getId()) || !controller.hasOpponent(permanent.getControllerId(), game)) {
continue;
}
permanent.sacrifice(source, game);
}
return true;
}
}

View file

@ -42,7 +42,7 @@ public final class AllOutAssault extends CardImpl {
extraCombatAbility.addEffect(new CreateDelayedTriggeredAbilityEffect(new WhenYouAttackDelayedTriggeredAbility( extraCombatAbility.addEffect(new CreateDelayedTriggeredAbilityEffect(new WhenYouAttackDelayedTriggeredAbility(
new UntapAllControllerEffect( new UntapAllControllerEffect(
StaticFilters.FILTER_CONTROLLED_CREATURE, "untap each creature you control"), Duration.EndOfTurn, true))); StaticFilters.FILTER_CONTROLLED_CREATURE, "untap each creature you control"), Duration.EndOfTurn, true)));
this.addAbility(extraCombatAbility.withInterveningIf(IsMainPhaseCondition.YOUR)); this.addAbility(extraCombatAbility.withInterveningIf(IsMainPhaseCondition.YOURS));
} }

View file

@ -0,0 +1,39 @@
package mage.cards.a;
import mage.abilities.effects.common.TargetsDamageTargetsEffect;
import mage.abilities.keyword.AffinityAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.AffinityType;
import mage.constants.CardType;
import mage.target.common.TargetControlledCreaturePermanent;
import mage.target.common.TargetOpponentsCreaturePermanent;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class AlliesAtLast extends CardImpl {
public AlliesAtLast(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{G}");
// Affinity for Allies
this.addAbility(new AffinityAbility(AffinityType.ALLIES));
// Up to two target creatures you control each deal damage equal to their power to target creature an opponent controls.
this.getSpellAbility().addEffect(new TargetsDamageTargetsEffect(true));
this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent(0, 2).setTargetTag(1));
this.getSpellAbility().addTarget(new TargetOpponentsCreaturePermanent().setTargetTag(3));
}
private AlliesAtLast(final AlliesAtLast card) {
super(card);
}
@Override
public AlliesAtLast copy() {
return new AlliesAtLast(this);
}
}

View file

@ -1,35 +1,60 @@
package mage.cards.a; package mage.cards.a;
import mage.MageInt; import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl; import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.TransformIntoSourceTriggeredAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.TransformSourceEffect;
import mage.abilities.keyword.TransformAbility; import mage.abilities.effects.common.continuous.BoostSourceEffect;
import mage.cards.CardImpl; import mage.abilities.effects.common.continuous.BoostTargetEffect;
import mage.abilities.effects.mana.UntilEndOfTurnManaEffect;
import mage.abilities.keyword.TrampleAbility;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.cards.TransformingDoubleFacedCard;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.Zone; import mage.constants.Zone;
import mage.filter.StaticFilters;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
import mage.target.TargetPermanent;
import java.util.UUID; import java.util.UUID;
/** /**
* @author TheElk801 * @author TheElk801
*/ */
public final class AlluringSuitor extends CardImpl { public final class AlluringSuitor extends TransformingDoubleFacedCard {
public AlluringSuitor(UUID ownerId, CardSetInfo setInfo) { public AlluringSuitor(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); super(ownerId, setInfo,
new CardType[]{CardType.CREATURE}, new SubType[]{SubType.VAMPIRE}, "{2}{R}",
this.subtype.add(SubType.VAMPIRE); "Deadly Dancer",
this.power = new MageInt(2); new CardType[]{CardType.CREATURE}, new SubType[]{SubType.VAMPIRE}, "R");
this.toughness = new MageInt(3); this.getLeftHalfCard().setPT(2, 3);
this.secondSideCardClazz = mage.cards.d.DeadlyDancer.class; this.getRightHalfCard().setPT(3, 3);
// When you attack with exactly two creatures, transform Alluring Suitor. // When you attack with exactly two creatures, transform Alluring Suitor.
this.addAbility(new TransformAbility()); this.getLeftHalfCard().addAbility(new AlluringSuitorTriggeredAbility());
this.addAbility(new AlluringSuitorTriggeredAbility());
// Deadly Dancer
// Trample
this.getRightHalfCard().addAbility(TrampleAbility.getInstance());
// When this creature transforms into Deadly Dancer, add {R}{R}. Until end of turn, you don't lose this mana as steps and phases end.
this.getRightHalfCard().addAbility(new TransformIntoSourceTriggeredAbility(new UntilEndOfTurnManaEffect(Mana.RedMana(2))));
// {R}{R}: Deadly Dancer and another target creature each get +1/+0 until end of turn.
Ability ability = new SimpleActivatedAbility(new BoostSourceEffect(
1, 0, Duration.EndOfTurn
).setText("{this}"), new ManaCostsImpl<>("{R}{R}"));
ability.addEffect(new BoostTargetEffect(1, 0)
.setText("and another target creature each get +1/+0 until end of turn"));
ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE));
this.getRightHalfCard().addAbility(ability);
} }
private AlluringSuitor(final AlluringSuitor card) { private AlluringSuitor(final AlluringSuitor card) {

View file

@ -10,10 +10,7 @@ import mage.abilities.keyword.ReachAbility;
import mage.abilities.keyword.VigilanceAbility; import mage.abilities.keyword.VigilanceAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.*;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.players.Player;
@ -42,8 +39,8 @@ public final class AloySaviorOfMeridian extends CardImpl {
this.addAbility(ReachAbility.getInstance()); this.addAbility(ReachAbility.getInstance());
// In You, All Things Are Possible -- Whenever one or more artifact creatures you control attack, discover X, where X is the greatest power among them. // In You, All Things Are Possible -- Whenever one or more artifact creatures you control attack, discover X, where X is the greatest power among them.
this.addAbility(new AttacksWithCreaturesTriggeredAbility( this.addAbility(new AttacksWithCreaturesTriggeredAbility(Zone.BATTLEFIELD,
new AloySaviorOfMeridianEffect(), 1, StaticFilters.FILTER_PERMANENT_ARTIFACT_CREATURE new AloySaviorOfMeridianEffect(), 1, StaticFilters.FILTER_PERMANENT_ARTIFACT_CREATURE, true
).setTriggerPhrase("Whenever one or more artifact creatures you control attack, ").withFlavorWord("In You, All Things Are Possible")); ).setTriggerPhrase("Whenever one or more artifact creatures you control attack, ").withFlavorWord("In You, All Things Are Possible"));
} }

View file

@ -1,45 +1,63 @@
package mage.cards.a; package mage.cards.a;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.common.SacrificeTargetCost;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ReturnSourceFromGraveyardToHandEffect; import mage.abilities.effects.common.ReturnSourceFromGraveyardToHandEffect;
import mage.abilities.keyword.CraftAbility; import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffect;
import mage.cards.CardImpl; import mage.abilities.keyword.*;
import mage.cards.Card;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.cards.TransformingDoubleFacedCard;
import mage.constants.Outcome; import mage.constants.*;
import mage.constants.Zone;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.game.ExileZone;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import mage.util.CardUtil;
import java.util.Set;
import java.util.UUID;
/** /**
* *
* @author jeffwadsworth * @author jeffwadsworth
*/ */
public final class AltarOfTheWretched extends CardImpl { public final class AltarOfTheWretched extends TransformingDoubleFacedCard {
public AltarOfTheWretched(UUID ownerId, CardSetInfo setInfo) { public AltarOfTheWretched(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{B}"); super(ownerId, setInfo,
this.secondSideCardClazz = mage.cards.w.WretchedBonemass.class; new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{2}{B}",
"Wretched Bonemass",
new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SKELETON, SubType.HORROR}, "B");
this.getRightHalfCard().setPT(0, 0);
// When Altar of the Wretched enters the battlefield, you may sacrifice a nontoken creature. If you do, draw X cards, then mill X cards, where X is that creatures power. // When Altar of the Wretched enters the battlefield, you may sacrifice a nontoken creature. If you do, draw X cards, then mill X cards, where X is that creatures power.
this.addAbility(new EntersBattlefieldTriggeredAbility(new AltarOfTheWretchedEffect(), true)); this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new AltarOfTheWretchedEffect(), true));
// Craft with one or more creatures {2}{B}{B} // Craft with one or more creatures {2}{B}{B}
this.addAbility(new CraftAbility( this.getLeftHalfCard().addAbility(new CraftAbility(
"{2}{B}{B}", "one or more creatures", "other creatures you control and/or" "{2}{B}{B}", "one or more creatures", "other creatures you control and/or"
+ "creature cards in your graveyard", 1, Integer.MAX_VALUE, CardType.CREATURE.getPredicate() + "creature cards in your graveyard", 1, Integer.MAX_VALUE, CardType.CREATURE.getPredicate()
)); ));
// {2}{B}: Return Altar of the Wretched from your graveyard to your hand. // {2}{B}: Return Altar of the Wretched from your graveyard to your hand.
this.addAbility(new SimpleActivatedAbility(Zone.GRAVEYARD, new ReturnSourceFromGraveyardToHandEffect(), new ManaCostsImpl<>("{2}{B}"))); this.getLeftHalfCard().addAbility(new SimpleActivatedAbility(Zone.GRAVEYARD, new ReturnSourceFromGraveyardToHandEffect(), new ManaCostsImpl<>("{2}{B}")));
// Wretched Bonemass
// Wretched Bonemasss power and toughness are each equal to the total power of the exiled cards used to craft it.
this.getRightHalfCard().addAbility(new SimpleStaticAbility(new SetBasePowerToughnessSourceEffect(WretchedBonemassDynamicValue.instance).setText("{this}'s power and toughness are each equal to the total power of the exiled cards used to craft it.")));
// Wretched Bonemass has flying as long as an exiled card used to craft it has flying. The same is true for first strike, double strike, deathtouch, haste, hexproof, indestructible, lifelink, menace, protection, reach, trample, and vigilance.
this.getRightHalfCard().addAbility(new SimpleStaticAbility(new WretchedBonemassGainAbilityEffect()));
} }
private AltarOfTheWretched(final AltarOfTheWretched card) { private AltarOfTheWretched(final AltarOfTheWretched card) {
@ -84,3 +102,124 @@ class AltarOfTheWretchedEffect extends OneShotEffect {
return new AltarOfTheWretchedEffect(this); return new AltarOfTheWretchedEffect(this);
} }
} }
enum WretchedBonemassDynamicValue implements DynamicValue {
instance;
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
int totalPower = 0;
Permanent permanent = sourceAbility.getSourcePermanentIfItStillExists(game);
if (permanent == null) {
return 0;
}
ExileZone exileZone = game
.getExile()
.getExileZone(CardUtil.getExileZoneId(
game, permanent.getMainCard().getId(), permanent.getZoneChangeCounter(game) - 1
));
if (exileZone == null) {
return 0;
}
for (Card card : exileZone.getCards(game)) {
totalPower += card.getPower().getValue();
}
return totalPower;
}
@Override
public WretchedBonemassDynamicValue copy() {
return this;
}
@Override
public String getMessage() {
return "total power of the exiled cards used to craft it";
}
@Override
public String toString() {
return "0";
}
}
class WretchedBonemassGainAbilityEffect extends ContinuousEffectImpl {
WretchedBonemassGainAbilityEffect() {
super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility);
staticText = "{this} has flying as long as an exiled card used to craft it has flying. The same is true for first strike, double strike, deathtouch, haste, hexproof, indestructible, lifelink, menace, protection, reach, trample, and vigilance.";
}
private WretchedBonemassGainAbilityEffect(final WretchedBonemassGainAbilityEffect effect) {
super(effect);
}
@Override
public WretchedBonemassGainAbilityEffect copy() {
return new WretchedBonemassGainAbilityEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent wretchedBonemass = source.getSourcePermanentIfItStillExists(game);
if (wretchedBonemass != null) {
ExileZone exileZone = game
.getExile()
.getExileZone(CardUtil.getExileZoneId(
game, wretchedBonemass.getMainCard().getId(), wretchedBonemass.getZoneChangeCounter(game) - 1
));
if (exileZone != null
&& !exileZone.isEmpty()) {
Set<Card> cardsInExile = exileZone.getCards(game);
for (Card card : cardsInExile) {
for (Ability a : card.getAbilities()) {
if (a instanceof FlyingAbility) {
wretchedBonemass.addAbility(a, source.getSourceId(), game);
}
if (a instanceof FirstStrikeAbility) {
wretchedBonemass.addAbility(a, source.getSourceId(), game);
}
if (a instanceof DoubleStrikeAbility) {
wretchedBonemass.addAbility(a, source.getSourceId(), game);
}
if (a instanceof DeathtouchAbility) {
wretchedBonemass.addAbility(a, source.getSourceId(), game);
}
if (a instanceof HasteAbility) {
wretchedBonemass.addAbility(a, source.getSourceId(), game);
}
if (a instanceof HexproofAbility) {
wretchedBonemass.addAbility(a, source.getSourceId(), game);
}
if (a instanceof IndestructibleAbility) {
wretchedBonemass.addAbility(a, source.getSourceId(), game);
}
if (a instanceof LifelinkAbility) {
wretchedBonemass.addAbility(a, source.getSourceId(), game);
}
if (a instanceof MenaceAbility) {
wretchedBonemass.addAbility(a, source.getSourceId(), game);
}
if (a instanceof ProtectionAbility) {
wretchedBonemass.addAbility(a, source.getSourceId(), game);
}
if (a instanceof IndestructibleAbility) {
wretchedBonemass.addAbility(a, source.getSourceId(), game);
}
if (a instanceof ReachAbility) {
wretchedBonemass.addAbility(a, source.getSourceId(), game);
}
if (a instanceof TrampleAbility) {
wretchedBonemass.addAbility(a, source.getSourceId(), game);
}
if (a instanceof VigilanceAbility) {
wretchedBonemass.addAbility(a, source.getSourceId(), game);
}
}
}
}
}
return true;
}
}

View file

@ -10,8 +10,7 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.cards.CardsImpl; import mage.cards.CardsImpl;
import mage.constants.*; import mage.constants.*;
import mage.filter.FilterPermanent; import mage.filter.StaticFilters;
import mage.filter.predicate.mageobject.AnotherPredicate;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
@ -23,12 +22,6 @@ import java.util.UUID;
*/ */
public final class AmarethTheLustrous extends CardImpl { public final class AmarethTheLustrous extends CardImpl {
private static final FilterPermanent filter = new FilterPermanent("another permanent");
static {
filter.add(AnotherPredicate.instance);
}
public AmarethTheLustrous(UUID ownerId, CardSetInfo setInfo) { public AmarethTheLustrous(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{W}{U}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{W}{U}");
@ -41,7 +34,9 @@ public final class AmarethTheLustrous extends CardImpl {
this.addAbility(FlyingAbility.getInstance()); this.addAbility(FlyingAbility.getInstance());
// Whenever another permanent you control enters, look at the top card of your library. If it shares a card type with that permanent, you may reveal that card and put it into your hand. // Whenever another permanent you control enters, look at the top card of your library. If it shares a card type with that permanent, you may reveal that card and put it into your hand.
this.addAbility(new EntersBattlefieldControlledTriggeredAbility(new AmarethTheLustrousEffect(), filter)); this.addAbility(new EntersBattlefieldControlledTriggeredAbility(
new AmarethTheLustrousEffect(), StaticFilters.FILTER_ANOTHER_PERMANENT
));
} }
private AmarethTheLustrous(final AmarethTheLustrous card) { private AmarethTheLustrous(final AmarethTheLustrous card) {

View file

@ -1,6 +1,5 @@
package mage.cards.a; package mage.cards.a;
import mage.MageInt;
import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.common.ActivateIfConditionActivatedAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.condition.common.CovenCondition; import mage.abilities.condition.common.CovenCondition;
@ -8,9 +7,9 @@ import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.TransformSourceEffect;
import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect;
import mage.abilities.hint.common.CovenHint; import mage.abilities.hint.common.CovenHint;
import mage.abilities.keyword.TransformAbility; import mage.abilities.keyword.LifelinkAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.cards.TransformingDoubleFacedCard;
import mage.constants.AbilityWord; import mage.constants.AbilityWord;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
@ -22,27 +21,31 @@ import java.util.UUID;
/** /**
* @author TheElk801 * @author TheElk801
*/ */
public final class AmbitiousFarmhand extends CardImpl { public final class AmbitiousFarmhand extends TransformingDoubleFacedCard {
public AmbitiousFarmhand(UUID ownerId, CardSetInfo setInfo) { public AmbitiousFarmhand(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.PEASANT}, "{1}{W}",
"Seasoned Cathar",
new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.KNIGHT}, "W");
this.subtype.add(SubType.HUMAN); // Ambitious Farmhand
this.subtype.add(SubType.PEASANT); this.getLeftHalfCard().setPT(1, 1);
this.power = new MageInt(1);
this.toughness = new MageInt(1);
this.secondSideCardClazz = mage.cards.s.SeasonedCathar.class;
// When Ambitious Farmhand enters the battlefield, you may search your library for a basic Plains card, reveal it, put it into your hand, then shuffle. // When Ambitious Farmhand enters the battlefield, you may search your library for a basic Plains card, reveal it, put it into your hand, then shuffle.
this.addAbility(new EntersBattlefieldTriggeredAbility( this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(
new SearchLibraryPutInHandEffect(new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_PLAINS), true), true new SearchLibraryPutInHandEffect(new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_PLAINS), true), true
)); ));
// Coven{1}{W}{W}: Transform Ambitious Farmhand. Activate only if you control three or more creatures with different powers. // Coven{1}{W}{W}: Transform Ambitious Farmhand. Activate only if you control three or more creatures with different powers.
this.addAbility(new TransformAbility()); this.getLeftHalfCard().addAbility(new ActivateIfConditionActivatedAbility(
this.addAbility(new ActivateIfConditionActivatedAbility(
new TransformSourceEffect(), new ManaCostsImpl<>("{1}{W}{W}"), CovenCondition.instance new TransformSourceEffect(), new ManaCostsImpl<>("{1}{W}{W}"), CovenCondition.instance
).setAbilityWord(AbilityWord.COVEN).addHint(CovenHint.instance)); ).setAbilityWord(AbilityWord.COVEN).addHint(CovenHint.instance));
// Seasoned Cathar
this.getRightHalfCard().setPT(3, 3);
// Lifelink
this.getRightHalfCard().addAbility(LifelinkAbility.getInstance());
} }
private AmbitiousFarmhand(final AmbitiousFarmhand card) { private AmbitiousFarmhand(final AmbitiousFarmhand card) {

View file

@ -1,18 +1,22 @@
package mage.cards.a; package mage.cards.a;
import mage.MageInt; import mage.MageObjectReference;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.common.ActivateAsSorceryActivatedAbility;
import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.common.DiesCreatureTriggeredAbility; import mage.abilities.common.DiesCreatureTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.common.SacrificeTargetCost;
import mage.abilities.dynamicvalue.common.CountersSourceCount;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.ReplacementEffectImpl;
import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.TransformSourceEffect;
import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.keyword.TransformAbility; import mage.abilities.keyword.LifelinkAbility;
import mage.cards.CardImpl; import mage.abilities.keyword.MenaceAbility;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.cards.TransformingDoubleFacedCard;
import mage.constants.*; import mage.constants.*;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
@ -20,38 +24,45 @@ import mage.game.Game;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
import mage.game.events.ZoneChangeEvent; import mage.game.events.ZoneChangeEvent;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.target.common.TargetControlledCreaturePermanent;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
import java.util.Iterator;
import java.util.UUID; import java.util.UUID;
/** /**
* @author Styxo * @author Styxo
*/ */
public final class AnakinSkywalker extends CardImpl { public final class AnakinSkywalker extends TransformingDoubleFacedCard {
public AnakinSkywalker(UUID ownerId, CardSetInfo setInfo) { public AnakinSkywalker(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{B}{R}"); super(ownerId, setInfo,
this.supertype.add(SuperType.LEGENDARY); new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.SITH}, "{3}{U}{B}{R}",
this.subtype.add(SubType.HUMAN); "Darth Vader",
this.subtype.add(SubType.SITH); new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.SITH}, "B");
this.power = new MageInt(4); this.getLeftHalfCard().setPT(4, 4);
this.toughness = new MageInt(4); this.getRightHalfCard().setPT(4, 4);
this.secondSideCardClazz = mage.cards.d.DarthVader.class;
// Whenever another creature dies, put a +1/+1 counter on Anakin Skywalker. // Whenever another creature dies, put a +1/+1 counter on Anakin Skywalker.
this.addAbility(new DiesCreatureTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false, true)); this.getLeftHalfCard().addAbility(new DiesCreatureTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false, true));
// Sacrifice another creature: Target creature gets -1/-1 until end of turn. Activate this ability only as a sorcery. // Sacrifice another creature: Target creature gets -1/-1 until end of turn. Activate this ability only as a sorcery.
Ability ability = new ActivateAsSorceryActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(-1, -1, Duration.EndOfTurn), Ability ability = new ActivateAsSorceryActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(-1, -1, Duration.EndOfTurn),
new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE)); new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE));
ability.addTarget(new TargetCreaturePermanent()); ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability); this.getLeftHalfCard().addAbility(ability);
// If Anakin Skywalker would be destroyed, regenerate, then transform him instead. // If Anakin Skywalker would be destroyed, regenerate, then transform him instead.
this.addAbility(new TransformAbility()); this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new AnakinSkywalkerEffect()));
this.addAbility(new SimpleStaticAbility(new AnakinSkywalkerEffect()));
// Darth Vader
// Menace
this.getRightHalfCard().addAbility(new MenaceAbility());
// Lifelink
this.getRightHalfCard().addAbility(LifelinkAbility.getInstance());
// Whenever Darth Vader attacks, creatures defending player controls get -1/-1 until end of turn for each +1/+1 counter on Darth Vader.
this.getRightHalfCard().addAbility(new AttacksTriggeredAbility(new UnboostCreaturesDefendingPlayerEffect(), false, null, SetTargetPointer.PLAYER));
} }
@ -101,3 +112,47 @@ class AnakinSkywalkerEffect extends ReplacementEffectImpl {
return new AnakinSkywalkerEffect(this); return new AnakinSkywalkerEffect(this);
} }
} }
class UnboostCreaturesDefendingPlayerEffect extends ContinuousEffectImpl {
UnboostCreaturesDefendingPlayerEffect() {
super(Duration.EndOfTurn, Layer.PTChangingEffects_7, SubLayer.ModifyPT_7c, Outcome.UnboostCreature);
staticText = "creatures defending player controls get -1/-1 until end of turn for each +1/+1 counter on Darth Vader";
}
private UnboostCreaturesDefendingPlayerEffect(final UnboostCreaturesDefendingPlayerEffect effect) {
super(effect);
}
@Override
public UnboostCreaturesDefendingPlayerEffect copy() {
return new UnboostCreaturesDefendingPlayerEffect(this);
}
@Override
public void init(Ability source, Game game) {
super.init(source, game);
if (getAffectedObjectsSet()) {
for (Permanent creature : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, getTargetPointer().getFirst(game, source), game)) {
affectedObjectList.add(new MageObjectReference(creature, game));
}
}
}
@Override
public boolean apply(Game game, Ability source) {
for (Iterator<MageObjectReference> it = affectedObjectList.iterator(); it.hasNext(); ) {
Permanent permanent = it.next().getPermanent(game);
if (permanent != null) {
int unboostCount = -1 * new CountersSourceCount(CounterType.P1P1).calculate(game, source, this);
permanent.addPower(unboostCount);
permanent.addToughness(unboostCount);
} else {
it.remove();
}
}
return true;
}
}

View file

@ -1,52 +0,0 @@
package mage.cards.a;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.AttachEffect;
import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect;
import mage.abilities.keyword.DisturbAbility;
import mage.abilities.keyword.EnchantAbility;
import mage.abilities.keyword.LifelinkAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.target.TargetPermanent;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class AncestorsEmbrace extends CardImpl {
public AncestorsEmbrace(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "");
this.subtype.add(SubType.AURA);
this.color.setWhite(true);
this.nightCard = true;
// Enchant creature
TargetPermanent auraTarget = new TargetCreaturePermanent();
this.getSpellAbility().addTarget(auraTarget);
this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature));
this.addAbility(new EnchantAbility(auraTarget));
// Enchanted creature has lifelink.
this.addAbility(new SimpleStaticAbility(new GainAbilityAttachedEffect(
LifelinkAbility.getInstance(), AttachmentType.AURA, Duration.WhileOnBattlefield
)));
// If Ancestor's Embrace would be put into a graveyard from anywhere, exile it instead.
this.addAbility(DisturbAbility.makeBackAbility());
}
private AncestorsEmbrace(final AncestorsEmbrace card) {
super(card);
}
@Override
public AncestorsEmbrace copy() {
return new AncestorsEmbrace(this);
}
}

View file

@ -1,42 +0,0 @@
package mage.cards.a;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.keyword.HexproofAbility;
import mage.abilities.keyword.TrampleAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
/**
*
* @author LevelX2
*/
public final class AncientOfTheEquinox extends CardImpl {
public AncientOfTheEquinox(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"");
this.subtype.add(SubType.TREEFOLK);
this.power = new MageInt(4);
this.toughness = new MageInt(4);
this.color.setGreen(true);
this.nightCard = true;
// Trample
this.addAbility(TrampleAbility.getInstance());
// Hexproof
this.addAbility(HexproofAbility.getInstance());
}
private AncientOfTheEquinox(final AncientOfTheEquinox card) {
super(card);
}
@Override
public AncientOfTheEquinox copy() {
return new AncientOfTheEquinox(this);
}
}

View file

@ -1,59 +0,0 @@
package mage.cards.a;
import mage.MageInt;
import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.dynamicvalue.common.ControllerLifeCount;
import mage.abilities.effects.common.GainLifeEffect;
import mage.abilities.effects.common.continuous.GainAbilityControllerEffect;
import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.HexproofAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Zone;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class AngelicEnforcer extends CardImpl {
public AngelicEnforcer(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "");
this.subtype.add(SubType.ANGEL);
this.power = new MageInt(0);
this.toughness = new MageInt(0);
this.color.setWhite(true);
this.nightCard = true;
// Flying
this.addAbility(FlyingAbility.getInstance());
// You have hexproof.
this.addAbility(new SimpleStaticAbility(new GainAbilityControllerEffect(HexproofAbility.getInstance())));
// Angelic Enforcer's power and toughness are each equal to your life total.
this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerToughnessSourceEffect(
ControllerLifeCount.instance
).setText("{this}'s power and toughness are each equal to your life total")));
// Whenever Angelic Enforcer attacks, double your life total.
this.addAbility(new AttacksTriggeredAbility(new GainLifeEffect(
ControllerLifeCount.instance
).setText("double your life total")));
}
private AngelicEnforcer(final AngelicEnforcer card) {
super(card);
}
@Override
public AngelicEnforcer copy() {
return new AngelicEnforcer(this);
}
}

View file

@ -1,92 +0,0 @@
package mage.cards.a;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.CardsInAllGraveyardsCount;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.common.continuous.BoostSourceEffect;
import mage.abilities.hint.Hint;
import mage.abilities.keyword.MenaceAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.filter.FilterCard;
import mage.filter.StaticFilters;
import mage.filter.common.FilterCreatureCard;
import mage.filter.predicate.card.DefendingPlayerOwnsCardPredicate;
import mage.game.Game;
import java.util.Objects;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* @author TheElk801
*/
public final class AnimusOfNightsReach extends CardImpl {
private static final FilterCard filter
= new FilterCreatureCard("creature cards in defending player's graveyard");
static {
filter.add(DefendingPlayerOwnsCardPredicate.instance);
}
private static final DynamicValue xValue = new CardsInAllGraveyardsCount(filter);
public AnimusOfNightsReach(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, "");
this.subtype.add(SubType.SPIRIT);
this.power = new MageInt(0);
this.toughness = new MageInt(4);
this.color.setBlack(true);
this.nightCard = true;
// Menace
this.addAbility(new MenaceAbility());
// Whenever Animus of Night's Reach attacks, it gets +X/+0 until end of turn, where X is the number of creature cards in defending player's graveyard.
this.addAbility(new AttacksTriggeredAbility(new BoostSourceEffect(
xValue, StaticValue.get(0), Duration.EndOfTurn
).setText("it gets +X/+0 until end of turn, where X is the number of creature cards in defending player's graveyard")).addHint(AnimusOfNightsReachHint.instance));
}
private AnimusOfNightsReach(final AnimusOfNightsReach card) {
super(card);
}
@Override
public AnimusOfNightsReach copy() {
return new AnimusOfNightsReach(this);
}
}
enum AnimusOfNightsReachHint implements Hint {
instance;
@Override
public String getText(Game game, Ability ability) {
return "Cards in each opponent's graveyard:<br>"
+ game
.getOpponents(ability.getControllerId())
.stream()
.map(game::getPlayer)
.filter(Objects::nonNull)
.map(player -> player
.getName()
+ ": " + player
.getGraveyard()
.count(StaticFilters.FILTER_CARD_CREATURE, game))
.collect(Collectors.joining("<br>"));
}
@Override
public AnimusOfNightsReachHint copy() {
return instance;
}
}

View file

@ -2,17 +2,15 @@ package mage.cards.a;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.OneShotNonTargetEffect;
import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.players.Player;
import mage.target.TargetCard;
import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetCardInYourGraveyard;
import java.util.UUID; import java.util.UUID;
@ -26,7 +24,9 @@ public final class AnotherChance extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{B}"); super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{B}");
// You may mill two cards. Then return up to two creature cards from your graveyard to your hand. // You may mill two cards. Then return up to two creature cards from your graveyard to your hand.
this.getSpellAbility().addEffect(new AnotherChanceEffect()); this.getSpellAbility().addEffect(new AnotherChanceMillEffect());
this.getSpellAbility().addEffect(new OneShotNonTargetEffect(new ReturnFromGraveyardToHandTargetEffect().setText("Then return up to two creature cards from your graveyard to your hand."),
new TargetCardInYourGraveyard(0, 2, StaticFilters.FILTER_CARD_CREATURES_YOUR_GRAVEYARD, true)).withTargetDescription("up to two creature cards"));
} }
private AnotherChance(final AnotherChance card) { private AnotherChance(final AnotherChance card) {
@ -39,23 +39,20 @@ public final class AnotherChance extends CardImpl {
} }
} }
/** class AnotherChanceMillEffect extends OneShotEffect {
* Inspired by {@link mage.cards.u.UnsealTheNecropolis}
*/
class AnotherChanceEffect extends OneShotEffect {
AnotherChanceEffect() { AnotherChanceMillEffect() {
super(Outcome.Benefit); super(Outcome.Benefit);
staticText = "You may mill two cards. Then return up to two creature cards from your graveyard to your hand"; staticText = "You may mill two cards.";
} }
private AnotherChanceEffect(final AnotherChanceEffect effect) { private AnotherChanceMillEffect(final AnotherChanceMillEffect effect) {
super(effect); super(effect);
} }
@Override @Override
public AnotherChanceEffect copy() { public AnotherChanceMillEffect copy() {
return new AnotherChanceEffect(this); return new AnotherChanceMillEffect(this);
} }
@Override @Override
@ -68,18 +65,6 @@ class AnotherChanceEffect extends OneShotEffect {
if (player.chooseUse(outcome, "Mill two cards?", source, game)) { if (player.chooseUse(outcome, "Mill two cards?", source, game)) {
player.millCards(2, source, game); player.millCards(2, source, game);
} }
// Make sure the mill has been processed.
game.processAction();
TargetCard target = new TargetCardInYourGraveyard(
0, 2, StaticFilters.FILTER_CARD_CREATURES_YOUR_GRAVEYARD, true
);
player.choose(outcome, target, source, game);
Cards cards = new CardsImpl(target.getTargets());
if (!cards.isEmpty()) {
player.moveCards(cards, Zone.HAND, source, game);
}
return true; return true;
} }
} }

View file

@ -1,241 +0,0 @@
package mage.cards.a;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.AsEntersBattlefieldAbility;
import mage.abilities.common.EntersBattlefieldTappedAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.choices.Choice;
import mage.choices.ChoiceCardType;
import mage.constants.*;
import mage.game.ExileZone;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.util.CardUtil;
import java.util.*;
import java.util.stream.Collectors;
import mage.abilities.SpellAbility;
import mage.abilities.effects.common.cost.CostModificationEffectImpl;
/**
* @author jeffwadsworth
*/
public class ApexObservatory extends CardImpl {
public ApexObservatory(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, null);
this.nightCard = true;
// Apex Observatory enters the battlefield tapped.
this.addAbility(new EntersBattlefieldTappedAbility());
// As it enters, choose a card type shared among two exiled cards used to craft it.
this.addAbility(new AsEntersBattlefieldAbility(new ChooseCardTypeEffect()));
// The next spell you cast this turn of the chosen type can be cast without paying its mana cost.
this.addAbility(new SimpleActivatedAbility(new ApexObservatoryEffect(), new TapSourceCost()));
}
private ApexObservatory(final ApexObservatory card) {
super(card);
}
@Override
public ApexObservatory copy() {
return new ApexObservatory(this);
}
}
class ChooseCardTypeEffect extends OneShotEffect {
public ChooseCardTypeEffect() {
super(Outcome.Neutral);
staticText = "choose a card type shared among two exiled cards used to craft it.";
}
protected ChooseCardTypeEffect(final ChooseCardTypeEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
MageObject mageObject = game.getPermanentEntering(source.getSourceId());
List<CardType> exiledCardsCardType = new ArrayList<>();
if (mageObject == null) {
mageObject = game.getObject(source);
}
if (controller != null && mageObject != null) {
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
if (permanent == null) {
return false;
}
// chase the exile zone down...
ExileZone exileZone = game.getState().getExile().getExileZone(CardUtil.getExileZoneId(game, source, game.getState().getZoneChangeCounter(mageObject.getId()) - 1));
if (exileZone == null) {
return false;
}
for (Card card : exileZone.getCards(game)) {
exiledCardsCardType.addAll(card.getCardType(game));
}
Choice cardTypeChoice = new ChoiceCardType();
cardTypeChoice.getChoices().clear();
cardTypeChoice.getChoices().addAll(exiledCardsCardType.stream().map(CardType::toString).collect(Collectors.toList()));
// find only card types that each card shares; some cards have more than 1 card type
Map<String, Integer> cardTypeCounts = new HashMap<>();
for (String cardType : cardTypeChoice.getChoices()) {
cardTypeCounts.put(cardType, 0);
}
for (Card c : exileZone.getCards(game)) {
for (CardType cardType : c.getCardType(game)) {
if (cardTypeCounts.containsKey(cardType.toString())) {
cardTypeCounts.put(cardType.toString(), cardTypeCounts.get(cardType.toString()) + 1);
}
}
}
List<String> sharedCardTypes = new ArrayList<>();
int numExiledCards = exileZone.getCards(game).size();
for (Map.Entry<String, Integer> entry : cardTypeCounts.entrySet()) {
if (entry.getValue() == numExiledCards) {
sharedCardTypes.add(entry.getKey());
}
}
// handle situations like the double-faced instant/land Jwari Disruption // Jwari Ruins
if (sharedCardTypes.isEmpty()) {
game.informPlayers(mageObject.getIdName() + " No exiled cards shared a type in exile, so nothing is done.");
if (mageObject instanceof Permanent) {
((Permanent) mageObject).addInfo("chosen type", CardUtil.addToolTipMarkTags("No exiled cards have the same card type."), game);
}
return false;
}
cardTypeChoice.getChoices().retainAll(sharedCardTypes);
if (controller.choose(Outcome.Benefit, cardTypeChoice, game)) {
if (!game.isSimulation()) {
game.informPlayers(mageObject.getName() + ": " + controller.getLogName() + " has chosen " + cardTypeChoice.getChoice());
}
game.getState().setValue("ApexObservatoryType_" + source.getSourceId().toString(), cardTypeChoice.getChoice());
if (mageObject instanceof Permanent) {
((Permanent) mageObject).addInfo("chosen type", CardUtil.addToolTipMarkTags("Chosen card type: " + cardTypeChoice.getChoice()), game);
}
return true;
}
}
return false;
}
@Override
public ChooseCardTypeEffect copy() {
return new ChooseCardTypeEffect(this);
}
}
class ApexObservatoryEffect extends OneShotEffect {
ApexObservatoryEffect() {
super(Outcome.Benefit);
staticText = "The next spell you cast this turn of the chosen type can be cast without paying its mana cost.";
}
private ApexObservatoryEffect(final ApexObservatoryEffect effect) {
super(effect);
}
@Override
public ApexObservatoryEffect copy() {
return new ApexObservatoryEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
String chosenCardType = (String) game.getState().getValue("ApexObservatoryType_" + source.getSourceId().toString());
if (chosenCardType == null) {
return false;
}
game.addEffect(new ApexObservatoryCastWithoutManaEffect(chosenCardType, source.getControllerId()), source);
return true;
}
}
class ApexObservatoryCastWithoutManaEffect extends CostModificationEffectImpl {
private final String chosenCardType;
private final UUID playerId;
private boolean used = false;
ApexObservatoryCastWithoutManaEffect(String chosenCardType, UUID playerId) {
super(Duration.EndOfTurn, Outcome.Benefit, CostModificationType.SET_COST);
this.chosenCardType = chosenCardType;
this.playerId = playerId;
staticText = "The next spell you cast this turn of the chosen type can be cast without paying its mana cost";
}
private ApexObservatoryCastWithoutManaEffect(final ApexObservatoryCastWithoutManaEffect effect) {
super(effect);
this.chosenCardType = effect.chosenCardType;
this.playerId = effect.playerId;
this.used = effect.used;
}
@Override
public boolean apply(Game game, Ability source, Ability abilityToModify) {
// Ask the player if they want to use the effect
Player controller = game.getPlayer(playerId);
if (controller != null) {
MageObject spell = abilityToModify.getSourceObject(game);
if (spell != null && !game.isSimulation()) {
String message = "Cast " + spell.getIdName() + " without paying its mana cost?";
if (controller.chooseUse(Outcome.Benefit, message, source, game)) {
// Set the cost to zero
abilityToModify.getManaCostsToPay().clear();
// Mark as used
used = true;
game.informPlayers(controller.getLogName() + " casts " + spell.getIdName() + " without paying its mana cost.");
return true;
} else {
// Player chose not to use the effect
return false;
}
}
}
return false;
}
@Override
public ApexObservatoryCastWithoutManaEffect copy() {
return new ApexObservatoryCastWithoutManaEffect(this);
}
@Override
public boolean isInactive(Ability source, Game game) {
return used || super.isInactive(source, game);
}
@Override
public boolean applies(Ability ability, Ability source, Game game) {
if (used) {
return false;
}
if (!ability.isControlledBy(playerId)) {
return false;
}
if (!(ability instanceof SpellAbility)) {
return false;
}
MageObject object = game.getObject(ability.getSourceId());
if (object != null && object.getCardType(game).stream()
.anyMatch(cardType -> cardType.toString().equals(chosenCardType))) {
return true;
}
return false;
}
}

View file

@ -0,0 +1,66 @@
package mage.cards.a;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.Mode;
import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility;
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
import mage.abilities.effects.keyword.AirbendTargetEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.constants.TargetController;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterNonlandPermanent;
import mage.filter.predicate.mageobject.AnotherPredicate;
import mage.target.TargetPermanent;
import mage.target.common.TargetControlledCreaturePermanent;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class AppaLoyalSkyBison extends CardImpl {
private static final FilterPermanent filter = new FilterNonlandPermanent("another target nonland permanent you control");
static {
filter.add(AnotherPredicate.instance);
filter.add(TargetController.YOU.getControllerPredicate());
}
public AppaLoyalSkyBison(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}{W}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.BISON);
this.subtype.add(SubType.ALLY);
this.power = new MageInt(4);
this.toughness = new MageInt(4);
// Flying
this.addAbility(FlyingAbility.getInstance());
// Whenever Appa enters or attacks, choose one --
// * Target creature you control gains flying until end of turn.
Ability ability = new EntersBattlefieldOrAttacksSourceTriggeredAbility(new GainAbilityTargetEffect(FlyingAbility.getInstance()));
ability.addTarget(new TargetControlledCreaturePermanent());
// * Airbend another target nonland permanent you control.
ability.addMode(new Mode(new AirbendTargetEffect()).addTarget(new TargetPermanent(filter)));
this.addAbility(ability);
}
private AppaLoyalSkyBison(final AppaLoyalSkyBison card) {
super(card);
}
@Override
public AppaLoyalSkyBison copy() {
return new AppaLoyalSkyBison(this);
}
}

View file

@ -0,0 +1,68 @@
package mage.cards.a;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldThisOrAnotherTriggeredAbility;
import mage.abilities.effects.common.continuous.BoostControlledEffect;
import mage.abilities.effects.common.continuous.GainAbilityControlledEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.VigilanceAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class AppaTheVigilant extends CardImpl {
private static final FilterPermanent filter = new FilterPermanent(SubType.ALLY, "Ally");
public AppaTheVigilant(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{W}{W}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.BISON);
this.subtype.add(SubType.ALLY);
this.power = new MageInt(6);
this.toughness = new MageInt(6);
// Flying
this.addAbility(FlyingAbility.getInstance());
// Vigilance
this.addAbility(VigilanceAbility.getInstance());
// Whenever Appa or another Ally you control enters, creatures you control get +1/+1 and gain flying and vigilance until end of turn.
Ability ability = new EntersBattlefieldThisOrAnotherTriggeredAbility(
new BoostControlledEffect(1, 1, Duration.EndOfTurn)
.setText("creatures you control get +1/+1"),
filter, false, true
);
ability.addEffect(new GainAbilityControlledEffect(
FlyingAbility.getInstance(), Duration.EndOfTurn,
StaticFilters.FILTER_PERMANENT_CREATURE
).setText("and gain flying"));
ability.addEffect(new GainAbilityControlledEffect(
VigilanceAbility.getInstance(), Duration.EndOfTurn,
StaticFilters.FILTER_PERMANENT_CREATURE
).setText("and vigilance until end of turn"));
this.addAbility(ability);
}
private AppaTheVigilant(final AppaTheVigilant card) {
super(card);
}
@Override
public AppaTheVigilant copy() {
return new AppaTheVigilant(this);
}
}

View file

@ -0,0 +1,132 @@
package mage.cards.a;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.hint.Hint;
import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.constants.WatcherScope;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.stack.Spell;
import mage.watchers.Watcher;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author TheElk801
*/
public final class AprilONeilHacktivist extends CardImpl {
public AprilONeilHacktivist(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.SCIENTIST);
this.power = new MageInt(1);
this.toughness = new MageInt(5);
// At the beginning of your end step, draw a card for each card type among spells you've cast this turn.
this.addAbility(new BeginningOfEndStepTriggeredAbility(
new DrawCardSourceControllerEffect(AprilONeilHacktivistValue.instance)
).addHint(AprilONeilHacktivistHint.instance), new AprilONeilHacktivistWatcher());
}
private AprilONeilHacktivist(final AprilONeilHacktivist card) {
super(card);
}
@Override
public AprilONeilHacktivist copy() {
return new AprilONeilHacktivist(this);
}
}
enum AprilONeilHacktivistValue implements DynamicValue {
instance;
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
return AprilONeilHacktivistWatcher.getCardTypesCast(sourceAbility.getControllerId(), game).size();
}
@Override
public AprilONeilHacktivistValue copy() {
return this;
}
@Override
public String getMessage() {
return "card type among spells you've cast this turn";
}
@Override
public String toString() {
return "1";
}
}
enum AprilONeilHacktivistHint implements Hint {
instance;
@Override
public String getText(Game game, Ability ability) {
List<String> types = AprilONeilHacktivistWatcher
.getCardTypesCast(ability.getControllerId(), game)
.stream()
.map(CardType::toString)
.sorted()
.collect(Collectors.toList());
return "Card types among spells you've cast this turn: " + types.size()
+ (types.size() > 0 ? " (" + String.join(", ", types) + ')' : "");
}
@Override
public Hint copy() {
return this;
}
}
class AprilONeilHacktivistWatcher extends Watcher {
private final Map<UUID, Set<CardType>> map = new HashMap<>();
AprilONeilHacktivistWatcher() {
super(WatcherScope.GAME);
}
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() != GameEvent.EventType.SPELL_CAST) {
return;
}
Spell spell = game.getSpell(event.getTargetId());
if (spell != null) {
map.computeIfAbsent(spell.getControllerId(), x -> new HashSet<>()).addAll(spell.getCardType(game));
}
}
@Override
public void reset() {
map.clear();
super.reset();
}
static Set<CardType> getCardTypesCast(UUID playerId, Game game) {
return game
.getState()
.getWatcher(AprilONeilHacktivistWatcher.class)
.map
.getOrDefault(playerId, Collections.emptySet());
}
}

View file

@ -1,21 +1,15 @@
package mage.cards.a; package mage.cards.a;
import mage.abilities.Ability; import mage.abilities.effects.common.DamageTargetAndTargetEffect;
import mage.abilities.effects.OneShotEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome;
import mage.filter.common.FilterAnyTarget; import mage.filter.common.FilterAnyTarget;
import mage.filter.common.FilterPermanentOrPlayer; import mage.filter.common.FilterPermanentOrPlayer;
import mage.filter.predicate.other.AnotherTargetPredicate; import mage.filter.predicate.other.AnotherTargetPredicate;
import mage.game.Game; import mage.target.common.TargetAnyTarget;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.Target;
import mage.target.common.TargetPermanentOrPlayer; import mage.target.common.TargetPermanentOrPlayer;
import java.io.ObjectStreamException;
import java.util.UUID; import java.util.UUID;
/** /**
@ -23,8 +17,7 @@ import java.util.UUID;
*/ */
public final class ArcTrail extends CardImpl { public final class ArcTrail extends CardImpl {
private static final FilterPermanentOrPlayer filter1 = new FilterAnyTarget("creature, player or planeswalker to deal 2 damage"); private static final FilterPermanentOrPlayer filter2 = new FilterAnyTarget("another target");
private static final FilterPermanentOrPlayer filter2 = new FilterAnyTarget("another creature, player or planeswalker to deal 1 damage");
static { static {
filter2.getPermanentFilter().add(new AnotherTargetPredicate(2)); filter2.getPermanentFilter().add(new AnotherTargetPredicate(2));
@ -34,10 +27,12 @@ public final class ArcTrail extends CardImpl {
public ArcTrail(UUID ownerId, CardSetInfo setInfo) { public ArcTrail(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{R}"); super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{R}");
// Arc Trail deals 2 damage to any target and 1 damage to another any target // Arc Trail deals 2 damage to any target and 1 damage to another target
this.getSpellAbility().addEffect(ArcTrailEffect.getInstance()); this.getSpellAbility().addEffect(new DamageTargetAndTargetEffect(2, 1));
this.getSpellAbility().addTarget(new TargetPermanentOrPlayer(filter1).setTargetTag(1)); this.getSpellAbility().addTarget(new TargetAnyTarget()
this.getSpellAbility().addTarget(new TargetPermanentOrPlayer(filter2).setTargetTag(2)); .withChooseHint("to deal 2 damage").setTargetTag(1));
this.getSpellAbility().addTarget(new TargetPermanentOrPlayer(filter2)
.withChooseHint("to deal 1 damage").setTargetTag(2));
} }
private ArcTrail(final ArcTrail card) { private ArcTrail(final ArcTrail card) {
@ -50,54 +45,3 @@ public final class ArcTrail extends CardImpl {
} }
} }
class ArcTrailEffect extends OneShotEffect {
private static final ArcTrailEffect instance = new ArcTrailEffect();
private Object readResolve() throws ObjectStreamException {
return instance;
}
public static ArcTrailEffect getInstance() {
return instance;
}
private ArcTrailEffect() {
super(Outcome.Damage);
staticText = "{this} deals 2 damage to any target and 1 damage to another target";
}
@Override
public boolean apply(Game game, Ability source) {
boolean applied = false;
boolean twoDamageDone = false;
int damage = 2;
for (Target target : source.getTargets()) {
Permanent permanent = game.getPermanent(target.getFirstTarget());
if (twoDamageDone) {
damage = 1;
}
if (permanent != null) {
applied |= (permanent.damage(damage, source.getSourceId(), source, game, false, true) > 0);
}
Player player = game.getPlayer(target.getFirstTarget());
if (player != null) {
applied |= (player.damage(damage, source.getSourceId(), source, game) > 0);
}
twoDamageDone = true;
}
return applied;
}
@Override
public ArcTrailEffect copy() {
return instance;
}
}

View file

@ -1,112 +0,0 @@
package mage.cards.a;
import mage.MageInt;
import mage.abilities.common.SpellCastControllerTriggeredAbility;
import mage.abilities.dynamicvalue.common.SavedDamageValue;
import mage.abilities.effects.common.TransformSourceEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.keyword.LivingMetalAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.counters.CounterType;
import mage.game.Controllable;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.stack.Spell;
import mage.target.Target;
import java.util.Collection;
import java.util.Objects;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class ArceeAcrobaticCoupe extends CardImpl {
public ArceeAcrobaticCoupe(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.VEHICLE);
this.power = new MageInt(2);
this.toughness = new MageInt(2);
this.color.setRed(true);
this.color.setWhite(true);
this.nightCard = true;
// Living metal
this.addAbility(new LivingMetalAbility());
// Whenever you cast a spell that targets one or more creatures or Vehicles you control, put that many +1/+1 counters on Arcee. Convert Arcee.
this.addAbility(new ArceeAcrobaticCoupeTriggeredAbility());
}
private ArceeAcrobaticCoupe(final ArceeAcrobaticCoupe card) {
super(card);
}
@Override
public ArceeAcrobaticCoupe copy() {
return new ArceeAcrobaticCoupe(this);
}
}
class ArceeAcrobaticCoupeTriggeredAbility extends SpellCastControllerTriggeredAbility {
ArceeAcrobaticCoupeTriggeredAbility() {
super(new AddCountersSourceEffect(
CounterType.P1P1.createInstance(0),
SavedDamageValue.MANY, false
), false);
this.addEffect(new TransformSourceEffect());
}
private ArceeAcrobaticCoupeTriggeredAbility(final ArceeAcrobaticCoupeTriggeredAbility ability) {
super(ability);
}
@Override
public ArceeAcrobaticCoupeTriggeredAbility copy() {
return new ArceeAcrobaticCoupeTriggeredAbility(this);
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (!super.checkTrigger(event, game)) {
return false;
}
Spell spell = game.getSpell(event.getTargetId());
if (spell == null) {
return false;
}
int targets = spell
.getStackAbility()
.getTargets()
.stream()
.map(Target::getTargets)
.flatMap(Collection::stream)
.map(game::getPermanent)
.filter(Objects::nonNull)
.filter(permanent -> permanent.isCreature(game)
|| permanent.hasSubtype(SubType.VEHICLE, game))
.map(Controllable::getControllerId)
.map(this::isControlledBy)
.mapToInt(x -> x ? 1 : 0)
.sum();
if (targets > 0) {
this.getEffects().setValue("damage", targets);
return true;
}
return false;
}
@Override
public String getRule() {
return "Whenever you cast a spell that targets one or more creatures or Vehicles " +
"you control, put that many +1/+1 counters on {this}. Convert {this}.";
}
}

View file

@ -1,44 +1,54 @@
package mage.cards.a; package mage.cards.a;
import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SpellCastControllerTriggeredAbility;
import mage.abilities.costs.common.RemoveVariableCountersSourceCost; import mage.abilities.costs.common.RemoveVariableCountersSourceCost;
import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.dynamicvalue.common.GetXValue; import mage.abilities.dynamicvalue.common.GetXValue;
import mage.abilities.dynamicvalue.common.SavedDamageValue;
import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.TransformSourceEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.keyword.FirstStrikeAbility; import mage.abilities.keyword.FirstStrikeAbility;
import mage.abilities.keyword.LivingMetalAbility;
import mage.abilities.keyword.MoreThanMeetsTheEyeAbility; import mage.abilities.keyword.MoreThanMeetsTheEyeAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.cards.TransformingDoubleFacedCard;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.SuperType; import mage.constants.SuperType;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.game.Controllable;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.stack.Spell;
import mage.target.Target;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
import java.util.Collection;
import java.util.Objects;
import java.util.UUID; import java.util.UUID;
/** /**
* @author TheElk801 * @author TheElk801
*/ */
public final class ArceeSharpshooter extends CardImpl { public final class ArceeSharpshooter extends TransformingDoubleFacedCard {
public ArceeSharpshooter(UUID ownerId, CardSetInfo setInfo) { public ArceeSharpshooter(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{1}{R}{W}"); super(ownerId, setInfo,
new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, new SubType[]{SubType.ROBOT}, "{1}{R}{W}",
"Arcee, Acrobatic Coupe",
new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.VEHICLE}, "RW");
this.supertype.add(SuperType.LEGENDARY); this.getLeftHalfCard().setPT(2, 2);
this.subtype.add(SubType.ROBOT); this.getRightHalfCard().setPT(2, 2);
this.power = new MageInt(2);
this.toughness = new MageInt(2);
this.secondSideCardClazz = mage.cards.a.ArceeAcrobaticCoupe.class;
// More Than Meets the Eye {R}{W} // More Than Meets the Eye {R}{W}
this.addAbility(new MoreThanMeetsTheEyeAbility(this, "{R}{W}")); this.getLeftHalfCard().addAbility(new MoreThanMeetsTheEyeAbility(this, "{R}{W}"));
// First strike // First strike
this.addAbility(FirstStrikeAbility.getInstance()); this.getLeftHalfCard().addAbility(FirstStrikeAbility.getInstance());
// {1}, Remove one or more +1/+1 counters from Arcee: It deals that much damage to target creature. Convert Arcee. // {1}, Remove one or more +1/+1 counters from Arcee: It deals that much damage to target creature. Convert Arcee.
Ability ability = new SimpleActivatedAbility( Ability ability = new SimpleActivatedAbility(
@ -49,7 +59,14 @@ public final class ArceeSharpshooter extends CardImpl {
ability.addCost(new RemoveVariableCountersSourceCost(CounterType.P1P1, 1)); ability.addCost(new RemoveVariableCountersSourceCost(CounterType.P1P1, 1));
ability.addEffect(new TransformSourceEffect().setText("convert {this}")); ability.addEffect(new TransformSourceEffect().setText("convert {this}"));
ability.addTarget(new TargetCreaturePermanent()); ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability); this.getLeftHalfCard().addAbility(ability);
// Arcee, Acrobatic Coupe
// Living metal
this.getRightHalfCard().addAbility(new LivingMetalAbility());
// Whenever you cast a spell that targets one or more creatures or Vehicles you control, put that many +1/+1 counters on Arcee. Convert Arcee.
this.getRightHalfCard().addAbility(new ArceeAcrobaticCoupeTriggeredAbility());
} }
private ArceeSharpshooter(final ArceeSharpshooter card) { private ArceeSharpshooter(final ArceeSharpshooter card) {
@ -61,3 +78,59 @@ public final class ArceeSharpshooter extends CardImpl {
return new ArceeSharpshooter(this); return new ArceeSharpshooter(this);
} }
} }
class ArceeAcrobaticCoupeTriggeredAbility extends SpellCastControllerTriggeredAbility {
ArceeAcrobaticCoupeTriggeredAbility() {
super(new AddCountersSourceEffect(
CounterType.P1P1.createInstance(0),
SavedDamageValue.MANY, false
), false);
this.addEffect(new TransformSourceEffect());
}
private ArceeAcrobaticCoupeTriggeredAbility(final ArceeAcrobaticCoupeTriggeredAbility ability) {
super(ability);
}
@Override
public ArceeAcrobaticCoupeTriggeredAbility copy() {
return new ArceeAcrobaticCoupeTriggeredAbility(this);
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (!super.checkTrigger(event, game)) {
return false;
}
Spell spell = game.getSpell(event.getTargetId());
if (spell == null) {
return false;
}
int targets = spell
.getStackAbility()
.getTargets()
.stream()
.map(Target::getTargets)
.flatMap(Collection::stream)
.map(game::getPermanent)
.filter(Objects::nonNull)
.filter(permanent -> permanent.isCreature(game)
|| permanent.hasSubtype(SubType.VEHICLE, game))
.map(Controllable::getControllerId)
.map(this::isControlledBy)
.mapToInt(x -> x ? 1 : 0)
.sum();
if (targets > 0) {
this.getEffects().setValue("damage", targets);
return true;
}
return false;
}
@Override
public String getRule() {
return "Whenever you cast a spell that targets one or more creatures or Vehicles " +
"you control, put that many +1/+1 counters on {this}. Convert {this}.";
}
}

View file

@ -1,66 +1,86 @@
package mage.cards.a; package mage.cards.a;
import mage.MageInt; import mage.abilities.Ability;
import mage.abilities.common.DiesCreatureTriggeredAbility; import mage.abilities.common.DiesCreatureTriggeredAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.TransformIntoSourceTriggeredAbility;
import mage.abilities.common.delayed.AtTheBeginOfNextUpkeepDelayedTriggeredAbility; import mage.abilities.common.delayed.AtTheBeginOfNextUpkeepDelayedTriggeredAbility;
import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
import mage.abilities.effects.common.DamageAllEffect;
import mage.abilities.effects.common.DamagePlayersEffect;
import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.TransformSourceEffect;
import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect;
import mage.abilities.keyword.*; import mage.abilities.keyword.FlashAbility;
import mage.cards.CardImpl; import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.IndestructibleAbility;
import mage.abilities.keyword.VigilanceAbility;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.cards.TransformingDoubleFacedCard;
import mage.constants.*; import mage.constants.*;
import mage.filter.FilterPermanent;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.AnotherPredicate;
import java.util.UUID; import java.util.UUID;
/** /**
* @author fireshoes * @author fireshoes
*/ */
public final class ArchangelAvacyn extends CardImpl { public final class ArchangelAvacyn extends TransformingDoubleFacedCard {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("a non-Angel creature you control"); private static final FilterCreaturePermanent nonAngelFilter = new FilterCreaturePermanent("a non-Angel creature you control");
private static final FilterPermanent otherCreatureFilter = new FilterCreaturePermanent("other creature");
static { static {
filter.add(Predicates.not(SubType.ANGEL.getPredicate())); otherCreatureFilter.add(AnotherPredicate.instance);
filter.add(TargetController.YOU.getControllerPredicate()); nonAngelFilter.add(Predicates.not(SubType.ANGEL.getPredicate()));
nonAngelFilter.add(TargetController.YOU.getControllerPredicate());
} }
public ArchangelAvacyn(UUID ownerId, CardSetInfo setInfo) { public ArchangelAvacyn(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{W}"); super(ownerId, setInfo,
new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ANGEL}, "{3}{W}{W}",
"Avacyn, the Purifier",
new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ANGEL}, "R");
this.supertype.add(SuperType.LEGENDARY); this.getLeftHalfCard().setPT(4, 4);
this.subtype.add(SubType.ANGEL); this.getRightHalfCard().setPT(6, 5);
this.power = new MageInt(4);
this.toughness = new MageInt(4);
this.secondSideCardClazz = mage.cards.a.AvacynThePurifier.class;
// Flash // Flash
this.addAbility(FlashAbility.getInstance()); this.getLeftHalfCard().addAbility(FlashAbility.getInstance());
// Flying // Flying
this.addAbility(FlyingAbility.getInstance()); this.getLeftHalfCard().addAbility(FlyingAbility.getInstance());
// Vigilance // Vigilance
this.addAbility(VigilanceAbility.getInstance()); this.getLeftHalfCard().addAbility(VigilanceAbility.getInstance());
// When Archangel Avacyn enters the battlefield, creatures you control gain indestructible until end of turn. // When Archangel Avacyn enters the battlefield, creatures you control gain indestructible until end of turn.
this.addAbility(new EntersBattlefieldTriggeredAbility(new GainAbilityControlledEffect( this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new GainAbilityControlledEffect(
IndestructibleAbility.getInstance(), Duration.EndOfTurn, IndestructibleAbility.getInstance(), Duration.EndOfTurn,
StaticFilters.FILTER_PERMANENT_CREATURES StaticFilters.FILTER_PERMANENT_CREATURES
), false)); ), false));
// When a non-Angel creature you control dies, transform Archangel Avacyn at the beginning of the next upkeep. // When a non-Angel creature you control dies, transform Archangel Avacyn at the beginning of the next upkeep.
this.addAbility(new TransformAbility()); this.getLeftHalfCard().addAbility(new DiesCreatureTriggeredAbility(
this.addAbility(new DiesCreatureTriggeredAbility(
new CreateDelayedTriggeredAbilityEffect( new CreateDelayedTriggeredAbilityEffect(
new AtTheBeginOfNextUpkeepDelayedTriggeredAbility(new TransformSourceEffect()) new AtTheBeginOfNextUpkeepDelayedTriggeredAbility(new TransformSourceEffect())
).setText("transform {this} at the beginning of the next upkeep"), false, filter ).setText("transform {this} at the beginning of the next upkeep"), false, nonAngelFilter
).setTriggerPhrase("When a non-Angel creature you control dies, ")); ).setTriggerPhrase("When a non-Angel creature you control dies, "));
// Avacyn, the Purifier
// Flying
this.getRightHalfCard().addAbility(FlyingAbility.getInstance());
// When this creature transforms into Avacyn, the Purifier, it deals 3 damage to each other creature and each opponent.
Ability ability = new TransformIntoSourceTriggeredAbility(
new DamageAllEffect(3, "it", otherCreatureFilter)
);
ability.addEffect(new DamagePlayersEffect(3, TargetController.OPPONENT).setText("and each opponent"));
this.getRightHalfCard().addAbility(ability);
} }
private ArchangelAvacyn(final ArchangelAvacyn card) { private ArchangelAvacyn(final ArchangelAvacyn card) {

View file

@ -1,54 +0,0 @@
package mage.cards.a;
import mage.MageInt;
import mage.abilities.costs.common.SacrificeTargetCost;
import mage.abilities.effects.common.DamageControllerEffect;
import mage.abilities.effects.common.DoIfCostPaid;
import mage.abilities.effects.common.TapSourceEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.TrampleAbility;
import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.filter.common.FilterControlledPermanent;
import java.util.UUID;
/**
* @author anonymous
*/
public final class ArchdemonOfGreed extends CardImpl {
private static final FilterControlledPermanent filter = new FilterControlledPermanent(SubType.HUMAN, "Human");
public ArchdemonOfGreed(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "");
this.subtype.add(SubType.DEMON);
this.color.setBlack(true);
this.nightCard = true;
this.power = new MageInt(9);
this.toughness = new MageInt(9);
this.addAbility(FlyingAbility.getInstance());
this.addAbility(TrampleAbility.getInstance());
// At the beginning of your upkeep, sacrifice a Human. If you can't, tap Archdemon of Greed and it deals 9 damage to you.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(new DoIfCostPaid(
null, new TapSourceEffect(), new SacrificeTargetCost(filter), false
).addOtherwiseEffect(new DamageControllerEffect(9))
.setText("sacrifice a Human. If you can't, tap {this} and it deals 9 damage to you")));
}
private ArchdemonOfGreed(final ArchdemonOfGreed card) {
super(card);
}
@Override
public ArchdemonOfGreed copy() {
return new ArchdemonOfGreed(this);
}
}

View file

@ -1,45 +0,0 @@
package mage.cards.a;
import mage.MageInt;
import mage.abilities.common.AttacksOrBlocksTriggeredAbility;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.keyword.VigilanceAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.game.permanent.token.SpiritToken;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class ArchitectOfRestoration extends CardImpl {
public ArchitectOfRestoration(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, "");
this.subtype.add(SubType.FOX);
this.subtype.add(SubType.MONK);
this.power = new MageInt(3);
this.toughness = new MageInt(4);
this.color.setWhite(true);
this.nightCard = true;
// Vigilance
this.addAbility(VigilanceAbility.getInstance());
// Whenever Architect of Restoration attacks or blocks, create a 1/1 colorless Spirit creature token.
this.addAbility(new AttacksOrBlocksTriggeredAbility(new CreateTokenEffect(new SpiritToken()), false));
}
private ArchitectOfRestoration(final ArchitectOfRestoration card) {
super(card);
}
@Override
public ArchitectOfRestoration copy() {
return new ArchitectOfRestoration(this);
}
}

View file

@ -1,48 +0,0 @@
package mage.cards.a;
import mage.MageInt;
import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.effects.common.DrawDiscardControllerEffect;
import mage.abilities.keyword.DisturbAbility;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class ArchiveHaunt extends CardImpl {
public ArchiveHaunt(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "");
this.subtype.add(SubType.SPIRIT);
this.subtype.add(SubType.WIZARD);
this.power = new MageInt(2);
this.toughness = new MageInt(1);
this.color.setBlue(true);
this.nightCard = true;
// Flying
this.addAbility(FlyingAbility.getInstance());
// Whenever Archive Haunt attacks, draw a card, then discard a card.
this.addAbility(new AttacksTriggeredAbility(new DrawDiscardControllerEffect(1, 1)));
// If Archive Haunt would be put into a graveyard from anywhere, exile it instead.
this.addAbility(DisturbAbility.makeBackAbility());
}
private ArchiveHaunt(final ArchiveHaunt card) {
super(card);
}
@Override
public ArchiveHaunt copy() {
return new ArchiveHaunt(this);
}
}

View file

@ -1,42 +1,56 @@
package mage.cards.a; package mage.cards.a;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.condition.common.FatefulHourCondition; import mage.abilities.condition.common.FatefulHourCondition;
import mage.abilities.costs.common.PayLifeCost; import mage.abilities.costs.common.PayLifeCost;
import mage.abilities.costs.common.SacrificeTargetCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.dynamicvalue.common.SacrificeCostCreaturesToughness;
import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.GainLifeEffect;
import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.TransformSourceEffect;
import mage.abilities.keyword.TransformAbility; import mage.abilities.mana.BlackManaAbility;
import mage.cards.CardImpl; import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.cards.TransformingDoubleFacedCard;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType; import mage.constants.SuperType;
import mage.constants.Zone; import mage.filter.StaticFilters;
import java.util.UUID; import java.util.UUID;
/** /**
* @author TheElk801 * @author TheElk801
*/ */
public final class ArguelsBloodFast extends CardImpl { public final class ArguelsBloodFast extends TransformingDoubleFacedCard {
public ArguelsBloodFast(UUID ownerId, CardSetInfo setInfo) { public ArguelsBloodFast(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}"); super(ownerId, setInfo,
new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ENCHANTMENT}, new SubType[]{}, "{1}{B}",
this.supertype.add(SuperType.LEGENDARY); "Temple of Aclazotz",
this.secondSideCardClazz = mage.cards.t.TempleOfAclazotz.class; new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.LAND}, new SubType[]{},"");
// {1}{B}, Pay 2 life: Draw a card. // {1}{B}, Pay 2 life: Draw a card.
Ability ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new ManaCostsImpl<>("{1}{B}")); Ability ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new ManaCostsImpl<>("{1}{B}"));
ability.addCost(new PayLifeCost(2)); ability.addCost(new PayLifeCost(2));
this.addAbility(ability); this.getLeftHalfCard().addAbility(ability);
// At the beginning of your upkeep, if you have 5 or less life, you may transform Arguel's Blood Fast. // At the beginning of your upkeep, if you have 5 or less life, you may transform Arguel's Blood Fast.
this.addAbility(new TransformAbility()); this.getLeftHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect(), true
this.addAbility(new BeginningOfUpkeepTriggeredAbility(new TransformSourceEffect(), true
).withInterveningIf(FatefulHourCondition.instance)); ).withInterveningIf(FatefulHourCondition.instance));
// Temple of Aclazotz
// {T}: Add {B}
this.getRightHalfCard().addAbility(new BlackManaAbility());
// {T}, Sacrifice a creature: You gain life equal to the sacrificed creature's toughness.
Ability activatedAbility = new SimpleActivatedAbility(new GainLifeEffect(SacrificeCostCreaturesToughness.instance)
.setText("you gain life equal to the sacrificed creature's toughness"), new TapSourceCost());
activatedAbility.addCost(new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_CREATURE));
this.getRightHalfCard().addAbility(activatedAbility);
} }
private ArguelsBloodFast(final ArguelsBloodFast card) { private ArguelsBloodFast(final ArguelsBloodFast card) {

View file

@ -1,68 +0,0 @@
package mage.cards.a;
import mage.abilities.Ability;
import mage.abilities.LoyaltyAbility;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.effects.common.GetEmblemEffect;
import mage.abilities.effects.common.TransformSourceEffect;
import mage.abilities.effects.common.continuous.BoostControlledEffect;
import mage.abilities.effects.common.continuous.GainAbilityControlledEffect;
import mage.abilities.keyword.TrampleAbility;
import mage.abilities.keyword.TransformAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.StaticFilters;
import mage.game.command.emblems.ArlinnEmbracedByTheMoonEmblem;
import mage.target.common.TargetAnyTarget;
import java.util.UUID;
/**
* @author fireshoes
*/
public final class ArlinnEmbracedByTheMoon extends CardImpl {
public ArlinnEmbracedByTheMoon(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.ARLINN);
this.color.setRed(true);
this.color.setGreen(true);
this.nightCard = true;
// +1: Creatures you control get +1/+1 and gain trample until end of turn.
Ability ability = new LoyaltyAbility(new BoostControlledEffect(
1, 1, Duration.EndOfTurn,
StaticFilters.FILTER_PERMANENT_CREATURE
).setText("Creatures you control get +1/+1"), 1);
ability.addEffect(new GainAbilityControlledEffect(
TrampleAbility.getInstance(), Duration.EndOfTurn,
StaticFilters.FILTER_PERMANENT_CREATURE
).setText("and gain trample until end of turn"));
this.addAbility(ability);
// -1: Arlinn, Embraced by the Moon deals 3 damage to any target. Transform Arlinn, Embraced by the Moon.
this.addAbility(new TransformAbility());
ability = new LoyaltyAbility(new DamageTargetEffect(3), -1);
ability.addTarget(new TargetAnyTarget());
ability.addEffect(new TransformSourceEffect());
this.addAbility(ability);
// -6: You get an emblem with "Creatures you control have haste and '{T}: This creature deals damage equal to its power to any target.'"
this.addAbility(new LoyaltyAbility(new GetEmblemEffect(new ArlinnEmbracedByTheMoonEmblem()), -6));
}
private ArlinnEmbracedByTheMoon(final ArlinnEmbracedByTheMoon card) {
super(card);
}
@Override
public ArlinnEmbracedByTheMoon copy() {
return new ArlinnEmbracedByTheMoon(this);
}
}

View file

@ -3,19 +3,26 @@ package mage.cards.a;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.LoyaltyAbility; import mage.abilities.LoyaltyAbility;
import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.effects.common.GetEmblemEffect;
import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.TransformSourceEffect;
import mage.abilities.effects.common.continuous.BoostControlledEffect;
import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect;
import mage.abilities.effects.common.continuous.GainAbilityControlledEffect;
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.HasteAbility;
import mage.abilities.keyword.TransformAbility; import mage.abilities.keyword.TrampleAbility;
import mage.abilities.keyword.VigilanceAbility; import mage.abilities.keyword.VigilanceAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.cards.TransformingDoubleFacedCard;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.SuperType; import mage.constants.SuperType;
import mage.filter.StaticFilters;
import mage.game.command.emblems.ArlinnEmbracedByTheMoonEmblem;
import mage.game.permanent.token.WolfToken; import mage.game.permanent.token.WolfToken;
import mage.target.common.TargetAnyTarget;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
import java.util.UUID; import java.util.UUID;
@ -23,16 +30,14 @@ import java.util.UUID;
/** /**
* @author fireshoes * @author fireshoes
*/ */
public final class ArlinnKord extends CardImpl { public final class ArlinnKord extends TransformingDoubleFacedCard {
public ArlinnKord(UUID ownerId, CardSetInfo setInfo) { public ArlinnKord(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{R}{G}"); super(ownerId, setInfo,
this.supertype.add(SuperType.LEGENDARY); new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.PLANESWALKER}, new SubType[]{SubType.ARLINN}, "{2}{R}{G}",
this.subtype.add(SubType.ARLINN); "Arlinn, Embraced by the Moon",
new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.PLANESWALKER}, new SubType[]{SubType.ARLINN}, "RG");
this.secondSideCardClazz = mage.cards.a.ArlinnEmbracedByTheMoon.class; this.getLeftHalfCard().setStartingLoyalty(3);
this.setStartingLoyalty(3);
// +1: Until end of turn, up to one target creature gets +2/+2 and gains vigilance and haste. // +1: Until end of turn, up to one target creature gets +2/+2 and gains vigilance and haste.
Ability ability = new LoyaltyAbility(new BoostTargetEffect( Ability ability = new LoyaltyAbility(new BoostTargetEffect(
@ -45,13 +50,34 @@ public final class ArlinnKord extends CardImpl {
HasteAbility.getInstance(), Duration.EndOfTurn HasteAbility.getInstance(), Duration.EndOfTurn
).setText("and haste")); ).setText("and haste"));
ability.addTarget(new TargetCreaturePermanent(0, 1)); ability.addTarget(new TargetCreaturePermanent(0, 1));
this.addAbility(ability); this.getLeftHalfCard().addAbility(ability);
// 0: Create a 2/2 green Wolf creature token. Transform Arlinn Kord. // 0: Create a 2/2 green Wolf creature token. Transform Arlinn Kord.
this.addAbility(new TransformAbility());
ability = new LoyaltyAbility(new CreateTokenEffect(new WolfToken()), 0); ability = new LoyaltyAbility(new CreateTokenEffect(new WolfToken()), 0);
ability.addEffect(new TransformSourceEffect()); ability.addEffect(new TransformSourceEffect());
this.addAbility(ability); this.getLeftHalfCard().addAbility(ability);
// Arlinn, Embraced by the Moon
// +1: Creatures you control get +1/+1 and gain trample until end of turn.
ability = new LoyaltyAbility(new BoostControlledEffect(
1, 1, Duration.EndOfTurn,
StaticFilters.FILTER_PERMANENT_CREATURE
).setText("Creatures you control get +1/+1"), 1);
ability.addEffect(new GainAbilityControlledEffect(
TrampleAbility.getInstance(), Duration.EndOfTurn,
StaticFilters.FILTER_PERMANENT_CREATURE
).setText("and gain trample until end of turn"));
this.getRightHalfCard().addAbility(ability);
// -1: Arlinn, Embraced by the Moon deals 3 damage to any target. Transform Arlinn, Embraced by the Moon.
ability = new LoyaltyAbility(new DamageTargetEffect(3), -1);
ability.addTarget(new TargetAnyTarget());
ability.addEffect(new TransformSourceEffect());
this.getRightHalfCard().addAbility(ability);
// -6: You get an emblem with "Creatures you control have haste and '{T}: This creature deals damage equal to its power to any target.'"
this.getRightHalfCard().addAbility(new LoyaltyAbility(new GetEmblemEffect(new ArlinnEmbracedByTheMoonEmblem()), -6));
} }
private ArlinnKord(final ArlinnKord card) { private ArlinnKord(final ArlinnKord card) {

View file

@ -1,118 +0,0 @@
package mage.cards.a;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.LoyaltyAbility;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.effects.mana.BasicManaEffect;
import mage.abilities.keyword.HasteAbility;
import mage.abilities.keyword.IndestructibleAbility;
import mage.abilities.keyword.NightboundAbility;
import mage.abilities.keyword.TrampleAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.game.Game;
import mage.game.permanent.Permanent;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class ArlinnTheMoonsFury extends CardImpl {
public ArlinnTheMoonsFury(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.ARLINN);
this.setStartingLoyalty(4);
this.color.setRed(true);
this.color.setGreen(true);
this.nightCard = true;
// Nightbound
this.addAbility(new NightboundAbility());
// +2: Add {R}{G}.
this.addAbility(new LoyaltyAbility(new BasicManaEffect(new Mana(
0, 0, 0, 1, 1, 0, 0, 0
)), 2));
// 0: Until end of turn, Arlinn, the Moon's Fury becomes a 5/5 Werewolf creature with trample, indestructible, and haste.
this.addAbility(new LoyaltyAbility(new ArlinnTheMoonsFuryEffect(), 0));
}
private ArlinnTheMoonsFury(final ArlinnTheMoonsFury card) {
super(card);
}
@Override
public ArlinnTheMoonsFury copy() {
return new ArlinnTheMoonsFury(this);
}
}
class ArlinnTheMoonsFuryEffect extends ContinuousEffectImpl {
ArlinnTheMoonsFuryEffect() {
super(Duration.EndOfTurn, Outcome.Benefit);
staticText = "until end of turn, {this} becomes a 5/5 Werewolf creature with trample, indestructible, and haste";
this.dependencyTypes.add(DependencyType.BecomeCreature);
}
private ArlinnTheMoonsFuryEffect(final ArlinnTheMoonsFuryEffect effect) {
super(effect);
}
@Override
public ArlinnTheMoonsFuryEffect copy() {
return new ArlinnTheMoonsFuryEffect(this);
}
@Override
public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) {
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
if (permanent == null) {
discard();
return false;
}
switch (layer) {
case TypeChangingEffects_4:
permanent.removeAllCardTypes(game);
permanent.addCardType(game, CardType.CREATURE);
permanent.removeAllCreatureTypes(game);
permanent.addSubType(game, SubType.WEREWOLF);
return true;
case AbilityAddingRemovingEffects_6:
permanent.addAbility(TrampleAbility.getInstance(), source.getSourceId(), game);
permanent.addAbility(IndestructibleAbility.getInstance(), source.getSourceId(), game);
permanent.addAbility(HasteAbility.getInstance(), source.getSourceId(), game);
return true;
case PTChangingEffects_7:
if (sublayer == SubLayer.SetPT_7b) {
permanent.getPower().setModifiedBaseValue(5);
permanent.getToughness().setModifiedBaseValue(5);
return true;
}
}
return false;
}
@Override
public boolean apply(Game game, Ability source) {
return false;
}
@Override
public boolean hasLayer(Layer layer) {
switch (layer) {
case TypeChangingEffects_4:
case AbilityAddingRemovingEffects_6:
case PTChangingEffects_7:
return true;
}
return false;
}
}

View file

@ -1,21 +1,23 @@
package mage.cards.a; package mage.cards.a;
import mage.Mana;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.LoyaltyAbility; import mage.abilities.LoyaltyAbility;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.CreateTokenEffect;
import mage.abilities.effects.common.EntersWithCountersControlledEffect; import mage.abilities.effects.common.EntersWithCountersControlledEffect;
import mage.abilities.effects.common.continuous.CastAsThoughItHadFlashAllEffect; import mage.abilities.effects.common.continuous.CastAsThoughItHadFlashAllEffect;
import mage.abilities.keyword.DayboundAbility; import mage.abilities.effects.mana.BasicManaEffect;
import mage.cards.CardImpl; import mage.abilities.keyword.*;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.cards.TransformingDoubleFacedCard;
import mage.constants.Duration; import mage.constants.*;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.filter.common.FilterCreatureCard; import mage.filter.common.FilterCreatureCard;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.game.permanent.token.WolfToken; import mage.game.permanent.token.WolfToken;
import java.util.UUID; import java.util.UUID;
@ -23,20 +25,20 @@ import java.util.UUID;
/** /**
* @author TheElk801 * @author TheElk801
*/ */
public final class ArlinnThePacksHope extends CardImpl { public final class ArlinnThePacksHope extends TransformingDoubleFacedCard {
private static final FilterCard filter = new FilterCreatureCard("creature spells"); private static final FilterCard filter = new FilterCreatureCard("creature spells");
public ArlinnThePacksHope(UUID ownerId, CardSetInfo setInfo) { public ArlinnThePacksHope(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{R}{G}"); super(ownerId, setInfo,
new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.PLANESWALKER}, new SubType[]{SubType.ARLINN}, "{2}{R}{G}",
this.supertype.add(SuperType.LEGENDARY); "Arlinn, the Moon's Fury",
this.subtype.add(SubType.ARLINN); new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.PLANESWALKER}, new SubType[]{SubType.ARLINN}, "RG");
this.setStartingLoyalty(4); this.getLeftHalfCard().setStartingLoyalty(4);
this.secondSideCardClazz = mage.cards.a.ArlinnTheMoonsFury.class; this.getRightHalfCard().setStartingLoyalty(4);
// Daybound // Daybound
this.addAbility(new DayboundAbility()); this.getLeftHalfCard().addAbility(new DayboundAbility());
// +1: Until your next turn, you may cast creature spells as though they had flash, and each creature you control enters the battlefield with an additional +1/+1 counter on it. // +1: Until your next turn, you may cast creature spells as though they had flash, and each creature you control enters the battlefield with an additional +1/+1 counter on it.
Ability ability = new LoyaltyAbility(new CastAsThoughItHadFlashAllEffect( Ability ability = new LoyaltyAbility(new CastAsThoughItHadFlashAllEffect(
@ -45,10 +47,23 @@ public final class ArlinnThePacksHope extends CardImpl {
ability.addEffect(new EntersWithCountersControlledEffect( ability.addEffect(new EntersWithCountersControlledEffect(
StaticFilters.FILTER_PERMANENT_CREATURE, CounterType.P1P1.createInstance(), false StaticFilters.FILTER_PERMANENT_CREATURE, CounterType.P1P1.createInstance(), false
).concatBy(", and")); ).concatBy(", and"));
this.addAbility(ability); this.getLeftHalfCard().addAbility(ability);
// 3: Create two 2/2 green Wolf creature tokens. // 3: Create two 2/2 green Wolf creature tokens.
this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new WolfToken(), 2), -3)); this.getLeftHalfCard().addAbility(new LoyaltyAbility(new CreateTokenEffect(new WolfToken(), 2), -3));
// Arlinn, the Moon's Fury
// Nightbound
this.getRightHalfCard().addAbility(new NightboundAbility());
// +2: Add {R}{G}.
this.getRightHalfCard().addAbility(new LoyaltyAbility(new BasicManaEffect(new Mana(
0, 0, 0, 1, 1, 0, 0, 0
)), 2));
// 0: Until end of turn, Arlinn, the Moon's Fury becomes a 5/5 Werewolf creature with trample, indestructible, and haste.
this.getRightHalfCard().addAbility(new LoyaltyAbility(new ArlinnTheMoonsFuryEffect(), 0));
} }
private ArlinnThePacksHope(final ArlinnThePacksHope card) { private ArlinnThePacksHope(final ArlinnThePacksHope card) {
@ -60,3 +75,66 @@ public final class ArlinnThePacksHope extends CardImpl {
return new ArlinnThePacksHope(this); return new ArlinnThePacksHope(this);
} }
} }
class ArlinnTheMoonsFuryEffect extends ContinuousEffectImpl {
ArlinnTheMoonsFuryEffect() {
super(Duration.EndOfTurn, Outcome.Benefit);
staticText = "until end of turn, {this} becomes a 5/5 Werewolf creature with trample, indestructible, and haste";
this.dependencyTypes.add(DependencyType.BecomeCreature);
}
private ArlinnTheMoonsFuryEffect(final ArlinnTheMoonsFuryEffect effect) {
super(effect);
}
@Override
public ArlinnTheMoonsFuryEffect copy() {
return new ArlinnTheMoonsFuryEffect(this);
}
@Override
public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) {
Permanent permanent = source.getSourcePermanentIfItStillExists(game);
if (permanent == null) {
discard();
return false;
}
switch (layer) {
case TypeChangingEffects_4:
permanent.removeAllCardTypes(game);
permanent.addCardType(game, CardType.CREATURE);
permanent.removeAllCreatureTypes(game);
permanent.addSubType(game, SubType.WEREWOLF);
return true;
case AbilityAddingRemovingEffects_6:
permanent.addAbility(TrampleAbility.getInstance(), source.getSourceId(), game);
permanent.addAbility(IndestructibleAbility.getInstance(), source.getSourceId(), game);
permanent.addAbility(HasteAbility.getInstance(), source.getSourceId(), game);
return true;
case PTChangingEffects_7:
if (sublayer == SubLayer.SetPT_7b) {
permanent.getPower().setModifiedBaseValue(5);
permanent.getToughness().setModifiedBaseValue(5);
return true;
}
}
return false;
}
@Override
public boolean apply(Game game, Ability source) {
return false;
}
@Override
public boolean hasLayer(Layer layer) {
switch (layer) {
case TypeChangingEffects_4:
case AbilityAddingRemovingEffects_6:
case PTChangingEffects_7:
return true;
}
return false;
}
}

View file

@ -7,7 +7,6 @@ import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.hint.common.RaidHint; import mage.abilities.hint.common.RaidHint;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.AbilityWord;
import mage.constants.CardType; import mage.constants.CardType;
import mage.target.common.TargetAnyTarget; import mage.target.common.TargetAnyTarget;
import mage.watchers.common.PlayerAttackedWatcher; import mage.watchers.common.PlayerAttackedWatcher;
@ -30,7 +29,7 @@ public final class ArrowStorm extends CardImpl {
this.getSpellAbility().addTarget(new TargetAnyTarget()); this.getSpellAbility().addTarget(new TargetAnyTarget());
// Raid - If you attacked with a creature this turn, instead Arrow Storm deals 5 damage to that creature or player and the damage can't be prevented. // Raid - If you attacked with a creature this turn, instead Arrow Storm deals 5 damage to that creature or player and the damage can't be prevented.
this.getSpellAbility().addEffect(new ConditionalOneShotEffect( this.getSpellAbility().addEffect(new ConditionalOneShotEffect(
new DamageTargetEffect(5, false), new DamageTargetEffect(5).withCantBePrevented(),
RaidCondition.instance, RaidCondition.instance,
"<br/><br/><i>Raid</i> &mdash; If you attacked this turn, instead {this} deals 5 damage to that permanent or player and the damage can't be prevented")); "<br/><br/><i>Raid</i> &mdash; If you attacked this turn, instead {this} deals 5 damage to that permanent or player and the damage can't be prevented"));
this.getSpellAbility().addWatcher(new PlayerAttackedWatcher()); this.getSpellAbility().addWatcher(new PlayerAttackedWatcher());

View file

@ -1,88 +0,0 @@
package mage.cards.a;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
import mage.abilities.condition.Condition;
import mage.abilities.decorator.ConditionalOneShotEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.keyword.MenaceAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.WatcherScope;
import mage.counters.CounterType;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.ZoneChangeEvent;
import mage.watchers.Watcher;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class AshenReaper extends CardImpl {
public AshenReaper(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "");
this.subtype.add(SubType.ZOMBIE);
this.subtype.add(SubType.ELEMENTAL);
this.power = new MageInt(2);
this.toughness = new MageInt(1);
this.color.setBlack(true);
this.color.setRed(true);
this.nightCard = true;
// Menace
this.addAbility(new MenaceAbility(false));
// At the beginning of your end step, put a +1/+1 counter on Ashen Reaper if a permanent was put into a graveyard from the battlefield this turn.
this.addAbility(new BeginningOfEndStepTriggeredAbility(
new ConditionalOneShotEffect(
new AddCountersSourceEffect(CounterType.P1P1.createInstance()),
AshenReaperCondition.instance, "put a +1/+1 counter on {this} " +
"if a permanent was put into a graveyard from the battlefield this turn"
)
));
}
private AshenReaper(final AshenReaper card) {
super(card);
}
@Override
public AshenReaper copy() {
return new AshenReaper(this);
}
public static AshenReaperWatcher makeWatcher() {
return new AshenReaperWatcher();
}
}
enum AshenReaperCondition implements Condition {
instance;
@Override
public boolean apply(Game game, Ability source) {
return game.getState().getWatcher(AshenReaperWatcher.class).conditionMet();
}
}
class AshenReaperWatcher extends Watcher {
AshenReaperWatcher() {
super(WatcherScope.GAME);
}
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() == GameEvent.EventType.ZONE_CHANGE
&& ((ZoneChangeEvent) event).isDiesEvent()) {
condition = true;
}
}
}

View file

@ -0,0 +1,76 @@
package mage.cards.a;
import mage.abilities.common.TransformIntoSourceTriggeredAbility;
import mage.abilities.common.TransformsOrEntersTriggeredAbility;
import mage.abilities.costs.common.DiscardCardCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.DoIfCostPaid;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.TransformSourceEffect;
import mage.abilities.effects.mana.AddConditionalManaOfAnyColorEffect;
import mage.abilities.mana.conditional.ConditionalSpellManaBuilder;
import mage.abilities.meta.OrTriggeredAbility;
import mage.abilities.triggers.BeginningOfFirstMainTriggeredAbility;
import mage.cards.CardSetInfo;
import mage.cards.TransformingDoubleFacedCard;
import mage.constants.*;
import mage.filter.FilterSpell;
import mage.filter.predicate.mageobject.ManaValuePredicate;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class AshlingRekindled extends TransformingDoubleFacedCard {
private static final FilterSpell filter = new FilterSpell("spells with mana value 4 or greater");
static {
filter.add(new ManaValuePredicate(ComparisonType.MORE_THAN, 3));
}
public AshlingRekindled(UUID ownerId, CardSetInfo setInfo) {
super(
ownerId, setInfo,
new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ELEMENTAL, SubType.SORCERER}, "{1}{R}",
"Ashling, Rimebound",
new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ELEMENTAL, SubType.WIZARD}, "U"
);
this.getLeftHalfCard().setPT(1, 3);
this.getRightHalfCard().setPT(1, 3);
// Whenever this creature enters or transforms into Ashling, Rekindled, you may discard a card. If you do, draw a card.
this.getLeftHalfCard().addAbility(new TransformsOrEntersTriggeredAbility(
new DoIfCostPaid(new DrawCardSourceControllerEffect(1), new DiscardCardCost()), false
));
// At the beginning of your first main phase, you may pay {U}. If you do, transform Ashling.
this.getLeftHalfCard().addAbility(new BeginningOfFirstMainTriggeredAbility(
new DoIfCostPaid(new TransformSourceEffect(), new ManaCostsImpl<>("{U}"))
));
// Ashling, Rimebound
// Whenever this creature transforms into Ashling, Rimebound and at the beginning of your first main phase, add two mana of any one color. Spend this mana only to cast spells with mana value 4 or greater.
this.getRightHalfCard().addAbility(new OrTriggeredAbility(
Zone.BATTLEFIELD,
new AddConditionalManaOfAnyColorEffect(2, new ConditionalSpellManaBuilder(filter)),
new TransformIntoSourceTriggeredAbility(null),
new BeginningOfFirstMainTriggeredAbility(null)
));
// At the beginning of your first main phase, you may pay {R}. If you do, transform Ashling.
this.getRightHalfCard().addAbility(new BeginningOfFirstMainTriggeredAbility(
new DoIfCostPaid(new TransformSourceEffect(), new ManaCostsImpl<>("{R}"))
));
}
private AshlingRekindled(final AshlingRekindled card) {
super(card);
}
@Override
public AshlingRekindled copy() {
return new AshlingRekindled(this);
}
}

View file

@ -1,48 +0,0 @@
package mage.cards.a;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.continuous.BoostEquippedEffect;
import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect;
import mage.abilities.keyword.EquipAbility;
import mage.abilities.keyword.FirstStrikeAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.AttachmentType;
import mage.constants.CardType;
import mage.constants.SubType;
import java.util.UUID;
/**
* @author fireshoes
*/
public final class AshmouthBlade extends CardImpl {
public AshmouthBlade(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "");
this.subtype.add(SubType.EQUIPMENT);
// this card is the second face of double-faced card
this.nightCard = true;
// Equipped creature gets +3/+3 and has first strike.
Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(3, 3));
ability.addEffect(new GainAbilityAttachedEffect(
FirstStrikeAbility.getInstance(), AttachmentType.EQUIPMENT
).setText("and has first strike"));
this.addAbility(ability);
// Equip {3}
this.addAbility(new EquipAbility(3, false));
}
private AshmouthBlade(final AshmouthBlade card) {
super(card);
}
@Override
public AshmouthBlade copy() {
return new AshmouthBlade(this);
}
}

View file

@ -1,50 +0,0 @@
package mage.cards.a;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SpellCastControllerTriggeredAbility;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.filter.StaticFilters;
import mage.target.common.TargetAnyTarget;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class AshmouthDragon extends CardImpl {
public AshmouthDragon(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "");
this.subtype.add(SubType.DRAGON);
this.power = new MageInt(4);
this.toughness = new MageInt(4);
this.color.setRed(true);
this.nightCard = true;
// Flying
this.addAbility(FlyingAbility.getInstance());
// Whenever you cast an instant or sorcery spell, Ashmouth Dragon deals 2 damage to any target.
Ability ability = new SpellCastControllerTriggeredAbility(
new DamageTargetEffect(2), StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false
);
ability.addTarget(new TargetAnyTarget());
this.addAbility(ability);
}
private AshmouthDragon(final AshmouthDragon card) {
super(card);
}
@Override
public AshmouthDragon copy() {
return new AshmouthDragon(this);
}
}

View file

@ -23,7 +23,7 @@ public final class AshmouthHound extends CardImpl {
this.toughness = new MageInt(1); this.toughness = new MageInt(1);
// Whenever Ashmouth Hound blocks or becomes blocked by a creature, Ashmouth Hound deals 1 damage to that creature. // Whenever Ashmouth Hound blocks or becomes blocked by a creature, Ashmouth Hound deals 1 damage to that creature.
this.addAbility(new BlocksOrBlockedByCreatureSourceTriggeredAbility(new DamageTargetEffect(1, true, "that creature"))); this.addAbility(new BlocksOrBlockedByCreatureSourceTriggeredAbility(new DamageTargetEffect(1).withTargetDescription("that creature")));
} }
private AshmouthHound(final AshmouthHound card) { private AshmouthHound(final AshmouthHound card) {

View file

@ -1,16 +1,14 @@
package mage.cards.a; package mage.cards.a;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.BlocksOrBlockedByCreatureSourceTriggeredAbility; import mage.abilities.common.BlocksOrBlockedByCreatureSourceTriggeredAbility;
import mage.abilities.effects.common.DamageTargetControllerEffect; import mage.abilities.effects.common.DamageTargetAndTargetControllerEffect;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.filter.StaticFilters;
import java.util.UUID;
/** /**
* *
@ -25,9 +23,8 @@ public final class AssembledAlphas extends CardImpl {
this.toughness = new MageInt(5); this.toughness = new MageInt(5);
// Whenever Assembled Alphas blocks or becomes blocked by a creature, Assembled Alphas deals 3 damage to that creature and 3 damage to that creature's controller. // Whenever Assembled Alphas blocks or becomes blocked by a creature, Assembled Alphas deals 3 damage to that creature and 3 damage to that creature's controller.
Ability ability = new BlocksOrBlockedByCreatureSourceTriggeredAbility(new DamageTargetEffect(3, true, "that creature")); this.addAbility(new BlocksOrBlockedByCreatureSourceTriggeredAbility(
ability.addEffect(new DamageTargetControllerEffect(3).setText("and 3 damage to that creature's controller")); new DamageTargetAndTargetControllerEffect(3, 3)));
this.addAbility(ability);
} }
private AssembledAlphas(final AssembledAlphas card) { private AssembledAlphas(final AssembledAlphas card) {

View file

@ -10,14 +10,10 @@ import mage.abilities.dynamicvalue.common.CountersControllerCount;
import mage.abilities.effects.common.DamagePlayersEffect; import mage.abilities.effects.common.DamagePlayersEffect;
import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.discard.DiscardControllerEffect; import mage.abilities.effects.common.discard.DiscardControllerEffect;
import mage.abilities.keyword.PartnerFatherAndSonAbility;
import mage.abilities.keyword.ReachAbility; import mage.abilities.keyword.ReachAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.*;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.constants.TargetController;
import mage.counters.CounterType; import mage.counters.CounterType;
import java.util.UUID; import java.util.UUID;
@ -50,7 +46,7 @@ public final class AtreusImpulsiveSon extends CardImpl {
this.addAbility(ability); this.addAbility(ability);
// Partner--Father & son // Partner--Father & son
this.addAbility(PartnerFatherAndSonAbility.getInstance()); this.addAbility(PartnerVariantType.FATHER_AND_SON.makeAbility());
} }
private AtreusImpulsiveSon(final AtreusImpulsiveSon card) { private AtreusImpulsiveSon(final AtreusImpulsiveSon card) {

View file

@ -0,0 +1,51 @@
package mage.cards.a;
import mage.MageInt;
import mage.abilities.common.AttacksPlayerWithCreaturesTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.continuous.BoostAllEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.common.FilterControlledCreaturePermanent;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class AttumaAtlanteanWarlord extends CardImpl {
private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(SubType.MERFOLK);
public AttumaAtlanteanWarlord(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{U}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.MERFOLK);
this.subtype.add(SubType.WARRIOR);
this.subtype.add(SubType.VILLAIN);
this.power = new MageInt(3);
this.toughness = new MageInt(4);
// Other Merfolk you control get +1/+1.
this.addAbility(new SimpleStaticAbility(new BoostAllEffect(
1, 1, Duration.WhileOnBattlefield, filter, true
)));
// Whenever one or more Merfolk you control attack a player, draw a card.
this.addAbility(new AttacksPlayerWithCreaturesTriggeredAbility(
new DrawCardSourceControllerEffect(1), filter, SetTargetPointer.NONE
));
}
private AttumaAtlanteanWarlord(final AttumaAtlanteanWarlord card) {
super(card);
}
@Override
public AttumaAtlanteanWarlord copy() {
return new AttumaAtlanteanWarlord(this);
}
}

View file

@ -1,51 +0,0 @@
package mage.cards.a;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect;
import mage.abilities.mana.AnyColorManaAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SuperType;
import mage.constants.Zone;
import mage.filter.StaticFilters;
import mage.target.common.TargetCardInYourGraveyard;
/**
*
* @author LevelX2
*/
public final class AtzalCaveOfEternity extends CardImpl {
public AtzalCaveOfEternity(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.LAND}, "");
this.supertype.add(SuperType.LEGENDARY);
this.nightCard = true;
// <i>(Transforms from Journey to Eternity.)</i>
// {t}: Add one mana of any color.
this.addAbility(new AnyColorManaAbility());
// {3}{B}{G}, {T}: Return target creature card from your graveyard to the battlefield.
Ability ability = new SimpleActivatedAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(), new ManaCostsImpl<>("{3}{B}{G}"));
ability.addCost(new TapSourceCost());
ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD));
this.addAbility(ability);
}
private AtzalCaveOfEternity(final AtzalCaveOfEternity card) {
super(card);
}
@Override
public AtzalCaveOfEternity copy() {
return new AtzalCaveOfEternity(this);
}
}

View file

@ -1,49 +0,0 @@
package mage.cards.a;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.effects.common.LoseLifeOpponentsEffect;
import mage.abilities.keyword.DeathtouchAbility;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
/**
*
* @author fireshoes
*/
public final class AuroraOfEmrakul extends CardImpl {
public AuroraOfEmrakul(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"");
this.subtype.add(SubType.ELDRAZI);
this.subtype.add(SubType.REFLECTION);
this.power = new MageInt(1);
this.toughness = new MageInt(4);
// this card is the second face of double-faced card
this.nightCard = true;
// Flying
this.addAbility(FlyingAbility.getInstance());
// Deathtouch
this.addAbility(DeathtouchAbility.getInstance());
// Whenever Aurora of Emrakul attacks, each opponent loses 3 life.
this.addAbility(new AttacksTriggeredAbility(new LoseLifeOpponentsEffect(3),false));
}
private AuroraOfEmrakul(final AuroraOfEmrakul card) {
super(card);
}
@Override
public AuroraOfEmrakul copy() {
return new AuroraOfEmrakul(this);
}
}

View file

@ -6,12 +6,14 @@ import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount; import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount;
import mage.abilities.effects.common.MillCardsControllerEffect; import mage.abilities.effects.common.MillCardsControllerEffect;
import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.TransformSourceEffect;
import mage.abilities.keyword.TransformAbility; import mage.abilities.keyword.HexproofAbility;
import mage.abilities.keyword.TrampleAbility;
import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.cards.TransformingDoubleFacedCard;
import mage.constants.AbilityWord; import mage.constants.AbilityWord;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.TargetController; import mage.constants.TargetController;
import java.util.UUID; import java.util.UUID;
@ -19,20 +21,28 @@ import java.util.UUID;
/** /**
* @author LevelX2 * @author LevelX2
*/ */
public final class AutumnalGloom extends CardImpl { public final class AutumnalGloom extends TransformingDoubleFacedCard {
public AutumnalGloom(UUID ownerId, CardSetInfo setInfo) { public AutumnalGloom(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}"); super(ownerId, setInfo,
this.secondSideCardClazz = mage.cards.a.AncientOfTheEquinox.class; new CardType[]{CardType.ENCHANTMENT}, new SubType[]{}, "{2}{G}",
"Ancient of the Equinox",
new CardType[]{CardType.CREATURE}, new SubType[]{SubType.TREEFOLK}, "G");
this.getRightHalfCard().setPT(4, 4);
// {B}: Put the top card of your library into your graveyard. // {B}: Put the top card of your library into your graveyard.
this.addAbility(new SimpleActivatedAbility(new MillCardsControllerEffect(1), new ManaCostsImpl<>("{B}"))); this.getLeftHalfCard().addAbility(new SimpleActivatedAbility(new MillCardsControllerEffect(1), new ManaCostsImpl<>("{B}")));
// <i>Delirium</i> &mdash; At the beginning of your end step, if there are four or more card types among cards in your graveyard, transform Autumnal Gloom. // <i>Delirium</i> &mdash; At the beginning of your end step, if there are four or more card types among cards in your graveyard, transform Autumnal Gloom.
this.addAbility(new TransformAbility()); this.getLeftHalfCard().addAbility(new BeginningOfEndStepTriggeredAbility(
this.addAbility(new BeginningOfEndStepTriggeredAbility(
TargetController.YOU, new TransformSourceEffect(), false, DeliriumCondition.instance TargetController.YOU, new TransformSourceEffect(), false, DeliriumCondition.instance
).setAbilityWord(AbilityWord.DELIRIUM).addHint(CardTypesInGraveyardCount.YOU.getHint())); ).setAbilityWord(AbilityWord.DELIRIUM).addHint(CardTypesInGraveyardCount.YOU.getHint()));
// Ancient of the Equinox
// Trample
this.getRightHalfCard().addAbility(TrampleAbility.getInstance());
// Hexproof
this.getRightHalfCard().addAbility(HexproofAbility.getInstance());
} }
private AutumnalGloom(final AutumnalGloom card) { private AutumnalGloom(final AutumnalGloom card) {

View file

@ -1,14 +1,18 @@
package mage.cards.a; package mage.cards.a;
import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.continuous.GainAbilityControlledEffect;
import mage.abilities.effects.common.counter.AddCountersAllEffect;
import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect;
import mage.abilities.keyword.DayboundAbility; import mage.abilities.keyword.DayboundAbility;
import mage.abilities.keyword.HexproofAbility; import mage.abilities.keyword.HexproofAbility;
import mage.abilities.keyword.NightboundAbility;
import mage.abilities.triggers.BeginningOfCombatTriggeredAbility; import mage.abilities.triggers.BeginningOfCombatTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.cards.TransformingDoubleFacedCard;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType; import mage.constants.SubType;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
@ -19,29 +23,49 @@ import java.util.UUID;
/** /**
* @author TheElk801 * @author TheElk801
*/ */
public final class AvabruckCaretaker extends CardImpl { public final class AvabruckCaretaker extends TransformingDoubleFacedCard {
public AvabruckCaretaker(UUID ownerId, CardSetInfo setInfo) { public AvabruckCaretaker(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}{G}"); super(ownerId, setInfo,
new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{4}{G}{G}",
this.subtype.add(SubType.HUMAN); "Hollowhenge Huntmaster",
this.subtype.add(SubType.WEREWOLF); new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "G");
this.power = new MageInt(4); this.getLeftHalfCard().setPT(4, 4);
this.toughness = new MageInt(4); this.getRightHalfCard().setPT(6, 6);
this.secondSideCardClazz = mage.cards.h.HollowhengeHuntmaster.class;
// Hexproof // Hexproof
this.addAbility(HexproofAbility.getInstance()); this.getLeftHalfCard().addAbility(HexproofAbility.getInstance());
// At the beginning of combat on your turn, put two +1/+1 counters on another target creature you control. // At the beginning of combat on your turn, put two +1/+1 counters on another target creature you control.
Ability ability = new BeginningOfCombatTriggeredAbility( Ability ability = new BeginningOfCombatTriggeredAbility(
new AddCountersTargetEffect(CounterType.P1P1.createInstance(2)) new AddCountersTargetEffect(CounterType.P1P1.createInstance(2))
); );
ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL)); ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE_YOU_CONTROL));
this.addAbility(ability); this.getLeftHalfCard().addAbility(ability);
// Daybound // Daybound
this.addAbility(new DayboundAbility()); this.getLeftHalfCard().addAbility(new DayboundAbility());
// Hollowhenge Huntmaster
// Hexproof
this.getRightHalfCard().addAbility(HexproofAbility.getInstance());
// Other permanents you control have hexproof.
this.getRightHalfCard().addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect(
HexproofAbility.getInstance(), Duration.WhileOnBattlefield,
StaticFilters.FILTER_PERMANENTS, true
)));
// At the beginning of combat on your turn, put two +1/+1 counters on each creature you control.
this.getRightHalfCard().addAbility(new BeginningOfCombatTriggeredAbility(
new AddCountersAllEffect(
CounterType.P1P1.createInstance(2),
StaticFilters.FILTER_CONTROLLED_CREATURE
)
));
// Nightbound
this.getRightHalfCard().addAbility(new NightboundAbility());
} }
private AvabruckCaretaker(final AvabruckCaretaker card) { private AvabruckCaretaker(final AvabruckCaretaker card) {

View file

@ -1,62 +0,0 @@
package mage.cards.a;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.TransformIntoSourceTriggeredAbility;
import mage.abilities.effects.common.DamageAllEffect;
import mage.abilities.effects.common.DamagePlayersEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.constants.TargetController;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.AnotherPredicate;
import java.util.UUID;
/**
* @author fireshoes
*/
public final class AvacynThePurifier extends CardImpl {
private static final FilterPermanent filter = new FilterCreaturePermanent("other creature");
static {
filter.add(AnotherPredicate.instance);
}
public AvacynThePurifier(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.ANGEL);
this.power = new MageInt(6);
this.toughness = new MageInt(5);
this.color.setRed(true);
// this card is the second face of double-faced card
this.nightCard = true;
// Flying
this.addAbility(FlyingAbility.getInstance());
// When this creature transforms into Avacyn, the Purifier, it deals 3 damage to each other creature and each opponent.
Ability ability = new TransformIntoSourceTriggeredAbility(
new DamageAllEffect(3, "it", filter)
);
ability.addEffect(new DamagePlayersEffect(3, TargetController.OPPONENT).setText("and each opponent"));
this.addAbility(ability);
}
private AvacynThePurifier(final AvacynThePurifier card) {
super(card);
}
@Override
public AvacynThePurifier copy() {
return new AvacynThePurifier(this);
}
}

View file

@ -1,37 +1,43 @@
package mage.cards.a; package mage.cards.a;
import java.util.UUID; import mage.abilities.Ability;
import mage.abilities.common.TransformIntoSourceTriggeredAbility;
import mage.MageInt;
import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
import mage.abilities.condition.common.EquippedSourceCondition; import mage.abilities.condition.common.EquippedSourceCondition;
import mage.abilities.effects.common.ExileUntilSourceLeavesEffect;
import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.TransformSourceEffect;
import mage.abilities.keyword.TransformAbility; import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.cards.TransformingDoubleFacedCard;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.TargetController; import mage.constants.TargetController;
import mage.filter.StaticFilters;
import mage.target.TargetPermanent;
import java.util.UUID;
/** /**
* @author fireshoes * @author fireshoes
*/ */
public final class AvacynianMissionaries extends CardImpl { public final class AvacynianMissionaries extends TransformingDoubleFacedCard {
public AvacynianMissionaries(UUID ownerId, CardSetInfo setInfo) { public AvacynianMissionaries(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); super(ownerId, setInfo,
this.subtype.add(SubType.HUMAN); new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.CLERIC}, "{3}{W}",
this.subtype.add(SubType.CLERIC); "Lunarch Inquisitors",
this.power = new MageInt(3); new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.CLERIC}, "W");
this.toughness = new MageInt(3); this.getLeftHalfCard().setPT(3, 3);
this.getRightHalfCard().setPT(4, 4);
this.secondSideCardClazz = mage.cards.l.LunarchInquisitors.class;
// At the beginning of your end step, if Avacynian Missionaries is equipped, transform it. // At the beginning of your end step, if Avacynian Missionaries is equipped, transform it.
this.addAbility(new TransformAbility()); this.getLeftHalfCard().addAbility(new BeginningOfEndStepTriggeredAbility(TargetController.YOU, new TransformSourceEffect().setText("transform it"),
this.addAbility(new BeginningOfEndStepTriggeredAbility(TargetController.YOU, new TransformSourceEffect().setText("transform it"),
false, EquippedSourceCondition.instance)); false, EquippedSourceCondition.instance));
// Lunarch Inquisitors
// When this creature transforms into Lunarch Inquisitors, you may exile another target creature until Lunarch Inquisitors leaves the battlefield.
Ability ability = new TransformIntoSourceTriggeredAbility(new ExileUntilSourceLeavesEffect(), true);
ability.addTarget(new TargetPermanent(StaticFilters.FILTER_ANOTHER_TARGET_CREATURE));
this.getRightHalfCard().addAbility(ability);
} }
private AvacynianMissionaries(final AvacynianMissionaries card) { private AvacynianMissionaries(final AvacynianMissionaries card) {

View file

@ -65,7 +65,7 @@ public final class AvalancheOfSector7 extends CardImpl {
class AvalancheOfSector7TriggeredAbility extends TriggeredAbilityImpl { class AvalancheOfSector7TriggeredAbility extends TriggeredAbilityImpl {
AvalancheOfSector7TriggeredAbility() { AvalancheOfSector7TriggeredAbility() {
super(Zone.BATTLEFIELD, new DamageTargetEffect(1, true, "that player", true)); super(Zone.BATTLEFIELD, new DamageTargetEffect(1).withTargetDescription("that player"));
setTriggerPhrase("Whenever an opponent activates an ability of an artifact they control, "); setTriggerPhrase("Whenever an opponent activates an ability of an artifact they control, ");
} }

View file

@ -1,50 +1,80 @@
package mage.cards.a; package mage.cards.a;
import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl; import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.Condition; import mage.abilities.condition.Condition;
import mage.abilities.costs.Cost;
import mage.abilities.costs.CostImpl;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.decorator.ConditionalOneShotEffect;
import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.*;
import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.keyword.FirebendingAbility; import mage.abilities.keyword.FirebendingAbility;
import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl; import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.cards.Card;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.cards.TransformingDoubleFacedCard;
import mage.constants.*; import mage.constants.*;
import mage.counters.CounterType;
import mage.filter.FilterCard;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
import mage.watchers.Watcher; import mage.watchers.Watcher;
import java.util.HashSet; import java.util.HashSet;
import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
/** /**
* @author TheElk801 * @author TheElk801
*/ */
public final class AvatarAang extends CardImpl { public final class AvatarAang extends TransformingDoubleFacedCard {
private static final FilterCard filter = new FilterCard("spells");
public AvatarAang(UUID ownerId, CardSetInfo setInfo) { public AvatarAang(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}{G}{W}{U}"); super(ownerId, setInfo,
new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.AVATAR, SubType.ALLY}, "{R}{G}{W}{U}",
"Aang, Master of Elements",
new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.AVATAR, SubType.ALLY}, "");
this.supertype.add(SuperType.LEGENDARY); this.getLeftHalfCard().setPT(4, 4);
this.subtype.add(SubType.HUMAN); this.getRightHalfCard().setPT(6, 6);
this.subtype.add(SubType.AVATAR);
this.subtype.add(SubType.ALLY);
this.power = new MageInt(4);
this.toughness = new MageInt(4);
this.secondSideCardClazz = mage.cards.a.AangMasterOfElements.class;
// Flying // Flying
this.addAbility(FlyingAbility.getInstance()); this.getLeftHalfCard().addAbility(FlyingAbility.getInstance());
// Firebending 2 // Firebending 2
this.addAbility(new FirebendingAbility(2)); this.getLeftHalfCard().addAbility(new FirebendingAbility(2));
// Whenever you waterbend, earthbend, firebend, or airbend, draw a card. Then if you've done all four this turn, transform Avatar Aang. // Whenever you waterbend, earthbend, firebend, or airbend, draw a card. Then if you've done all four this turn, transform Avatar Aang.
this.addAbility(new AvatarAangTriggeredAbility()); this.getLeftHalfCard().addAbility(new AvatarAangTriggeredAbility());
// Aang, Master of Elements
// Flying
this.getRightHalfCard().addAbility(FlyingAbility.getInstance());
// Spells you cast cost {W}{U}{B}{R}{G} less to cast.
this.getRightHalfCard().addAbility(new SimpleStaticAbility(new SpellsCostReductionControllerEffect(
filter, new ManaCostsImpl<>("{W}{U}{B}{R}{G}"), StaticValue.get(1), true
)));
// At the beginning of each upkeep, you may transform Aang, Master of Elements. If you do, you gain 4 life, draw four cards, put four +1/+1 counters on him, and he deals 4 damage to each opponent.
this.getRightHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility(
TargetController.ANY,
new DoIfCostPaid(new GainLifeEffect(4), new AangMasterOfElementsCost())
.addEffect(new DrawCardSourceControllerEffect(4).concatBy(","))
.addEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance(4))
.setText(", put four +1/+1 counters on him"))
.addEffect(new DamagePlayersEffect(4, TargetController.OPPONENT)
.setText(", and he deals 4 damage to each opponent")),
false
));
} }
private AvatarAang(final AvatarAang card) { private AvatarAang(final AvatarAang card) {
@ -154,3 +184,37 @@ class AvatarAangWatcher extends Watcher {
return game.getState().getWatcher(AvatarAangWatcher.class).checkPlayer(source.getControllerId()); return game.getState().getWatcher(AvatarAangWatcher.class).checkPlayer(source.getControllerId());
} }
} }
class AangMasterOfElementsCost extends CostImpl {
AangMasterOfElementsCost() {
super();
text = "transform {this}";
}
private AangMasterOfElementsCost(final AangMasterOfElementsCost cost) {
super(cost);
}
@Override
public AangMasterOfElementsCost copy() {
return new AangMasterOfElementsCost(this);
}
@Override
public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) {
return Optional
.ofNullable(source.getSourcePermanentIfItStillExists(game))
.filter(Card::isTransformable)
.isPresent();
}
@Override
public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) {
paid = Optional
.ofNullable(source.getSourcePermanentIfItStillExists(game))
.filter(permanent -> permanent.transform(source, game))
.isPresent();
return paid;
}
}

View file

@ -0,0 +1,110 @@
package mage.cards.a;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.DiesAttachedTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.AttachEffect;
import mage.abilities.effects.common.ReturnToHandSourceEffect;
import mage.abilities.effects.common.continuous.AddCardSubtypeAttachedEffect;
import mage.abilities.effects.common.continuous.BoostEnchantedEffect;
import mage.abilities.keyword.EnchantAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.Cards;
import mage.constants.*;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.TargetCard;
import mage.target.TargetPermanent;
import mage.target.common.TargetControlledCreaturePermanent;
import java.util.Optional;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class AvatarDestiny extends CardImpl {
private static final DynamicValue xValue = new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_CREATURE);
public AvatarDestiny(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}{G}");
this.subtype.add(SubType.AURA);
// Enchant creature you control
TargetPermanent auraTarget = new TargetControlledCreaturePermanent();
this.getSpellAbility().addTarget(auraTarget);
this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature));
this.addAbility(new EnchantAbility(auraTarget));
// Enchanted creature gets +1/+1 for each creature card in your graveyard and is an Avatar in addition to its other types.
Ability ability = new SimpleStaticAbility(new BoostEnchantedEffect(xValue, xValue));
ability.addEffect(new AddCardSubtypeAttachedEffect(
SubType.AVATAR, AttachmentType.AURA
).setText("and is an Avatar in addition to its other types"));
this.addAbility(ability);
// When enchanted creature dies, mill cards equal to its power. Return this card to its owner's hand and up to one creature card milled this way to the battlefield under your control.
this.addAbility(new DiesAttachedTriggeredAbility(new AvatarDestinyEffect(), "enchanted creature"));
}
private AvatarDestiny(final AvatarDestiny card) {
super(card);
}
@Override
public AvatarDestiny copy() {
return new AvatarDestiny(this);
}
}
class AvatarDestinyEffect extends OneShotEffect {
AvatarDestinyEffect() {
super(Outcome.Benefit);
staticText = "mill cards equal to its power. Return this card to its owner's hand and up to one " +
"creature card milled this way to the battlefield under your control";
}
private AvatarDestinyEffect(final AvatarDestinyEffect effect) {
super(effect);
}
@Override
public AvatarDestinyEffect copy() {
return new AvatarDestinyEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player == null) {
return false;
}
int count = Optional
.ofNullable((Permanent) getValue("attachedTo"))
.map(MageObject::getPower)
.map(MageInt::getValue)
.orElse(0);
Cards cards = player.millCards(count, source, game);
game.processAction();
new ReturnToHandSourceEffect(false, true).apply(game, source);
TargetCard target = new TargetCard(0, 1, Zone.ALL, StaticFilters.FILTER_CARD_CREATURE);
target.withNotTarget(true);
player.choose(Outcome.PutCreatureInPlay, cards, target, source, game);
player.moveCards(
game.getCard(target.getFirstTarget()), Zone.BATTLEFIELD, source,
game, true, false, false, null
);
return true;
}
}

View file

@ -0,0 +1,58 @@
package mage.cards.a;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.MyTurnCondition;
import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.common.UntapTargetEffect;
import mage.abilities.effects.common.continuous.GainAbilitySourceEffect;
import mage.abilities.effects.keyword.EarthbendTargetEffect;
import mage.abilities.keyword.HexproofAbility;
import mage.abilities.triggers.BeginningOfCombatTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.target.common.TargetControlledLandPermanent;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class AvatarKyoshiEarthbender extends CardImpl {
public AvatarKyoshiEarthbender(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{G}{G}{G}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.AVATAR);
this.power = new MageInt(6);
this.toughness = new MageInt(6);
// During your turn, Avatar Kyoshi has hexproof.
this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect(
new GainAbilitySourceEffect(HexproofAbility.getInstance(), Duration.WhileOnBattlefield),
MyTurnCondition.instance, "during your turn, {this} has hexproof"
)));
// At the beginning of combat on your turn, earthbend 8, then untap that land.
Ability ability = new BeginningOfCombatTriggeredAbility(new EarthbendTargetEffect(8, false));
ability.addEffect(new UntapTargetEffect().setText(", then untap that land"));
ability.addTarget(new TargetControlledLandPermanent());
this.addAbility(ability);
}
private AvatarKyoshiEarthbender(final AvatarKyoshiEarthbender card) {
super(card);
}
@Override
public AvatarKyoshiEarthbender copy() {
return new AvatarKyoshiEarthbender(this);
}
}

View file

@ -0,0 +1,108 @@
package mage.cards.a;
import mage.MageInt;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.continuous.BoostTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.players.Player;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class AvatarRokuFirebender extends CardImpl {
public AvatarRokuFirebender(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{R}{R}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.AVATAR);
this.power = new MageInt(6);
this.toughness = new MageInt(6);
// Whenever a player attacks, add six {R}. Until end of combat, you don't lose this mana as steps end.
this.addAbility(new AvatarRokuFirebenderTriggeredAbility());
// {R}{R}{R}: Target creature gets +3/+0 until end of turn.
Ability ability = new SimpleActivatedAbility(
new BoostTargetEffect(3, 0), new ManaCostsImpl<>("{R}{R}{R}")
);
ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability);
}
private AvatarRokuFirebender(final AvatarRokuFirebender card) {
super(card);
}
@Override
public AvatarRokuFirebender copy() {
return new AvatarRokuFirebender(this);
}
}
class AvatarRokuFirebenderTriggeredAbility extends TriggeredAbilityImpl {
AvatarRokuFirebenderTriggeredAbility() {
super(Zone.BATTLEFIELD, new AvatarRokuFirebenderEffect());
setTriggerPhrase("Whenever a player attacks, ");
}
private AvatarRokuFirebenderTriggeredAbility(final AvatarRokuFirebenderTriggeredAbility ability) {
super(ability);
}
@Override
public AvatarRokuFirebenderTriggeredAbility copy() {
return new AvatarRokuFirebenderTriggeredAbility(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DECLARED_ATTACKERS;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
return !game.getCombat().getAttackers().isEmpty();
}
}
class AvatarRokuFirebenderEffect extends OneShotEffect {
AvatarRokuFirebenderEffect() {
super(Outcome.Benefit);
staticText = "add six {R}. Until end of combat, you don't lose this mana as steps end";
}
private AvatarRokuFirebenderEffect(final AvatarRokuFirebenderEffect effect) {
super(effect);
}
@Override
public AvatarRokuFirebenderEffect copy() {
return new AvatarRokuFirebenderEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player == null) {
return false;
}
player.getManaPool().addMana(Mana.RedMana(6), game, source, Duration.EndOfCombat);
return true;
}
}

View file

@ -0,0 +1,114 @@
package mage.cards.a;
import mage.abilities.Ability;
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ExileSpellEffect;
import mage.abilities.effects.keyword.AirbendTargetEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.target.common.TargetCreaturePermanent;
import mage.target.targetpointer.FixedTargets;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class AvatarsWrath extends CardImpl {
public AvatarsWrath(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{W}{W}");
// Choose up to one target creature, then airbend all other creatures.
this.getSpellAbility().addEffect(new AvatarsWrathAirbendEffect());
this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 1));
// Until your next turn, your opponents can't cast spells from anywhere other than their hand.
this.getSpellAbility().addEffect(new AvatarsWrathRuleEffect());
// Exile Avatar's Wrath.
this.getSpellAbility().addEffect(new ExileSpellEffect().concatBy("<br>"));
}
private AvatarsWrath(final AvatarsWrath card) {
super(card);
}
@Override
public AvatarsWrath copy() {
return new AvatarsWrath(this);
}
}
class AvatarsWrathAirbendEffect extends OneShotEffect {
AvatarsWrathAirbendEffect() {
super(Outcome.Benefit);
staticText = "choose up to one target creature, then airbend all other creatures";
}
private AvatarsWrathAirbendEffect(final AvatarsWrathAirbendEffect effect) {
super(effect);
}
@Override
public AvatarsWrathAirbendEffect copy() {
return new AvatarsWrathAirbendEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
List<Permanent> permanents = game
.getBattlefield()
.getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game);
Optional.ofNullable(game.getPermanent(getTargetPointer().getFirst(game, source)))
.ifPresent(permanents::remove);
return !permanents.isEmpty()
&& new AirbendTargetEffect()
.setTargetPointer(new FixedTargets(permanents, game))
.apply(game, source);
}
}
class AvatarsWrathRuleEffect extends ContinuousRuleModifyingEffectImpl {
AvatarsWrathRuleEffect() {
super(Duration.UntilYourNextTurn, Outcome.Benefit);
staticText = "<br>Until your next turn, your opponents can't cast spells from anywhere other than their hand.";
}
private AvatarsWrathRuleEffect(final AvatarsWrathRuleEffect effect) {
super(effect);
}
@Override
public AvatarsWrathRuleEffect copy() {
return new AvatarsWrathRuleEffect(this);
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.CAST_SPELL;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (!game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) {
return false;
}
Card card = game.getCard(event.getSourceId());
return card != null && game.getState().getZone(card.getId()) != Zone.HAND;
}
}

Some files were not shown because too many files have changed in this diff Show more