diff --git a/projects/mtg/bin/Res/rules/Blitzkrieg.txt b/projects/mtg/bin/Res/rules/Blitzkrieg.txt index ac5692b10..15f48cd95 100644 --- a/projects/mtg/bin/Res/rules/Blitzkrieg.txt +++ b/projects/mtg/bin/Res/rules/Blitzkrieg.txt @@ -18,6 +18,7 @@ auto=overloadrule auto=attackrule auto=attackcostrule auto=blockrule +auto=blockcostrule auto=combattriggerrule auto=legendrule auto=planeswalkerrule diff --git a/projects/mtg/bin/Res/rules/hermit.txt b/projects/mtg/bin/Res/rules/hermit.txt index 7d08bdcbb..8cf5a7139 100644 --- a/projects/mtg/bin/Res/rules/hermit.txt +++ b/projects/mtg/bin/Res/rules/hermit.txt @@ -17,6 +17,7 @@ auto=overloadrule auto=attackrule auto=attackcostrule auto=blockrule +auto=blockcostrule auto=combattriggerrule auto=legendrule auto=planeswalkerrule diff --git a/projects/mtg/bin/Res/rules/mtg.txt b/projects/mtg/bin/Res/rules/mtg.txt index 44beaae5d..202dcc3cb 100644 --- a/projects/mtg/bin/Res/rules/mtg.txt +++ b/projects/mtg/bin/Res/rules/mtg.txt @@ -21,6 +21,7 @@ auto=overloadrule auto=attackrule auto=attackcostrule auto=blockrule +auto=blockcostrule auto=combattriggerrule auto=legendrule auto=planeswalkerrule diff --git a/projects/mtg/bin/Res/sets/primitives/borderline.txt b/projects/mtg/bin/Res/sets/primitives/borderline.txt index b7c085302..8f95f9539 100644 --- a/projects/mtg/bin/Res/sets/primitives/borderline.txt +++ b/projects/mtg/bin/Res/sets/primitives/borderline.txt @@ -1,17 +1,4 @@ grade=borderline -#planeswalker and creature attack cost... -[card] -name=Archangel of Tithes -abilities=flying -auto=this(untapped) lord(creature|opponentbattlefield) transforms((,newability[@each mycombatbegins:pay[[{1}]] name(pay 1 mana) donothing?cantattack all(this)])) -auto=@combat(attacking) source(this):all(creature|opponentbattlefield) transforms((,newability[pay[[{1}]] name(pay 1 mana) donothing?cantblock all(this)])) -text=Flying -- As long as Archangel of Tithes is untapped, creatures can't attack you or a planeswalker you control unless their controller pays {1} for each of those creatures. -- As long as Archangel of Tithes is attacking, creatures can't block unless their controller pays {1} for each of those creatures. -mana={1}{W}{W}{W} -type=Creature -subtype=Angel -power=3 -toughness=5 -[/card] [card] name=Autumn Willow abilities=opponentshroud,shroud diff --git a/projects/mtg/bin/Res/sets/primitives/mtg.txt b/projects/mtg/bin/Res/sets/primitives/mtg.txt index fe472d015..e4e187b9c 100644 --- a/projects/mtg/bin/Res/sets/primitives/mtg.txt +++ b/projects/mtg/bin/Res/sets/primitives/mtg.txt @@ -4290,6 +4290,18 @@ power=5 toughness=5 [/card] [card] +name=Archangel of Tithes +abilities=flying +auto=this(untapped) lord(creature|opponentbattlefield) transforms((,newability[attackpwcost:1])) +auto=this(attacking) lord(creature|opponentbattlefield) transforms((,newability[blockcost:1])) +text=Flying -- As long as Archangel of Tithes is untapped, creatures can't attack you or a planeswalker you control unless their controller pays {1} for each of those creatures. -- As long as Archangel of Tithes is attacking, creatures can't block unless their controller pays {1} for each of those creatures. +mana={1}{W}{W}{W} +type=Creature +subtype=Angel +power=3 +toughness=5 +[/card] +[card] name=Archangel of Thune abilities=flying,lifelink auto=@lifeof(player):all(creature|mybattlefield) counter(1/1,1) @@ -18359,6 +18371,17 @@ mana={3}{G}{G}{W} type=Enchantment [/card] [card] +name=Collective Restraint +auto=aslongas(forest|mybattlefield) lord(creature|opponentbattlefield) transforms((,newability[attackcost:1])) +auto=aslongas(island|mybattlefield) lord(creature|opponentbattlefield) transforms((,newability[attackcost:1])) +auto=aslongas(mountain|mybattlefield) lord(creature|opponentbattlefield) transforms((,newability[attackcost:1])) +auto=aslongas(swamp|mybattlefield) lord(creature|opponentbattlefield) transforms((,newability[attackcost:1])) +auto=aslongas(plains|mybattlefield) lord(creature|opponentbattlefield) transforms((,newability[attackcost:1])) +text=Domain — Creatures can't attack you unless their controller pays {X} for each creature he or she controls that's attacking you, where X is the number of basic land types among lands you control. +mana={3}{U} +type=Enchantment +[/card] +[card] name=Collective Unconscious auto=foreach(creature|myBattlefield)draw:1 text=Draw a card for each creature you control. @@ -112257,11 +112280,10 @@ power=3 toughness=6 [/card] [card] -name=War Dance -auto=@each my upkeep:may counter(0/0,1,Verse) -auto={S}:thisforeach(counter{0/0.1.Verse}) 1/1 target(creature) -text=At the beginning of your upkeep, you may put a verse counter on War Dance. -- Sacrifice War Dance: Target creature gets +X/+X until end of turn, where X is the number of verse counters on War Dance. -mana={G} +name=War Cadence +auto={X}{U}:name(Block X Cost) thisforeach(X) all(creature) transforms((,newability[blockcost:1])) ueot +text={X}{R}: This turn, creatures can't block unless their controller pays {X} for each blocking creature he or she controls. +mana={2}{R} type=Enchantment [/card] [card] @@ -112272,6 +112294,14 @@ mana={3} type=Artifact [/card] [card] +name=War Dance +auto=@each my upkeep:may counter(0/0,1,Verse) +auto={S}:thisforeach(counter{0/0.1.Verse}) 1/1 target(creature) +text=At the beginning of your upkeep, you may put a verse counter on War Dance. -- Sacrifice War Dance: Target creature gets +X/+X until end of turn, where X is the number of verse counters on War Dance. +mana={G} +type=Enchantment +[/card] +[card] name=War Elemental auto=this(opponentdamagecount < 1) aslongas(War Elemental|mybattlefield) sacrifice oneshot auto=@damagefoeof(player):may all(trigger[to]) dynamicability @@ -112348,6 +112378,13 @@ mana={3}{W} type=Instant [/card] [card] +name=War Tax +auto={X}{U}:name(Attack X Cost) thisforeach(X) all(creature) transforms((,newability[attackcost:1])) ueot +text={X}{U}: This turn, creatures can't attack unless their controller pays {X} for each attacking creature he or she controls. +mana={2}{U} +type=Enchantment +[/card] +[card] name=War-Name Aspirant auto=if raid then counter(1/1,1) auto=cantbeblockedby(creature[power<=1]) diff --git a/projects/mtg/bin/Res/sets/primitives/unsupported.txt b/projects/mtg/bin/Res/sets/primitives/unsupported.txt index 60c8029f3..6b9e24599 100644 --- a/projects/mtg/bin/Res/sets/primitives/unsupported.txt +++ b/projects/mtg/bin/Res/sets/primitives/unsupported.txt @@ -3770,12 +3770,6 @@ mana={3}{G} type=Instant [/card] [card] -name=Collective Restraint -text=Domain — Creatures can't attack you unless their controller pays {X} for each creature he or she controls that's attacking you, where X is the number of basic land types among lands you control. -mana={3}{U} -type=Enchantment -[/card] -[card] name=Collective Voyage text=Join forces — Starting with you, each player may pay any amount of mana. Each player searches his or her library for up to X basic land cards, where X is the total amount of mana paid this way, puts them onto the battlefield tapped, then shuffles his or her library. mana={G} @@ -25525,12 +25519,6 @@ mana={4} type=Artifact [/card] [card] -name=War Cadence -text={X}{R}: This turn, creatures can't block unless their controller pays {X} for each blocking creature he or she controls. -mana={2}{R} -type=Enchantment -[/card] -[card] name=War Elephant text=Trample; banding (Any creatures with banding, and up to one without, can attack in a band. Bands are blocked as a group. If any creatures with banding you control are blocking or being blocked by a creature, you divide that creature's combat damage, not its controller, among any of the creatures it's being blocked by or is blocking.) mana={3}{W} @@ -25540,12 +25528,6 @@ power=2 toughness=2 [/card] [card] -name=War Tax -text={X}{U}: This turn, creatures can't attack unless their controller pays {X} for each attacking creature he or she controls. -mana={2}{U} -type=Enchantment -[/card] -[card] name=Warbringer text=Dash costs you pay cost {2} less (as long as this creature is on the battlefield). -- Dash {2}{R} (You may cast this spell for its dash cost. If you do, it gains haste, and it's returned from the battlefield to its owner's hand at the beginning of the next end step.) mana={3}{R} diff --git a/projects/mtg/include/AllAbilities.h b/projects/mtg/include/AllAbilities.h index a1d78ee48..b7b4766b6 100644 --- a/projects/mtg/include/AllAbilities.h +++ b/projects/mtg/include/AllAbilities.h @@ -4868,7 +4868,8 @@ class AAttackSetCost: public MTGAbility { public: string number; - AAttackSetCost(GameObserver* observer, int _id, MTGCardInstance * _source, string number); + bool pw; + AAttackSetCost(GameObserver* observer, int _id, MTGCardInstance * _source, string number, bool pw = false); void Update(float dt); int addToGame(); int destroy(); @@ -4876,6 +4877,19 @@ public: AAttackSetCost * clone() const; }; +//ABlockSetCost +class ABlockSetCost: public MTGAbility +{ +public: + string number; + ABlockSetCost(GameObserver* observer, int _id, MTGCardInstance * _source, string number); + void Update(float dt); + int addToGame(); + int destroy(); + const string getMenuText(); + ABlockSetCost * clone() const; +}; + //ABlink class ABlink: public MTGAbility { diff --git a/projects/mtg/include/MTGAbility.h b/projects/mtg/include/MTGAbility.h index 973a9246e..ee2ca98f4 100644 --- a/projects/mtg/include/MTGAbility.h +++ b/projects/mtg/include/MTGAbility.h @@ -217,7 +217,7 @@ public: OVERLOAD_COST = 34, BESTOW_COST = 35, ATTACK_COST = 36, - ATTACKPLANESWALKER_COST = 37, + BLOCK_COST = 37, }; }; diff --git a/projects/mtg/include/MTGCardInstance.h b/projects/mtg/include/MTGCardInstance.h index cb5786293..045044d4b 100644 --- a/projects/mtg/include/MTGCardInstance.h +++ b/projects/mtg/include/MTGCardInstance.h @@ -261,6 +261,9 @@ public: int attackCost; int attackCostBackup; int attackPlaneswalkerCost; + int attackPlaneswalkerCostBackup; + int blockCost; + int blockCostBackup; int imprintG; int imprintU; int imprintR; diff --git a/projects/mtg/include/MTGRules.h b/projects/mtg/include/MTGRules.h index 4a477f169..a4f783111 100644 --- a/projects/mtg/include/MTGRules.h +++ b/projects/mtg/include/MTGRules.h @@ -286,6 +286,18 @@ public: virtual MTGCombatTriggersRule * clone() const; }; +class MTGBlockCostRule: public PermanentAbility +{ +public: + string scost; + int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL); + int reactToClick(MTGCardInstance * card); + virtual ostream& toString(ostream& out) const; + MTGBlockCostRule(GameObserver* observer, int _id); + const string getMenuText(); + virtual MTGBlockCostRule * clone() const; +}; + class MTGBlockRule: public PermanentAbility { public: diff --git a/projects/mtg/src/AllAbilities.cpp b/projects/mtg/src/AllAbilities.cpp index 46ab2ad83..7b4da141e 100644 --- a/projects/mtg/src/AllAbilities.cpp +++ b/projects/mtg/src/AllAbilities.cpp @@ -5372,8 +5372,8 @@ APhaseActionGeneric::~APhaseActionGeneric() } //AAttackSetCost -AAttackSetCost::AAttackSetCost(GameObserver* observer, int _id, MTGCardInstance * _source, string number) : - MTGAbility(observer, _id, _source), number(number) +AAttackSetCost::AAttackSetCost(GameObserver* observer, int _id, MTGCardInstance * _source, string number, bool pw) : + MTGAbility(observer, _id, _source), number(number), pw(pw) { } @@ -5382,6 +5382,8 @@ void AAttackSetCost::Update(float dt) if(game->getCurrentGamePhase() != MTG_PHASE_COMBATATTACKERS) { source->attackCost = source->attackCostBackup; + if(pw) + source->attackPlaneswalkerCost = source->attackPlaneswalkerCostBackup; MTGAbility::Update(dt); } } @@ -5391,6 +5393,11 @@ int AAttackSetCost::addToGame() WParsedInt attackcost(number, NULL, source); source->attackCost += attackcost.getValue(); source->attackCostBackup += attackcost.getValue(); + if(pw) + { + source->attackPlaneswalkerCost += attackcost.getValue(); + source->attackPlaneswalkerCostBackup += attackcost.getValue(); + } return MTGAbility::addToGame(); } @@ -5401,6 +5408,11 @@ int AAttackSetCost::destroy() WParsedInt attackcost(number, NULL, source); source->attackCost -= attackcost.getValue(); source->attackCostBackup -= attackcost.getValue(); + if(pw) + { + source->attackPlaneswalkerCost -= attackcost.getValue(); + source->attackPlaneswalkerCostBackup -= attackcost.getValue(); + } return 1; } @@ -5415,6 +5427,49 @@ AAttackSetCost * AAttackSetCost::clone() const return NEW AAttackSetCost(*this); } +//ABlockSetCost +ABlockSetCost::ABlockSetCost(GameObserver* observer, int _id, MTGCardInstance * _source, string number) : + MTGAbility(observer, _id, _source), number(number) +{ +} + +void ABlockSetCost::Update(float dt) +{ + if(game->getCurrentGamePhase() != MTG_PHASE_COMBATBLOCKERS) + { + source->blockCost = source->blockCostBackup; + MTGAbility::Update(dt); + } +} + +int ABlockSetCost::addToGame() +{ + WParsedInt blockCost(number, NULL, source); + source->blockCost += blockCost.getValue(); + source->blockCostBackup += blockCost.getValue(); + + return MTGAbility::addToGame(); +} + +int ABlockSetCost::destroy() +{ + + WParsedInt blockCost(number, NULL, source); + source->blockCost -= blockCost.getValue(); + source->blockCostBackup -= blockCost.getValue(); + + return 1; +} + +const string ABlockSetCost::getMenuText() +{ + return "Block Cost"; +} + +ABlockSetCost * ABlockSetCost::clone() const +{ + return NEW ABlockSetCost(*this); +} //a blink ABlink::ABlink(GameObserver* observer, int _id, MTGCardInstance * card, MTGCardInstance * _target, bool blinkueot, bool blinkForSource, bool blinkhand, MTGAbility * stored) : diff --git a/projects/mtg/src/MTGAbility.cpp b/projects/mtg/src/MTGAbility.cpp index 808723055..6d57241f6 100644 --- a/projects/mtg/src/MTGAbility.cpp +++ b/projects/mtg/src/MTGAbility.cpp @@ -1193,6 +1193,13 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG observer->addObserver(NEW MTGBlockRule(observer, -1)); return NULL; } + //this rule handles blocking cost ability during blocker phase + found = s.find("blockcostrule"); + if(found != string::npos) + { + observer->addObserver(NEW MTGBlockCostRule(observer, -1)); + return NULL; + } //this rule handles cards that have soulbond found = s.find("soulbondrule"); if(found != string::npos) @@ -2842,6 +2849,18 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG return NEW AAttackSetCost(observer, id, card, s.substr(11)); } + //attack cost + planeswalker + if (s.find("attackpwcost:") != string::npos) + { + return NEW AAttackSetCost(observer, id, card, s.substr(13),true); + } + + //block cost + if (s.find("blockcost:") != string::npos) + { + return NEW ABlockSetCost(observer, id, card, s.substr(10)); + } + //flanking if (s.find("flanker") != string::npos) { diff --git a/projects/mtg/src/MTGCardInstance.cpp b/projects/mtg/src/MTGCardInstance.cpp index 3987c578b..70e8b32cf 100644 --- a/projects/mtg/src/MTGCardInstance.cpp +++ b/projects/mtg/src/MTGCardInstance.cpp @@ -212,6 +212,9 @@ void MTGCardInstance::initMTGCI() attackCost = 0; attackCostBackup = 0; attackPlaneswalkerCost = 0; + attackPlaneswalkerCostBackup = 0; + blockCost = 0; + blockCostBackup = 0; imprintG = 0; imprintU = 0; imprintR = 0; diff --git a/projects/mtg/src/MTGRules.cpp b/projects/mtg/src/MTGRules.cpp index e7d291dee..d2ead3181 100644 --- a/projects/mtg/src/MTGRules.cpp +++ b/projects/mtg/src/MTGRules.cpp @@ -1348,6 +1348,7 @@ MTGOverloadRule * MTGOverloadRule::clone() const /////////////////////////////////////////////////////////////////////////////////////////////////// +//ATTACK COST MTGAttackCostRule::MTGAttackCostRule(GameObserver* observer, int _id) : PermanentAbility(observer, _id) { @@ -1387,9 +1388,17 @@ int MTGAttackCostRule::reactToClick(MTGCardInstance * card) ManaCost * attackcost = NEW ManaCost(ManaCost::parseManaCost("{0}",NULL,NULL)); attackcost->add(0,card->attackCostBackup); ManaCost * playerMana = player->getManaPool(); - playerMana->pay(attackcost); + playerMana->pay(attackcost);//I think you can't pay partial cost to attack cost so you pay full (508.1i) card->attackCost = 0; + card->attackPlaneswalkerCost = 0; return 1; + /* + 508.1g: If any of the chosen creatures require paying costs to attack, the active player determines the total cost to attack. + Costs may include paying mana, tapping permanents, sacrificing permanents, discarding cards, and so on. Once the total cost is determined, it becomes “locked in.” + If effects would change the total cost after this time, ignore this change. + 508.1h: If any of the costs require mana, the active player then has a chance to activate mana abilities (see rule 605, “Mana Abilities”). + 508.1i: Once the player has enough mana in his or her mana pool, he or she pays all costs in any order. Partial payments are not allowed. + */ } ostream& MTGAttackCostRule::toString(ostream& out) const @@ -1409,6 +1418,77 @@ MTGAttackCostRule * MTGAttackCostRule::clone() const return NEW MTGAttackCostRule(*this); } +//BLOCK COST +MTGBlockCostRule::MTGBlockCostRule(GameObserver* observer, int _id) : + PermanentAbility(observer, _id) +{ + aType = MTGAbility::BLOCK_COST; + scost = "Pay to block"; +} + +int MTGBlockCostRule::isReactingToClick(MTGCardInstance * card, ManaCost *) +{ + if (currentPhase == MTG_PHASE_COMBATBLOCKERS && !game->isInterrupting + && card->controller() != game->currentPlayer + ) + { + if(card->isPhased) + return 0; + if(card->blockCost < 1) + return 0; + + ManaCost * playerMana = card->controller()->getManaPool(); + ManaCost * blockcost = NEW ManaCost(ManaCost::parseManaCost("{0}",NULL,NULL)); + blockcost->add(0,card->blockCostBackup); + if(blockcost->extraCosts) + for(unsigned int i = 0; i < blockcost->extraCosts->costs.size();i++) + { + blockcost->extraCosts->costs[i]->setSource(card); + } + scost = blockcost->getConvertedCost(); + if (playerMana->canAfford(blockcost)) + return 1; + } + return 0; +} + +int MTGBlockCostRule::reactToClick(MTGCardInstance * card) +{ + if (!isReactingToClick(card)) + return 0; + Player * player = game->currentlyActing(); + ManaCost * blockcost = NEW ManaCost(ManaCost::parseManaCost("{0}",NULL,NULL)); + blockcost->add(0,card->blockCostBackup); + ManaCost * playerMana = player->getManaPool(); + playerMana->pay(blockcost);//I think you can't pay partial cost to block cost so you pay full (509.1f) + card->blockCost = 0; + return 1; + /* + 509.1d: If any of the chosen creatures require paying costs to block, the defending player determines the total cost to block. + Costs may include paying mana, tapping permanents, sacrificing permanents, discarding cards, and so on. + Once the total cost is determined, it becomes “locked in.” If effects would change the total cost after this time, ignore this change. + 509.1e: If any of the costs require mana, the defending player then has a chance to activate mana abilities (see rule 605, “Mana Abilities”). + 509.1f: Once the player has enough mana in his or her mana pool, he or she pays all costs in any order. Partial payments are not allowed. + */ +} + +ostream& MTGBlockCostRule::toString(ostream& out) const +{ + out << "MTGBlockCostRule ::: ("; + return MTGAbility::toString(out) << ")"; +} + +const string MTGBlockCostRule::getMenuText() +{ + sprintf(menuText, "Pay to block"); + return menuText; +} + +MTGBlockCostRule * MTGBlockCostRule::clone() const +{ + return NEW MTGBlockCostRule(*this); +} + /////////////////////////////////////////////////////////////////////////////////////////////////// bool MTGAttackRule::select(Target* t) { @@ -1780,7 +1860,7 @@ int MTGBlockRule::receiveEvent(WEvent *e) { MTGCardInstance * card = z->cards[i]; if ((card->defenser && !card->defenser->has(Constants::LURE))||!card->defenser) - if(card->canBlock(lurer)) + if(card->canBlock(lurer) && card->blockCost < 1) card->setDefenser(lurer); //force a block on a lurer, the player has a chance to set his own choice on multiple lures //but this action can not be ignored. @@ -1798,7 +1878,7 @@ int MTGBlockRule::isReactingToClick(MTGCardInstance * card, ManaCost *) && card->controller() != game->currentPlayer ) { - if (card->canBlock() && !card->isPhased) + if (card->canBlock() && !card->isPhased && card->blockCost < 1) { if(card->isDefenser()) blockmenu = "Remove Blocker";