Merge pull request #695 from kevlahnota/master

Block Cost Rule
This commit is contained in:
Anthony Calosa
2016-06-15 23:09:56 +08:00
committed by GitHub
14 changed files with 238 additions and 43 deletions
@@ -18,6 +18,7 @@ auto=overloadrule
auto=attackrule auto=attackrule
auto=attackcostrule auto=attackcostrule
auto=blockrule auto=blockrule
auto=blockcostrule
auto=combattriggerrule auto=combattriggerrule
auto=legendrule auto=legendrule
auto=planeswalkerrule auto=planeswalkerrule
+1
View File
@@ -17,6 +17,7 @@ auto=overloadrule
auto=attackrule auto=attackrule
auto=attackcostrule auto=attackcostrule
auto=blockrule auto=blockrule
auto=blockcostrule
auto=combattriggerrule auto=combattriggerrule
auto=legendrule auto=legendrule
auto=planeswalkerrule auto=planeswalkerrule
+1
View File
@@ -21,6 +21,7 @@ auto=overloadrule
auto=attackrule auto=attackrule
auto=attackcostrule auto=attackcostrule
auto=blockrule auto=blockrule
auto=blockcostrule
auto=combattriggerrule auto=combattriggerrule
auto=legendrule auto=legendrule
auto=planeswalkerrule auto=planeswalkerrule
@@ -1,17 +1,4 @@
grade=borderline 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] [card]
name=Autumn Willow name=Autumn Willow
abilities=opponentshroud,shroud abilities=opponentshroud,shroud
+42 -5
View File
@@ -4290,6 +4290,18 @@ power=5
toughness=5 toughness=5
[/card] [/card]
[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 name=Archangel of Thune
abilities=flying,lifelink abilities=flying,lifelink
auto=@lifeof(player):all(creature|mybattlefield) counter(1/1,1) auto=@lifeof(player):all(creature|mybattlefield) counter(1/1,1)
@@ -18359,6 +18371,17 @@ mana={3}{G}{G}{W}
type=Enchantment type=Enchantment
[/card] [/card]
[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 name=Collective Unconscious
auto=foreach(creature|myBattlefield)draw:1 auto=foreach(creature|myBattlefield)draw:1
text=Draw a card for each creature you control. text=Draw a card for each creature you control.
@@ -112257,11 +112280,10 @@ power=3
toughness=6 toughness=6
[/card] [/card]
[card] [card]
name=War Dance name=War Cadence
auto=@each my upkeep:may counter(0/0,1,Verse) auto={X}{U}:name(Block X Cost) thisforeach(X) all(creature) transforms((,newability[blockcost:1])) ueot
auto={S}:thisforeach(counter{0/0.1.Verse}) 1/1 target(creature) text={X}{R}: This turn, creatures can't block unless their controller pays {X} for each blocking creature he or she controls.
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={2}{R}
mana={G}
type=Enchantment type=Enchantment
[/card] [/card]
[card] [card]
@@ -112272,6 +112294,14 @@ mana={3}
type=Artifact type=Artifact
[/card] [/card]
[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 name=War Elemental
auto=this(opponentdamagecount < 1) aslongas(War Elemental|mybattlefield) sacrifice oneshot auto=this(opponentdamagecount < 1) aslongas(War Elemental|mybattlefield) sacrifice oneshot
auto=@damagefoeof(player):may all(trigger[to]) dynamicability<!myfoe thatmuchcountersoneone tosrc!> auto=@damagefoeof(player):may all(trigger[to]) dynamicability<!myfoe thatmuchcountersoneone tosrc!>
@@ -112348,6 +112378,13 @@ mana={3}{W}
type=Instant type=Instant
[/card] [/card]
[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 name=War-Name Aspirant
auto=if raid then counter(1/1,1) auto=if raid then counter(1/1,1)
auto=cantbeblockedby(creature[power<=1]) auto=cantbeblockedby(creature[power<=1])
@@ -3770,12 +3770,6 @@ mana={3}{G}
type=Instant type=Instant
[/card] [/card]
[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 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. 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} mana={G}
@@ -25525,12 +25519,6 @@ mana={4}
type=Artifact type=Artifact
[/card] [/card]
[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 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.) 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} mana={3}{W}
@@ -25540,12 +25528,6 @@ power=2
toughness=2 toughness=2
[/card] [/card]
[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 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.) 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} mana={3}{R}
+15 -1
View File
@@ -4868,7 +4868,8 @@ class AAttackSetCost: public MTGAbility
{ {
public: public:
string number; 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); void Update(float dt);
int addToGame(); int addToGame();
int destroy(); int destroy();
@@ -4876,6 +4877,19 @@ public:
AAttackSetCost * clone() const; 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 //ABlink
class ABlink: public MTGAbility class ABlink: public MTGAbility
{ {
+1 -1
View File
@@ -217,7 +217,7 @@ public:
OVERLOAD_COST = 34, OVERLOAD_COST = 34,
BESTOW_COST = 35, BESTOW_COST = 35,
ATTACK_COST = 36, ATTACK_COST = 36,
ATTACKPLANESWALKER_COST = 37, BLOCK_COST = 37,
}; };
}; };
+3
View File
@@ -261,6 +261,9 @@ public:
int attackCost; int attackCost;
int attackCostBackup; int attackCostBackup;
int attackPlaneswalkerCost; int attackPlaneswalkerCost;
int attackPlaneswalkerCostBackup;
int blockCost;
int blockCostBackup;
int imprintG; int imprintG;
int imprintU; int imprintU;
int imprintR; int imprintR;
+12
View File
@@ -286,6 +286,18 @@ public:
virtual MTGCombatTriggersRule * clone() const; 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 class MTGBlockRule: public PermanentAbility
{ {
public: public:
+57 -2
View File
@@ -5372,8 +5372,8 @@ APhaseActionGeneric::~APhaseActionGeneric()
} }
//AAttackSetCost //AAttackSetCost
AAttackSetCost::AAttackSetCost(GameObserver* observer, int _id, MTGCardInstance * _source, string number) : AAttackSetCost::AAttackSetCost(GameObserver* observer, int _id, MTGCardInstance * _source, string number, bool pw) :
MTGAbility(observer, _id, _source), number(number) MTGAbility(observer, _id, _source), number(number), pw(pw)
{ {
} }
@@ -5382,6 +5382,8 @@ void AAttackSetCost::Update(float dt)
if(game->getCurrentGamePhase() != MTG_PHASE_COMBATATTACKERS) if(game->getCurrentGamePhase() != MTG_PHASE_COMBATATTACKERS)
{ {
source->attackCost = source->attackCostBackup; source->attackCost = source->attackCostBackup;
if(pw)
source->attackPlaneswalkerCost = source->attackPlaneswalkerCostBackup;
MTGAbility::Update(dt); MTGAbility::Update(dt);
} }
} }
@@ -5391,6 +5393,11 @@ int AAttackSetCost::addToGame()
WParsedInt attackcost(number, NULL, source); WParsedInt attackcost(number, NULL, source);
source->attackCost += attackcost.getValue(); source->attackCost += attackcost.getValue();
source->attackCostBackup += attackcost.getValue(); source->attackCostBackup += attackcost.getValue();
if(pw)
{
source->attackPlaneswalkerCost += attackcost.getValue();
source->attackPlaneswalkerCostBackup += attackcost.getValue();
}
return MTGAbility::addToGame(); return MTGAbility::addToGame();
} }
@@ -5401,6 +5408,11 @@ int AAttackSetCost::destroy()
WParsedInt attackcost(number, NULL, source); WParsedInt attackcost(number, NULL, source);
source->attackCost -= attackcost.getValue(); source->attackCost -= attackcost.getValue();
source->attackCostBackup -= attackcost.getValue(); source->attackCostBackup -= attackcost.getValue();
if(pw)
{
source->attackPlaneswalkerCost -= attackcost.getValue();
source->attackPlaneswalkerCostBackup -= attackcost.getValue();
}
return 1; return 1;
} }
@@ -5415,6 +5427,49 @@ AAttackSetCost * AAttackSetCost::clone() const
return NEW AAttackSetCost(*this); 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 //a blink
ABlink::ABlink(GameObserver* observer, int _id, MTGCardInstance * card, MTGCardInstance * _target, bool blinkueot, bool blinkForSource, bool blinkhand, MTGAbility * stored) : ABlink::ABlink(GameObserver* observer, int _id, MTGCardInstance * card, MTGCardInstance * _target, bool blinkueot, bool blinkForSource, bool blinkhand, MTGAbility * stored) :
+19
View File
@@ -1193,6 +1193,13 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
observer->addObserver(NEW MTGBlockRule(observer, -1)); observer->addObserver(NEW MTGBlockRule(observer, -1));
return NULL; 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 //this rule handles cards that have soulbond
found = s.find("soulbondrule"); found = s.find("soulbondrule");
if(found != string::npos) 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)); 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 //flanking
if (s.find("flanker") != string::npos) if (s.find("flanker") != string::npos)
{ {
+3
View File
@@ -212,6 +212,9 @@ void MTGCardInstance::initMTGCI()
attackCost = 0; attackCost = 0;
attackCostBackup = 0; attackCostBackup = 0;
attackPlaneswalkerCost = 0; attackPlaneswalkerCost = 0;
attackPlaneswalkerCostBackup = 0;
blockCost = 0;
blockCostBackup = 0;
imprintG = 0; imprintG = 0;
imprintU = 0; imprintU = 0;
imprintR = 0; imprintR = 0;
+83 -3
View File
@@ -1348,6 +1348,7 @@ MTGOverloadRule * MTGOverloadRule::clone() const
/////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////
//ATTACK COST
MTGAttackCostRule::MTGAttackCostRule(GameObserver* observer, int _id) : MTGAttackCostRule::MTGAttackCostRule(GameObserver* observer, int _id) :
PermanentAbility(observer, _id) PermanentAbility(observer, _id)
{ {
@@ -1387,9 +1388,17 @@ int MTGAttackCostRule::reactToClick(MTGCardInstance * card)
ManaCost * attackcost = NEW ManaCost(ManaCost::parseManaCost("{0}",NULL,NULL)); ManaCost * attackcost = NEW ManaCost(ManaCost::parseManaCost("{0}",NULL,NULL));
attackcost->add(0,card->attackCostBackup); attackcost->add(0,card->attackCostBackup);
ManaCost * playerMana = player->getManaPool(); 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->attackCost = 0;
card->attackPlaneswalkerCost = 0;
return 1; 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 ostream& MTGAttackCostRule::toString(ostream& out) const
@@ -1409,6 +1418,77 @@ MTGAttackCostRule * MTGAttackCostRule::clone() const
return NEW MTGAttackCostRule(*this); 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) bool MTGAttackRule::select(Target* t)
{ {
@@ -1780,7 +1860,7 @@ int MTGBlockRule::receiveEvent(WEvent *e)
{ {
MTGCardInstance * card = z->cards[i]; MTGCardInstance * card = z->cards[i];
if ((card->defenser && !card->defenser->has(Constants::LURE))||!card->defenser) if ((card->defenser && !card->defenser->has(Constants::LURE))||!card->defenser)
if(card->canBlock(lurer)) if(card->canBlock(lurer) && card->blockCost < 1)
card->setDefenser(lurer); card->setDefenser(lurer);
//force a block on a lurer, the player has a chance to set his own choice on multiple lures //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. //but this action can not be ignored.
@@ -1798,7 +1878,7 @@ int MTGBlockRule::isReactingToClick(MTGCardInstance * card, ManaCost *)
&& card->controller() != game->currentPlayer && card->controller() != game->currentPlayer
) )
{ {
if (card->canBlock() && !card->isPhased) if (card->canBlock() && !card->isPhased && card->blockCost < 1)
{ {
if(card->isDefenser()) if(card->isDefenser())
blockmenu = "Remove Blocker"; blockmenu = "Remove Blocker";