From cf50b7d4038aa74eed67f26eb30abb6690611e24 Mon Sep 17 00:00:00 2001 From: Dmitry Panin Date: Tue, 22 Oct 2013 20:29:06 +0400 Subject: [PATCH] Fizzle unless pay x (thanks to excessum) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - saves source card in storedSourceCard for ATransform - adds support for WParsedInt in pay as "pay[[{value:WParsedInt}]]": name=Spell Rupture target=*|stack auto=if cantargetcard(*|opponentstack) then transforms((,newability[pay[[{value:power:highest:creature:opponentbattlefield}]] name(pay {value} mana) donothing?fizzle])) forever text=Counter target spell unless its controller pays {X}, where X is the greatest power among creatures you control. mana={1}{U} type=Instant - adds support for {x} in *some* “pay” abilities (Syncopate): name=Syncopate target=*|stack auto=transforms((,newability[pay[[{x}]] name(pay {value} mana) donothing?fizzleto(exile)])) forever text=Counter target spell unless its controller pays {X}. If that spell is countered this way, exile it instead of putting it into its owner's graveyard. mana={X}{U} type=Instant - support of "name(pay {value} mana)" in pay abilities to show actual number to pay (see example above) --- projects/mtg/bin/Res/sets/primitives/mtg.txt | 16 +++++ projects/mtg/bin/Res/test/_tests.txt | 1 + projects/mtg/src/AllAbilities.cpp | 66 +++++++++++++------- projects/mtg/src/MTGAbility.cpp | 5 +- projects/mtg/src/ManaCost.cpp | 9 +++ 5 files changed, 72 insertions(+), 25 deletions(-) diff --git a/projects/mtg/bin/Res/sets/primitives/mtg.txt b/projects/mtg/bin/Res/sets/primitives/mtg.txt index 79547c7d7..97adaf357 100644 --- a/projects/mtg/bin/Res/sets/primitives/mtg.txt +++ b/projects/mtg/bin/Res/sets/primitives/mtg.txt @@ -83702,6 +83702,14 @@ mana={U} type=Instant [/card] [card] +name=Spell Rupture +target=*|stack +auto=if cantargetcard(*|opponentstack) then transforms((,newability[pay[[{value:power:highest:creature:opponentbattlefield}]] name(pay {value} mana) donothing?fizzle])) forever else transforms((,newability[pay[[{value:power:highest:creature:mybattlefield.}]] name(pay {value} mana) donothing?fizzle])) forever +text=Counter target spell unless its controller pays {X}, where X is the greatest power among creatures you control. +mana={1}{U} +type=Instant +[/card] +[card] name=Spell Snare target=*[manacost=2]|stack auto=fizzle @@ -88470,6 +88478,14 @@ power=3 toughness=3 [/card] [card] +name=Syncopate +target=*|stack +auto=transforms((,newability[pay[[{x}]] name(pay {value} mana) donothing?fizzleto(exile)])) forever +text=Counter target spell unless its controller pays {X}. If that spell is countered this way, exile it instead of putting it into its owner's graveyard. +mana={X}{U} +type=Instant +[/card] +[card] name=Syndic of Tithes auto=@movedto(*|mystack):pay({WB}) life:-1 opponent && life:1 controller text=Extort (Whenever you cast a spell, you may pay {WB}. If you do, each opponent loses 1 life and you gain that much life.) diff --git a/projects/mtg/bin/Res/test/_tests.txt b/projects/mtg/bin/Res/test/_tests.txt index 54b97ea8d..75676ef73 100644 --- a/projects/mtg/bin/Res/test/_tests.txt +++ b/projects/mtg/bin/Res/test/_tests.txt @@ -238,6 +238,7 @@ counterspell.txt counterspell2.txt counterspell3.txt counterspell4.txt +counter_unless_pay.txt Covetous_Dragon_ASLONGAS_3.txt Covetous_Dragon_ASLONGAS_4.txt cranial_plating.txt diff --git a/projects/mtg/src/AllAbilities.cpp b/projects/mtg/src/AllAbilities.cpp index 79f6dd7e3..ea19b136a 100644 --- a/projects/mtg/src/AllAbilities.cpp +++ b/projects/mtg/src/AllAbilities.cpp @@ -1110,9 +1110,12 @@ AASetCoin * AASetCoin::clone() const AASetCoin::~AASetCoin() { } + //paying for an ability as an effect but as a cost -GenericPaidAbility::GenericPaidAbility(GameObserver* observer, int id, MTGCardInstance * source, Targetable * target,string _newName,string _castRestriction,string mayCost,string _toAdd,ManaCost * cost) : -ActivatedAbility(observer, id, source, cost, 0),newName(_newName),restrictions(_castRestriction),baseCost(mayCost), baseAbilityStr(_toAdd) +GenericPaidAbility::GenericPaidAbility(GameObserver* observer, int id, MTGCardInstance * source, + Targetable * target, string _newName, string _castRestriction, string mayCost, string _toAdd, ManaCost * cost) : +ActivatedAbility(observer, id, source, cost, 0), + newName(_newName), restrictions(_castRestriction), baseCost(mayCost), baseAbilityStr(_toAdd) { this->GetId(); baseAbility = NULL; @@ -1124,8 +1127,7 @@ int GenericPaidAbility::resolve() if (!target) return 0; - - if(restrictions.size()) + if (restrictions.size()) { AbilityFactory af(game); int checkCond = af.parseCastRestrictions(source,source->controller(),restrictions); @@ -1136,21 +1138,35 @@ int GenericPaidAbility::resolve() } AbilityFactory Af(game); vector baseAbilityStrSplit = split(baseAbilityStr,'?'); - vectorselection; - if(baseAbilityStrSplit.size() > 1) + vector selection; + if (baseAbilityStrSplit.size() > 1) { - baseAbility = Af.parseMagicLine(baseAbilityStrSplit[0], this->GetId(), NULL, source); - baseAbility->target = target; - optionalCost = ManaCost::parseManaCost(baseCost, NULL, source); - MTGAbility * set = baseAbility->clone(); - set->oneShot = true; - selection.push_back(set); - SAFE_DELETE(baseAbility); - baseAbility = Af.parseMagicLine(baseAbilityStrSplit[1], this->GetId(), NULL, source); - baseAbility->target = target; - set = baseAbility->clone(); - set->oneShot = true; - selection.push_back(set); + baseAbility = Af.parseMagicLine(baseAbilityStrSplit[0], this->GetId(), NULL, source); + baseAbility->target = target; + optionalCost = ManaCost::parseManaCost(baseCost, NULL, source); + if (optionalCost->hasX()) { + optionalCost->add(Constants::MTG_COLOR_ARTIFACT, source->storedSourceCard->X); + } + + // hacky way to produce better MenuText + AAFakeAbility* isFake = dynamic_cast< AAFakeAbility* >( baseAbility ); + size_t findPayN = isFake->named.find(" {value} mana"); + if (isFake && findPayN != string::npos) { + stringstream parseN; + parseN << optionalCost->getCost(Constants::MTG_COLOR_ARTIFACT); + isFake->named.replace(findPayN + 1, 7, parseN.str()); + } + + MTGAbility * set = baseAbility->clone(); + set->oneShot = true; + selection.push_back(set); + SAFE_DELETE(baseAbility); + + baseAbility = Af.parseMagicLine(baseAbilityStrSplit[1], this->GetId(), NULL, source); + baseAbility->target = target; + set = baseAbility->clone(); + set->oneShot = true; + selection.push_back(set); } else { @@ -1162,20 +1178,20 @@ int GenericPaidAbility::resolve() selection.push_back(set); } - if(selection.size()) + if (selection.size()) { - MTGAbility * a1 = NEW MenuAbility(game, this->GetId(), target, source,baseAbilityStrSplit.size() >1?true:false,selection,NULL,newName); - dynamic_cast(a1)->optionalCosts.push_back(NEW ManaCost(optionalCost)); + bool must = baseAbilityStrSplit.size() > 1 ? true : false; + MenuAbility * a1 = NEW MenuAbility(game, this->GetId(), target, source, must, selection, NULL, newName); + a1->optionalCosts.push_back(NEW ManaCost(optionalCost)); game->mLayers->actionLayer()->currentActionCard = (MTGCardInstance *)target; a1->resolve(); } return 1; - } const char* GenericPaidAbility::getMenuText() { - if( newName.size()) + if (newName.size()) return newName.c_str(); return "Pay For Effect"; } @@ -3922,6 +3938,10 @@ ATransformer::ATransformer(GameObserver* observer, int id, MTGCardInstance * sou MTGAbility(observer, id, source, target),newpower(newpower),newpowerfound(newpowerfound),newtoughness(newtoughness),newtoughnessfound(newtoughnessfound),newAbilitiesList(newAbilitiesList),newAbilityFound(newAbilityFound),aForever(aForever),UYNT(aUntilNext),menutext(_menu) { + if (target != source) { + target->storedSourceCard = source; + } + PopulateAbilityIndexVector(abilities, sabilities); PopulateColorIndexVector(colors, sabilities); if(sabilities.find("chosencolor") != string::npos) diff --git a/projects/mtg/src/MTGAbility.cpp b/projects/mtg/src/MTGAbility.cpp index 74919cf8a..4535f1d13 100644 --- a/projects/mtg/src/MTGAbility.cpp +++ b/projects/mtg/src/MTGAbility.cpp @@ -1961,9 +1961,10 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG a->canBeInterrupted = false; return a; } - //may pay ability + + //may pay ability vector splitMayPaysub = parseBetween(s, "pay[[","]]", true); - if(splitMayPaysub.size()) + if (splitMayPaysub.size()) { GenericPaidAbility * a = NEW GenericPaidAbility(observer, id, card, target,newName,castRestriction,splitMayPaysub[1],storedPayString); a->oneShot = 1; diff --git a/projects/mtg/src/ManaCost.cpp b/projects/mtg/src/ManaCost.cpp index cee99c7cb..be10a2b55 100644 --- a/projects/mtg/src/ManaCost.cpp +++ b/projects/mtg/src/ManaCost.cpp @@ -7,6 +7,7 @@ #include "Player.h" #include "WEvent.h" #include "MTGAbility.h" +#include "AllAbilities.h" #include "iterator" SUPPORT_OBJECT_ANALYTICS(ManaCost) @@ -119,6 +120,14 @@ ManaCost * ManaCost::parseManaCost(string s, ManaCost * _manaCost, MTGCardInstan } } break; + case 'v': + if (value.find("value:") != string::npos) { + vector splitParsedVar = parseBetween(value, "value:", " ", false); + WParsedInt* res = NEW WParsedInt(splitParsedVar[1], NULL, c); + manaCost->add(Constants::MTG_COLOR_ARTIFACT, res->getValue()); + SAFE_DELETE(res); + } + break; case 't': //Tap if (value == "t") {