From 7322d4da8b812b0eba68b40de8f26fe0e5a7c122 Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Mon, 30 Jan 2017 07:09:21 +0800 Subject: [PATCH 1/9] fix castcard opponent spell the casted non-permanent card from opponent will now move to its owner graveyard... --- projects/mtg/src/AllAbilities.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/mtg/src/AllAbilities.cpp b/projects/mtg/src/AllAbilities.cpp index 424f3776c..6a216aa64 100644 --- a/projects/mtg/src/AllAbilities.cpp +++ b/projects/mtg/src/AllAbilities.cpp @@ -7953,7 +7953,7 @@ int AACastCard::resolveSpell() if (putinplay && (_target->hasType(Subtypes::TYPE_ARTIFACT)||_target->hasType(Subtypes::TYPE_CREATURE)||_target->hasType(Subtypes::TYPE_ENCHANTMENT)||_target->hasType(Subtypes::TYPE_PLANESWALKER))) copy =_target->controller()->game->putInZone(_target, _target->currentZone, source->controller()->game->battlefield,noEvent); else - copy =_target->controller()->game->putInZone(_target, _target->currentZone, source->controller()->game->stack,noEvent); + copy =_target->controller()->game->putInZone(_target, _target->currentZone, _target->controller()->game->stack,noEvent); copy->changeController(source->controller(),true); if(asNormalMadness) copy->MadnessPlay = true; From 7029636291c5ceafbaa372a0eba665a53a3d577f Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Tue, 31 Jan 2017 04:16:47 +0800 Subject: [PATCH 2/9] some corrections --- .../mtg/bin/Res/missing_cards_by_sets/KLD.txt | 6 --- projects/mtg/bin/Res/sets/primitives/mtg.txt | 41 ++++++++++++++++--- projects/mtg/src/AIPlayerBaka.cpp | 2 +- 3 files changed, 36 insertions(+), 13 deletions(-) diff --git a/projects/mtg/bin/Res/missing_cards_by_sets/KLD.txt b/projects/mtg/bin/Res/missing_cards_by_sets/KLD.txt index 9eb623332..228687a01 100644 --- a/projects/mtg/bin/Res/missing_cards_by_sets/KLD.txt +++ b/projects/mtg/bin/Res/missing_cards_by_sets/KLD.txt @@ -136,12 +136,6 @@ power=2 toughness=3 [/card] [card] -name=Harnessed Lightning -text=Choose target creature. You get {E}{E}{E} (three energy counters), then you may pay any amount of {E}. Harnessed Lightning deals that much damage to that creature. -mana={1}{R} -type=Instant -[/card] -[card] name=Insidious Will text=Choose one — -- • Counter target spell. -- • You may choose new targets for target spell. -- • Copy target instant or sorcery spell. You may choose new targets for the copy. mana={2}{U}{U} diff --git a/projects/mtg/bin/Res/sets/primitives/mtg.txt b/projects/mtg/bin/Res/sets/primitives/mtg.txt index d0df067b8..b2a91bcb1 100644 --- a/projects/mtg/bin/Res/sets/primitives/mtg.txt +++ b/projects/mtg/bin/Res/sets/primitives/mtg.txt @@ -291,7 +291,7 @@ subtype=Aura [/card] [card] name=Abundant Maw -autostack=if casted(this) then target(opponent) life:-3 && life:3 controller +autostack=if casted(this) then choice target(opponent) life:-3 && life:3 controller text=Emerge {6}{B} (You may cast this spell by sacrificing a creature and paying the emerge cost reduced by that creature's converted mana cost.) -- When you cast Abundant Maw, target opponent loses 3 life and you gain 3 life. mana={8} other={emerge}{6}{B} name(Emerge) @@ -32091,7 +32091,7 @@ toughness=1 [/card] [card] name=Due Respect -auto=emblem transforms((,newability[@movedTo(*|Battlefield):all(trigger) tap(noevent)])) ueot +auto=emblem transforms((,newability[lord(*[recent]|battlefield) tap(noevent)])) ueot auto=draw:1 controller mana={1}{W} type=Instant @@ -51372,6 +51372,35 @@ mana={2}{G} type=Sorcery [/card] [card] +name=Harnessed Lightning +#AUTO_DEFINE _HARNESSED_LIGHTNING_($c) this(variable{penergy}>=$c) choice damage:$c && alterenergy:-$c controller +target=creature +auto=alterenergy:3 controller +auto=_HARNESSED_LIGHTNING_(1) +auto=_HARNESSED_LIGHTNING_(2) +auto=_HARNESSED_LIGHTNING_(3) +auto=_HARNESSED_LIGHTNING_(4) +auto=_HARNESSED_LIGHTNING_(5) +auto=_HARNESSED_LIGHTNING_(6) +auto=_HARNESSED_LIGHTNING_(7) +auto=_HARNESSED_LIGHTNING_(8) +auto=_HARNESSED_LIGHTNING_(9) +auto=_HARNESSED_LIGHTNING_(10) +auto=_HARNESSED_LIGHTNING_(11) +auto=_HARNESSED_LIGHTNING_(12) +auto=_HARNESSED_LIGHTNING_(13) +auto=_HARNESSED_LIGHTNING_(14) +auto=_HARNESSED_LIGHTNING_(15) +auto=_HARNESSED_LIGHTNING_(16) +auto=_HARNESSED_LIGHTNING_(17) +auto=_HARNESSED_LIGHTNING_(18) +auto=_HARNESSED_LIGHTNING_(19) +auto=_HARNESSED_LIGHTNING_(20) +text=Choose target creature. You get {E}{E}{E} (three energy counters), then you may pay any amount of {E}. Harnessed Lightning deals that much damage to that creature. +mana={1}{R} +type=Instant +[/card] +[card] name=Harpoon Sniper auto={W}{T}:damage:type:merfolk:mybattlefield target(creature[attacking;blocking]) text={W}, {T}: Harpoon Sniper deals X damage to target attacking or blocking creature, where X is the number of Merfolk you control. @@ -76392,8 +76421,8 @@ type=Sorcery [card] name=Nahiri, the Harbinger auto=counter(0/0,4,loyalty) -auto={C(0/0,1,Loyalty)}:name(+1: Reveal) reveal:1 optionone name(Choose to put in Graveyard) target(*|reveal) moveto(mygraveyard) optiononeend optiontwo name(put Back and draw) target(<1>*|reveal) moveto(mylibrary) optiontwoend afterrevealed choice draw:1 controller afterrevealedend revealend -auto={C(0/0,-2,Loyalty)}:name(-2: Exile tapped Artifact or Creature) target(creature,artifact[tapped]) moveto(exile) +auto={C(0/0,2,Loyalty)}:name(+2: Discard to draw) notatarget(*|myhand) transforms((,newability[reject and!(draw:1)!])) forever +auto={C(0/0,-2,Loyalty)}:name(-2: Exile tapped Artifact or Creature) target(*[artifact;creature;tapped]) moveto(exile) auto={C(0/0,-2,Loyalty)}:name(-2: Exile target Enchantment) target(enchantment) moveto(exile) auto={C(0/0,-8,Loyalty)}:name(-8: Fetch) moveto(mybattlefield) notatarget(artifact,creature|mylibrary) and!( transforms((,newability[haste],newability[phaseaction[endofturn sourceinplay] moveTo(ownerhand)])) forever )! text=+2: You may discard a card. If you do, draw a card. -- -2: Exile target enchantment, tapped artifact, or tapped creature. -- -8: Search your library for an artifact or creature card, put it onto the battlefield, then shuffle your library. It gains haste. Return it to your hand at the beginning of the next end step. @@ -117089,8 +117118,8 @@ toughness=1 [card] name=Thalia, Heretic Cathar abilities=first strike -auto=@movedTo(*[recent;land;-basic]|opponentBattlefield):all(trigger) tap(noevent) -auto=@movedTo(*[recent;creature]|opponentBattlefield):all(trigger) tap(noevent) +auto=lord(*[recent;land;-basic]|opponentbattlefield) transforms((,newability[tap(noevent)])) +auto=lord(*[recent;creature]|opponentbattlefield) transforms((,newability[tap(noevent)])) text=First strike -- Creatures and nonbasic lands your opponents control enter the battlefield tapped. mana={2}{W} type=Legendary Creature diff --git a/projects/mtg/src/AIPlayerBaka.cpp b/projects/mtg/src/AIPlayerBaka.cpp index f0ce55514..f88eff2b1 100644 --- a/projects/mtg/src/AIPlayerBaka.cpp +++ b/projects/mtg/src/AIPlayerBaka.cpp @@ -2768,7 +2768,7 @@ int AIPlayerBaka::chooseAttackers() opponentCreatures = getCreaturesInfo(opponent(), INFO_NBCREATURES, -1); opponentForce = getCreaturesInfo(opponent(), INFO_CREATURESPOWER, -1); attack = (myCreatures >= opponentCreatures && myForce > opponentForce) - || (myForce > opponentForce) || (myForce > opponent()->life); + || (myForce > opponentForce) || (myForce > opponent()->life) || ((life - opponentForce) > 30) ; } printf("Choose attackers : %i %i %i %i -> %i\n", opponentForce, opponentCreatures, myForce, myCreatures, attack); From 41d925d7c910a9934823a33921816774942de5a3 Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Tue, 31 Jan 2017 20:11:09 +0800 Subject: [PATCH 3/9] add support for activated copier thespian stage etc... --- projects/mtg/include/AllAbilities.h | 1 + projects/mtg/include/MTGCardInstance.h | 1 + projects/mtg/src/AllAbilities.cpp | 54 ++++++++++++++++++++++++++ projects/mtg/src/MTGAbility.cpp | 1 + projects/mtg/src/MTGCardInstance.cpp | 15 ++++--- 5 files changed, 67 insertions(+), 5 deletions(-) diff --git a/projects/mtg/include/AllAbilities.h b/projects/mtg/include/AllAbilities.h index c590a55b6..753eb6d59 100644 --- a/projects/mtg/include/AllAbilities.h +++ b/projects/mtg/include/AllAbilities.h @@ -2055,6 +2055,7 @@ public: class AACopier: public ActivatedAbility { public: + bool isactivated; vector currentAbilities; MTGAbility * andAbility; AACopier(GameObserver* observer, int _id, MTGCardInstance * _source, MTGCardInstance * _target = NULL, ManaCost * _cost = NULL); diff --git a/projects/mtg/include/MTGCardInstance.h b/projects/mtg/include/MTGCardInstance.h index 6d278cbf3..6242cfcfe 100644 --- a/projects/mtg/include/MTGCardInstance.h +++ b/projects/mtg/include/MTGCardInstance.h @@ -123,6 +123,7 @@ public: MTGCardInstance * previous; MTGCardInstance * next; MTGAbility * TokenAndAbility; + MTGAbility * GrantedAndAbility; int doDamageTest; bool skipDamageTestOnce; int summoningSickness; diff --git a/projects/mtg/src/AllAbilities.cpp b/projects/mtg/src/AllAbilities.cpp index 6a216aa64..5fad65b81 100644 --- a/projects/mtg/src/AllAbilities.cpp +++ b/projects/mtg/src/AllAbilities.cpp @@ -1539,6 +1539,7 @@ AACopier::AACopier(GameObserver* observer, int _id, MTGCardInstance * _source, M { target = _target; andAbility = NULL; + isactivated = false; } int AACopier::resolve() @@ -1546,6 +1547,8 @@ int AACopier::resolve() MTGCardInstance * _target = (MTGCardInstance *) target; if (_target) { + if(isactivated) + source->isPhased = true; bool tokencopied = false; if(_target->isToken || (_target->isACopier && _target->hasCopiedToken)) tokencopied = true; @@ -1606,6 +1609,57 @@ int AACopier::resolve() TokenandAbilityClone->addToGame(); } } + if(isactivated) + {//activated version grant + source->GrantedAndAbility = andAbility; + AbilityFactory af(game); + for(unsigned int i = 0;i < source->cardsAbilities.size();i++) + { + MTGAbility * a = dynamic_cast(source->cardsAbilities[i]); + + if(a) game->removeObserver(a); + } + source->cardsAbilities.clear(); + source->magicText = _target->magicText; + + af.getAbilities(¤tAbilities, NULL, source); + for (size_t i = 0; i < currentAbilities.size(); ++i) + { + MTGAbility * a = currentAbilities[i]; + a->source = (MTGCardInstance *) source; + if (a) + { + if (a->oneShot) + { + SAFE_DELETE(a); + } + else + { + a->addToGame(); + MayAbility * dontAdd = dynamic_cast(a); + if(!dontAdd) + { + source->cardsAbilities.push_back(a); + } + } + } + } + if(source->GrantedAndAbility) + { + MTGAbility * andAbilityClone = source->GrantedAndAbility->clone(); + andAbilityClone->target = source; + if(andAbility->oneShot) + { + andAbilityClone->resolve(); + SAFE_DELETE(andAbilityClone); + } + else + { + andAbilityClone->addToGame(); + } + } + source->isPhased = false; + } return 1; } return 0; diff --git a/projects/mtg/src/MTGAbility.cpp b/projects/mtg/src/MTGAbility.cpp index b93383c0f..ef20270f4 100644 --- a/projects/mtg/src/MTGAbility.cpp +++ b/projects/mtg/src/MTGAbility.cpp @@ -2781,6 +2781,7 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG MTGAbility * a = NEW AACopier(observer, id, card, target); a->oneShot = 1; a->canBeInterrupted = false; + ((AACopier*)a)->isactivated = activated; //andability if(storedAndAbility.size()) { diff --git a/projects/mtg/src/MTGCardInstance.cpp b/projects/mtg/src/MTGCardInstance.cpp index 76dadda37..c73d0797c 100644 --- a/projects/mtg/src/MTGCardInstance.cpp +++ b/projects/mtg/src/MTGCardInstance.cpp @@ -140,11 +140,15 @@ void MTGCardInstance::copy(MTGCardInstance * card) int castMethodBackUP = this->castMethod; mtgid = source->getId(); MTGCardInstance * oldStored = this->storedSourceCard; - Spell * spell = NEW Spell(observer, this); - observer = card->observer; - AbilityFactory af(observer); - af.addAbilities(observer->mLayers->actionLayer()->getMaxId(), spell); - delete spell; + if(!isPhased) + { + Spell * spell = NEW Spell(observer, this); + observer = card->observer; + AbilityFactory af(observer); + af.addAbilities(observer->mLayers->actionLayer()->getMaxId(), spell); + delete spell; + } + if(observer->players[1]->playMode == Player::MODE_TEST_SUITE) mtgid = backupid; // there must be a way to get the token id... else @@ -284,6 +288,7 @@ void MTGCardInstance::initMTGCI() previous = NULL; next = NULL; TokenAndAbility = NULL; + GrantedAndAbility = NULL; lastController = NULL; regenerateTokens = 0; blocked = false; From 3998c21178916bb70bcc02464716a4c1f750204c Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Tue, 31 Jan 2017 20:11:59 +0800 Subject: [PATCH 4/9] fix persist on copied card --- projects/mtg/src/Counters.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/projects/mtg/src/Counters.cpp b/projects/mtg/src/Counters.cpp index a08c4402e..4b89c10dd 100644 --- a/projects/mtg/src/Counters.cpp +++ b/projects/mtg/src/Counters.cpp @@ -129,8 +129,9 @@ int Counters::addCounter(const char * _name, int _power, int _toughness, bool _n g->receiveEvent(w); } mCount++; - this->target->doDamageTest = 1; - this->target->afterDamage(); + /*the damage test should be handled on game state based effect i think*/ + //this->target->doDamageTest = 1; + //this->target->afterDamage(); } delete(e); return mCount; From 92b4909fc8aa53b2ac74be765cb7157edb8f286f Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Tue, 31 Jan 2017 21:19:34 +0800 Subject: [PATCH 5/9] add some cards --- .../bin/Res/sets/primitives/borderline.txt | 47 ------------------- projects/mtg/bin/Res/sets/primitives/mtg.txt | 47 +++++++++++++++++++ 2 files changed, 47 insertions(+), 47 deletions(-) diff --git a/projects/mtg/bin/Res/sets/primitives/borderline.txt b/projects/mtg/bin/Res/sets/primitives/borderline.txt index 618ce1ebb..820e28a92 100644 --- a/projects/mtg/bin/Res/sets/primitives/borderline.txt +++ b/projects/mtg/bin/Res/sets/primitives/borderline.txt @@ -92,16 +92,6 @@ power=3 toughness=3 [/card] [card] -name=Cemetery Puca -text=Whenever a creature is put into a graveyard from the battlefield, you may pay {1}. If you do, Cemetery Puca becomes a copy of that creature and gains this ability. -auto=@movedto(creature|graveyard) from(battlefield):all(trigger[from]) pay[[{1}]] copy -mana={1}{UB}{UB} -type=Creature -subtype=Shapeshifter -power=1 -toughness=2 -[/card] -[card] name=Conflux auto=ability$!name(white card) moveto(myhand) notatarget(*[white]|mylibrary)!$ controller auto=ability$!name(blue card) moveto(myhand) notatarget(*[blue]|mylibrary)!$ controller @@ -123,16 +113,6 @@ mana={1}{B}{G} type=Instant [/card] [card] -name=Cryptoplasm -auto=@each my upkeep:may copy target(other creature|battlefield) -text=At the beginning of your upkeep, you may have Cryptoplasm become a copy of another target creature. If you do, Cryptoplasm gains this ability. -mana={1}{U}{U} -type=Creature -subtype=Shapeshifter -power=2 -toughness=2 -[/card] -[card] name=Demon of Wailing Agonies abilities=flying #wagic doesnt have commander zone @@ -157,16 +137,6 @@ power=2 toughness=3 [/card] [card] -name=Dimir Doppelganger -auto={1}{U}{B}:target(creature|graveyard) moveto(exile) and!(copy)! -text={1}{U}{B}: Exile target creature card from a graveyard. Dimir Doppelganger becomes a copy of that card and gains this ability. -mana={1}{U}{B} -type=Creature -subtype=Shapeshifter -power=0 -toughness=2 -[/card] -[card] name=Eureka auto=ability$! moveto(ownerbattlefield) notatarget(artifact,creature,enchantment,land,planeswalker|myhand) !$ controller auto=ability$! moveto(ownerbattlefield) notatarget(artifact,creature,enchantment,land,planeswalker|myhand) !$ opponent @@ -762,13 +732,6 @@ power=3 toughness=4 [/card] [card] -name=Thespian's Stage -auto={T}:Add{1} -auto={2}{T}:copy target(land|battlefield) -text={T}: Add {1} to your mana pool. -- {2}, {T}: Thespian's Stage becomes a copy of target land and gains this ability. -type=Land -[/card] -[card] name=Thunderfoot Baloth abilities=trample #wagic doesnt have commander zone @@ -814,16 +777,6 @@ mana={2}{G}{U} type=Sorcery [/card] [card] -name=Unstable Shapeshifter -auto=@movedto(other creature|battlefield):all(trigger[from]) copy -text=Whenever another creature enters the battlefield, Unstable Shapeshifter becomes a copy of that creature and gains this ability. -mana={3}{U} -type=Creature -subtype=Shapeshifter -power=0 -toughness=1 -[/card] -[card] name=Venser's Diffusion target=*[-land] auto=moveTo(ownerhand) diff --git a/projects/mtg/bin/Res/sets/primitives/mtg.txt b/projects/mtg/bin/Res/sets/primitives/mtg.txt index b2a91bcb1..22faeb4da 100644 --- a/projects/mtg/bin/Res/sets/primitives/mtg.txt +++ b/projects/mtg/bin/Res/sets/primitives/mtg.txt @@ -17634,6 +17634,16 @@ power=0 toughness=5 [/card] [card] +name=Cemetery Puca +auto=@movedto(creature|graveyard) from(battlefield):all(trigger[from]) pay[[{1}]] copy +text=Whenever a creature is put into a graveyard from the battlefield, you may pay {1}. If you do, Cemetery Puca becomes a copy of that creature and gains this ability. +mana={1}{UB}{UB} +type=Creature +subtype=Shapeshifter +power=1 +toughness=2 +[/card] +[card] name=Cemetery Reaper auto=lord(other zombie|myBattlefield) 1/1 auto={2}{B}{T}:moveTo(Exile) target(creature|graveyard) && token(Zombie,Creature Zombie,2/2,black) @@ -24048,6 +24058,16 @@ mana={1}{G} type=Enchantment [/card] [card] +name=Cryptoplasm +auto=@each my upkeep:may target(other creature|battlefield) copy and!( transforms((,newability[@each my upkeep:may copy target(other creature|battlefield)])) forever )! +text=At the beginning of your upkeep, you may have Cryptoplasm become a copy of another target creature. If you do, Cryptoplasm gains this ability. +mana={1}{U}{U} +type=Creature +subtype=Shapeshifter +power=2 +toughness=2 +[/card] +[card] name=Cryptwailing auto={1}{E(creature|mygraveyard)}{E(creature|mygraveyard)}:target(player) ability$!name(discard) target(*|myhand) reject!$ targetedplayer asSorcery text={1}, Exile two creature cards from your graveyard: Target player discards a card. Activate this ability only any time you could cast a sorcery. @@ -28850,6 +28870,16 @@ power=2 toughness=2 [/card] [card] +name=Dimir Doppelganger +auto={1}{U}{B}:name(exile) target(creature|nonbattlezone) copy and!( {1}{U}{B}:name(exile) target(creature|nonbattlezone) copy && moveto(exile) )! && moveto(exile) +text={1}{U}{B}: Exile target creature card from a graveyard. Dimir Doppelganger becomes a copy of that card and gains this ability. +mana={1}{U}{B} +type=Creature +subtype=Shapeshifter +power=0 +toughness=2 +[/card] +[card] name=Dimir Guildgate auto=tap(noevent) auto={T}:add{U} @@ -117523,6 +117553,13 @@ power=4 toughness=3 [/card] [card] +name=Thespian's Stage +auto={T}:Add{1} +auto={2}{T}:copy target(other land|battlefield) and!( {2}{T}:copy target(other land|battlefield) )! +text={T}: Add {1} to your mana pool. -- {2}, {T}: Thespian's Stage becomes a copy of target land and gains this ability. +type=Land +[/card] +[card] name=Thicket Basilisk auto=@combat(blocking,blocked) source(this) from(creature[-wall]):all(trigger[from]) phaseaction[combatends once] destroy text=Whenever Thicket Basilisk blocks or becomes blocked by a non-Wall creature, destroy that creature at end of combat. @@ -123750,6 +123787,16 @@ mana={3} type=Artifact [/card] [card] +name=Unstable Shapeshifter +auto=@movedto(other creature|battlefield):all(trigger[from]) copy and!( transforms((,newability[@movedto(other creature|battlefield):all(trigger[from]) copy])) forever )! +text=Whenever another creature enters the battlefield, Unstable Shapeshifter becomes a copy of that creature and gains this ability. +mana={3}{U} +type=Creature +subtype=Shapeshifter +power=0 +toughness=1 +[/card] +[card] name=Unstoppable Ash abilities=trample auto=aslongas(other treefolk|mybattlefield) choice notatarget(other treefolk|mybattlefield) (blink)forsrc oneshot From a97a7edca6ad6254f69f9fb240a232ca4bafc878 Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Tue, 31 Jan 2017 22:01:19 +0800 Subject: [PATCH 6/9] minor refactor --- projects/mtg/bin/Res/sets/primitives/mtg.txt | 26 ++++++++++---------- projects/mtg/src/MTGAbility.cpp | 8 ++++++ 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/projects/mtg/bin/Res/sets/primitives/mtg.txt b/projects/mtg/bin/Res/sets/primitives/mtg.txt index 22faeb4da..0c2c4d3f7 100644 --- a/projects/mtg/bin/Res/sets/primitives/mtg.txt +++ b/projects/mtg/bin/Res/sets/primitives/mtg.txt @@ -29396,7 +29396,7 @@ type=Instant [/card] [card] name=Dismiss into Dream -auto=lord(creature|opponentbattlefield) transforms((Illusion,newability[@targeted(this):sacrifice])) +auto=lord(creature|opponentbattlefield) transforms((Illusion,newability[while(restriction{cardistargeted}) sacrifice])) text=Enchantment. -- Each creature your opponents control is an Illusion in addition to its other types and has "When this creature becomes the target of a spell or ability, sacrifice it." mana={6}{U} type=Enchantment @@ -42891,7 +42891,7 @@ toughness=2 [/card] [card] name=Frost Walker -auto=@targeted(this):sacrifice +auto=while(restriction{cardistargeted}) sacrifice text=When Frost Walker becomes the target of a spell or ability, sacrifice it. mana={1}{U} type=Creature @@ -48227,7 +48227,7 @@ toughness=2 [card] name=Gossamer Phantasm abilities=flying -auto=@targeted(this):sacrifice +auto=while(restriction{cardistargeted}) sacrifice text=Flying -- When Gossamer Phantasm becomes the target of a spell or ability, sacrifice it. mana={1}{U} type=Creature @@ -55990,7 +55990,7 @@ toughness=4 [card] name=Illusionary Servant abilities=flying -auto=@targeted(this):sacrifice +auto=while(restriction{cardistargeted}) sacrifice text=Flying -- When Illusionary Servant becomes the target of a spell or ability, sacrifice it. mana={1}{U}{U} type=Creature @@ -83968,7 +83968,7 @@ toughness=1 [card] name=Phantasmal Abomination abilities=defender -auto=@targeted(this):sacrifice +auto=while(restriction{cardistargeted}) sacrifice text=Defender -- When Phantasmal Abomination becomes the target of a spell or ability, sacrifice it. mana={1}{U}{U} type=Creature @@ -83978,7 +83978,7 @@ toughness=5 [/card] [card] name=Phantasmal Bear -auto=@targeted(this):sacrifice +auto=while(restriction{cardistargeted}) sacrifice text=When Phantasmal Bear becomes the target of a spell or ability, sacrifice it. mana={U} type=Creature @@ -83989,7 +83989,7 @@ toughness=2 [card] name=Phantasmal Dragon abilities=flying -auto=@targeted(this):sacrifice +auto=while(restriction{cardistargeted}) sacrifice text=Flying -- When Phantasmal Dragon becomes the target of a spell or ability, sacrifice it. mana={2}{U}{U} type=Creature @@ -84022,7 +84022,7 @@ toughness=1 [card] name=Phantasmal Image auto=may copy NotATarget(creature) -auto=while(restriction{copiedacard}) transforms((Illusion,newability[@targeted(this):sacrifice])) forever +auto=while(restriction{copiedacard}) transforms((Illusion,newability[while(restriction{cardistargeted}) sacrifice])) forever text=You may have Phantasmal Image enter the battlefield as a copy of any creature on the battlefield, except it's an Illusion in addition to its other types and it gains "When this creature becomes the target of a spell or ability, sacrifice it." mana={1}{U} type=Creature @@ -84093,7 +84093,7 @@ toughness=2 [/card] [card] name=Phantom Beast -auto=@targeted(this):sacrifice +auto=while(restriction{cardistargeted}) sacrifice text=When Phantom Beast becomes the target of a spell or ability, sacrifice it. mana={3}{U} type=Creature @@ -104621,7 +104621,7 @@ type=Instant [/card] [card] name=Skulking Fugitive -auto=@targeted(this):sacrifice +auto=while(restriction{cardistargeted}) sacrifice text=When Skulking Fugitive becomes the target of a spell or ability, sacrifice it. mana={2}{B} type=Creature @@ -104632,7 +104632,7 @@ toughness=4 [card] name=Skulking Ghost abilities=flying -auto=@targeted(this):sacrifice +auto=while(restriction{cardistargeted}) sacrifice text=Flying -- When Skulking Ghost becomes the target of a spell or ability, sacrifice it. mana={1}{B} type=Creature @@ -104643,7 +104643,7 @@ toughness=1 [card] name=Skulking Knight abilities=flanking -auto=@targeted(this):sacrifice +auto=while(restriction{cardistargeted}) sacrifice text=Flanking (Whenever a creature without flanking blocks this creature, the blocking creature gets -1/-1 until end of turn.) -- When Skulking Knight becomes the target of a spell or ability, sacrifice it. mana={2}{B} type=Creature @@ -115504,7 +115504,7 @@ type=Artifact [/card] [card] name=Tar Pit Warrior -auto=@targeted(this):sacrifice +auto=while(restriction{cardistargeted}) sacrifice text=When Tar Pit Warrior becomes the target of a spell or ability, sacrifice it. mana={2}{B} type=Creature diff --git a/projects/mtg/src/MTGAbility.cpp b/projects/mtg/src/MTGAbility.cpp index ef20270f4..f0a4446b3 100644 --- a/projects/mtg/src/MTGAbility.cpp +++ b/projects/mtg/src/MTGAbility.cpp @@ -536,6 +536,14 @@ int AbilityFactory::parseCastRestrictions(MTGCardInstance * card, Player * playe if(!card->discarded) return 0; } + + check = restriction[i].find("cardistargeted"); + if(check != string::npos) + { + bool istarget = card->isTargetted(); + if(!istarget) + return 0; + } check = restriction[i].find("copiedacard"); if(check != string::npos) From 5504bf23d134ab932592d32a3330b7f21a718aed Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Wed, 1 Feb 2017 09:47:31 +0800 Subject: [PATCH 7/9] corrected dimir doppelganger --- projects/mtg/bin/Res/sets/primitives/mtg.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/mtg/bin/Res/sets/primitives/mtg.txt b/projects/mtg/bin/Res/sets/primitives/mtg.txt index 0c2c4d3f7..79aba4ea4 100644 --- a/projects/mtg/bin/Res/sets/primitives/mtg.txt +++ b/projects/mtg/bin/Res/sets/primitives/mtg.txt @@ -28871,7 +28871,7 @@ toughness=2 [/card] [card] name=Dimir Doppelganger -auto={1}{U}{B}:name(exile) target(creature|nonbattlezone) copy and!( {1}{U}{B}:name(exile) target(creature|nonbattlezone) copy && moveto(exile) )! && moveto(exile) +auto={1}{U}{B}:name(exile) target(creature|graveyard) copy and!( {1}{U}{B}:name(exile) target(creature|graveyard) copy && moveto(exile) )! && moveto(exile) text={1}{U}{B}: Exile target creature card from a graveyard. Dimir Doppelganger becomes a copy of that card and gains this ability. mana={1}{U}{B} type=Creature From c0afb3b95e0e99ff05b0f29e09ffca502bc94a83 Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Wed, 1 Feb 2017 09:48:40 +0800 Subject: [PATCH 8/9] added WEventGameStateBasedChecked --- projects/mtg/src/GameObserver.cpp | 3 +++ projects/mtg/src/WEvent.cpp | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/projects/mtg/src/GameObserver.cpp b/projects/mtg/src/GameObserver.cpp index 292eb3d08..fbc671f99 100644 --- a/projects/mtg/src/GameObserver.cpp +++ b/projects/mtg/src/GameObserver.cpp @@ -1061,6 +1061,9 @@ void GameObserver::gameStateBasedEffects() || mCurrentGamePhase == MTG_PHASE_COMBATDAMAGE)) userRequestNextGamePhase(); } + + //WEventGameStateBasedChecked event checked + receiveEvent(NEW WEventGameStateBasedChecked()); } void GameObserver::enchantmentStatus() diff --git a/projects/mtg/src/WEvent.cpp b/projects/mtg/src/WEvent.cpp index 0bf9b176d..d58377c7e 100644 --- a/projects/mtg/src/WEvent.cpp +++ b/projects/mtg/src/WEvent.cpp @@ -31,6 +31,11 @@ WEventDamageStackResolved::WEventDamageStackResolved() : { } +WEventGameStateBasedChecked::WEventGameStateBasedChecked() : + WEvent() +{ +} + WEventCardUpdate::WEventCardUpdate(MTGCardInstance * card) : WEvent(), card(card) { From 7b0fdcd7219842d912373a92b99d9310c5104a00 Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Wed, 1 Feb 2017 09:49:36 +0800 Subject: [PATCH 9/9] refactor Legendary Rule --- .../mtg/bin/Res/test/generic/legendary.txt | 1 + projects/mtg/include/MTGCardInstance.h | 1 + projects/mtg/include/MTGRules.h | 18 ++-- projects/mtg/include/WEvent.h | 5 + projects/mtg/src/MTGCardInstance.cpp | 16 +++ projects/mtg/src/MTGRules.cpp | 101 +++++++----------- 6 files changed, 72 insertions(+), 70 deletions(-) diff --git a/projects/mtg/bin/Res/test/generic/legendary.txt b/projects/mtg/bin/Res/test/generic/legendary.txt index 44a74aa94..46f5a1ed6 100644 --- a/projects/mtg/bin/Res/test/generic/legendary.txt +++ b/projects/mtg/bin/Res/test/generic/legendary.txt @@ -10,6 +10,7 @@ inplay:22897 [DO] 106525 choice 0 +106525 [ASSERT] FIRSTMAIN [PLAYER1] diff --git a/projects/mtg/include/MTGCardInstance.h b/projects/mtg/include/MTGCardInstance.h index 6242cfcfe..8c64487de 100644 --- a/projects/mtg/include/MTGCardInstance.h +++ b/projects/mtg/include/MTGCardInstance.h @@ -250,6 +250,7 @@ public: int getCurrentToughness(); int LKIpower; int LKItoughness; + int countDuplicateCardNames(); void cdaPT(int p = 0, int t = 0); bool isCDA; void switchPT(bool apply = false); diff --git a/projects/mtg/include/MTGRules.h b/projects/mtg/include/MTGRules.h index bc4e44d98..ecb6fde33 100644 --- a/projects/mtg/include/MTGRules.h +++ b/projects/mtg/include/MTGRules.h @@ -423,19 +423,19 @@ public: }; /* - * Rule 420.5e (Legend Rule) - * If two or more legendary permanents with the same name are in play, all are put into their - * owners' graveyards. This is called the "legend rule." If only one of those permanents is - * legendary, this rule doesn't apply. + * 704.5k If a player controls two or more legendary permanents with the same name, + * that player chooses one of them, and the rest are put into their owners’ graveyards. + * This is called the “legend rule.” */ -class MTGLegendRule: public ListMaintainerAbility +class MTGLegendRule: public PermanentAbility { public: + TargetChooser * tcL; + MTGAbility * Legendrule; + MTGAbility * LegendruleAbility; + MTGAbility * LegendruleGeneric; MTGLegendRule(GameObserver* observer, int _id); - int canBeInList(MTGCardInstance * card); - int added(MTGCardInstance * card); - int removed(MTGCardInstance * card); - int testDestroy(); + int receiveEvent(WEvent * event); virtual ostream& toString(ostream& out) const; virtual MTGLegendRule * clone() const; }; diff --git a/projects/mtg/include/WEvent.h b/projects/mtg/include/WEvent.h index 1358bf57d..29dee342a 100644 --- a/projects/mtg/include/WEvent.h +++ b/projects/mtg/include/WEvent.h @@ -79,6 +79,11 @@ struct WEventDamageStackResolved : public WEvent { WEventDamageStackResolved(); }; + +struct WEventGameStateBasedChecked : public WEvent { + WEventGameStateBasedChecked(); +}; + struct WEventPhasePreChange : public WEvent { Phase * from; Phase * to; diff --git a/projects/mtg/src/MTGCardInstance.cpp b/projects/mtg/src/MTGCardInstance.cpp index c73d0797c..ed7f7e932 100644 --- a/projects/mtg/src/MTGCardInstance.cpp +++ b/projects/mtg/src/MTGCardInstance.cpp @@ -828,6 +828,22 @@ int MTGCardInstance::getCurrentToughness() return toughness; } +int MTGCardInstance::countDuplicateCardNames() +{ + int count = 0; + + if(observer) + { + int nb_cards = controller()->game->battlefield->nb_cards; + for(int x = 0; x < nb_cards; x++) + { + if(controller()->game->battlefield->cards[x]->name == this->name) + count+=1; + } + } + return count; +} + //check stack bool MTGCardInstance::StackIsEmptyandSorcerySpeed() { diff --git a/projects/mtg/src/MTGRules.cpp b/projects/mtg/src/MTGRules.cpp index bbd92a56f..259c285da 100644 --- a/projects/mtg/src/MTGRules.cpp +++ b/projects/mtg/src/MTGRules.cpp @@ -3205,76 +3205,55 @@ MTGTokensCleanup * MTGTokensCleanup::clone() const /* Legend Rule */ MTGLegendRule::MTGLegendRule(GameObserver* observer, int _id) : -ListMaintainerAbility(observer, _id) +PermanentAbility(observer, _id) { + tcL = NULL; + Legendrule = NULL; + LegendruleAbility = NULL; + LegendruleGeneric = NULL; } ; -int MTGLegendRule::canBeInList(MTGCardInstance * card) +int MTGLegendRule::receiveEvent(WEvent * event) { - if(card->isPhased) - return 0; - if (card->hasType(Subtypes::TYPE_LEGENDARY) && card->controller()->game->inPlay->hasCard(card)) + WEventGameStateBasedChecked * e = dynamic_cast (event); + if (e) { - if(card->has(Constants::NOLEGEND)||card->controller()->opponent()->inPlay()->hasAbility(Constants::NOLEGENDRULE)||card->controller()->inPlay()->hasAbility(Constants::NOLEGENDRULE)) - return 0; - else - return 1; - } - return 0; -} - -int MTGLegendRule::added(MTGCardInstance * card) -{ - map::iterator it; - int destroy = 0; - - vectoroldCards; - for (it = cards.begin(); it != cards.end(); it++) - { - MTGCardInstance * comparison = (*it).first; - if (comparison != card && comparison->controller() == card->controller() && !(comparison->getName().compare(card->getName()))) + for (int i = 0; i < 2; i++) { - oldCards.push_back(comparison); - destroy = 1; + MTGGameZone * zone = game->players[i]->game->inPlay; + for (int k = zone->nb_cards - 1; k >= 0; k--) + { + MTGCardInstance * card = zone->cards[k]; + if (card && card->hasType(Subtypes::TYPE_LEGENDARY) && !card->isPhased) + { + if(card->has(Constants::NOLEGEND)||card->controller()->opponent()->inPlay()->hasAbility(Constants::NOLEGENDRULE)||card->controller()->inPlay()->hasAbility(Constants::NOLEGENDRULE)) + ; + else + if(card->countDuplicateCardNames() > 1) + { + vectorselection; + TargetChooserFactory tfL(game); + tcL = tfL.createTargetChooser("*[share!name!]|mybattlefield",card->clone()); + tcL->targetter = NULL; + tcL->maxtargets = card->countDuplicateCardNames()-1; + Legendrule = NEW AAMover(game, game->mLayers->actionLayer()->getMaxId(), card, NULL,"ownergraveyard","Put in Graveyard"); + Legendrule->oneShot = true; + Legendrule->canBeInterrupted = false; + LegendruleAbility = NEW GenericTargetAbility(game, "","",game->mLayers->actionLayer()->getMaxId(), card,tcL, Legendrule->clone()); + LegendruleAbility->oneShot = true; + LegendruleAbility->canBeInterrupted = false; + LegendruleGeneric = NEW GenericAddToGame(game, game->mLayers->actionLayer()->getMaxId(), card,NULL,LegendruleAbility->clone()); + LegendruleGeneric->oneShot = true; + selection.push_back(LegendruleGeneric->clone()); + MTGAbility * menuChoice = NEW MenuAbility(game, game->mLayers->actionLayer()->getMaxId(), card, card,true,selection,card->controller(),"Legendary Rule"); + menuChoice->addToGame(); + return 1; + } + } + } } } - if (game->mLayers->stackLayer()->count(0, NOT_RESOLVED) != 0) - destroy = 0; - if (game->mLayers->actionLayer()->menuObject) - destroy = 0; - if (game->getCurrentTargetChooser() || game->mLayers->actionLayer()->isWaitingForAnswer()) - destroy = 0; - if(destroy) - { - vectorselection; - MultiAbility * multi = NEW MultiAbility(game, game->mLayers->actionLayer()->getMaxId(), card, card, NULL); - for(unsigned int i = 0;i < oldCards.size();i++) - { - AAMover *a = NEW AAMover(game, game->mLayers->actionLayer()->getMaxId(), card, oldCards[i],"ownergraveyard","Keep New"); - a->oneShot = true; - multi->Add(a); - } - multi->oneShot = 1; - MTGAbility * a1 = multi; - selection.push_back(a1); - AAMover *b = NEW AAMover(game, game->mLayers->actionLayer()->getMaxId(), card, card,"ownergraveyard","Keep Old"); - b->oneShot = true; - MTGAbility * b1 = b; - selection.push_back(b1); - MTGAbility * menuChoice = NEW MenuAbility(game, game->mLayers->actionLayer()->getMaxId(), card, card,true,selection,card->controller(),"Legendary Rule"); - menuChoice->addToGame(); - } - return 1; -} - -int MTGLegendRule::removed(MTGCardInstance *) -{ - return 0; -} - -int MTGLegendRule::testDestroy() -{ return 0; }