From 6bd09e42e01d054924743f74a691b4ce7d5748e3 Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Thu, 3 Aug 2017 09:49:37 +0800 Subject: [PATCH] Add support for Amonkhet Mechanics and fix some cards. Added exerted trigger, event and add removemc keyword inside transforms ability so we can soft code Embalm and Eternalize... --- projects/mtg/bin/Res/sets/primitives/mtg.txt | 13 ++-- projects/mtg/include/AllAbilities.h | 74 ++++++++++++++++++++ projects/mtg/include/MTGCardInstance.h | 1 + projects/mtg/include/WEvent.h | 6 ++ projects/mtg/src/ActionStack.cpp | 2 +- projects/mtg/src/AllAbilities.cpp | 4 ++ projects/mtg/src/MTGAbility.cpp | 23 +++++- projects/mtg/src/MTGCardInstance.cpp | 1 + projects/mtg/src/MTGDeck.cpp | 38 +++++----- projects/mtg/src/MTGGameZones.cpp | 27 +++++-- projects/mtg/src/WEvent.cpp | 11 +++ 11 files changed, 166 insertions(+), 34 deletions(-) diff --git a/projects/mtg/bin/Res/sets/primitives/mtg.txt b/projects/mtg/bin/Res/sets/primitives/mtg.txt index 773e745ac..c11da5943 100644 --- a/projects/mtg/bin/Res/sets/primitives/mtg.txt +++ b/projects/mtg/bin/Res/sets/primitives/mtg.txt @@ -41166,8 +41166,7 @@ type=Enchantment [card] name=Flagstones of Trokair auto={T}:Add{W} -aicode=activate moveTo(myBattlefield) and!(tap(noevent))! target(plains|myLibrary) -auto=@movedTo(this|graveyard) from(battlefield):name(search card) reveal:plibrarycount optionone name(choose card) target(plains|reveal) moveto(ownerlibrary) and!( becomes(tobecast) ueot )! optiononeend optiontwo name(put back) target(<1>*|reveal) moveto(ownerlibrary) and!( all(*|reveal) moveto(ownerlibrary) and!(shuffle)! )! optiontwoend afterrevealed all(tobecast|mylibrary) moveto(ownerlibrary) and!(moveTo(myBattlefield) and!(tap(noevent))!)! afterrevealedend revealend +auto=@movedTo(this|graveyard) from(battlefield):name(search card) ability$!moveTo(myBattlefield) and!(tap(noevent))! target(plains|myLibrary)!$ controller text={T}: Add {W} to your mana pool. -- When Flagstones of Trokair is put into a graveyard from the battlefield, you may search your library for a Plains card and put it onto the battlefield tapped. If you do, shuffle your library. type=Legendary Land [/card] @@ -64909,7 +64908,7 @@ toughness=5 name=Krosan Verge auto=tap(noevent) auto={T}:Add{1} -auto={2}{T}{S}:name(sacrifice to search) ability$! name(search forest) notatarget(forest|mylibrary) moveto(ownerbattlefield) and!(tap(noevent))! !$ controller && ability$! name(search plains) notatarget(plains|mylibrary) moveto(ownerbattlefield) and!(tap(noevent))! !$ controller +auto={2}{T}{S}:name(sacrifice to search) transforms((,newability[ability$! name(search forest) notatarget(forest|mylibrary) moveto(ownerbattlefield) and!(tap(noevent))! !$ controller],newability[ability$! name(search plains) notatarget(plains|mylibrary) moveto(ownerbattlefield) and!(tap(noevent))! !$ controller])) oneshot text=Krosan Verge enters the battlefield tapped. -- {T}: Add {1} to your mana pool. -- {2}, {T}, Sacrifice Krosan Verge: Search your library for a Forest card and a Plains card and put them onto the battlefield tapped. Then shuffle your library. type=Land [/card] @@ -79818,7 +79817,7 @@ name=Niblis of the Breath abilities=flying auto={U}{T}:may tap target(creature) auto={U}{T}:may untap target(creature) -text=Flying -- Whenever Niblis of the Urn attacks, you may tap target creature. +text=Flying -- {U}, {T}: You may tap or untap target creature. mana={2}{U} type=Creature subtype=Spirit @@ -90652,8 +90651,8 @@ toughness=5 [card] name=Quarantine Field auto=counter(0/0,xx,Isolation) -auto=(blink)forsrc target(*[-land]|opponentbattlefield) -text=Quarantine Field enters the battlefield with X isolation counters on it. -- When Quarantine Field enters the battlefield, for each isolation counter on it, exile up to one target nonland permanent an opponent controls until Quarantine Field leaves the battlefield. (WORKAROUND ONLY EXILES UP TO X AND NOT FOR EACH COUNTER) +auto=this(variable{xx} >0) (blink)forsrc target(*[-land]|opponentbattlefield) +text=Quarantine Field enters the battlefield with X isolation counters on it. -- When Quarantine Field enters the battlefield, for each isolation counter on it, exile up to one target nonland permanent an opponent controls until Quarantine Field leaves the battlefield. mana={X}{X}{W}{W} type=Enchantment [/card] @@ -109371,7 +109370,7 @@ type=Instant [/card] [card] name=Solitary Confinement -auto=upcost[{D(*|myhand)}] sacrifice +auto=@each my upkeep :name(discard or sacrifice) ability$!if type(*|myhand)~morethan~0 then choice reject notatarget(*|myhand) _ choice sacrifice all(mystored)!$ controller auto=phasealter(remove,draw,controller) abilities=playershroud auto=preventalldamage to(controller) diff --git a/projects/mtg/include/AllAbilities.h b/projects/mtg/include/AllAbilities.h index 59ec7f9bf..b8ff0c4e8 100644 --- a/projects/mtg/include/AllAbilities.h +++ b/projects/mtg/include/AllAbilities.h @@ -1406,6 +1406,28 @@ public: } }; +class TrCardExerted: public Trigger +{ +public: + TrCardExerted(GameObserver* observer, int id, MTGCardInstance * source, TargetChooser * tc, bool once = false) : + Trigger(observer, id, source, once, tc) + { + } + + int triggerOnEventImpl(WEvent * event) + { + WEventCardExerted * e = dynamic_cast (event); + if (!e) return 0; + if (!tc->canTarget(e->card)) return 0; + return 1; + } + + TrCardExerted * clone() const + { + return NEW TrCardExerted(*this); + } +}; + class TrCombatTrigger: public Trigger { public: @@ -5174,6 +5196,7 @@ public: list oldcolors; list oldtypes; vector dontremove; + bool removemc; bool addNewColors; bool remove; bool removeCreatureSubtypes; @@ -7290,6 +7313,57 @@ public: return NEW AProvoke(*this); } }; +//exert +class AExert: public InstantAbility +{ +public: + MTGAbility * andAbility; + AExert(GameObserver* observer, int _id, MTGCardInstance * _source, MTGCardInstance * _target) : + InstantAbility(observer, _id, _source) + { + target = _target; + andAbility = NULL; + } + + int resolve() + { + MTGCardInstance * card = (MTGCardInstance *) target; + if (card) + { + card->exerted = true; + WEvent * e = NEW WEventCardExerted(card); + game->receiveEvent(e); + if(andAbility) + { + MTGAbility * andAbilityClone = andAbility->clone(); + andAbilityClone->target = card; + if(andAbility->oneShot) + { + andAbilityClone->resolve(); + SAFE_DELETE(andAbilityClone); + } + else + { + andAbilityClone->addToGame(); + } + } + } + return 1; + } + const string getMenuText() + { + return "Exert"; + } + virtual ostream& toString(ostream& out) const + { + out << "AAExert ::: ("; + return InstantAbility::toString(out) << ")"; + } + AExert * clone() const + { + return NEW AExert(*this); + } +}; //------------------ //trigger regen class ATriggerRegen: public InstantAbility diff --git a/projects/mtg/include/MTGCardInstance.h b/projects/mtg/include/MTGCardInstance.h index e7e9b40e8..77760f9ea 100644 --- a/projects/mtg/include/MTGCardInstance.h +++ b/projects/mtg/include/MTGCardInstance.h @@ -90,6 +90,7 @@ public: bool blinked; bool isExtraCostTarget; bool morphed; + bool exerted; bool turningOver; bool isMorphed; bool isFlipped; diff --git a/projects/mtg/include/WEvent.h b/projects/mtg/include/WEvent.h index de99e6a5d..9cb1788a7 100644 --- a/projects/mtg/include/WEvent.h +++ b/projects/mtg/include/WEvent.h @@ -205,6 +205,12 @@ struct WEventCardCycle : public WEventCardUpdate { virtual Targetable * getTarget(int target); }; +//event when card is exerted. +struct WEventCardExerted : public WEventCardUpdate { + WEventCardExerted(MTGCardInstance * card); + virtual Targetable * getTarget(int target); +}; + //Event when a card's "defenser" status changes //before : attacker that card was blocking previously //after: attacker that card is blocking now diff --git a/projects/mtg/src/ActionStack.cpp b/projects/mtg/src/ActionStack.cpp index 0db48ea37..43f943b27 100644 --- a/projects/mtg/src/ActionStack.cpp +++ b/projects/mtg/src/ActionStack.cpp @@ -1040,7 +1040,7 @@ void ActionStack::Update(float dt) if (getCurrentTutorial() && (observer->players[0]->isHuman() || observer->players[1]->isHuman() ) ) return; - if (observer->mLayers->actionLayer()->menuObject || observer->LPWeffect) + if (observer->mLayers->actionLayer()->menuObject)// || observer->LPWeffect) //test fix for hang for both legendary with action/reveal if(observer->players[0]->isHuman() || observer->players[1]->isHuman()) return;//dont do any of this if a menuobject exist. diff --git a/projects/mtg/src/AllAbilities.cpp b/projects/mtg/src/AllAbilities.cpp index 31f2f7111..68e71ae06 100644 --- a/projects/mtg/src/AllAbilities.cpp +++ b/projects/mtg/src/AllAbilities.cpp @@ -6046,6 +6046,7 @@ ATransformer::ATransformer(GameObserver* observer, int id, MTGCardInstance * sou } myCurrentTurn = 1000; //this subkeyword adds a color without removing the existing colors. + removemc = (sabilities.find("removemc") != string::npos); addNewColors = (sabilities.find("newcolors") != string::npos); remove = (stypes.find("removealltypes") != string::npos); removeCreatureSubtypes = (stypes.find("removecreaturesubtypes") != string::npos); @@ -6235,6 +6236,9 @@ for (it = types.begin(); it != types.end(); it++) _target->addbaseT(val->getValue()); delete val; } + //remove manacost + if(removemc) + _target->getManaCost()->resetCosts(); return MTGAbility::addToGame(); } diff --git a/projects/mtg/src/MTGAbility.cpp b/projects/mtg/src/MTGAbility.cpp index 28d9007cf..91b885f41 100644 --- a/projects/mtg/src/MTGAbility.cpp +++ b/projects/mtg/src/MTGAbility.cpp @@ -439,7 +439,7 @@ int AbilityFactory::parseCastRestrictions(MTGCardInstance * card, Player * playe if (grave->hasType("land")) checkTypesAmount++; if (grave->hasType("artifact")) checkTypesAmount++; if (grave->hasType("planeswalker")) checkTypesAmount++; - if (grave->hasType("tribal")) checkTypesAmount++; + if (grave->hasType("tribal")) checkTypesAmount++; if (checkTypesAmount < 4) return 0; } @@ -458,7 +458,7 @@ int AbilityFactory::parseCastRestrictions(MTGCardInstance * card, Player * playe if (grave->hasType("land")) checkTypesAmount++; if (grave->hasType("artifact")) checkTypesAmount++; if (grave->hasType("planeswalker")) checkTypesAmount++; - if (grave->hasType("tribal")) checkTypesAmount++; + if (grave->hasType("tribal")) checkTypesAmount++; if (checkTypesAmount > 3) return 0; } @@ -1070,6 +1070,10 @@ TriggeredAbility * AbilityFactory::parseTrigger(string s, string, int id, Spell if (TargetChooser *tc = parseSimpleTC(s,"phasedin", card)) return NEW TrCardPhasesIn(observer, id, card, tc,once); + //Card Exerted + if (TargetChooser *tc = parseSimpleTC(s,"exerted", card)) + return NEW TrCardExerted(observer, id, card, tc,once); + //CombatTrigger //Card card attacked and is blocked found = s.find("combat("); @@ -2928,7 +2932,20 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG ((AManifest*)a)->withenchant = true; return a; } - + //exert + found = s.find("exert"); + if (found != string::npos) + { + MTGAbility * a = NEW AExert(observer, id, card, target); + a->oneShot = 1; + if(storedAndAbility.size()) + { + string stored = storedAndAbility; + storedAndAbility.clear(); + ((AExert*)a)->andAbility = parseMagicLine(stored, id, spell, card); + } + return a; + } //provoke found = s.find("provoke"); if (found != string::npos) diff --git a/projects/mtg/src/MTGCardInstance.cpp b/projects/mtg/src/MTGCardInstance.cpp index 9bd209250..27edf2909 100644 --- a/projects/mtg/src/MTGCardInstance.cpp +++ b/projects/mtg/src/MTGCardInstance.cpp @@ -224,6 +224,7 @@ void MTGCardInstance::initMTGCI() blinked = false; isExtraCostTarget = false; morphed = false; + exerted = false; turningOver = false; isMorphed = false; MeldedFrom = ""; diff --git a/projects/mtg/src/MTGDeck.cpp b/projects/mtg/src/MTGDeck.cpp index 7dd645ff5..642dcb99a 100644 --- a/projects/mtg/src/MTGDeck.cpp +++ b/projects/mtg/src/MTGDeck.cpp @@ -1219,12 +1219,12 @@ int MTGDeck::save(const string& destFileName, bool useExpandedDescriptions, cons void MTGDeck::printDetailedDeckText(std::ofstream& file ) { ostringstream currentCard, creatures, lands, spells, types; - ostringstream ss_creatures, ss_lands, ss_spells; - int numberOfCreatures = 0; - int numberOfSpells = 0; - int numberOfLands = 0; + ostringstream ss_creatures, ss_lands, ss_spells; + int numberOfCreatures = 0; + int numberOfSpells = 0; + int numberOfLands = 0; - map::iterator it; + map::iterator it; for (it = cards.begin(); it != cards.end(); it++) { int cardId = it->first; @@ -1271,29 +1271,29 @@ void MTGDeck::printDetailedDeckText(std::ofstream& file ) currentCard <data->isLand() ) - { + { lands<< currentCard.str(); - numberOfLands+=nbCards; - } + numberOfLands+=nbCards; + } else if ( card->data->isCreature() ) - { + { creatures << currentCard.str(); - numberOfCreatures+=nbCards; - } + numberOfCreatures+=nbCards; + } else - { + { spells << currentCard.str(); - numberOfSpells+=nbCards; - } + numberOfSpells+=nbCards; + } currentCard.str(""); } - ss_creatures << numberOfCreatures; - ss_spells << numberOfSpells; - ss_lands << numberOfLands; + ss_creatures << numberOfCreatures; + ss_spells << numberOfSpells; + ss_lands << numberOfLands; - file << getCardBlockText( "Creatures x " + ss_creatures.str(), creatures.str() ) << endl; + file << getCardBlockText( "Creatures x " + ss_creatures.str(), creatures.str() ) << endl; file << getCardBlockText( "Spells x " + ss_spells.str(), spells.str() ) << endl; file << getCardBlockText( "Lands x " + ss_lands.str(), lands.str() ) << endl; creatures.str(""); diff --git a/projects/mtg/src/MTGGameZones.cpp b/projects/mtg/src/MTGGameZones.cpp index aac91f1f5..9960b8b76 100644 --- a/projects/mtg/src/MTGGameZones.cpp +++ b/projects/mtg/src/MTGGameZones.cpp @@ -554,6 +554,13 @@ MTGCardInstance * MTGPlayerCards::putInZone(MTGCardInstance * card, MTGGameZone } } } + //remove exerted if changing controls + if((to == g->players[0]->game->battlefield && from == g->players[1]->game->battlefield)|| + (to == g->players[1]->game->battlefield && from == g->players[0]->game->battlefield)) + { + if(ret->exerted) + ret->exerted = false; + } } if(!asCopy) { @@ -1125,13 +1132,25 @@ void MTGInPlay::untapAll() card->setUntapping(); if (!card->basicAbilities[(int)Constants::DOESNOTUNTAP] && !card->basicAbilities[(int)Constants::SHACKLER]) { - if (card->frozen < 1) + if(card->exerted) { - card->attemptUntap(); + card->exerted = false; + if (card->frozen >= 1) + { + card->frozen = 0; + } } - if (card->frozen >= 1) + else { - card->frozen = 0; + card->exerted = false; + if (card->frozen < 1) + { + card->attemptUntap(); + } + if (card->frozen >= 1) + { + card->frozen = 0; + } } } } diff --git a/projects/mtg/src/WEvent.cpp b/projects/mtg/src/WEvent.cpp index 21923024f..a88aa85d3 100644 --- a/projects/mtg/src/WEvent.cpp +++ b/projects/mtg/src/WEvent.cpp @@ -121,6 +121,11 @@ WEventCardUpdate(card) { } +WEventCardExerted::WEventCardExerted(MTGCardInstance * card) : +WEventCardUpdate(card) +{ +} + WEventVampire::WEventVampire(MTGCardInstance * card,MTGCardInstance * source,MTGCardInstance * victem) : WEventCardUpdate(card),source(source),victem(victem) { @@ -377,6 +382,12 @@ Targetable * WEventCardCycle::getTarget(int target) return NULL; } +Targetable * WEventCardExerted::getTarget(int target) +{ + if (target) return card; + return NULL; +} + Targetable * WEventCardAttackedNotBlocked::getTarget(int target) { if (target) return card;