From ced2c850766e20dae8b3c746fbedf52f9208e06b Mon Sep 17 00:00:00 2001 From: valfieri Date: Sun, 6 Dec 2020 20:11:51 +0100 Subject: [PATCH] Implemented Commander mode and rules, added Command Zone to game, added/fixed primitives, increased the major release version. --- projects/mtg/Android/AndroidManifest.xml | 2 +- projects/mtg/Android/res/values/strings.xml | 2 +- .../mtg/bin/Res/graphics/iconcommandzone.png | Bin 0 -> 11722 bytes projects/mtg/bin/Res/rules/Commander.txt | 77 ++++++++++ .../bin/Res/sets/primitives/borderline.txt | 84 ++++++++--- .../bin/Res/sets/primitives/planeswalkers.txt | 15 +- .../bin/Res/sets/primitives/unsupported.txt | 6 - projects/mtg/build.number.properties | 4 +- projects/mtg/include/AllAbilities.h | 8 +- projects/mtg/include/GuiAvatars.h | 2 + projects/mtg/include/GuiStatic.h | 10 ++ projects/mtg/include/MTGCardInstance.h | 2 + projects/mtg/include/MTGDeck.h | 1 + projects/mtg/include/MTGDefinitions.h | 4 +- projects/mtg/include/MTGGameZones.h | 9 ++ projects/mtg/include/PlayGuiObject.h | 1 + projects/mtg/include/Player.h | 1 + projects/mtg/include/Wagic_Version.h | 4 +- projects/mtg/src/AIPlayerBaka.cpp | 137 +++++++++++++++++- projects/mtg/src/AllAbilities.cpp | 4 +- projects/mtg/src/Damage.cpp | 4 + projects/mtg/src/GameObserver.cpp | 2 + projects/mtg/src/GuiAvatars.cpp | 45 ++++-- projects/mtg/src/GuiStatic.cpp | 59 +++++++- projects/mtg/src/MTGAbility.cpp | 8 +- projects/mtg/src/MTGCardInstance.cpp | 2 + projects/mtg/src/MTGDeck.cpp | 70 ++++++++- projects/mtg/src/MTGDefinitions.cpp | 6 +- projects/mtg/src/MTGGameZones.cpp | 64 +++++++- projects/mtg/src/MTGRules.cpp | 2 +- projects/mtg/src/Player.cpp | 1 + projects/mtg/src/Rules.cpp | 6 +- projects/mtg/src/TargetChooser.cpp | 24 ++- 33 files changed, 588 insertions(+), 78 deletions(-) create mode 100644 projects/mtg/bin/Res/graphics/iconcommandzone.png create mode 100644 projects/mtg/bin/Res/rules/Commander.txt diff --git a/projects/mtg/Android/AndroidManifest.xml b/projects/mtg/Android/AndroidManifest.xml index ca2a98ace..b39ff5d03 100644 --- a/projects/mtg/Android/AndroidManifest.xml +++ b/projects/mtg/Android/AndroidManifest.xml @@ -1,5 +1,5 @@ - + diff --git a/projects/mtg/Android/res/values/strings.xml b/projects/mtg/Android/res/values/strings.xml index 6336fcee8..dffe9fcfa 100644 --- a/projects/mtg/Android/res/values/strings.xml +++ b/projects/mtg/Android/res/values/strings.xml @@ -1,6 +1,6 @@ Wagic - 0.22.3 + 0.23.1 All Rights Reserved. diff --git a/projects/mtg/bin/Res/graphics/iconcommandzone.png b/projects/mtg/bin/Res/graphics/iconcommandzone.png new file mode 100644 index 0000000000000000000000000000000000000000..d1c3cec88fc6053a955d14189ac0bb92d7c22564 GIT binary patch literal 11722 zcmeI2?Mq};9LLXyt~xrVnUpk9k?zx}&-tYO{ z(V2et4q2poVfR2ZWIl6l2c<6YTIH2QUVvepJ zIvzS6CJyL$n3$uhhmObpHXi&Dh(B5=Pg>7$Z4gCybeaN~U6cj`bhl5-$7lnt1^M@tkE^C~X$~sl^7c@R)`-t@ui|lqg z_4M@6_VzaI?d?%tUmq107gI<`2;dJ{i>#MeCu+Wi25cYe0M2G-XH$1~H?6I$N#L28 z8JeD+rp?Vw+S=NZ@I^&M6c!c+_}i>m)(b4t<}2u@_$u$Qehvr-ptQ6!YHVzzyu3WX zcvMzaMngkGG&MCvb8~aFzP>JB5S-7?&sXqw_?!{evCf|t`Z1oomvz9RtgI~R?ChkL zmKI7*PNt@&Ch08P9UUDdKx152SC?l$jx8-M(az2e_4f9X)9Iw(;9!jVoi)cg;`~{m z<9ISGupbbE^z?KIyRx!Et*xz;o0}`$tgWr}xZK>_EEgfbqNAgw;{Y}av4JqAu&|J< zRx8d&#hGS3&ywx5&5jT6vZ`{77YBFMG4E|oPR@~Is>+Ovj8Iio6~)BF0QN7|b(WJQ+i}pz zd=#bYW?*0-WoBl|#k07$=!pStr8me~oW?x!^YgNPW3krM)F@a0f6jW9^^bNOG#;_r zEW$#=Egu^jleHFEgTvmy>UZxy6bz?Ze%`ZO6GVqPn`8Vq;?gi^uw> ztYVgFyBD-N8HIj@^+#xED3z3y(7?a|?e6Z%e0zhV9>Z~!Z`=jsw4$OyI*D3dUte!@ z_A8$IHP(sRNukwbFLMVqlWaDdbbfevSgv%ecw=l-iNjbWyqMC`Qc6fjQ2RdPV<(2? zv9g^OTAi1|9n{RjsHiCEJZdUxHKbyL{Nqj1`1m;0)zulD{hH6k7n}lFr*3D3Ru_Wv zJFGi+y9pQZ-U6}N-`}T+i3wR}Urs0?^0Bqk;* z*f0241~^(L#670dE@`&Ve=&ilRZ`NQ^p y2Q~6(Xrmkc>}#j}>8^2Z?X=MifA%f>5Tj?GxOwQ*[artifact;enchantment]|reveal) moveto(myhand) optiononeend optiontwo name(put on bottom) target(<4>*|reveal) bottomoflibrary optiontwoend revealend @@ -4048,6 +4060,7 @@ toughness=2 [/card] [card] name=Blaring Captain +abilities=partner auto=may moveto(myhand) notatarget(blaring recruiter|mylibrary) auto=@combat(attacking) source(this):all(warrior[attacking]) 1/1 text=Partner with Blaring Recruiter (When this creature enters the battlefield, target player may put Blaring Recruiter into their hand from their library, then shuffle.) -- Whenever Blaring Captain attacks, attacking Warriors get +1/+1 until end of turn. @@ -4059,6 +4072,7 @@ toughness=2 [/card] [card] name=Blaring Recruiter +abilities=partner auto=may moveto(myhand) notatarget(blaring captain|mylibrary) auto={2}{W}:create(warrior:creature warrior:1/1:white:) text=Partner with Blaring Captain (When this creature enters the battlefield, target player may put Blaring Captain into their hand from their library, then shuffle.) -- {2}{W}: Create a 1/1 white Warrior creature token. @@ -5154,12 +5168,12 @@ type=Enchantment [/card] [card] name=Brallin, Skyshark Rider -abilities=hiddenface +abilities=hiddenface,partner aicode=activate moveTo(myhand) target(Shabraz, the Skyshark|mylibrary) auto=name(search card) Reveal:type:*:mylibrary revealzone(mylibrary) optionone name(choose card) target(Shabraz, the Skyshark|reveal) transforms((,newability[all(other *|reveal) moveto(mylibrary) and!(shuffle)!],newability[moveto(myhand)])) optiononeend optiontwo name(shuffle) bottomoflibrary target(Shabraz, the Skyshark|reveal) and!( all(*|reveal) bottomoflibrary and!(shuffle)! )! optiontwoend revealend auto=@discarded(*|myHand):all(this) counter(1/1,1) && damage:1 opponent auto={R}:target(creature[Shark]) trample ueot -text=Partner with Shabraz, the Skyshark (When this creature enters the battlefield, target player may put Shabraz into their hand from their library, then shuffle.) -- Whenever you discard a card, put a +1/+1 counter on Brallin, Skyshark Rider and it deals 1 damage to each opponent. / {R}: Target Shark gains trample until end of turn. +text=Partner with Shabraz, the Skyshark (When this creature enters the battlefield, target player may put Shabraz into their hand from their library, then shuffle.) -- Whenever you discard a card, put a +1/+1 counter on Brallin, Skyshark Rider and it deals 1 damage to each opponent. -- {R}: Target Shark gains trample until end of turn. mana={3}{R} type=Legendary Creature subtype=Human Shaman @@ -6590,7 +6604,7 @@ toughness=4 [/card] [card] name=Cazur, Ruthless Stalker -abilities=hiddenface +abilities=hiddenface,partner aicode=activate moveTo(myhand) target(Ukkima, Stalking Shadow|mylibrary) auto=name(search card) Reveal:type:*:mylibrary revealzone(mylibrary) optionone name(choose card) target(Ukkima, Stalking Shadow|reveal) transforms((,newability[all(other *|reveal) moveto(mylibrary) and!(shuffle)!],newability[moveto(myhand)])) optiononeend optiontwo name(shuffle) bottomoflibrary target(Ukkima, Stalking Shadow|reveal) and!( all(*|reveal) bottomoflibrary and!(shuffle)! )! optiontwoend revealend auto=@combatdamaged(player) from(creature|myBattlefield):all(trigger[from]) counter(1/1) @@ -6766,6 +6780,7 @@ toughness=4 [/card] [card] name=Chakram Retriever +abilities=partner auto=may moveto(myhand) notatarget(chakram slinger|mylibrary) auto=@movedTo(*|mystack) restriction{myturnonly}:untap target(creature) text=Partner with Chakram Slinger (When this creature enters the battlefield, target player may put Chakram Slinger into their hand from their library, then shuffle.) -- Whenever you cast a spell during your turn, untap target creature. @@ -6777,6 +6792,7 @@ toughness=4 [/card] [card] name=Chakram Slinger +abilities=partner auto=may moveto(myhand) notatarget(chakram retriever|mylibrary) auto={R}{T}:damage:2 target(player) text=Partner with Chakram Retriever (When this creature enters the battlefield, target player may put Chakram Retriever into their hand from their library, then shuffle.) -- {R}, {T}: Chakram Slinger deals 2 damage to target player or planeswalker. @@ -8200,7 +8216,12 @@ type=Land [/card] [card] name=Command Tower -auto=chooseacolor transforms((,newability[{T}:add{chosencolor}])) forever chooseend +auto=if type(*[red]|myzones)~morethan~0 then transforms((,newability[{T}:add{R}])) forever +auto=if type(*[white]|myzones)~morethan~0 then transforms((,newability[{T}:add{W}])) forever +auto=if type(*[green]|myzones)~morethan~0 then transforms((,newability[{T}:add{G}])) forever +auto=if type(*[blue]|myzones)~morethan~0 then transforms((,newability[{T}:add{U}])) forever +auto=if type(*[black]|myzones)~morethan~0 then transforms((,newability[{T}:add{B}])) forever +auto=if type(artifact|myzones)~morethan~0 then transforms((,newability[{T}:add{C}])) forever text={T}: Add to your mana pool one mana of any color in your commander's color identity. type=Land [/card] @@ -8223,8 +8244,15 @@ type=Instant [card] name=Commander's Plate target=creature -auto={3}:equip +auto={5}:equip +auto={3} restriction{type(creature[iscommander]|mybattlefield)~morethan~0}:name(equip commander) rehook target(creature[iscommander]|mybattlefield) auto=teach(creature) 3/3 +auto=if type(*[red]|myzones)~lessthan~1 then teach(creature) protection from red +auto=if type(*[white]|myzones)~lessthan~1 then teach(creature) protection from white +auto=if type(*[green]|myzones)~lessthan~1 then teach(creature) protection from green +auto=if type(*[blue]|myzones)~lessthan~1 then teach(creature) protection from blue +auto=if type(*[black]|myzones)~lessthan~1 then teach(creature) protection from black +auto=if type(artifact|myzones)~lessthan~1 then teach(creature) protection from(artifact) text=Equipped creature gets +3/+3 and has protection from each color that's not in your commander's color identity. -- Equip commander {3} -- Equip {5} mana={1} type=Artifact @@ -8232,7 +8260,12 @@ subtype=Equipment [/card] [card] name=Commander's Sphere -auto=chooseacolor transforms((,newability[{T}:add{chosencolor}])) forever chooseend +auto=if type(*[red]|myzones)~morethan~0 then transforms((,newability[{T}:add{R}])) forever +auto=if type(*[white]|myzones)~morethan~0 then transforms((,newability[{T}:add{W}])) forever +auto=if type(*[green]|myzones)~morethan~0 then transforms((,newability[{T}:add{G}])) forever +auto=if type(*[blue]|myzones)~morethan~0 then transforms((,newability[{T}:add{U}])) forever +auto=if type(*[black]|myzones)~morethan~0 then transforms((,newability[{T}:add{B}])) forever +auto=if type(artifact|myzones)~morethan~0 then transforms((,newability[{T}:add{C}])) forever auto={S}:draw:1 controller text={T}: Add to your mana pool one mana of any color in your commander's color identity. -- Sacrifice Commander's Sphere: Draw a card. mana={3} @@ -18560,7 +18593,7 @@ toughness=3 [/card] [card] name=Gorm the Great -abilities=vigilance,menace +abilities=vigilance,menace,partner auto=may moveto(myhand) notatarget(Virtus the Veiled|mylibrary) and!(shuffle)! auto=@combat(attacking) source(this):all(creature|opponentbattlefield) mustblock ueot text=Partner with Virtus the Veiled (When this creature enters the battlefield, target player may put Virtus into their hand from their library, then shuffle.) -- Vigilance -- Gorm the Great must be blocked if able, and Gorm must be blocked by two or more creatures if able. @@ -19416,7 +19449,7 @@ toughness=4 [/card] [card] name=Haldan, Avid Arcanist -abilities=hiddenface,canplayfromexile +abilities=hiddenface,canplayfromexile,partner aicode=activate moveTo(myhand) target(Pako, Arcane Retriever|mylibrary) auto=name(search card) Reveal:type:*:mylibrary revealzone(mylibrary) optionone name(choose card) target(Pako, Arcane Retriever|reveal) transforms((,newability[all(other *|reveal) moveto(mylibrary) and!(shuffle)!],newability[moveto(myhand)])) optiononeend optiontwo name(shuffle) bottomoflibrary target(Pako, Arcane Retriever|reveal) and!( all(*|reveal) bottomoflibrary and!(shuffle)! )! optiontwoend revealend auto=lord(*[-creature]|mycastingzone) transforms((,newability[anytypeofmana])) @@ -24029,7 +24062,7 @@ toughness=4 [/card] [card] name=Khorvath Brightflame -abilities=flying,haste +abilities=flying,haste,partner auto=may moveto(myhand) notatarget(sylvia brightspear|mylibrary) auto=lord(knight|myBattlefield) flying auto=lord(knight|myBattlefield) haste @@ -25427,6 +25460,7 @@ type=Sorcery [/card] [card] name=Ley Weaver +abilities=partner auto=may moveto(myhand) notatarget(lore weaver|mylibrary) auto={T}:untap <2>target(land) text=Partner with Lore Weaver (When this creature enters the battlefield, target player may put Lore Weaver into their hand from their library, then shuffle.) -- {T}: Untap two target lands. @@ -26256,6 +26290,7 @@ toughness=3 [/card] [card] name=Lore Weaver +abilities=partner auto=may moveto(myhand) notatarget(ley weaver|mylibrary) auto={5}{U}{U}:draw:2 target(player) text=Partner with Ley Weaver (When this creature enters the battlefield, target player may put Ley Weaver into their hand from their library, then shuffle.) -- {5}{U}{U}: Target player draws two cards. @@ -30120,7 +30155,7 @@ toughness=2 [/card] [card] name=Nikara, Lair Scavenger -abilities=menace +abilities=menace,partner auto=may moveto(myhand) target(Yannik, Scavenging Sentinel|mylibrary) auto=@movedTo(other creature[counter{1/1}]|nonbattlezone) from(mybattlefield):draw:1 && life:-1 controller text=Partner with Yannik, Scavenging Sentinel (When this creature enters the battlefield, target player may put Yannik into their hand from their library, then shuffle.) -- Menace -- Whenever another creature you control leaves the battlefield, if it had one or more counters on it, you draw a card and you lose 1 life. @@ -32023,7 +32058,7 @@ toughness=2 [/card] [card] name=Pako, Arcane Retriever -abilities=hiddenface,haste +abilities=hiddenface,haste,partner aicode=activate moveTo(myhand) target(Haldan, Avid Arcanist|mylibrary) auto=name(search card) Reveal:type:*:mylibrary revealzone(mylibrary) optionone name(choose card) target(Haldan, Avid Arcanist|reveal) transforms((,newability[all(other *|reveal) moveto(mylibrary) and!(shuffle)!],newability[moveto(myhand)])) optiononeend optiontwo name(shuffle) bottomoflibrary target(Haldan, Avid Arcanist|reveal) and!( all(*|reveal) bottomoflibrary and!(shuffle)! )! optiontwoend revealend auto=@combat(attacking) source(this):NOTCODED @@ -33755,6 +33790,7 @@ type=Artifact [/card] [card] name=Proud Mentor +abilities=partner auto=may moveto(myhand) notatarget(impetuous protege|mylibrary) auto={W}{T}:tap target(creature) text=Partner with Impetuous Protege (When this creature enters the battlefield, target player may put Impetuous Protege into their hand from their library, then shuffle.) -- {W}, {T}: Tap target creature. @@ -35434,7 +35470,7 @@ type=Sorcery [/card] [card] name=Regna, the Redeemer -abilities=flying +abilities=flying,partner auto=may moveto(myhand) notatarget(krav, the unredeemed|mylibrary) auto=@each endofturn restriction{compare(lifegain)~morethan~0}:create(warrior:creature warrior:1/1:white:)*2 text=Partner with Krav, the Unredeemed (When this creature enters the battlefield, target player may put Krav into their hand from their library, then shuffle.) -- Flying -- At the beginning of each end step, if your team gained life this turn, create two 1/1 white Warrior creature tokens. @@ -39372,7 +39408,7 @@ toughness=2 [/card] [card] name=Shabraz, the Skyshark -abilities=hiddenface +abilities=hiddenface,partner aicode=activate moveTo(myhand) target(Brallin, Skyshark Rider|mylibrary) auto=name(search card) Reveal:type:*:mylibrary revealzone(mylibrary) optionone name(choose card) target(Brallin, Skyshark Rider|reveal) transforms((,newability[all(other *|reveal) moveto(mylibrary) and!(shuffle)!],newability[moveto(myhand)])) optiononeend optiontwo name(shuffle) bottomoflibrary target(Brallin, Skyshark Rider|reveal) and!( all(*|reveal) bottomoflibrary and!(shuffle)! )! optiontwoend revealend auto=@drawof(player:all(this) counter(1/1,1) && life:1 controller @@ -40459,7 +40495,7 @@ type=Instant [/card] [card] name=Silvar, Devourer of the Free -abilities=hiddenface,menace +abilities=hiddenface,menace,partner aicode=activate moveTo(myhand) target(Trynn, Champion of Freedom|mylibrary) auto=name(search card) Reveal:type:*:mylibrary revealzone(mylibrary) optionone name(choose card) target(Trynn, Champion of Freedom|reveal) transforms((,newability[all(other *|reveal) moveto(mylibrary) and!(shuffle)!],newability[moveto(myhand)])) optiononeend optiontwo name(shuffle) bottomoflibrary target(Trynn, Champion of Freedom|reveal) and!( all(*|reveal) bottomoflibrary and!(shuffle)! )! optiontwoend revealend auto={S(Human|myBattlefield)}:all(this) counter(1/1) && indestructible ueot @@ -42131,7 +42167,7 @@ subtype=Aura [/card] [card] name=Soulblade Corrupter -abilities=deathtouch +abilities=deathtouch,partner auto=may moveto(myhand) notatarget(soulblade renewer|mylibrary) auto=@combat(attacking) source(creature[counter{1/1.1}]|mybattlefield):deathtouch ueot text=Partner with Soulblade Renewer (When this creature enters the battlefield, target player may put Soulblade Renewer into their hand from their library, then shuffle.) -- Deathtouch -- Whenever a creature with a +1/+1 counter on it attacks one of your opponents, that creature gains deathtouch until end of turn. @@ -42143,6 +42179,7 @@ toughness=3 [/card] [card] name=Soulblade Renewer +abilities=partner auto=may moveto(myhand) notatarget(soulblade corrupter|mylibrary) auto=target(other creature|battlefield) counter(1/1) text=Partner with Soulblade Corrupter (When this creature enters the battlefield, target player may put Soulblade Corrupter into their hand from their library, then shuffle.) -- When Soulblade Renewer enters the battlefield, support 2. (Put a +1/+1 counter on each of up to two other target creatures.) @@ -44878,7 +44915,7 @@ type=Sorcery [/card] [card] name=Sylvia Brightspear -abilities=double strike +abilities=double strike,partner auto=lord(dragon|myBattlefield) haste double strike auto=may moveto(myhand) notatarget(khorvath brightflame|mylibrary) text=Partner with Khorvath Brightflame (When this creature enters the battlefield, target player may put Khorvath into their hand from their library, then shuffle.) -- Double strike -- Dragons your team controls have double strike. @@ -47500,6 +47537,7 @@ toughness=3 [/card] [card] name=Toothy, Imaginary Friend +abilities=partner auto=may moveto(myhand) notatarget(pir, imaginative rascal|mylibrary) auto=@drawof(player):counter(1/1) auto=@movedTo(this|nonbattlezone) from(myBattlefield):thisforeach(counter{1/1,1}) draw:1 controller @@ -48261,7 +48299,7 @@ toughness=3 [/card] [card] name=Trynn, Champion of Freedom -abilities=hiddenface +abilities=hiddenface,partner aicode=activate moveTo(myhand) target(Silvar, Devourer of the Free|mylibrary) auto=name(search card) Reveal:type:*:mylibrary revealzone(mylibrary) optionone name(choose card) target(Silvar, Devourer of the Free|reveal) transforms((,newability[all(other *|reveal) moveto(mylibrary) and!(shuffle)!],newability[moveto(myhand)])) optiononeend optiontwo name(shuffle) bottomoflibrary target(Silvar, Devourer of the Free|reveal) and!( all(*|reveal) bottomoflibrary and!(shuffle)! )! optiontwoend revealend auto=@each my endofturn:if raid then token(Soldier Try) @@ -48646,7 +48684,7 @@ toughness=0 [/card] [card] name=Ukkima, Stalking Shadow -abilities=hiddenface,unblockable +abilities=hiddenface,unblockable,partner aicode=activate moveTo(myhand) target(Cazur, Ruthless Stalker|mylibrary) auto=name(search card) Reveal:type:*:mylibrary revealzone(mylibrary) optionone name(choose card) target(Cazur, Ruthless Stalker|reveal) transforms((,newability[all(other *|reveal) moveto(mylibrary) and!(shuffle)!],newability[moveto(myhand)])) optiononeend optiontwo name(shuffle) bottomoflibrary target(Cazur, Ruthless Stalker|reveal) and!( all(*|reveal) bottomoflibrary and!(shuffle)! )! optiontwoend revealend auto=@movedto(this|nonbattlezone):damage:storedpower target(opponent) && life:storedpower controller @@ -50284,7 +50322,7 @@ type=Sorcery [/card] [card] name=Virtus the Veiled -abilities=deathtouch +abilities=deathtouch,partner auto=may moveto(myhand) notatarget(gorm the great|mylibrary) auto=@combatdamaged(player) from(this):life:-halfdownopponentlifetotal opponent text=Partner with Gorm the Great (When this creature enters the battlefield, target player may put Gorm into their hand from their library, then shuffle.) -- Deathtouch -- Whenever Virtus the Veiled deals combat damage to a player, that player loses half their life, rounded up. @@ -50974,7 +51012,11 @@ type=Artifact [card] name=War Room auto={T}:add{C} -auto={L:1}{3}{T}:draw:1 controller +auto={L:1}{3}{T}:name(1 color in your identity) name(1 color in your identity) draw:1 controller +auto={L:2}{3}{T}:name(2 colors in your identity) name(2 colors in your identity) draw:1 controller +auto={L:3}{3}{T}:name(3 colors in your identity) name(3 colors in your identity) draw:1 controller +auto={L:4}{3}{T}:name(4 colors in your identity) name(4 colors in your identity) draw:1 controller +auto={L:5}{3}{T}:name(5 colors in your identity) name(5 colors in your identity) draw:1 controller text={T}: Add {C}. -- {3}, {T}, Pay life equal to the number of colors in your commanders' color identity: Draw a card. type=Land [/card] @@ -52374,7 +52416,7 @@ toughness=4 [/card] [card] name=Yannik, Scavenging Sentinel -abilities=vigilance +abilities=vigilance,partner auto=may moveto(myhand) target(Nikara, Lair Scavenger|mylibrary) auto=(blink)forsrc target(other creature|mybattlefield) && target(creature) counter(1/1,storedpower) text=Partner with Nikara, Lair Scavenger -- Vigilance -- When Yannik, Scavenging Sentinel enters the battlefield, exile another creature you control until Yannik leaves the battlefield. When you do, distribute X +1/+1 counters among any number of target creatures, where X is the exiled creature's power. diff --git a/projects/mtg/bin/Res/sets/primitives/planeswalkers.txt b/projects/mtg/bin/Res/sets/primitives/planeswalkers.txt index 2d6038ec6..0a6dfd1b7 100644 --- a/projects/mtg/bin/Res/sets/primitives/planeswalkers.txt +++ b/projects/mtg/bin/Res/sets/primitives/planeswalkers.txt @@ -181,6 +181,7 @@ subtype=Ajani [/card] [card] name=Aminatou, the Fateshifter +abilities=canbecommander auto=counter(0/0,3,loyalty) auto={C(0/0,1,Loyalty)}:name(+1: Draw a card and return a card on top) ability$!draw:1 controller _ choice target(*|myhand) moveTo(mylibrary)!$ controller auto={C(0/0,-3,Loyalty)}:name(-1: Exile other permanent and return it) moveTo(exile) target(other *|myBattlefield) and! moveTo(myBattlefield)! @@ -601,6 +602,7 @@ subtype=Daretti [/card] [card] name=Daretti, Scrap Savant +abilities=canbecommander auto=counter(0/0,3,loyalty) auto={C(0/0,2,Loyalty)}:name(+2: Discard and Draw) reject notatarget(*|myhand) and!( draw:1 controller )! auto={C(0/0,-2,Loyalty)}:name(-2: Sacrifice an Artifact) sacrifice notatarget(artifact|mybattlefield) and!( moveto(mybattlefield) target(artifact|mygraveyard) )! @@ -792,6 +794,7 @@ subtype=Elspeth [/card] [card] name=Estrid, the Masked +abilities=canbecommander auto=counter(0/0,3,loyalty) auto={C(0/0,2,Loyalty)}:name(+2: Untap each enchanted permanent) untap all(*[geared]|myBattlefield) auto={C(0/0,-1,Loyalty)}:name(-1: Create an Aura Mask) token(Mask Est) @@ -803,6 +806,7 @@ subtype=Estrid [/card] [card] name=Freyalise, Llanowar's Fury +abilities=canbecommander auto=counter(0/0,3,loyalty) auto={C(0/0,2,Loyalty)}:name(+2: Create a 1/1 Elf Druid) token(Elf Druid,Creature Elf Druid,1/1,green) and!(transforms((,newability[{T}:Add{G}])) forever)! auto={C(0/0,-2,Loyalty)}:name(-2: Destroy target artifact or enchantment) target(artifact,enchantment) destroy @@ -1550,6 +1554,7 @@ subtype=Liliana [/card] [card] name=Lord Windgrace +abilities=canbecommander auto=counter(0/0,5,Loyalty) auto={C(0/0,2,Loyalty)}:name(+2: Discard and Draw) draw:1 controller && ability$!name(Choose one) choice name(Discard land) reject notatarget(*[land]|myhand) && draw:1 conroller _ choice name(Discard non-land) reject notatarget(*[-land]|myhand)!$ controller auto={C(0/0,-3,Loyalty)}:name(-3: Return up to two lands from graveyard) moveTo(myBattlefield) target(*[land]|myGraveyard) @@ -1648,6 +1653,7 @@ subtype=Nahiri [/card] [card] name=Nahiri, the Lithomancer +abilities=canbecommander auto=counter(0/0,3,loyalty) auto={C(0/0,2,Loyalty)}:name(+2: Create a 1/1 Soldier and may equip) token(Kor Soldier,Creature Kor Soldier,1/1,white) and!(transforms((,newability[may target(equipment|mybattlefield) newhook])) oneshot)! auto={C(0/0,-2,Loyalty)}:name(-2: Put an Equipment from hand or graveyard) notatarget(equipment|mygraveyard,myhand) moveto(ownerbattlefield) @@ -1866,6 +1872,7 @@ subtype=Nissa [/card] [card] name=Ob Nixilis of the Black Oath +abilities=canbecommander auto=counter(0/0,3,loyalty) auto={C(0/0,2,Loyalty)}:name(+2: Each opponent loses 1 life...) life:-1 opponent && life:1 controller auto={C(0/0,-2,Loyalty)}:name(-2: Create a 5/5 black Demon with flying...) token(Demon,Creature Demon,5/5,black,flying) && life:-2 controller @@ -1976,6 +1983,7 @@ subtype=Rowan [/card] [card] name=Rowan Kenrith +abilities=partner,canbecommander auto=counter(0/0,4,loyalty) auto={C(0/0,2,Loyalty)}:name(+2: Opponent creatures must attack) all(creature|opponentbattlefield) mustattack ueot auto={C(0/0,2,Loyalty)}:name(+2: Your creatures must attack) all(creature|mybattlefield) mustattack ueot @@ -2009,6 +2017,7 @@ subtype=Saheeli [/card] [card] name=Saheeli, the Gifted +abilities=canbecommander auto=counter(0/0,4,loyalty) auto={C(0/0,1,Loyalty)}:name(+1: Create a 1/1 colorless Servo) token(Servo,Artifact Creature Servo,1/1) auto={C(0/0,-1,Loyalty)}:name(-1: The next spell has affinity for artifacts) lord(*|mycastingzone):affinityartifacts oneshot @@ -2303,6 +2312,7 @@ subtype=Teferi [/card] [card] name=Teferi, Temporal Archmage +abilities=canbecommander auto=counter(0/0,5,loyalty) aicode=activate transforms((,newability[moveto(myhand) all(*[zpos=1]|mylibrary) && bottomoflibrary all(*[zpos=2]|mylibrary)])) ueot auto={C(0/0,1,Loyalty)}:name(+1: Look at the top two, one in hand other to bottom) name(Look) reveal:2 optionone name(Get a card) target(<1>*|reveal) moveto(myhand) optiononeend optiontwo name(put on bottom) target(<2>*|reveal) bottomoflibrary optiontwoend revealend @@ -2348,7 +2358,7 @@ subtype=Teferi [/card] [card] name=Tevesh Szat, Doom of Fools -abilities=partner +abilities=partner,canbecommander auto=counter(0/0,4,loyalty) auto={C(0/0,1,Loyalty)}:name(+1: Sacrifice and draw 2 cards) target(*[creature;planeswalker]|mybattlefield) sacrifice and!(draw:1)! auto={C(0/0,2,Loyalty)}:name(+2: Create two 0/1 black Thrull) token(Thrull,Creature Thrull,0/1,black)*2 @@ -2696,9 +2706,10 @@ subtype=Vraska [/card] [card] name=Will Kenrith +abilities=partner,canbecommander auto=counter(0/0,4,loyalty) auto={C(0/0,2,Loyalty)}:name(+2: Up to two creatures 0/3 no abilities) target(creatures) transforms(setpower=0,settoughness=3,loseabilities) uynt -auto={C(0/0,-2,Loyalty)}:name(-2: Draw two cards and cost {2} less) target(player) draw:2 targetedplayer && emblem transforms((,newability[lord(*[instant;sorcery;planeswalker]|mycastingzone) altercost(colorless,-2)])) uynt +auto={C(0/0,-2,Loyalty)}:name(-2: Draw two cards and cost {2} less) target(player) draw:2 targetedplayer && all(this) transforms((,newability[lord(*[instant;sorcery;planeswalker]|mycastingzone) altercost(colorless,-2)])) uynt auto={C(0/0,-8,Loyalty)}:name(-8: Whenever cast instant or sorcery copy spell) emblem transforms((,newability[@movedTo(*[instant;sorcery]|myStack):may castcard(copied noevent) target(*[instant;sorcery]|mystack)])) forever dontremove text=+2: Until your next turn, up to two target creatures each have base power and toughness 0/3 and lose all abilities. -- −2: Target player draws two cards. Until your next turn, instant, sorcery, and planeswalker spells that player casts cost {2} less to cast. -- −8: Target player gets an emblem with "Whenever you cast an instant or sorcery spell, copy it. You may choose new targets for the copy." -- Partner with Rowan Kenrith -- Will Kenrith can be your commander. mana={4}{U}{U} diff --git a/projects/mtg/bin/Res/sets/primitives/unsupported.txt b/projects/mtg/bin/Res/sets/primitives/unsupported.txt index 5afc8c130..c3ed706bf 100644 --- a/projects/mtg/bin/Res/sets/primitives/unsupported.txt +++ b/projects/mtg/bin/Res/sets/primitives/unsupported.txt @@ -478,12 +478,6 @@ power=3 toughness=3 [/card] [card] -name=Arcane Signet -text={T}: Add one mana of any color in your commander's color identity. -mana={2} -type=Artifact -[/card] -[card] name=Arcanum Wings text=Enchant creature -- Enchanted creature has flying. -- Aura swap {2}{U} ({2}{U}: Exchange this Aura with an Aura card in your hand.) mana={1}{U} diff --git a/projects/mtg/build.number.properties b/projects/mtg/build.number.properties index 807a5918c..8f2618df6 100644 --- a/projects/mtg/build.number.properties +++ b/projects/mtg/build.number.properties @@ -1,6 +1,6 @@ #build.number.properties (normally this file is maintained by build.xml) #Sun, 20 May 2020 11:56:35 +0200 build.major=0 -build.minor=22 -build.point=3 +build.minor=23 +build.point=1 diff --git a/projects/mtg/include/AllAbilities.h b/projects/mtg/include/AllAbilities.h index babc3f013..8804cc004 100644 --- a/projects/mtg/include/AllAbilities.h +++ b/projects/mtg/include/AllAbilities.h @@ -429,8 +429,8 @@ private: for (int i = 0; i < 2; i++) { Player * p = card->getObserver()->players[i]; - MTGGameZone * zones[] = { p->game->inPlay, p->game->graveyard, p->game->hand, p->game->library, p->game->exile, p->game->sideboard };//wish cards use sideboard - for (int k = 0; k < 6; k++) + MTGGameZone * zones[] = { p->game->inPlay, p->game->graveyard, p->game->hand, p->game->library, p->game->exile, p->game->sideboard, p->game->commandzone };//wish cards use sideboard + for (int k = 0; k < 7; k++) { MTGGameZone * zone = zones[k]; if (tc->targetsZone(zone, card)) @@ -606,6 +606,10 @@ private: { intValue = card->controller()->game->stack->seenThisTurn("*[-creature]", Constants::CAST_ALL); } + else if(s == "pnumofcommandcast" || s == "onumofcommandcast") + { + intValue = (s == "pnumofcommandcast")?card->controller()->numOfCommandCast:card->controller()->opponent()->numOfCommandCast; + } else if (s == "evictg") { intValue = card->imprintG; diff --git a/projects/mtg/include/GuiAvatars.h b/projects/mtg/include/GuiAvatars.h index 36622051b..501e530d6 100644 --- a/projects/mtg/include/GuiAvatars.h +++ b/projects/mtg/include/GuiAvatars.h @@ -8,6 +8,7 @@ class GuiGraveyard; class GuiLibrary; class GuiOpponentHand; class GuiExile; +class GuiCommandZone; class GuiAvatars: public GuiLayer { protected: @@ -16,6 +17,7 @@ protected: GuiLibrary* selfLibrary, *opponentLibrary; GuiOpponentHand *opponentHand; GuiExile* selfExile, *opponentExile; + GuiCommandZone* selfCommandZone, *opponentCommandZone; GuiAvatar* active; public: diff --git a/projects/mtg/include/GuiStatic.h b/projects/mtg/include/GuiStatic.h index 513d7848b..1d28aa268 100644 --- a/projects/mtg/include/GuiStatic.h +++ b/projects/mtg/include/GuiStatic.h @@ -98,4 +98,14 @@ public: virtual ostream& toString(ostream& out) const; }; +class GuiCommandZone: public GuiGameZone +{ +public: + Player * player; + GuiCommandZone(float _x, float _y, bool hasFocus, Player * player, GuiAvatars* parent); + int receiveEventPlus(WEvent*); + int receiveEventMinus(WEvent*); + virtual ostream& toString(ostream& out) const; +}; + #endif // _GUISTATIC_H_ diff --git a/projects/mtg/include/MTGCardInstance.h b/projects/mtg/include/MTGCardInstance.h index e69ee6854..d73612d69 100644 --- a/projects/mtg/include/MTGCardInstance.h +++ b/projects/mtg/include/MTGCardInstance.h @@ -63,6 +63,8 @@ public: int sunburst; int equipment; int mutation; + int damageInflictedAsCommander; + int numofcastfromcommandzone; int auras; bool wasDealtDamage; bool combatdamageToOpponent; diff --git a/projects/mtg/include/MTGDeck.h b/projects/mtg/include/MTGDeck.h index 053ea1a00..63e2a9217 100644 --- a/projects/mtg/include/MTGDeck.h +++ b/projects/mtg/include/MTGDeck.h @@ -215,6 +215,7 @@ public: string meta_name; vector meta_AIHints; vector Sideboard; + vector CommandZone; string meta_unlockRequirements; int meta_id; diff --git a/projects/mtg/include/MTGDefinitions.h b/projects/mtg/include/MTGDefinitions.h index fdb5b3730..75308de82 100644 --- a/projects/mtg/include/MTGDefinitions.h +++ b/projects/mtg/include/MTGDefinitions.h @@ -288,7 +288,9 @@ class Constants NOFIZZLEALTERNATIVE = 162, HASOTHERKICKER = 163, PARTNER = 164, - NB_BASIC_ABILITIES = 165, + CANBECOMMANDER = 165, + ISCOMMANDER = 166, + NB_BASIC_ABILITIES = 167, RARITY_S = 'S', //Special Rarity RARITY_M = 'M', //Mythics diff --git a/projects/mtg/include/MTGGameZones.h b/projects/mtg/include/MTGGameZones.h index 65a022d28..d9135cf47 100644 --- a/projects/mtg/include/MTGGameZones.h +++ b/projects/mtg/include/MTGGameZones.h @@ -87,6 +87,14 @@ class MTGGameZone { SIDEBOARD = 85, OWNER_SIDEBOARD = 86, TARGETED_PLAYER_SIDEBOARD = 87, + + MY_COMMANDZONE = 88, + OPPONENT_COMMANDZONE = 89, + TARGET_OWNER_COMMANDZONE = 90, + TARGET_CONTROLLER_COMMANDZONE = 91, + COMMANDZONE = 92, + OWNER_COMMANDZONE = 93, + TARGETED_PLAYER_COMMANDZONE = 94, }; Player * owner; @@ -214,6 +222,7 @@ public: MTGGameZone * garbageLastTurn; MTGGameZone * reveal; MTGGameZone * sideboard; + MTGGameZone * commandzone; MTGGameZone * temp; MTGPlayerCards(); diff --git a/projects/mtg/include/PlayGuiObject.h b/projects/mtg/include/PlayGuiObject.h index 2f4dbcf67..b7ec15ac1 100644 --- a/projects/mtg/include/PlayGuiObject.h +++ b/projects/mtg/include/PlayGuiObject.h @@ -11,6 +11,7 @@ #define GUI_LIBRARY 4 #define GUI_OPPONENTHAND 5 #define GUI_EXILE 6 +#define GUI_COMMANDZONE 7 #include #include "WEvent.h" diff --git a/projects/mtg/include/Player.h b/projects/mtg/include/Player.h index e84e56564..b32d6d5ca 100644 --- a/projects/mtg/include/Player.h +++ b/projects/mtg/include/Player.h @@ -44,6 +44,7 @@ public: int drawCounter; int energyCount; int yidaroCount; + int numOfCommandCast; int monarch; int surveilOffset; int epic; diff --git a/projects/mtg/include/Wagic_Version.h b/projects/mtg/include/Wagic_Version.h index 1f431c0dd..fdcf09ac5 100644 --- a/projects/mtg/include/Wagic_Version.h +++ b/projects/mtg/include/Wagic_Version.h @@ -13,8 +13,8 @@ Mod by: Vitty85 /* Wagic versions */ #define WAGIC_VERSION_MAJOR 0 -#define WAGIC_VERSION_MEDIUM 22 -#define WAGIC_VERSION_MINOR 3 +#define WAGIC_VERSION_MEDIUM 23 +#define WAGIC_VERSION_MINOR 1 #define VERSION_DOT(a, b, c) a ##.## b ##.## c #define VERSION_WITHOUT_DOT(a, b, c) a ## b ## c diff --git a/projects/mtg/src/AIPlayerBaka.cpp b/projects/mtg/src/AIPlayerBaka.cpp index be0524a25..f437342a3 100644 --- a/projects/mtg/src/AIPlayerBaka.cpp +++ b/projects/mtg/src/AIPlayerBaka.cpp @@ -1908,7 +1908,7 @@ int AIPlayerBaka::createAbilityTargets(MTGAbility * a, MTGCardInstance * c, Rank for (int i = 0; i < 2; i++) { Player * p = observer->players[i]; - MTGGameZone * playerZones[] = { p->game->graveyard, p->game->library, p->game->hand, p->game->inPlay,p->game->stack,p->game->exile, p->game->reveal, p->game->sideboard }; + MTGGameZone * playerZones[] = { p->game->graveyard, p->game->library, p->game->hand, p->game->inPlay,p->game->stack,p->game->exile, p->game->reveal, p->game->sideboard, p->game->commandzone }; if(a->getActionTc()->canTarget((Targetable*)p)) { if(a->getActionTc()->maxtargets == 1) @@ -1919,7 +1919,7 @@ int AIPlayerBaka::createAbilityTargets(MTGAbility * a, MTGCardInstance * c, Rank else potentialTargets.push_back(p); } - for (int j = 0; j < 6; j++) + for (int j = 0; j < 9; j++) { MTGGameZone * zone = playerZones[j]; for (int k = 0; k < zone->nb_cards; k++) @@ -2395,8 +2395,8 @@ int AIPlayerBaka::chooseTarget(TargetChooser * _tc, Player * forceTarget,MTGCard } } MTGPlayerCards * playerZones = target->game; - MTGGameZone * zones[] = { playerZones->hand, playerZones->library, playerZones->inPlay, playerZones->graveyard,playerZones->stack,playerZones->exile,playerZones->reveal, playerZones->sideboard }; - for (int j = 0; j < 8; j++) + MTGGameZone * zones[] = { playerZones->hand, playerZones->library, playerZones->inPlay, playerZones->graveyard,playerZones->stack,playerZones->exile,playerZones->reveal, playerZones->sideboard, playerZones->commandzone }; + for (int j = 0; j < 9; j++) { MTGGameZone * zone = zones[j]; for (int k = 0; k < zone->nb_cards; k++) @@ -3054,6 +3054,135 @@ MTGCardInstance * AIPlayerBaka::FindCardToPlay(ManaCost * pMana, const char * ty maxCost = pMana->getConvertedCost(); } } + //play from commandzone + while ((card = cd.nextmatch(game->commandzone, card))) + { + if (!CanHandleCost(card->getManaCost(),card)) + continue; + + if (game->playRestrictions->canPutIntoZone(card, game->stack) == PlayRestriction::CANT_PLAY) + continue; + + if (card->hasType(Subtypes::TYPE_LEGENDARY) && game->inPlay->findByName(card->name)) + continue; + + if(hints && hints->HintSaysItsForCombo(observer,card)) + { + if(hints->canWeCombo(observer,card,this)) + { + AbilityFactory af(observer); + int canPlay = af.parseCastRestrictions(card,card->controller(),card->getRestrictions()); + if(!canPlay) + continue; + nextCardToPlay = card; + gotPayments.clear(); + if((!pMana->canAfford(nextCardToPlay->getManaCost()) || nextCardToPlay->getManaCost()->getKicker())) + gotPayments = canPayMana(nextCardToPlay,nextCardToPlay->getManaCost()); + return activateCombo(); + } + else + { + nextCardToPlay = NULL; + continue; + } + } + int currentCost = card->getManaCost()->getConvertedCost(); + int hasX = card->getManaCost()->hasX(); + gotPayments.clear(); + if((!pMana->canAfford(card->getManaCost()) || card->getManaCost()->getKicker())) + gotPayments = canPayMana(card,card->getManaCost()); + //for preformence reason we only look for specific mana if the payment couldn't be made with pmana. + if ((currentCost > maxCost || hasX) && (gotPayments.size() || pMana->canAfford(card->getManaCost()))) + { + TargetChooserFactory tcf(observer); + TargetChooser * tc = tcf.createTargetChooser(card); + int shouldPlayPercentage = 0; + if (tc) + { + int hasTarget = chooseTarget(tc,NULL,NULL,true); + if( + (tc->maxtargets > hasTarget && tc->maxtargets > 1 && !tc->targetMin && tc->maxtargets != TargetChooser::UNLITMITED_TARGETS) ||//target=<3>creature + (tc->maxtargets == TargetChooser::UNLITMITED_TARGETS && hasTarget < 1)//target=creatures + ) + hasTarget = 0; + if (!hasTarget)//single target covered here. + { + SAFE_DELETE(tc); + continue; + } + shouldPlayPercentage = 90; + if(tc->targetMin && hasTarget < tc->maxtargets) + shouldPlayPercentage = 0; + if(tc->maxtargets > 1 && tc->maxtargets != TargetChooser::UNLITMITED_TARGETS && hasTarget <= tc->maxtargets) + { + int maxA = hasTarget-tc->maxtargets; + shouldPlayPercentage += (10*maxA);//reduce the chances of playing multitarget if we are not above max targets. + } + if(tc->maxtargets == TargetChooser::UNLITMITED_TARGETS) + { + shouldPlayPercentage = 40 + (10*hasTarget); + int totalCost = pMana->getConvertedCost()-currentCost; + int totalTargets = hasTarget+hasTarget; + if(hasX && totalCost <= totalTargets)// {x} spell with unlimited targeting tend to divide damage, we want atleast 1 damage per target before casting. + { + shouldPlayPercentage = 0; + } + } + SAFE_DELETE(tc); + } + else + { + int shouldPlay = effectBadOrGood(card); + if (shouldPlay == BAKA_EFFECT_GOOD) { + shouldPlayPercentage = 90; + } + else if (BAKA_EFFECT_DONTKNOW == shouldPlay) { + //previously shouldPlayPercentage = 80;, I found this a little to high + //for cards which AI had no idea how to use. + shouldPlayPercentage = 60; + } + else { + // shouldPlay == baka_effect_bad giving it a 10 for odd ball lottery chance. + shouldPlayPercentage = 10; + } + } + //Reduce the chances of playing a spell with X cost if available mana is low + if (hasX) + { + int xDiff = pMana->getConvertedCost() - currentCost; + if (xDiff < 0) + xDiff = 0; + shouldPlayPercentage = shouldPlayPercentage - static_cast ((shouldPlayPercentage * 1.9f) / (1 + xDiff)); + } + if(card->getManaCost() && card->getManaCost()->getKicker() && card->getManaCost()->getKicker()->isMulti) + { + shouldPlayPercentage = 10* size_t(gotPayments.size())/int(1+(card->getManaCost()->getConvertedCost()+card->getManaCost()->getKicker()->getConvertedCost())); + if(shouldPlayPercentage <= 10) + shouldPlayPercentage = shouldPlayPercentage/3; + } + DebugTrace("Should I play from commandzone" << (card ? card->name : "Nothing" ) << "?" << endl + <<"shouldPlayPercentage = "<< shouldPlayPercentage); + if(card->getRestrictions().size()) + { + AbilityFactory af(observer); + int canPlay = af.parseCastRestrictions(card,card->controller(),card->getRestrictions()); + if(!canPlay) + continue; + } + int randomChance = randomGenerator.random(); + int chance = randomChance % 100; + if (chance > shouldPlayPercentage) + continue; + if(shouldPlayPercentage <= 10) + { + DebugTrace("shouldPlayPercentage was less than 10 this was a lottery roll on RNG"); + } + nextCardToPlay = card; + maxCost = currentCost; + if (hasX) + maxCost = pMana->getConvertedCost(); + } + } if(nextCardToPlay) { if(!pMana->canAfford(nextCardToPlay->getManaCost()) || nextCardToPlay->getManaCost()->getKicker()) diff --git a/projects/mtg/src/AllAbilities.cpp b/projects/mtg/src/AllAbilities.cpp index 9bc12bf13..21eed8202 100644 --- a/projects/mtg/src/AllAbilities.cpp +++ b/projects/mtg/src/AllAbilities.cpp @@ -1152,10 +1152,10 @@ int AAAlterMonarch::resolve() { if(!pTarget->monarch){ pTarget->monarch = 1; - pTarget->opponent()->monarch = 0; + pTarget->opponent()->monarch = 0; WEvent * e = NEW WEventplayerMonarch(pTarget); game->receiveEvent(e); - } + } } } return 0; diff --git a/projects/mtg/src/Damage.cpp b/projects/mtg/src/Damage.cpp index ed2f88ae9..072ebdc2c 100644 --- a/projects/mtg/src/Damage.cpp +++ b/projects/mtg/src/Damage.cpp @@ -256,6 +256,8 @@ int Damage::resolve() else { ((MTGCardInstance*)source)->damageToOpponent = true; + if(((MTGCardInstance*)source)->basicAbilities[Constants::ISCOMMANDER]) + ((MTGCardInstance*)source)->damageInflictedAsCommander += damage; } target->lifeLostThisTurn += damage; if ( typeOfDamage == 1 && target == source->controller()->opponent() )//add vector prowledtypes. @@ -271,6 +273,8 @@ int Damage::resolve() } WEvent * lifed = NEW WEventLife((Player*)target,-damage, source); observer->receiveEvent(lifed); + if(((MTGCardInstance*)source)->damageInflictedAsCommander > 20) // if a Commander has dealt 21 or more damages to a player, he loose game. + observer->setLoser(((MTGCardInstance*)source)->controller()->opponent()); } } diff --git a/projects/mtg/src/GameObserver.cpp b/projects/mtg/src/GameObserver.cpp index f4beb3a97..68ecc5918 100644 --- a/projects/mtg/src/GameObserver.cpp +++ b/projects/mtg/src/GameObserver.cpp @@ -1346,6 +1346,8 @@ void GameObserver::ButtonPressed(PlayGuiObject * target) graveyard->toggleDisplay(); else if (GuiExile* exile = dynamic_cast(target)) exile->toggleDisplay(); + else if (GuiCommandZone* commandzone = dynamic_cast(target)) + commandzone->toggleDisplay(); //opponenthand else if (GuiOpponentHand* opponentHand = dynamic_cast(target)) if (opponentHand->showCards) diff --git a/projects/mtg/src/GuiAvatars.cpp b/projects/mtg/src/GuiAvatars.cpp index b823e07fa..5c215f924 100644 --- a/projects/mtg/src/GuiAvatars.cpp +++ b/projects/mtg/src/GuiAvatars.cpp @@ -16,6 +16,8 @@ GuiAvatars::GuiAvatars(DuelLayers* duelLayers) : Add(selfLibrary = NEW GuiLibrary(SCREEN_WIDTH - GuiAvatar::Width - GuiGameZone::Width / 2 - 11, SCREEN_HEIGHT - GuiAvatar::Height - 5 + GuiGameZone::Height + 5, false, mpDuelLayers->getRenderedPlayer(), this)); //myexile Add(selfExile = NEW GuiExile(SCREEN_WIDTH - GuiAvatar::Width - GuiGameZone::Width / 2 - 11, SCREEN_HEIGHT - GuiAvatar::Height - 30, false, mpDuelLayers->getRenderedPlayer(), this)); + //mycommandZone + Add(selfCommandZone = NEW GuiCommandZone(SCREEN_WIDTH - GuiAvatar::Width - GuiGameZone::Width / 2 + 9, SCREEN_HEIGHT - GuiAvatar::Height - 30, false, mpDuelLayers->getRenderedPlayer(), this)); Add(opponent = NEW GuiAvatar(0, 0, false, mpDuelLayers->getRenderedPlayerOpponent(), GuiAvatar::TOP_LEFT, this)); opponent->zoom = 0.9f; @@ -29,19 +31,24 @@ GuiAvatars::GuiAvatars(DuelLayers* duelLayers) : Add(opponentHand = NEW GuiOpponentHand(-15 + GuiAvatar::Width * 1.4 - GuiGameZone::Width / 2, 43 + GuiGameZone::Height - 10, false, mpDuelLayers->getRenderedPlayerOpponent(), this)); //opponentLibrary - Add(opponentLibrary = NEW GuiLibrary(-30 + GuiAvatar::Width * 1.2 - GuiGameZone::Width / 2, 43 + GuiGameZone::Height - 10, - false, mpDuelLayers->getRenderedPlayerOpponent(), this)); + Add(opponentLibrary = NEW GuiLibrary(-30 + GuiAvatar::Width * 1.2 - GuiGameZone::Width / 2, 43 + GuiGameZone::Height - 10, false, + mpDuelLayers->getRenderedPlayerOpponent(), this)); + //opponentCommandZone + Add(opponentCommandZone = NEW GuiCommandZone(5 + GuiAvatar::Width * 1.4 - GuiGameZone::Width / 2, 43 + GuiGameZone::Height -10, false, + mpDuelLayers->getRenderedPlayerOpponent(), this)); observer->getCardSelector()->Add(self); observer->getCardSelector()->Add(selfGraveyard); observer->getCardSelector()->Add(selfExile); + observer->getCardSelector()->Add(selfCommandZone); observer->getCardSelector()->Add(selfLibrary); observer->getCardSelector()->Add(opponent); observer->getCardSelector()->Add(opponentGraveyard); observer->getCardSelector()->Add(opponentExile); + observer->getCardSelector()->Add(opponentCommandZone); observer->getCardSelector()->Add(opponentLibrary); observer->getCardSelector()->Add(opponentHand); - selfGraveyard->alpha = selfExile->alpha = opponentExile->alpha = selfLibrary->alpha = opponentGraveyard->alpha = opponentLibrary->alpha = opponentHand->alpha = 0; + selfGraveyard->alpha = selfExile->alpha = selfCommandZone->alpha = opponentCommandZone->alpha = opponentExile->alpha = selfLibrary->alpha = opponentGraveyard->alpha = opponentLibrary->alpha = opponentHand->alpha = 0; } float GuiAvatars::LeftBoundarySelf() @@ -58,15 +65,15 @@ void GuiAvatars::Activate(PlayGuiObject* c) c->zoom = 1.2f; c->mHasFocus = true; - if ((opponentGraveyard == c) || (opponentExile == c) || (opponentLibrary == c) || (opponent == c) || (opponentHand == c)) + if ((opponentGraveyard == c) || (opponentExile == c) || (opponentCommandZone == c) || (opponentLibrary == c) || (opponent == c) || (opponentHand == c)) { - opponentGraveyard->alpha = opponentExile->alpha = opponentLibrary->alpha = opponentHand->alpha = 128.0f; + opponentGraveyard->alpha = opponentExile->alpha = opponentCommandZone->alpha = opponentLibrary->alpha = opponentHand->alpha = 128.0f; active = opponent; opponent->zoom = 1.2f; } - else if ((selfGraveyard == c) || (selfExile == c) || (selfLibrary == c) || (self == c)) + else if ((selfGraveyard == c) || (selfExile == c) || (selfCommandZone == c) || (selfLibrary == c) || (self == c)) { - selfGraveyard->alpha = selfExile->alpha = selfLibrary->alpha = 128.0f; + selfGraveyard->alpha = selfExile->alpha = selfCommandZone->alpha = selfLibrary->alpha = 128.0f; self->zoom = 1.0f; active = self; } @@ -77,15 +84,15 @@ void GuiAvatars::Deactivate(PlayGuiObject* c) { c->zoom = 1.0; c->mHasFocus = false; - if ((opponentGraveyard == c) || (opponentExile == c) || (opponentLibrary == c) || (opponentHand == c) || (opponent == c)) + if ((opponentGraveyard == c) || (opponentExile == c) || (opponentCommandZone == c) || (opponentLibrary == c) || (opponentHand == c) || (opponent == c)) { - opponentGraveyard->alpha = opponentExile->alpha = opponentLibrary->alpha = opponentHand->alpha = 0; + opponentGraveyard->alpha = opponentExile->alpha = opponentCommandZone->alpha = opponentLibrary->alpha = opponentHand->alpha = 0; opponent->zoom = 0.9f; active = NULL; } - else if ((selfGraveyard == c) || (selfExile == c) || (selfLibrary == c) || (self == c)) + else if ((selfGraveyard == c) || (selfExile == c) || (selfCommandZone == c) || (selfLibrary == c) || (self == c)) { - selfGraveyard->alpha = selfExile->alpha = selfLibrary->alpha = 0; + selfGraveyard->alpha = selfExile->alpha = selfCommandZone->alpha = selfLibrary->alpha = 0; self->zoom = 0.5f; active = NULL; } @@ -93,15 +100,17 @@ void GuiAvatars::Deactivate(PlayGuiObject* c) int GuiAvatars::receiveEventPlus(WEvent* e) { - return selfGraveyard->receiveEventPlus(e) | selfExile->receiveEventPlus(e) | opponentExile->receiveEventPlus(e) | opponentGraveyard->receiveEventPlus(e) | opponentHand->receiveEventPlus(e); + return selfGraveyard->receiveEventPlus(e) | selfExile->receiveEventPlus(e) | selfCommandZone->receiveEventPlus(e) | opponentExile->receiveEventPlus(e) | opponentCommandZone->receiveEventPlus(e) | opponentGraveyard->receiveEventPlus(e) | opponentHand->receiveEventPlus(e); } int GuiAvatars::receiveEventMinus(WEvent* e) { selfGraveyard->receiveEventMinus(e); selfExile->receiveEventMinus(e); + selfCommandZone->receiveEventMinus(e); opponentGraveyard->receiveEventMinus(e); opponentExile->receiveEventMinus(e); + opponentCommandZone->receiveEventMinus(e); opponentHand->receiveEventMinus(e); return 1; } @@ -116,10 +125,14 @@ bool GuiAvatars::CheckUserInput(JButton key) return true; if (selfExile->CheckUserInput(key)) return true; + if (selfCommandZone->CheckUserInput(key)) + return true; if (opponentGraveyard->CheckUserInput(key)) return true; if (opponentExile->CheckUserInput(key)) return true; + if (opponentCommandZone->CheckUserInput(key)) + return true; if (opponentHand->CheckUserInput(key)) return true; if (selfLibrary->CheckUserInput(key)) @@ -135,9 +148,11 @@ void GuiAvatars::Update(float dt) opponent->Update(dt); selfGraveyard->Update(dt); selfExile->Update(dt); + selfCommandZone->Update(dt); opponentHand->Update(dt); opponentGraveyard->Update(dt); opponentExile->Update(dt); + opponentCommandZone->Update(dt); selfLibrary->Update(dt); opponentLibrary->Update(dt); } @@ -150,12 +165,12 @@ void GuiAvatars::Render() if (opponent == active) { r->FillRect(opponent->actX, opponent->actY, 40 * opponent->actZ, h+25 * opponent->actZ, ARGB(200,0,0,0)); - r->FillRect(opponent->actX, opponent->actY, w * opponent->actZ, h * opponent->actZ, ARGB(200,0,0,0)); + r->FillRect(opponent->actX, opponent->actY, w * opponent->actZ, h+25 * opponent->actZ, ARGB(200,0,0,0)); } else if (self == active) { - r->FillRect(self->actX - w * self->actZ - 4.5f, self->actY - h-28 * self->actZ, 24 * self->actZ, h+28 * self->actZ, ARGB(200,0,0,0)); - r->FillRect(self->actX - w * self->actZ - 4.5f, self->actY - h * self->actZ, w * self->actZ, h * self->actZ, ARGB(200,0,0,0)); + r->FillRect(self->actX - w * self->actZ - 4.5f, self->actY - h-28 * self->actZ, 24 * self->actZ + 19, h+28 * self->actZ, ARGB(200,0,0,0)); + //r->FillRect(self->actX - w * self->actZ - 4.5f, self->actY - h * self->actZ, w * self->actZ, h * self->actZ, ARGB(200,0,0,0)); } GuiLayer::Render(); diff --git a/projects/mtg/src/GuiStatic.cpp b/projects/mtg/src/GuiStatic.cpp index d5b000533..43b4c7f31 100644 --- a/projects/mtg/src/GuiStatic.cpp +++ b/projects/mtg/src/GuiStatic.cpp @@ -207,7 +207,7 @@ void GuiGameZone::Render() bool showopponenttop = (zone && zone->owner->opponent()->game->battlefield->nb_cards && zone->owner->opponent()->game->battlefield->hasAbility(Constants::SHOWOPPONENTTOPLIBRARY))?true:false; quad->SetColor(ARGB((int)(actA),255,255,255)); - if(type == GUI_EXILE) + if(type == GUI_EXILE || type == GUI_COMMANDZONE) { quad->SetColor(ARGB((int)(actA),255,240,255)); } @@ -217,7 +217,8 @@ void GuiGameZone::Render() JQuadPtr iconhand = WResourceManager::Instance()->RetrieveTempQuad("iconhand.png"); JQuadPtr iconlibrary = WResourceManager::Instance()->RetrieveTempQuad("iconlibrary.png"); JQuadPtr iconexile = WResourceManager::Instance()->RetrieveTempQuad("iconexile.png"); - + JQuadPtr iconcommandzone = WResourceManager::Instance()->RetrieveTempQuad("iconcommandzone.png"); + if(iconlibrary && type == GUI_LIBRARY) { scale2 = defaultHeight / iconlibrary->mHeight; @@ -250,6 +251,14 @@ void GuiGameZone::Render() iconexile->SetColor(ARGB((int)(actA),255,255,255)); quad = iconexile; } + if(iconcommandzone && type == GUI_COMMANDZONE) + { + scale2 = defaultHeight / iconcommandzone->mHeight; + modx = -0.f; + mody = -2.f; + iconcommandzone->SetColor(ARGB((int)(actA),255,255,255)); + quad = iconcommandzone; + } // if(type == GUI_LIBRARY && zone->nb_cards && !showCards) @@ -520,6 +529,52 @@ ostream& GuiExile::toString(ostream& out) const return out << "GuiExile :::"; } +GuiCommandZone::GuiCommandZone(float x, float y, bool hasFocus, Player * player, GuiAvatars* parent) : + GuiGameZone(x, y, hasFocus, player->game->commandzone, parent), player(player) +{ + type = GUI_COMMANDZONE; +} + +int GuiCommandZone::receiveEventPlus(WEvent* e) +{ + if (WEventZoneChange* event = dynamic_cast(e)) + if (event->to == zone) + { + CardView* t; + if (event->card->view) + t = NEW CardView(CardView::nullZone, event->card, *(event->card->view)); + else + t = NEW CardView(CardView::nullZone, event->card, x, y); + t->x = x + Width / 2; + t->y = y + Height / 2; + t->zoom = 0.6f; + t->alpha = 0; + cards.push_back(t); + return 1; + } + return 0; +} + +int GuiCommandZone::receiveEventMinus(WEvent* e) +{ + if (WEventZoneChange* event = dynamic_cast(e)) + if (event->from == zone) + for (vector::iterator it = cards.begin(); it != cards.end(); ++it) + if (event->card->previous == (*it)->card) + { + CardView* cv = *it; + cards.erase(it); + zone->owner->getObserver()->mTrash->trash(cv); + return 1; + } + return 0; +} + +ostream& GuiCommandZone::toString(ostream& out) const +{ + return out << "GuiCommandZone :::"; +} + //opponenthand begins GuiOpponentHand::GuiOpponentHand(float x, float y, bool hasFocus, Player * player, GuiAvatars* parent) : GuiGameZone(x, y, hasFocus, player->game->hand, parent), player(player) diff --git a/projects/mtg/src/MTGAbility.cpp b/projects/mtg/src/MTGAbility.cpp index a003dcfc2..5e0e1985c 100644 --- a/projects/mtg/src/MTGAbility.cpp +++ b/projects/mtg/src/MTGAbility.cpp @@ -6506,8 +6506,8 @@ void ListMaintainerAbility::updateTargets() for (int i = 0; i < 2; i++) { Player * p = game->players[i]; - MTGGameZone * zones[] = { p->game->inPlay, p->game->graveyard, p->game->hand, p->game->library, p->game->stack, p->game->exile ,p->game->reveal, p->game->sideboard }; - for (int k = 0; k < 8; k++) + MTGGameZone * zones[] = { p->game->inPlay, p->game->graveyard, p->game->hand, p->game->library, p->game->stack, p->game->exile ,p->game->reveal, p->game->sideboard, p->game->commandzone }; + for (int k = 0; k < 9; k++) { MTGGameZone * zone = zones[k]; if (canTarget(zone)) @@ -6578,8 +6578,8 @@ void ListMaintainerAbility::checkTargets() for (int i = 0; i < 2; i++) { Player * p = game->players[i]; - MTGGameZone * zones[] = { p->game->inPlay, p->game->graveyard, p->game->hand, p->game->library, p->game->stack, p->game->exile, p->game->reveal, p->game->sideboard }; - for (int k = 0; k < 8; k++) + MTGGameZone * zones[] = { p->game->inPlay, p->game->graveyard, p->game->hand, p->game->library, p->game->stack, p->game->exile, p->game->reveal, p->game->sideboard, p->game->commandzone }; + for (int k = 0; k < 9; k++) { MTGGameZone * zone = zones[k]; if (canTarget(zone)) diff --git a/projects/mtg/src/MTGCardInstance.cpp b/projects/mtg/src/MTGCardInstance.cpp index 7019ba96b..cbb6d50d2 100644 --- a/projects/mtg/src/MTGCardInstance.cpp +++ b/projects/mtg/src/MTGCardInstance.cpp @@ -238,6 +238,8 @@ void MTGCardInstance::initMTGCI() sunburst = 0; equipment = 0; mutation = 0; + damageInflictedAsCommander = 0; + numofcastfromcommandzone = 0; auras = 0; combatdamageToOpponent = false; damageToOpponent = false; diff --git a/projects/mtg/src/MTGDeck.cpp b/projects/mtg/src/MTGDeck.cpp index 7f8aefd5e..4e719162c 100644 --- a/projects/mtg/src/MTGDeck.cpp +++ b/projects/mtg/src/MTGDeck.cpp @@ -887,10 +887,76 @@ MTGDeck::MTGDeck(const string& config_file, MTGAllCards * _allcards, int meta_on meta_unlockRequirements = s.substr(found + 7); continue; } - found = s.find("SB:"); + found = s.find("SB:"); // Now it's possible to add cards to Sideboard even using their Name instead of ID such as normal deck cards. if (found != string::npos) { - Sideboard.push_back(s.substr(found + 3)); + s = s.substr(found + 3); + s.erase(s.find_last_not_of("\t\n\v\f\r ") + 1); + s.erase(0, s.find_first_not_of("\t\n\v\f\r ")); + std::string::const_iterator it = s.begin(); + while (it != s.end() && std::isdigit(*it)) ++it; + if(!s.empty() && it == s.end()) + Sideboard.push_back(s); + else { + int numberOfCopies = 1; + size_t found = s.find(" *"); + if (found != string::npos){ + numberOfCopies = atoi(s.substr(found + 2).c_str()); + s = s.substr(0, found); + } + MTGCard * card = database->getCardByName(s); + if (card){ + for (int i = 0; i < numberOfCopies; i++){ + std::stringstream str_id; + str_id << card->getId(); + Sideboard.push_back(str_id.str()); + } + }else { + DebugTrace("could not add to Sideboard any card with name: " << s); + } + } + continue; + } + found = s.find("CMD:"); // Now it's possible to add a card to Command Zone even using their Name instead of ID such as normal deck cards. + if (found != string::npos) + { + s = s.substr(found + 4); + s.erase(s.find_last_not_of("\t\n\v\f\r ") + 1); + s.erase(0, s.find_first_not_of("\t\n\v\f\r ")); + std::string::const_iterator it = s.begin(); + while (it != s.end() && std::isdigit(*it)) ++it; + if(!s.empty() && it == s.end()){ + MTGCard * newcard = database->getCardById(atoi(s.c_str())); + if(!CommandZone.size() && newcard->data->hasType("Legendary") && (newcard->data->hasType("Creature") || newcard->data->basicAbilities[Constants::CANBECOMMANDER])) // If no commander has been added you can add one. + CommandZone.push_back(s); + else if(CommandZone.size() == 1 && newcard->data->hasType("Legendary") && (newcard->data->hasType("Creature") || newcard->data->basicAbilities[Constants::CANBECOMMANDER])){ // If a commander has been added you can add a new one just if both have partner ability. + if(newcard && newcard->data->basicAbilities[Constants::PARTNER]){ + MTGCard * oldcard = database->getCardById(atoi((CommandZone.at(0)).c_str())); + if(oldcard && oldcard->data->basicAbilities[Constants::PARTNER] && oldcard->data->name != newcard->data->name) + CommandZone.push_back(s); + } + } + }else { + size_t found = s.find(" *"); + if (found != string::npos) + s = s.substr(0, found); + MTGCard * newcard = database->getCardByName(s); + if (newcard){ + std::stringstream str_id; + str_id << newcard->getId(); + if(!CommandZone.size() && newcard->data->hasType("Legendary") && (newcard->data->hasType("Creature") || newcard->data->basicAbilities[Constants::CANBECOMMANDER])) // If no commander has been added you can add one. + CommandZone.push_back(str_id.str()); + else if(CommandZone.size() == 1 && newcard->data->hasType("Legendary") && (newcard->data->hasType("Creature") || newcard->data->basicAbilities[Constants::CANBECOMMANDER])){ // If a commander has been added you can add a new one just if both have partner ability. + if(newcard->data->basicAbilities[Constants::PARTNER]){ + MTGCard * oldcard = database->getCardById(atoi((CommandZone.at(0)).c_str())); + if(oldcard && oldcard->data->basicAbilities[Constants::PARTNER] && oldcard->data->name != newcard->data->name) + CommandZone.push_back(str_id.str()); + } + } + }else { + DebugTrace("could not add to CommandZone any card with name: " << s); + } + } continue; } continue; diff --git a/projects/mtg/src/MTGDefinitions.cpp b/projects/mtg/src/MTGDefinitions.cpp index c4fd5c1f9..b4bf3f79d 100644 --- a/projects/mtg/src/MTGDefinitions.cpp +++ b/projects/mtg/src/MTGDefinitions.cpp @@ -194,8 +194,10 @@ const char* Constants::MTGBasicAbilities[] = { "mentor", "prowess", "nofizzle alternative", //No fizzle if card has been paid with alternative cost. - "hasotherkicker", //Kicker cost is expressed with "other" keyword (es. not mana kicker such as life and/or tap a creature), - "partner" //Has partner ability + "hasotherkicker", //Kicker cost is expressed with "other" keyword (eg. not mana kicker such as life and/or tap a creature), + "partner", //Has partner ability + "canbecommander", //Can be a commander (eg. some planeswalkers can) + "iscommander" //It's the current commander }; map Constants::MTGBasicAbilitiesMap; diff --git a/projects/mtg/src/MTGGameZones.cpp b/projects/mtg/src/MTGGameZones.cpp index 33e7d0fdd..386de5c44 100644 --- a/projects/mtg/src/MTGGameZones.cpp +++ b/projects/mtg/src/MTGGameZones.cpp @@ -78,6 +78,22 @@ void MTGPlayerCards::initDeck(MTGDeck * deck) } } } + //commander zone init + if(deck->CommandZone.size()) + { + for(unsigned int j = 0; j < deck->CommandZone.size(); j++) + { + string cardID = deck->CommandZone[j]; + MTGCard * card = MTGCollection()->getCardById(atoi(cardID.c_str())); + if(card) + { + MTGCardInstance * newCard = NEW MTGCardInstance(card, this); + //commander zone + newCard->basicAbilities[Constants::ISCOMMANDER] = 1; + commandzone->addCard(newCard); + } + } + } } MTGPlayerCards::~MTGPlayerCards() @@ -91,6 +107,7 @@ MTGPlayerCards::~MTGPlayerCards() SAFE_DELETE(garbage); SAFE_DELETE(reveal); SAFE_DELETE(sideboard); + SAFE_DELETE(commandzone); SAFE_DELETE(temp); SAFE_DELETE(playRestrictions); } @@ -110,6 +127,7 @@ void MTGPlayerCards::beforeBeginPhase() garbage->beforeBeginPhase(); reveal->beforeBeginPhase(); sideboard->beforeBeginPhase(); + commandzone->beforeBeginPhase(); temp->beforeBeginPhase(); } @@ -126,6 +144,7 @@ void MTGPlayerCards::setOwner(Player * player) garbageLastTurn->setOwner(player); reveal->setOwner(player); sideboard->setOwner(player); + commandzone->setOwner(player); temp->setOwner(player); } @@ -301,6 +320,7 @@ void MTGPlayerCards::init() garbageLastTurn = garbage; reveal = NEW MTGGameZone(); sideboard = NEW MTGGameZone(); + commandzone = NEW MTGGameZone(); temp = NEW MTGGameZone(); playRestrictions = NEW PlayRestrictions(); @@ -393,7 +413,7 @@ MTGCardInstance * MTGPlayerCards::putInZone(MTGCardInstance * card, MTGGameZone } //close the currently open MAIN display. - if (from == g->players[i]->game->library || from == g->players[i]->game->graveyard || from == g->players[i]->game->exile) + if (from == g->players[i]->game->library || from == g->players[i]->game->graveyard || from == g->players[i]->game->exile || from == g->players[i]->game->commandzone) { if (g->guiOpenDisplay) { @@ -418,6 +438,12 @@ MTGCardInstance * MTGPlayerCards::putInZone(MTGCardInstance * card, MTGGameZone inplaytoinplay = true;//try sending different event... } + //Increase the number of time this card has been casted from commandzone to recalculate cost. + if(from == g->players[0]->game->commandzone || from == g->players[1]->game->commandzone){ + card->numofcastfromcommandzone++; + card->controller()->numOfCommandCast++; + } + if (!(copy = from->removeCard(card, doCopy))) return NULL; //ERROR @@ -430,6 +456,12 @@ MTGCardInstance * MTGPlayerCards::putInZone(MTGCardInstance * card, MTGGameZone } } + //Commander is going back to Command Zone, so we recalculate cost according to how many times it has been casted from there. + if(to == g->players[0]->game->commandzone || to == g->players[1]->game->commandzone){ + for(int i = 0; i < copy->numofcastfromcommandzone; i++) + copy->getManaCost()->add(Constants::MTG_COLOR_ARTIFACT,2); + } + if (card->miracle) { copy->miracle = true; @@ -713,6 +745,9 @@ MTGCardInstance * MTGGameZone::removeCard(MTGCardInstance * card, int createCopy copy->storedSourceCard = card->storedSourceCard; copy->lastController = card->controller(); copy->previousController = card->controller(); + copy->basicAbilities[Constants::ISCOMMANDER] = card->basicAbilities[Constants::ISCOMMANDER]; + copy->damageInflictedAsCommander = card->damageInflictedAsCommander; + copy->numofcastfromcommandzone = card->numofcastfromcommandzone; for (int i = 0; i < ManaCost::MANA_PAID_WITH_BESTOW +1; i++) copy->alternateCostPaid[i] = card->alternateCostPaid[i]; @@ -1237,6 +1272,13 @@ MTGGameZone * MTGGameZone::intToZone(int zoneId, Player * p, Player * p2) case SIDEBOARD: return p->game->sideboard; + case MY_COMMANDZONE: + return p->game->commandzone; + case OPPONENT_COMMANDZONE: + return p->opponent()->game->commandzone; + case COMMANDZONE: + return p->game->commandzone; + } if (!p2) return NULL; switch (zoneId) @@ -1265,6 +1307,9 @@ MTGGameZone * MTGGameZone::intToZone(int zoneId, Player * p, Player * p2) case TARGET_CONTROLLER_SIDEBOARD: return p2->game->sideboard; + case TARGET_CONTROLLER_COMMANDZONE: + return p2->game->commandzone; + default: return NULL; } @@ -1385,6 +1430,17 @@ MTGGameZone * MTGGameZone::intToZone(GameObserver *g, int zoneId, MTGCardInstanc return source->playerTarget->game->sideboard; else return source->controller()->game->sideboard; + case TARGET_OWNER_COMMANDZONE: + return target->owner->game->commandzone; + case COMMANDZONE: + return target->owner->game->commandzone; + case OWNER_COMMANDZONE: + return target->owner->game->commandzone; + case TARGETED_PLAYER_COMMANDZONE: + if (source->playerTarget) + return source->playerTarget->game->commandzone; + else return source->controller()->game->commandzone; + default: return NULL; } @@ -1416,6 +1472,8 @@ int MTGGameZone::zoneStringToId(string zoneName) "mysideboard", "opponentsideboard", "targetownersideboard", "targetcontrollersideboard", "ownersideboard", "sideboard","targetedpersonssideboard", + "mycommandzone", "opponentcommandzone", "targetownercommandzone", "targetcontrollercommandzone", "ownercommandzone", "commandzone","targetedpersonscommandzone", + }; int values[] = { MY_GRAVEYARD, OPPONENT_GRAVEYARD, TARGET_OWNER_GRAVEYARD, TARGET_CONTROLLER_GRAVEYARD, OWNER_GRAVEYARD, @@ -1439,7 +1497,9 @@ int MTGGameZone::zoneStringToId(string zoneName) MY_REVEAL, OPPONENT_REVEAL, TARGET_OWNER_REVEAL, TARGET_CONTROLLER_REVEAL, OWNER_REVEAL, REVEAL,TARGETED_PLAYER_REVEAL, - MY_SIDEBOARD, OPPONENT_SIDEBOARD, TARGET_OWNER_SIDEBOARD, TARGET_CONTROLLER_SIDEBOARD, OWNER_SIDEBOARD, SIDEBOARD,TARGETED_PLAYER_SIDEBOARD }; + MY_SIDEBOARD, OPPONENT_SIDEBOARD, TARGET_OWNER_SIDEBOARD, TARGET_CONTROLLER_SIDEBOARD, OWNER_SIDEBOARD, SIDEBOARD,TARGETED_PLAYER_SIDEBOARD, + + MY_COMMANDZONE, OPPONENT_COMMANDZONE, TARGET_OWNER_COMMANDZONE, TARGET_CONTROLLER_COMMANDZONE, OWNER_COMMANDZONE, COMMANDZONE,TARGETED_PLAYER_COMMANDZONE }; int max = sizeof(values) / sizeof *(values); diff --git a/projects/mtg/src/MTGRules.cpp b/projects/mtg/src/MTGRules.cpp index 4b9933208..dbfbc8d77 100644 --- a/projects/mtg/src/MTGRules.cpp +++ b/projects/mtg/src/MTGRules.cpp @@ -304,7 +304,7 @@ int MTGPutInPlayRule::isReactingToClick(MTGCardInstance * card, ManaCost *) int cardsinhand = game->players[0]->game->hand->nb_cards; defaultPlayName = card->isLand()?"Play Land":"Cast Card Normally"; Player * player = game->currentlyActing(); - if (!player->game->hand->hasCard(card) && !player->game->graveyard->hasCard(card) && !player->game->exile->hasCard(card) && !player->game->library->hasCard(card)) + if (!player->game->hand->hasCard(card) && !player->game->graveyard->hasCard(card) && !player->game->exile->hasCard(card) && !player->game->library->hasCard(card) && !player->game->commandzone->hasCard(card)) return 0; if ((player->game->library->hasCard(card) && !card->canPlayFromLibrary()) || (player->game->graveyard->hasCard(card) && !card->has(Constants::CANPLAYFROMGRAVEYARD)) || (player->game->exile->hasCard(card) && !card->has(Constants::CANPLAYFROMEXILE))) return 0; diff --git a/projects/mtg/src/Player.cpp b/projects/mtg/src/Player.cpp index 5699dedac..4c0a76976 100644 --- a/projects/mtg/src/Player.cpp +++ b/projects/mtg/src/Player.cpp @@ -36,6 +36,7 @@ Player::Player(GameObserver *observer, string file, string fileSmall, MTGDeck * drawCounter = 0; energyCount = 0; yidaroCount = 0; + numOfCommandCast = 0; monarch = 0; surveilOffset = 0; epic = 0; diff --git a/projects/mtg/src/Rules.cpp b/projects/mtg/src/Rules.cpp index b0df7960b..6c0522519 100644 --- a/projects/mtg/src/Rules.cpp +++ b/projects/mtg/src/Rules.cpp @@ -598,20 +598,22 @@ void Rules::initGame(GameObserver *g, bool currentPlayerSet) p->preventable = initState.playerData[i].player->preventable; p->energyCount = initState.playerData[i].player->energyCount; p->yidaroCount = initState.playerData[i].player->yidaroCount; + p->numOfCommandCast = initState.playerData[i].player->numOfCommandCast; p->monarch = initState.playerData[i].player->monarch; p->surveilOffset = initState.playerData[i].player->surveilOffset; if (initState.playerData[i].player->mAvatarName.size()) { p->mAvatarName = initState.playerData[i].player->mAvatarName; } - MTGGameZone * playerZones[] = { p->game->graveyard, p->game->library, p->game->hand, p->game->inPlay, p->game->exile , p->game->reveal, p->game->sideboard }; + MTGGameZone * playerZones[] = { p->game->graveyard, p->game->library, p->game->hand, p->game->inPlay, p->game->exile , p->game->reveal, p->game->sideboard, p->game->commandzone }; MTGGameZone * loadedPlayerZones[] = { initState.playerData[i].player->game->graveyard, initState.playerData[i].player->game->library, initState.playerData[i].player->game->hand, initState.playerData[i].player->game->inPlay, initState.playerData[i].player->game->exile, initState.playerData[i].player->game->reveal, - initState.playerData[i].player->game->sideboard }; + initState.playerData[i].player->game->sideboard, + initState.playerData[i].player->game->commandzone }; for (int j = 0; j < 5; j++) { MTGGameZone * zone = playerZones[j]; diff --git a/projects/mtg/src/TargetChooser.cpp b/projects/mtg/src/TargetChooser.cpp index 338d6c864..6406fc2e7 100644 --- a/projects/mtg/src/TargetChooser.cpp +++ b/projects/mtg/src/TargetChooser.cpp @@ -175,6 +175,11 @@ TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInsta zones[nbzones++] = MTGGameZone::MY_SIDEBOARD; zones[nbzones++] = MTGGameZone::OPPONENT_SIDEBOARD; } + else if (zoneName.compare("commandzone") == 0) + { + zones[nbzones++] = MTGGameZone::MY_COMMANDZONE; + zones[nbzones++] = MTGGameZone::OPPONENT_COMMANDZONE; + } else if (zoneName.compare("reveal") == 0) { zones[nbzones++] = MTGGameZone::MY_REVEAL; @@ -210,6 +215,8 @@ TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInsta zones[nbzones++] = MTGGameZone::OPPONENT_HAND; zones[nbzones++] = MTGGameZone::MY_EXILE; zones[nbzones++] = MTGGameZone::OPPONENT_EXILE; + zones[nbzones++] = MTGGameZone::MY_COMMANDZONE; + zones[nbzones++] = MTGGameZone::OPPONENT_COMMANDZONE; } else if (zoneName.compare("stack") == 0) { @@ -228,6 +235,7 @@ TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInsta zones[nbzones++] = MTGGameZone::MY_HAND; zones[nbzones++] = MTGGameZone::MY_EXILE; zones[nbzones++] = MTGGameZone::MY_SIDEBOARD; + zones[nbzones++] = MTGGameZone::MY_COMMANDZONE; } else if (zoneName.compare("opponentcastingzone") == 0) { @@ -235,18 +243,22 @@ TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInsta zones[nbzones++] = MTGGameZone::OPPONENT_LIBRARY; zones[nbzones++] = MTGGameZone::OPPONENT_HAND; zones[nbzones++] = MTGGameZone::OPPONENT_EXILE; + zones[nbzones++] = MTGGameZone::OPPONENT_SIDEBOARD; + zones[nbzones++] = MTGGameZone::OPPONENT_COMMANDZONE; } else if (zoneName.compare("mynonplaynonexile") == 0) { zones[nbzones++] = MTGGameZone::MY_GRAVEYARD; zones[nbzones++] = MTGGameZone::MY_LIBRARY; zones[nbzones++] = MTGGameZone::MY_HAND; + zones[nbzones++] = MTGGameZone::MY_COMMANDZONE; } else if (zoneName.compare("opponentnonplaynonexile") == 0) { zones[nbzones++] = MTGGameZone::OPPONENT_GRAVEYARD; zones[nbzones++] = MTGGameZone::OPPONENT_LIBRARY; zones[nbzones++] = MTGGameZone::OPPONENT_HAND; + zones[nbzones++] = MTGGameZone::OPPONENT_COMMANDZONE; } else if (zoneName.compare("myzones") == 0) { @@ -256,6 +268,8 @@ TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInsta zones[nbzones++] = MTGGameZone::MY_LIBRARY; zones[nbzones++] = MTGGameZone::MY_HAND; zones[nbzones++] = MTGGameZone::MY_EXILE; + zones[nbzones++] = MTGGameZone::MY_SIDEBOARD; + zones[nbzones++] = MTGGameZone::MY_COMMANDZONE; } else if (zoneName.compare("opponentzones") == 0) { @@ -265,6 +279,8 @@ TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInsta zones[nbzones++] = MTGGameZone::OPPONENT_LIBRARY; zones[nbzones++] = MTGGameZone::OPPONENT_HAND; zones[nbzones++] = MTGGameZone::OPPONENT_EXILE; + zones[nbzones++] = MTGGameZone::OPPONENT_SIDEBOARD; + zones[nbzones++] = MTGGameZone::OPPONENT_COMMANDZONE; } else { @@ -1154,8 +1170,8 @@ bool TargetChooser::validTargetsExist(int maxTargets) int maxAmount = 0; Player *p = observer->players[i]; if (canTarget(p)) return true; - MTGGameZone * zones[] = { p->game->inPlay, p->game->graveyard, p->game->hand, p->game->library, p->game->exile, p->game->stack, p->game->reveal, p->game->sideboard }; - for (int k = 0; k < 8; k++) + MTGGameZone * zones[] = { p->game->inPlay, p->game->graveyard, p->game->hand, p->game->library, p->game->exile, p->game->stack, p->game->reveal, p->game->sideboard, p->game->commandzone }; + for (int k = 0; k < 9; k++) { MTGGameZone * z = zones[k]; if (targetsZone(z)) @@ -1188,8 +1204,8 @@ int TargetChooser::countValidTargets(bool withoutProtections) Player *p = observer->players[i]; if(canTarget(p)) result++; - MTGGameZone * zones[] = { p->game->inPlay, p->game->graveyard, p->game->hand, p->game->library, p->game->exile, p->game->stack, p->game->reveal, p->game->sideboard }; - for (int k = 0; k < 8; k++) + MTGGameZone * zones[] = { p->game->inPlay, p->game->graveyard, p->game->hand, p->game->library, p->game->exile, p->game->stack, p->game->reveal, p->game->sideboard, p->game->commandzone }; + for (int k = 0; k < 9; k++) { MTGGameZone * z = zones[k]; if (targetsZone(z))