1928 lines
68 KiB
C++
1928 lines
68 KiB
C++
#include "../include/config.h"
|
|
#include "../include/MTGRules.h"
|
|
#include "../include/Translate.h"
|
|
#include "../include/Subtypes.h"
|
|
#include "../include/GameOptions.h"
|
|
|
|
|
|
|
|
MTGPutInPlayRule::MTGPutInPlayRule(int _id):MTGAbility(_id, NULL){
|
|
aType=MTGAbility::PUT_INTO_PLAY;
|
|
}
|
|
|
|
int MTGPutInPlayRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana){
|
|
int cardsinhand = game->players[0]->game->hand->nb_cards;
|
|
Player * player = game->currentlyActing();
|
|
Player * currentPlayer = game->currentPlayer;
|
|
if (!player->game->hand->hasCard(card)) return 0;
|
|
if ((game->turn < 1) && (cardsinhand != 0) && (card->hasType("leyline"))
|
|
&& game->currentGamePhase == Constants::MTG_PHASE_FIRSTMAIN
|
|
&& game->players[0]->game->graveyard->nb_cards == 0
|
|
&& game->players[0]->game->exile->nb_cards == 0){
|
|
Player * p = game->currentPlayer;
|
|
if (card->hasType("leyline")){
|
|
MTGCardInstance * copy = player->game->putInZone(card, player->game->hand, player->game->temp);
|
|
Spell * spell = NEW Spell(copy);
|
|
spell->resolve();
|
|
delete spell;}
|
|
return 1;}
|
|
if (card->hasType("land")){
|
|
if (player == currentPlayer && currentPlayer->canPutLandsIntoPlay && (game->currentGamePhase == Constants::MTG_PHASE_FIRSTMAIN || game->currentGamePhase == Constants::MTG_PHASE_SECONDMAIN)){
|
|
return 1;
|
|
}
|
|
}else if ((card->hasType("instant")) || card->has(Constants::FLASH) || (player == currentPlayer && !game->isInterrupting && (game->currentGamePhase == Constants::MTG_PHASE_FIRSTMAIN || game->currentGamePhase == Constants::MTG_PHASE_SECONDMAIN))){
|
|
ManaCost * playerMana = player->getManaPool();
|
|
ManaCost * cost = card->getManaCost();
|
|
ManaCost * alternative = card->getManaCost()->alternative;
|
|
ManaCost * BuyBack = card->getManaCost()->BuyBack;
|
|
|
|
#ifdef WIN32
|
|
cost->Dump();
|
|
#endif
|
|
if(player->castrestrictedspell > 0 && !card->hasType("land")){ return 0;}
|
|
if(player->onlyonecast > 0 && player->castcount >= 1){return 0;}
|
|
if(player->nospellinstant > 0){return 0;}
|
|
if(player->onlyoneinstant > 0){ if(player->castcount >= 1){return 0;}}
|
|
if(player->nocreatureinstant > 0 && card->hasType("creature")){return 0;}
|
|
if(player->castrestrictedcreature > 0 && card->hasType("creature")){return 0;}
|
|
|
|
//cost of card.
|
|
if (playerMana->canAfford(cost)){
|
|
return 1;//play if you can afford too.
|
|
}
|
|
}
|
|
return 0;//dont play if you cant afford it.
|
|
}
|
|
int MTGPutInPlayRule::reactToClick(MTGCardInstance * card){
|
|
if (!isReactingToClick(card)) return 0;
|
|
Player * player = game->currentlyActing();
|
|
ManaCost * cost = card->getManaCost();
|
|
ManaCost * playerMana = player->getManaPool();
|
|
//this handles extra cost payments at the moment a card is played.
|
|
|
|
if (cost->isExtraPaymentSet()){
|
|
if (!game->targetListIsSet(card)){
|
|
return 0;
|
|
}
|
|
}else{
|
|
cost->setExtraCostsAction(this, card);
|
|
game->waitForExtraPayment = cost->extraCosts;
|
|
return 0;
|
|
}
|
|
|
|
ManaCost * previousManaPool = NEW ManaCost(player->getManaPool());
|
|
int payResult = player->getManaPool()->pay(card->getManaCost());
|
|
card->getManaCost()->doPayExtra();
|
|
|
|
ManaCost * spellCost = previousManaPool->Diff(player->getManaPool());
|
|
|
|
delete previousManaPool;
|
|
if (card->hasType("land")){
|
|
MTGCardInstance * copy = player->game->putInZone(card, player->game->hand, player->game->temp);
|
|
Spell * spell = NEW Spell(copy);
|
|
spell->resolve();
|
|
delete spellCost;
|
|
delete spell;
|
|
player->canPutLandsIntoPlay--;
|
|
}else{
|
|
Spell * spell = NULL;
|
|
MTGCardInstance * copy = player->game->putInZone(card, player->game->hand, player->game->stack);
|
|
if (game->targetChooser){
|
|
spell = game->mLayers->stackLayer()->addSpell(copy,game->targetChooser, spellCost,payResult,0);
|
|
game->targetChooser = NULL;
|
|
player->castedspellsthisturn += 1;
|
|
if(player->onlyonecast > 0 || player->onlyoneinstant > 0){player->castcount += 1;}
|
|
}else{
|
|
spell = game->mLayers->stackLayer()->addSpell(copy,NULL, spellCost, payResult,0);
|
|
player->castedspellsthisturn += 1;
|
|
if(player->onlyonecast > 0 || player->onlyoneinstant > 0){player->castcount += 1;}
|
|
}
|
|
|
|
if(card->has(Constants::STORM)){
|
|
int storm = player->castedspellsthisturn;
|
|
ManaCost * spellCost = player->getManaPool();
|
|
for(int i = storm; i > 1; i--){
|
|
spell = game->mLayers->stackLayer()->addSpell(copy,NULL, spellCost, payResult,1);
|
|
|
|
}
|
|
}//end of storm
|
|
if(!card->has(Constants::STORM)){
|
|
copy->X = spell->computeX(copy);
|
|
copy->XX = spell->computeXX(copy);
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
//The Put into play rule is never destroyed
|
|
int MTGPutInPlayRule::testDestroy(){
|
|
return 0;
|
|
}
|
|
|
|
ostream& MTGPutInPlayRule::toString(ostream& out) const
|
|
{
|
|
out << "MTGPutInPlayRule ::: (";
|
|
return MTGAbility::toString(out) << ")";
|
|
}
|
|
|
|
MTGPutInPlayRule * MTGPutInPlayRule::clone() const{
|
|
MTGPutInPlayRule * a = NEW MTGPutInPlayRule(*this);
|
|
a->isClone = 1;
|
|
return a;
|
|
}
|
|
//cast from anywhere possible with this??
|
|
|
|
//Alternative cost rules
|
|
//-------------------------------------------------------------------------
|
|
//-------------------------------------------------------------------------
|
|
//-------------------------------------------------------------------------
|
|
//-------------------------------------------------------------------------
|
|
//-------------------------------------------------------------------------
|
|
|
|
MTGAlternativeCostRule::MTGAlternativeCostRule(int _id):MTGAbility(_id, NULL){
|
|
aType=MTGAbility::ALTERNATIVE_COST;
|
|
}
|
|
int MTGAlternativeCostRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana){
|
|
int cardsinhand = game->players[0]->game->hand->nb_cards;
|
|
Player * player = game->currentlyActing();
|
|
Player * currentPlayer = game->currentPlayer;
|
|
if (!player->game->hand->hasCard(card)) return 0;
|
|
if (!card->getManaCost()->alternative) return 0;
|
|
if (card->hasType("land")){
|
|
if (player == currentPlayer && currentPlayer->canPutLandsIntoPlay && (game->currentGamePhase == Constants::MTG_PHASE_FIRSTMAIN || game->currentGamePhase == Constants::MTG_PHASE_SECONDMAIN)){
|
|
return 1;
|
|
}
|
|
}else if ((card->hasType("instant")) || card->has(Constants::FLASH) || (player == currentPlayer && !game->isInterrupting && (game->currentGamePhase == Constants::MTG_PHASE_FIRSTMAIN || game->currentGamePhase == Constants::MTG_PHASE_SECONDMAIN))){
|
|
ManaCost * playerMana = player->getManaPool();
|
|
ManaCost * cost = card->getManaCost();
|
|
ManaCost * alternative = card->getManaCost()->alternative;
|
|
|
|
#ifdef WIN32
|
|
cost->Dump();
|
|
#endif
|
|
if(player->castrestrictedspell > 0 && !card->hasType("land")){ return 0;}
|
|
if(player->onlyonecast > 0 && player->castcount >= 1){return 0;}
|
|
if(player->nospellinstant > 0){return 0;}
|
|
if(player->onlyoneinstant > 0){ if(player->castcount >= 1){return 0;}}
|
|
if(player->nocreatureinstant > 0 && card->hasType("creature")){return 0;}
|
|
if(player->castrestrictedcreature > 0 && card->hasType("creature")){return 0;}
|
|
//cost of card.
|
|
if(alternative && playerMana->canAfford(alternative)){
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;//dont play if you cant afford it.
|
|
}
|
|
int MTGAlternativeCostRule::reactToClick(MTGCardInstance * card){
|
|
if (!isReactingToClick(card)) return 0;
|
|
Player * player = game->currentlyActing();
|
|
ManaCost * cost = card->getManaCost();
|
|
ManaCost * alternative = card->getManaCost()->alternative;
|
|
ManaCost * playerMana = player->getManaPool();
|
|
//this handles extra cost payments at the moment a card is played.
|
|
if(playerMana->canAfford(alternative)){
|
|
if (cost->alternative->isExtraPaymentSet()){
|
|
card->paymenttype = 1;
|
|
if (!game->targetListIsSet(card)){
|
|
return 0;
|
|
}
|
|
}else{
|
|
cost->alternative->setExtraCostsAction(this, card);
|
|
game->waitForExtraPayment = cost->alternative->extraCosts;
|
|
card->paymenttype = 1;
|
|
return 0;
|
|
}
|
|
}
|
|
//------------------------------------------------------------------------
|
|
ManaCost * previousManaPool = NEW ManaCost(player->getManaPool());
|
|
int payResult = player->getManaPool()->pay(card->getManaCost()->alternative);
|
|
card->getManaCost()->alternative->doPayExtra();
|
|
payResult = ManaCost::MANA_PAID_WITH_ALTERNATIVE;
|
|
//if alternative has a extra payment thats set, this code pays it.the if statement is 100% needed as it would cause a crash on cards that dont have the alternative cost.
|
|
if(alternative){
|
|
card->getManaCost()->alternative->doPayExtra();
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
ManaCost * spellCost = previousManaPool->Diff(player->getManaPool());
|
|
delete previousManaPool;
|
|
if (card->hasType("land")){
|
|
MTGCardInstance * copy = player->game->putInZone(card, player->game->hand, player->game->temp);
|
|
Spell * spell = NEW Spell(copy);
|
|
spell->resolve();
|
|
delete spellCost;
|
|
delete spell;
|
|
player->canPutLandsIntoPlay--;
|
|
payResult = ManaCost::MANA_PAID_WITH_ALTERNATIVE;
|
|
spell = game->mLayers->stackLayer()->addSpell(copy,NULL, spellCost, payResult,1);
|
|
}else{
|
|
Spell * spell = NULL;
|
|
MTGCardInstance * copy = player->game->putInZone(card, player->game->hand, player->game->stack);
|
|
if (game->targetChooser){
|
|
spell = game->mLayers->stackLayer()->addSpell(copy,game->targetChooser, spellCost,payResult,0);
|
|
game->targetChooser = NULL;
|
|
player->castedspellsthisturn += 1;
|
|
if(player->onlyonecast > 0 || player->onlyoneinstant > 0){player->castcount += 1;}
|
|
}else{
|
|
spell = game->mLayers->stackLayer()->addSpell(copy,NULL, spellCost, payResult,0);
|
|
player->castedspellsthisturn += 1;
|
|
if(player->onlyonecast > 0 || player->onlyoneinstant > 0){player->castcount += 1;
|
|
}
|
|
}
|
|
if(card->has(Constants::STORM)){
|
|
int storm = player->castedspellsthisturn;
|
|
ManaCost * spellCost = player->getManaPool();
|
|
for(int i = storm; i > 1; i--){
|
|
spell = game->mLayers->stackLayer()->addSpell(copy,NULL, spellCost, payResult,1);
|
|
}
|
|
}//end of storm
|
|
if(!card->has(Constants::STORM)){
|
|
copy->X = spell->computeX(copy);
|
|
copy->XX = spell->computeXX(copy);
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
//The Put into play rule is never destroyed
|
|
int MTGAlternativeCostRule::testDestroy(){
|
|
return 0;
|
|
}
|
|
|
|
ostream& MTGAlternativeCostRule::toString(ostream& out) const
|
|
{
|
|
out << "MTGAlternativeCostRule ::: (";
|
|
return MTGAbility::toString(out) << ")";
|
|
}
|
|
MTGAlternativeCostRule * MTGAlternativeCostRule::clone() const{
|
|
MTGAlternativeCostRule * a = NEW MTGAlternativeCostRule(*this);
|
|
a->isClone = 1;
|
|
return a;
|
|
}
|
|
|
|
//-------------------------------------------------------------------------
|
|
//-------------------------------------------------------------------------
|
|
//-------------------------------------------------------------------------
|
|
//-------------------------------------------------------------------------
|
|
|
|
//buyback follows its own resolving rules
|
|
MTGBuyBackRule::MTGBuyBackRule(int _id):MTGAbility(_id, NULL){
|
|
aType=MTGAbility::BUYBACK_COST;
|
|
}
|
|
int MTGBuyBackRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana){
|
|
int cardsinhand = game->players[0]->game->hand->nb_cards;
|
|
Player * player = game->currentlyActing();
|
|
Player * currentPlayer = game->currentPlayer;
|
|
if (!player->game->hand->hasCard(card)) return 0;
|
|
if (!card->getManaCost()->BuyBack) return 0;
|
|
if (card->hasType("land")){
|
|
if (player == currentPlayer && currentPlayer->canPutLandsIntoPlay && (game->currentGamePhase == Constants::MTG_PHASE_FIRSTMAIN || game->currentGamePhase == Constants::MTG_PHASE_SECONDMAIN)){
|
|
return 1;
|
|
}
|
|
}else if ((card->hasType("instant")) || card->has(Constants::FLASH) || (player == currentPlayer && !game->isInterrupting && (game->currentGamePhase == Constants::MTG_PHASE_FIRSTMAIN || game->currentGamePhase == Constants::MTG_PHASE_SECONDMAIN))){
|
|
ManaCost * playerMana = player->getManaPool();
|
|
ManaCost * cost = card->getManaCost();
|
|
ManaCost * BuyBack = card->getManaCost()->BuyBack;
|
|
|
|
#ifdef WIN32
|
|
cost->Dump();
|
|
#endif
|
|
if(player->castrestrictedspell > 0 && !card->hasType("land")){ return 0;}
|
|
if(player->onlyonecast > 0 && player->castcount >= 1){return 0;}
|
|
if(player->nospellinstant > 0){return 0;}
|
|
if(player->onlyoneinstant > 0){ if(player->castcount >= 1){return 0;}}
|
|
if(player->nocreatureinstant > 0 && card->hasType("creature")){return 0;}
|
|
if(player->castrestrictedcreature > 0 && card->hasType("creature")){return 0;}
|
|
//cost of card.
|
|
if(BuyBack && playerMana->canAfford(BuyBack)){
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;//dont play if you cant afford it.
|
|
}
|
|
int MTGBuyBackRule::reactToClick(MTGCardInstance * card){
|
|
if (!isReactingToClick(card)) return 0;
|
|
Player * player = game->currentlyActing();
|
|
ManaCost * cost = card->getManaCost();
|
|
ManaCost * BuyBack = card->getManaCost()->BuyBack;
|
|
ManaCost * playerMana = player->getManaPool();
|
|
//this handles extra cost payments at the moment a card is played.
|
|
if(playerMana->canAfford(BuyBack)){
|
|
if (cost->BuyBack->isExtraPaymentSet()){
|
|
card->paymenttype = 2;
|
|
if (!game->targetListIsSet(card)){
|
|
return 0;
|
|
}
|
|
}else{
|
|
cost->BuyBack->setExtraCostsAction(this, card);
|
|
game->waitForExtraPayment = cost->BuyBack->extraCosts;
|
|
card->paymenttype = 2;
|
|
return 0;
|
|
}
|
|
}
|
|
//------------------------------------------------------------------------
|
|
ManaCost * previousManaPool = NEW ManaCost(player->getManaPool());
|
|
int payResult = player->getManaPool()->pay(card->getManaCost()->BuyBack);
|
|
card->getManaCost()->doPayExtra();
|
|
payResult = ManaCost::MANA_PAID_WITH_BUYBACK;
|
|
//if BuyBack has a extra payment thats set, this code pays it.the if statement is 100% needed as it would cause a crash on cards that dont have the BuyBack cost.
|
|
if(BuyBack){
|
|
card->getManaCost()->BuyBack->doPayExtra();
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
ManaCost * spellCost = previousManaPool->Diff(player->getManaPool());
|
|
card->boughtback = 1;
|
|
delete previousManaPool;
|
|
if (card->hasType("land")){
|
|
MTGCardInstance * copy = player->game->putInZone(card, player->game->hand, player->game->temp);
|
|
Spell * spell = NEW Spell(copy);
|
|
copy->boughtback = 1;
|
|
spell->resolve();
|
|
delete spellCost;
|
|
delete spell;
|
|
player->canPutLandsIntoPlay--;
|
|
payResult = ManaCost::MANA_PAID_WITH_BUYBACK;
|
|
spell = game->mLayers->stackLayer()->addSpell(copy,NULL, spellCost, payResult,1);
|
|
}else{
|
|
Spell * spell = NULL;
|
|
card->boughtback = 1;
|
|
MTGCardInstance * copy = player->game->putInZone(card, player->game->hand, player->game->stack);
|
|
copy->boughtback = 1;
|
|
if (game->targetChooser){
|
|
spell = game->mLayers->stackLayer()->addSpell(copy,game->targetChooser, spellCost,payResult,0);
|
|
game->targetChooser = NULL;
|
|
player->castedspellsthisturn += 1;
|
|
if(player->onlyonecast > 0 || player->onlyoneinstant > 0){player->castcount += 1;}
|
|
}else{
|
|
spell = game->mLayers->stackLayer()->addSpell(copy,NULL, spellCost, payResult,0);
|
|
player->castedspellsthisturn += 1;
|
|
if(player->onlyonecast > 0 || player->onlyoneinstant > 0){player->castcount += 1;
|
|
|
|
}
|
|
}
|
|
if(card->has(Constants::STORM)){
|
|
int storm = player->castedspellsthisturn;
|
|
ManaCost * spellCost = player->getManaPool();
|
|
for(int i = storm; i > 1; i--){
|
|
spell = game->mLayers->stackLayer()->addSpell(copy,NULL, spellCost, payResult,1);
|
|
}
|
|
}//end of storm
|
|
if(!card->has(Constants::STORM)){
|
|
copy->X = spell->computeX(copy);
|
|
copy->XX = spell->computeXX(copy);
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
//The Put into play rule is never destroyed
|
|
int MTGBuyBackRule::testDestroy(){
|
|
return 0;
|
|
}
|
|
|
|
ostream& MTGBuyBackRule::toString(ostream& out) const
|
|
{
|
|
out << "MTGBuyBackRule ::: (";
|
|
return MTGAbility::toString(out) << ")";
|
|
}
|
|
MTGBuyBackRule * MTGBuyBackRule::clone() const{
|
|
MTGBuyBackRule * a = NEW MTGBuyBackRule(*this);
|
|
a->isClone = 1;
|
|
return a;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------
|
|
//-------------------------------------------------------------------------
|
|
//-------------------------------------------------------------------------
|
|
//-------------------------------------------------------------------------
|
|
//flashback follows its own resolving rules
|
|
MTGFlashBackRule::MTGFlashBackRule(int _id):MTGAbility(_id, NULL){
|
|
aType=MTGAbility::FLASHBACK_COST;
|
|
}
|
|
int MTGFlashBackRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana){
|
|
int cardsingraveyard = game->players[0]->game->graveyard->nb_cards;
|
|
Player * player = game->currentlyActing();
|
|
Player * currentPlayer = game->currentPlayer;
|
|
if (!player->game->graveyard->hasCard(card)) return 0;
|
|
if (!card->getManaCost()->FlashBack) return 0;
|
|
if ((card->hasType("instant")) || card->has(Constants::FLASH) || (player == currentPlayer && !game->isInterrupting && (game->currentGamePhase == Constants::MTG_PHASE_FIRSTMAIN || game->currentGamePhase == Constants::MTG_PHASE_SECONDMAIN))){
|
|
ManaCost * playerMana = player->getManaPool();
|
|
ManaCost * cost = card->getManaCost();
|
|
ManaCost * FlashBack = card->getManaCost()->FlashBack;
|
|
|
|
#ifdef WIN32
|
|
cost->Dump();
|
|
#endif
|
|
if(player->castrestrictedspell > 0 && !card->hasType("land")){ return 0;}
|
|
if(player->onlyonecast > 0 && player->castcount >= 1){return 0;}
|
|
if(player->nospellinstant > 0){return 0;}
|
|
if(player->onlyoneinstant > 0){ if(player->castcount >= 1){return 0;}}
|
|
if(player->nocreatureinstant > 0 && card->hasType("creature")){return 0;}
|
|
if(player->castrestrictedcreature > 0 && card->hasType("creature")){return 0;}
|
|
//cost of card.
|
|
if(FlashBack && playerMana->canAfford(FlashBack)){
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;//dont play if you cant afford it.
|
|
}
|
|
int MTGFlashBackRule::reactToClick(MTGCardInstance * card){
|
|
if (!isReactingToClick(card)) return 0;
|
|
Player * player = game->currentlyActing();
|
|
ManaCost * cost = card->getManaCost();
|
|
ManaCost * FlashBack = card->getManaCost()->FlashBack;
|
|
ManaCost * playerMana = player->getManaPool();
|
|
//this handles extra cost payments at the moment a card is played.
|
|
if(playerMana->canAfford(FlashBack)){
|
|
if (cost->FlashBack->isExtraPaymentSet()){
|
|
card->paymenttype = 3;
|
|
if (!game->targetListIsSet(card)){
|
|
return 0;
|
|
}
|
|
}else{
|
|
cost->FlashBack->setExtraCostsAction(this, card);
|
|
game->waitForExtraPayment = cost->FlashBack->extraCosts;
|
|
card->paymenttype = 3;
|
|
return 0;
|
|
}
|
|
}
|
|
//------------------------------------------------------------------------
|
|
ManaCost * previousManaPool = NEW ManaCost(player->getManaPool());
|
|
int payResult = player->getManaPool()->pay(card->getManaCost()->FlashBack);
|
|
card->getManaCost()->doPayExtra();
|
|
payResult = ManaCost::MANA_PAID_WITH_FLASHBACK;
|
|
//if flashBack has a extra payment thats set, this code pays it.the if statement is 100% needed as it would cause a crash on cards that dont have the flashBack cost.
|
|
if(FlashBack){
|
|
card->getManaCost()->FlashBack->doPayExtra();
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
ManaCost * spellCost = previousManaPool->Diff(player->getManaPool());
|
|
card->flashedback = 1;
|
|
delete previousManaPool;
|
|
if (card->hasType("land")){
|
|
MTGCardInstance * copy = player->game->putInZone(card, player->game->graveyard, player->game->temp);
|
|
Spell * spell = NEW Spell(copy);
|
|
copy->flashedback = 1;
|
|
spell->resolve();
|
|
delete spellCost;
|
|
delete spell;
|
|
player->canPutLandsIntoPlay--;
|
|
payResult = ManaCost::MANA_PAID_WITH_FLASHBACK;
|
|
spell = game->mLayers->stackLayer()->addSpell(copy,NULL, spellCost, payResult,1);
|
|
}else{
|
|
Spell * spell = NULL;
|
|
card->flashedback = 1;
|
|
MTGCardInstance * copy = player->game->putInZone(card, player->game->graveyard, player->game->stack);
|
|
copy->flashedback = 1;
|
|
if (game->targetChooser){
|
|
spell = game->mLayers->stackLayer()->addSpell(copy,game->targetChooser, spellCost,payResult,0);
|
|
game->targetChooser = NULL;
|
|
player->castedspellsthisturn += 1;
|
|
if(player->onlyonecast > 0 || player->onlyoneinstant > 0){player->castcount += 1;}
|
|
}else{
|
|
spell = game->mLayers->stackLayer()->addSpell(copy,NULL, spellCost, payResult,0);
|
|
player->castedspellsthisturn += 1;
|
|
if(player->onlyonecast > 0 || player->onlyoneinstant > 0){player->castcount += 1;
|
|
|
|
}
|
|
}
|
|
if(card->has(Constants::STORM)){
|
|
int storm = player->castedspellsthisturn;
|
|
ManaCost * spellCost = player->getManaPool();
|
|
for(int i = storm; i > 1; i--){
|
|
spell = game->mLayers->stackLayer()->addSpell(copy,NULL, spellCost, payResult,1);
|
|
}
|
|
}//end of storm
|
|
if(!card->has(Constants::STORM)){
|
|
copy->X = spell->computeX(copy);
|
|
copy->XX = spell->computeXX(copy);
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
//The Put into play rule is never destroyed
|
|
int MTGFlashBackRule::testDestroy(){
|
|
return 0;
|
|
}
|
|
|
|
ostream& MTGFlashBackRule::toString(ostream& out) const
|
|
{
|
|
out << "MTGFlashBackRule ::: (";
|
|
return MTGAbility::toString(out) << ")";
|
|
}
|
|
MTGFlashBackRule * MTGFlashBackRule::clone() const{
|
|
MTGFlashBackRule * a = NEW MTGFlashBackRule(*this);
|
|
a->isClone = 1;
|
|
return a;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------
|
|
//-------------------------------------------------------------------------
|
|
//-------------------------------------------------------------------------
|
|
//-------------------------------------------------------------------------
|
|
|
|
|
|
bool MTGAttackRule::select(Target* t)
|
|
{
|
|
if (CardView* c = dynamic_cast<CardView*>(t)) {
|
|
MTGCardInstance * card = c->getCard();
|
|
if (card->canAttack()) return true;
|
|
}
|
|
return false;
|
|
}
|
|
bool MTGAttackRule::greyout(Target* t)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
MTGAttackRule::MTGAttackRule(int _id):MTGAbility(_id,NULL){
|
|
aType=MTGAbility::MTG_ATTACK_RULE;
|
|
}
|
|
|
|
int MTGAttackRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana){
|
|
if (currentPhase == Constants::MTG_PHASE_COMBATATTACKERS && card->controller() == game->currentPlayer){
|
|
if (card->isAttacker()) return 1;
|
|
if (card->canAttack()) return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int MTGAttackRule::receiveEvent(WEvent *e){
|
|
if (WEventPhaseChange* event = dynamic_cast<WEventPhaseChange*>(e)) {
|
|
if (Constants::MTG_PHASE_COMBATATTACKERS == event->from->id) {
|
|
Player * p = game->currentPlayer;
|
|
MTGGameZone * z = p->game->inPlay;
|
|
for (int i= 0; i < z->nb_cards; i++){
|
|
MTGCardInstance * card = z->cards[i];
|
|
if (!card->isAttacker() && card->has(Constants::MUSTATTACK)) reactToClick(card);
|
|
}
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int MTGAttackRule::reactToClick(MTGCardInstance * card){
|
|
if (!isReactingToClick(card)) return 0;
|
|
|
|
//Graphically select the next card that can attack
|
|
if(!card->isAttacker()){
|
|
CardSelector * cs = game->mLayers->cs;
|
|
cs->PushLimitor();
|
|
cs->Limit(this,CardSelector::playZone);
|
|
cs->CheckUserInput(JGE_BTN_RIGHT);
|
|
cs->Limit(NULL,CardSelector::playZone);
|
|
cs->PopLimitor();
|
|
}
|
|
card->toggleAttacker();
|
|
return 1;
|
|
}
|
|
|
|
//The Attack rule is never destroyed
|
|
int MTGAttackRule::testDestroy(){
|
|
return 0;
|
|
}
|
|
|
|
ostream& MTGAttackRule::toString(ostream& out) const
|
|
{
|
|
out << "MTGAttackRule ::: (";
|
|
return MTGAbility::toString(out) << ")";
|
|
}
|
|
|
|
MTGAttackRule * MTGAttackRule::clone() const{
|
|
MTGAttackRule * a = NEW MTGAttackRule(*this);
|
|
a->isClone = 1;
|
|
return a;
|
|
}
|
|
|
|
|
|
OtherAbilitiesEventReceiver::OtherAbilitiesEventReceiver(int _id):MTGAbility(_id,NULL){
|
|
}
|
|
|
|
|
|
int OtherAbilitiesEventReceiver::receiveEvent(WEvent *e){
|
|
if (WEventZoneChange* event = dynamic_cast<WEventZoneChange*>(e)) {
|
|
if (event->to && (event->to != event->from)){
|
|
GameObserver * g = GameObserver::GetInstance();
|
|
for (int i = 0; i < 2; ++i){
|
|
if (event->to == g->players[i]->game->inPlay) return 0;
|
|
}
|
|
AbilityFactory af;
|
|
af.magicText(g->mLayers->actionLayer()->getMaxId(), NULL, event->card, 1, 0,event->to);
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int OtherAbilitiesEventReceiver::testDestroy(){
|
|
return 0;
|
|
}
|
|
|
|
OtherAbilitiesEventReceiver * OtherAbilitiesEventReceiver::clone() const{
|
|
OtherAbilitiesEventReceiver * a = NEW OtherAbilitiesEventReceiver(*this);
|
|
a->isClone = 1;
|
|
return a;
|
|
}
|
|
|
|
|
|
MTGBlockRule::MTGBlockRule(int _id):MTGAbility(_id,NULL){
|
|
aType=MTGAbility::MTG_BLOCK_RULE;
|
|
}
|
|
|
|
int MTGBlockRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana){
|
|
if (currentPhase == Constants::MTG_PHASE_COMBATBLOCKERS && !game->isInterrupting && card->controller() == game->currentlyActing()){
|
|
if (card->canBlock()) return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int MTGBlockRule::reactToClick(MTGCardInstance * card){
|
|
if (!isReactingToClick(card)) return 0;
|
|
MTGCardInstance * currentOpponent = card->isDefenser();
|
|
bool result = false;
|
|
int candefend = 0;
|
|
while (!result){
|
|
currentOpponent = game->currentPlayer->game->inPlay->getNextAttacker(currentOpponent);
|
|
#if defined (WIN32) || defined (LINUX)
|
|
char buf[4096];
|
|
sprintf(buf,"Defenser Toggle %s \n", card->getName().c_str());
|
|
OutputDebugString(buf);
|
|
#endif
|
|
candefend = card->toggleDefenser(currentOpponent);
|
|
result = (candefend || currentOpponent == NULL);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
|
|
|
|
//The Block rule is never destroyed
|
|
int MTGBlockRule::testDestroy(){
|
|
return 0;
|
|
}
|
|
|
|
ostream& MTGBlockRule::toString(ostream& out) const
|
|
{
|
|
out << "MTGBlockRule ::: (";
|
|
return MTGAbility::toString(out) << ")";
|
|
}
|
|
|
|
MTGBlockRule * MTGBlockRule::clone() const{
|
|
MTGBlockRule * a = NEW MTGBlockRule(*this);
|
|
a->isClone = 1;
|
|
return a;
|
|
}
|
|
//
|
|
// Attacker chooses blockers order
|
|
//
|
|
|
|
//
|
|
// * Momir
|
|
//
|
|
|
|
int MTGMomirRule::initialized = 0;
|
|
vector<int> MTGMomirRule::pool[20];
|
|
|
|
MTGMomirRule::MTGMomirRule(int _id, MTGAllCards * _collection):MTGAbility(_id, NULL){
|
|
collection = _collection;
|
|
if (!initialized){
|
|
for (size_t i = 0; i < collection->ids.size(); i++){
|
|
MTGCard * card = collection->collection[collection->ids[i]];
|
|
if (card->data->isCreature()){
|
|
int convertedCost = card->data->getManaCost()->getConvertedCost();
|
|
if (convertedCost>20) continue;
|
|
pool[convertedCost].push_back(card->getMTGId());
|
|
}
|
|
}
|
|
initialized =1;
|
|
}
|
|
alreadyplayed = 0;
|
|
aType=MTGAbility::MOMIR;
|
|
textAlpha = 0;
|
|
}
|
|
|
|
int MTGMomirRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana){
|
|
if (alreadyplayed) return 0;
|
|
Player * player = game->currentlyActing();
|
|
Player * currentPlayer = game->currentPlayer;
|
|
if (!player->game->hand->hasCard(card)) return 0;
|
|
if (player == currentPlayer && !game->isInterrupting && (game->currentGamePhase == Constants::MTG_PHASE_FIRSTMAIN || game->currentGamePhase == Constants::MTG_PHASE_SECONDMAIN)){
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int MTGMomirRule::reactToClick(MTGCardInstance * card_to_discard){
|
|
Player * player = game->currentlyActing();
|
|
ManaCost * cost = player->getManaPool();
|
|
int converted = cost->getConvertedCost();
|
|
int id = genRandomCreatureId(converted);
|
|
return reactToClick(card_to_discard, id);
|
|
}
|
|
|
|
int MTGMomirRule::reactToClick(MTGCardInstance * card_to_discard, int cardId){
|
|
if (!isReactingToClick(card_to_discard)) return 0;
|
|
Player * player = game->currentlyActing();
|
|
ManaCost * cost = player->getManaPool();
|
|
player->getManaPool()->pay(cost);
|
|
MTGCardInstance * card = genCreature(cardId);
|
|
player->game->putInZone(card_to_discard, player->game->hand, player->game->graveyard);
|
|
|
|
player->game->stack->addCard(card);
|
|
Spell * spell = NEW Spell(card);
|
|
spell->resolve();
|
|
spell->source->isToken = 1;
|
|
delete spell;
|
|
alreadyplayed = 1;
|
|
textAlpha = 255;
|
|
text = card->name;
|
|
return 1;
|
|
}
|
|
|
|
MTGCardInstance * MTGMomirRule::genCreature( int id){
|
|
if (!id) return NULL;
|
|
Player * p = game->currentlyActing();
|
|
MTGCard * card = collection->getCardById(id);
|
|
return NEW MTGCardInstance(card,p->game);
|
|
}
|
|
|
|
int MTGMomirRule::genRandomCreatureId(int convertedCost){
|
|
if (convertedCost >= 20) convertedCost = 19;
|
|
int total_cards = 0;
|
|
int i = convertedCost;
|
|
while (!total_cards && i >=0){
|
|
#ifdef WIN32
|
|
char buf[4096];
|
|
sprintf(buf,"Converted Cost in momir: %i\n", i);
|
|
OutputDebugString(buf);
|
|
#endif
|
|
total_cards = pool[i].size();
|
|
convertedCost = i;
|
|
i--;
|
|
}
|
|
if (!total_cards) return 0;
|
|
int start = (WRand() % total_cards);
|
|
return pool[convertedCost][start];
|
|
}
|
|
|
|
//The Momir rule is never destroyed
|
|
int MTGMomirRule::testDestroy(){
|
|
return 0;
|
|
}
|
|
|
|
void MTGMomirRule::Update(float dt){
|
|
if (newPhase != currentPhase && newPhase == Constants::MTG_PHASE_UNTAP){
|
|
alreadyplayed = 0;
|
|
}
|
|
if (textAlpha){
|
|
textAlpha -= (200*dt);
|
|
if (textAlpha <0) textAlpha = 0;
|
|
}
|
|
MTGAbility::Update(dt);
|
|
}
|
|
|
|
void MTGMomirRule::Render(){
|
|
if (!textAlpha) return;
|
|
WFont * mFont = resources.GetWFont(Constants::MENU_FONT);
|
|
mFont->SetScale(2 - (float)textAlpha/130);
|
|
mFont->SetColor(ARGB(textAlpha,255,255,255));
|
|
mFont->DrawString(text.c_str(),SCREEN_WIDTH/2,SCREEN_HEIGHT/2,JGETEXT_CENTER);
|
|
}
|
|
|
|
ostream& MTGMomirRule::toString(ostream& out) const
|
|
{
|
|
out << "MTGMomirRule ::: pool : " << pool << " ; initialized : " << initialized << " ; textAlpha : " << textAlpha << " ; text " << text << " ; alreadyplayed : " << alreadyplayed << " ; collection : " << collection << "(";
|
|
return MTGAbility::toString(out) << ")";
|
|
}
|
|
|
|
|
|
MTGMomirRule * MTGMomirRule::clone() const{
|
|
MTGMomirRule * a = NEW MTGMomirRule(*this);
|
|
a->isClone = 1;
|
|
return a;
|
|
}
|
|
|
|
//HUDDisplay
|
|
int HUDDisplay::testDestroy(){
|
|
return 0;
|
|
}
|
|
|
|
void HUDDisplay::Update(float dt){
|
|
timestamp += dt;
|
|
popdelay +=dt;
|
|
if (events.size()){
|
|
list<HUDString *>::iterator it = events.begin();
|
|
HUDString * hs = *it;
|
|
if (popdelay > 1 && timestamp - hs->timestamp > 2){
|
|
events.pop_front();
|
|
delete hs;
|
|
if (events.size()) popdelay = 0;
|
|
}
|
|
}else{
|
|
maxWidth = 0;
|
|
}
|
|
}
|
|
|
|
int HUDDisplay::addEvent(string s){
|
|
events.push_back(NEW HUDString(s, timestamp));
|
|
float width = f->GetStringWidth(s.c_str());
|
|
if (width > maxWidth) maxWidth = width;
|
|
return 1;
|
|
}
|
|
|
|
int HUDDisplay::receiveEvent(WEvent * event){
|
|
|
|
WEventZoneChange * ezc = dynamic_cast<WEventZoneChange*>(event);
|
|
if (ezc) {
|
|
for (int i = 0; i < 2 ; i++){
|
|
Player * p = game->players[i];
|
|
if (ezc->to == p->game->graveyard ){
|
|
char buffer[512];
|
|
sprintf(buffer,_("%s goes to graveyard").c_str(), _(ezc->card->getName()).c_str());
|
|
string s = buffer;
|
|
return addEvent(s);
|
|
}
|
|
}
|
|
}
|
|
|
|
WEventDamage * ed = dynamic_cast<WEventDamage*>(event);
|
|
if (ed) {
|
|
char buffer[512];
|
|
sprintf(buffer, "%s: %i -> %s", _(ed->damage->source->name).c_str(), ed->damage->damage, _(ed->damage->target->getDisplayName()).c_str());
|
|
string s = buffer;
|
|
return addEvent(s);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
void HUDDisplay::Render(){
|
|
if (!options[Options::OSD].number) return;
|
|
if (!events.size()) return;
|
|
|
|
f->SetColor(ARGB(255,255,255,255));
|
|
|
|
list<HUDString *>::reverse_iterator it;
|
|
|
|
float x0 = SCREEN_WIDTH-10-maxWidth-10;
|
|
float y0 = 20;
|
|
float size = events.size() * 16;
|
|
JRenderer * r = JRenderer::GetInstance();
|
|
r->FillRoundRect(x0,y0,maxWidth + 10,size,5,ARGB(50,0,0,0));
|
|
|
|
int i = 0;
|
|
for (it = events.rbegin(); it !=events.rend(); ++it){
|
|
HUDString * hs = *it;
|
|
f->DrawString(hs->value.c_str(),x0 + 5, y0 + 16 * i);
|
|
i++;
|
|
}
|
|
}
|
|
HUDDisplay::HUDDisplay(int _id):MTGAbility(_id, NULL){
|
|
timestamp = 0;
|
|
popdelay = 2;
|
|
f = resources.GetWFont(Constants::MAIN_FONT);
|
|
maxWidth = 0;
|
|
}
|
|
|
|
HUDDisplay::~HUDDisplay(){
|
|
list<HUDString *>::iterator it;
|
|
for (it = events.begin(); it !=events.end(); ++it){
|
|
HUDString * hs = *it;
|
|
delete hs;
|
|
}
|
|
events.clear();
|
|
}
|
|
|
|
HUDDisplay * HUDDisplay::clone() const{
|
|
HUDDisplay * a = NEW HUDDisplay(*this);
|
|
a->isClone = 1;
|
|
return a;
|
|
}
|
|
|
|
|
|
/* Persist */
|
|
MTGPersistRule::MTGPersistRule(int _id):MTGAbility(_id,NULL){};
|
|
|
|
int MTGPersistRule::receiveEvent(WEvent * event){
|
|
if (event->type == WEvent::CHANGE_ZONE){
|
|
WEventZoneChange * e = (WEventZoneChange *) event;
|
|
MTGCardInstance * card = e->card->previous;
|
|
if (card && card->basicAbilities[Constants::PERSIST] && !card->counters->hasCounter(-1,-1)){
|
|
int ok = 0;
|
|
for (int i = 0; i < 2 ; i++){
|
|
Player * p = game->players[i];
|
|
if (e->from == p->game->inPlay) ok = 1;
|
|
}
|
|
if (!ok) return 0;
|
|
for (int i = 0; i < 2 ; i++){
|
|
Player * p = game->players[i];
|
|
if (e->to == p->game->graveyard){
|
|
MTGCardInstance * copy = p->game->putInZone(e->card, p->game->graveyard, e->card->owner->game->stack);
|
|
Spell * spell = NEW Spell(copy);
|
|
spell->resolve();
|
|
spell->source->counters->addCounter(-1,-1);
|
|
delete spell;
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
ostream& MTGPersistRule::toString(ostream& out) const
|
|
{
|
|
out << "MTGPersistRule ::: (";
|
|
return MTGAbility::toString(out) << ")";
|
|
}
|
|
int MTGPersistRule::testDestroy(){return 0;}
|
|
MTGPersistRule * MTGPersistRule::clone() const{
|
|
MTGPersistRule * a = NEW MTGPersistRule(*this);
|
|
a->isClone = 1;
|
|
return a;
|
|
}
|
|
|
|
//putting cards with restricting effects inplay
|
|
MTGCantCasterstart::MTGCantCasterstart(int _id):MTGAbility(_id,NULL){};
|
|
|
|
int MTGCantCasterstart::receiveEvent(WEvent * event){
|
|
if (event->type == WEvent::CHANGE_ZONE){
|
|
WEventZoneChange * e = (WEventZoneChange *) event;
|
|
MTGCardInstance * card = e->card->previous;
|
|
if(card){
|
|
if (card->basicAbilities[Constants::BOTHCANTCAST] || card->basicAbilities[Constants::BOTHNOCREATURE] || card->basicAbilities[Constants::CANTCAST] || card->basicAbilities[Constants::CANTCASTCREATURE] || card->basicAbilities[Constants::CANTCASTTWO] || card->basicAbilities[Constants::ONLYONEBOTH]){
|
|
int ok = 0;
|
|
|
|
|
|
|
|
for (int i = 0; i < 2 ; i++){
|
|
Player * p = game->players[i];
|
|
if (e->from == p->game->graveyard || e->from == p->game->hand || e->from == p->game->library || e->from == p->game->exile){ ok = 1;
|
|
}
|
|
|
|
for (int i = 0; i < 2 ; i++){
|
|
Player * p = game->players[i];
|
|
if (e->to == p->game->inPlay){//this will trigger a check if opponent or player cast the card.
|
|
|
|
MTGGameZone * z = card->controller()->game->inPlay;
|
|
MTGGameZone * y = card->controller()->opponent()->game->inPlay;
|
|
int nbcards = z->nb_cards;
|
|
int onbcards = y->nb_cards;
|
|
//check my battlefield and opponents
|
|
for (int j = 0; j < nbcards; ++j){
|
|
MTGCardInstance * c = z->cards[j];
|
|
if (c->has(Constants::BOTHCANTCAST)){
|
|
card->controller()->castrestrictedspell = 1;
|
|
card->controller()->opponent()->castrestrictedspell = 1;
|
|
}
|
|
} //any on other side?
|
|
for (int j = 0; j < onbcards; ++j){
|
|
MTGCardInstance * c = y->cards[j];
|
|
if (c->has(Constants::BOTHCANTCAST)){
|
|
card->controller()->castrestrictedspell = 1;
|
|
card->controller()->opponent()->castrestrictedspell = 1;
|
|
}
|
|
}
|
|
//maybe one of us is still restricted, lets check...
|
|
for (int j = 0; j < nbcards; ++j){
|
|
MTGCardInstance * c = z->cards[j];
|
|
if (c->has(Constants::CANTCAST)){
|
|
card->controller()->castrestrictedspell = 1;
|
|
}
|
|
} //any on other side?
|
|
for (int j = 0; j < onbcards; ++j){
|
|
MTGCardInstance * c = y->cards[j];
|
|
if (c->has(Constants::CANTCAST)){
|
|
card->controller()->opponent()->castrestrictedspell = 1;
|
|
}
|
|
}
|
|
|
|
//---how about if we cant cast creatures---
|
|
|
|
for (int j = 0; j < nbcards; ++j){
|
|
MTGCardInstance * c = z->cards[j];
|
|
if (c->has(Constants::BOTHNOCREATURE)){
|
|
card->controller()->castrestrictedcreature += 1;
|
|
card->controller()->opponent()->castrestrictedcreature += 1;
|
|
}
|
|
}
|
|
//maybe opponent has one....
|
|
for (int j = 0; j < onbcards; ++j){
|
|
MTGCardInstance * c = y->cards[j];
|
|
if (c->has(Constants::BOTHNOCREATURE)){
|
|
|
|
card->controller()->castrestrictedcreature = 1;
|
|
card->controller()->opponent()->castrestrictedcreature = 1;
|
|
}
|
|
}
|
|
//---
|
|
for (int j = 0; j < nbcards; ++j){
|
|
MTGCardInstance * c = z->cards[j];
|
|
if (c->has(Constants::CANTCASTCREATURE)){
|
|
card->controller()->castrestrictedcreature = 1;
|
|
}
|
|
}
|
|
//maybe opponent has one....
|
|
for (int j = 0; j < onbcards; ++j){
|
|
MTGCardInstance * c = y->cards[j];
|
|
if (c->has(Constants::CANTCASTCREATURE)){
|
|
card->controller()->opponent()->castrestrictedcreature = 1;
|
|
}
|
|
}
|
|
//---what if i can only cast 1?
|
|
for (int j = 0; j < nbcards; ++j){
|
|
|
|
MTGCardInstance * c = z->cards[j];
|
|
if (c->has(Constants::ONLYONEBOTH)){
|
|
card->controller()->onlyonecast = 1;
|
|
card->controller()->opponent()->onlyonecast = 1;
|
|
}
|
|
}
|
|
//maybe opponent has one....
|
|
for (int j = 0; j < onbcards; ++j){
|
|
MTGCardInstance * c = y->cards[j];
|
|
if (c->has(Constants::ONLYONEBOTH)){
|
|
card->controller()->onlyonecast = 1;
|
|
card->controller()->opponent()->onlyonecast = 1;
|
|
}
|
|
}
|
|
//---
|
|
for (int j = 0; j < nbcards; ++j){
|
|
MTGCardInstance * c = z->cards[j];
|
|
if (c->has(Constants::CANTCASTTWO)){
|
|
card->controller()->onlyonecast = 1;
|
|
}
|
|
}
|
|
//maybe opponent has one....
|
|
for (int j = 0; j < onbcards; ++j){
|
|
MTGCardInstance * c = y->cards[j];
|
|
if (c->has(Constants::CANTCASTTWO)){
|
|
card->controller()->opponent()->onlyonecast = 1;
|
|
}
|
|
}
|
|
//-----if a card with both*restrict* was found then the players are still restricted, if one player is still restricted he stays restricted.
|
|
return 1;
|
|
}
|
|
return 1;
|
|
}
|
|
return 1;
|
|
}
|
|
return 1;
|
|
}
|
|
return 1;
|
|
}
|
|
return 1;
|
|
}
|
|
return 1;
|
|
}
|
|
ostream& MTGCantCasterstart::toString(ostream& out) const
|
|
{
|
|
out << "MTGCantCasterstart ::: (";
|
|
return MTGAbility::toString(out) << ")";
|
|
}
|
|
int MTGCantCasterstart::testDestroy(){return 0;}
|
|
MTGCantCasterstart * MTGCantCasterstart::clone() const{
|
|
MTGCantCasterstart * a = NEW MTGCantCasterstart(*this);
|
|
a->isClone = 1;
|
|
return a;
|
|
}
|
|
|
|
//check if cast resristrictions are lifted when a card leaves play
|
|
MTGCantCastercheck::MTGCantCastercheck(int _id):MTGAbility(_id,NULL){};
|
|
|
|
int MTGCantCastercheck::receiveEvent(WEvent * event){
|
|
if (event->type == WEvent::CHANGE_ZONE){
|
|
WEventZoneChange * e = (WEventZoneChange *) event;
|
|
MTGCardInstance * card = e->card->previous;
|
|
if (card && (card->basicAbilities[Constants::BOTHCANTCAST] || card->basicAbilities[Constants::BOTHNOCREATURE] || card->basicAbilities[Constants::CANTCAST] || card->basicAbilities[Constants::CANTCASTCREATURE] || card->basicAbilities[Constants::CANTCASTTWO] || card->basicAbilities[Constants::ONLYONEBOTH])){
|
|
int ok = 0;
|
|
for (int i = 0; i < 2 ; i++){
|
|
Player * p = game->players[i];
|
|
if (e->from == p->game->inPlay) ok = 1;
|
|
}
|
|
if (!ok) return 0;
|
|
for (int i = 0; i < 2 ; i++){
|
|
Player * p = game->players[i];
|
|
if (e->to == p->game->graveyard || e->to == p->game->hand || e->to == p->game->library || e->to == p->game->exile){//if it goes ANYWHERE but inplay.
|
|
//check happens----------
|
|
//reset restrictions
|
|
p->onlyonecast = 0;
|
|
p->opponent()->onlyonecast = 0;
|
|
p->castrestrictedspell = 0;//0 means no restrictions apply.
|
|
p->castrestrictedcreature = 0;
|
|
p->opponent()->castrestrictedspell = 0;
|
|
p->opponent()->castrestrictedcreature = 0;
|
|
/*--------------------------------------------------------------*/
|
|
MTGGameZone * z = card->controller()->game->inPlay;
|
|
MTGGameZone * y = card->controller()->opponent()->game->inPlay;
|
|
int nbcards = z->nb_cards;
|
|
int onbcards = y->nb_cards;
|
|
//check my battlefield and opponents
|
|
for (int j = 0; j < nbcards; ++j){
|
|
MTGCardInstance * c = z->cards[j];
|
|
if (c->has(Constants::BOTHCANTCAST)){
|
|
p->castrestrictedspell = 1;
|
|
p->opponent()->castrestrictedspell = 1;
|
|
}
|
|
} //any on other side?
|
|
for (int j = 0; j < onbcards; ++j){
|
|
MTGCardInstance * c = y->cards[j];
|
|
if (c->has(Constants::BOTHCANTCAST)){
|
|
p->castrestrictedspell = 1;
|
|
p->opponent()->castrestrictedspell = 1;
|
|
}
|
|
}
|
|
//maybe one of us is still restricted, lets check...
|
|
for (int j = 0; j < nbcards; ++j){
|
|
MTGCardInstance * c = z->cards[j];
|
|
if (c->has(Constants::CANTCAST)){
|
|
p->castrestrictedspell = 1;
|
|
}
|
|
} //any on other side?
|
|
for (int j = 0; j < onbcards; ++j){
|
|
MTGCardInstance * c = y->cards[j];
|
|
if (c->has(Constants::CANTCAST)){
|
|
p->opponent()->castrestrictedspell = 1;
|
|
}
|
|
}
|
|
|
|
//---how about if we cant cast creatures---
|
|
|
|
for (int j = 0; j < nbcards; ++j){
|
|
MTGCardInstance * c = z->cards[j];
|
|
if (c->has(Constants::BOTHNOCREATURE)){
|
|
p->castrestrictedcreature = 1;
|
|
p->opponent()->castrestrictedcreature = 1;
|
|
}
|
|
}
|
|
//maybe opponent has one....
|
|
for (int j = 0; j < onbcards; ++j){
|
|
MTGCardInstance * c = y->cards[j];
|
|
if (c->has(Constants::BOTHNOCREATURE)){
|
|
p->castrestrictedcreature = 1;
|
|
p->opponent()->castrestrictedcreature = 1;
|
|
}
|
|
}
|
|
//---
|
|
for (int j = 0; j < nbcards; ++j){
|
|
MTGCardInstance * c = z->cards[j];
|
|
if (c->has(Constants::CANTCASTCREATURE)){
|
|
p->castrestrictedcreature = 1;
|
|
}
|
|
}
|
|
//maybe opponent has one....
|
|
for (int j = 0; j < onbcards; ++j){
|
|
MTGCardInstance * c = y->cards[j];
|
|
if (c->has(Constants::CANTCASTCREATURE)){
|
|
p->opponent()->castrestrictedcreature = 1;
|
|
}
|
|
}
|
|
//---what if i can only cast 1?
|
|
for (int j = 0; j < nbcards; ++j){
|
|
MTGCardInstance * c = z->cards[j];
|
|
if (c->has(Constants::ONLYONEBOTH)){
|
|
p->onlyonecast = 1;
|
|
p->opponent()->onlyonecast = 1;
|
|
}
|
|
}
|
|
//maybe opponent has one....
|
|
for (int j = 0; j < onbcards; ++j){
|
|
MTGCardInstance * c = y->cards[j];
|
|
if (c->has(Constants::ONLYONEBOTH)){
|
|
p->onlyonecast = 1;
|
|
p->opponent()->onlyonecast = 1;
|
|
}
|
|
}
|
|
//---
|
|
for (int j = 0; j < nbcards; ++j){
|
|
MTGCardInstance * c = z->cards[j];
|
|
if (c->has(Constants::CANTCASTTWO)){
|
|
p->onlyonecast = 1;
|
|
}
|
|
}
|
|
//maybe opponent has one....
|
|
for (int j = 0; j < onbcards; ++j){
|
|
MTGCardInstance * c = y->cards[j];
|
|
if (c->has(Constants::CANTCASTTWO)){
|
|
p->opponent()->onlyonecast = 1;
|
|
}
|
|
}
|
|
//-----if a card with both*restrict* was found then the players are still restricted, if one player is still restricted he stays restricted.
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
ostream& MTGCantCastercheck::toString(ostream& out) const
|
|
{
|
|
out << "MTGCantCastercheck ::: (";
|
|
return MTGAbility::toString(out) << ")";
|
|
}
|
|
int MTGCantCastercheck::testDestroy(){return 0;}
|
|
MTGCantCastercheck * MTGCantCastercheck::clone() const{
|
|
MTGCantCastercheck * a = NEW MTGCantCastercheck(*this);
|
|
a->isClone = 1;
|
|
return a;
|
|
}
|
|
//the end of this very complex code line.
|
|
|
|
|
|
|
|
//unearth rule----------------------------------
|
|
//if the card leaves play, exile it instead.
|
|
MTGUnearthRule::MTGUnearthRule(int _id):MTGAbility(_id,NULL){};
|
|
|
|
int MTGUnearthRule::receiveEvent(WEvent * event){
|
|
if (event->type == WEvent::CHANGE_ZONE){
|
|
WEventZoneChange * e = (WEventZoneChange *) event;
|
|
MTGCardInstance * card = e->card->previous;
|
|
if (card && card->basicAbilities[Constants::UNEARTH]){
|
|
int ok = 0;
|
|
for (int i = 0; i < 2 ; i++){
|
|
Player * p = game->players[i];
|
|
if (e->from == p->game->inPlay) ok = 1;
|
|
}
|
|
if (!ok) return 0;
|
|
for (int i = 0; i < 2 ; i++){
|
|
Player * p = game->players[i];
|
|
if (e->to == p->game->graveyard || e->to == p->game->hand || e->to == p->game->library){
|
|
p->game->putInExile(e->card);
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
ostream& MTGUnearthRule::toString(ostream& out) const
|
|
{
|
|
out << "MTGUnearthRule ::: (";
|
|
return MTGAbility::toString(out) << ")";
|
|
}
|
|
int MTGUnearthRule::testDestroy(){return 0;}
|
|
MTGUnearthRule * MTGUnearthRule::clone() const{
|
|
MTGUnearthRule * a = NEW MTGUnearthRule(*this);
|
|
a->isClone = 1;
|
|
return a;
|
|
}
|
|
//----------------------------------------------------------------------
|
|
//sneakattack rule------------------------------------------------------
|
|
//this rule also handles the exile of unearth cards at end of turn.
|
|
|
|
MTGSneakAttackRule::MTGSneakAttackRule(int _id):MTGAbility(_id,NULL){};
|
|
|
|
int MTGSneakAttackRule::receiveEvent(WEvent *e){
|
|
if (WEventPhaseChange* event = dynamic_cast<WEventPhaseChange*>(e)) {
|
|
if (Constants::MTG_PHASE_ENDOFTURN == event->from->id) {
|
|
for (int j = 0; j < 2 ; j++){
|
|
Player * p = game->players[j];
|
|
MTGGameZone * z = p->game->inPlay;
|
|
for (int i= 0; i < z->nb_cards; i++){
|
|
MTGCardInstance * card = z->cards[i];
|
|
if (card->has(Constants::TREASON)) {p->game->putInGraveyard(card);i--;}
|
|
if (card->has(Constants::UNEARTH)) {p->game->putInExile(card);i--;}
|
|
}
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
ostream& MTGSneakAttackRule::toString(ostream& out) const
|
|
{
|
|
out << "MTGSneakAttackRule ::: (";
|
|
return MTGAbility::toString(out) << ")";
|
|
}
|
|
int MTGSneakAttackRule::testDestroy(){return 0;}
|
|
MTGSneakAttackRule * MTGSneakAttackRule::clone() const{
|
|
MTGSneakAttackRule * a = NEW MTGSneakAttackRule(*this);
|
|
a->isClone = 1;
|
|
return a;
|
|
}
|
|
//-------------------------------------------------------------------
|
|
//Affinity rule------------------------------------------------------
|
|
//this rule is for Affinity cards.
|
|
|
|
MTGAffinityRule::MTGAffinityRule(int _id):MTGAbility(_id,NULL){};
|
|
int MTGAffinityRule::receiveEvent(WEvent * event){
|
|
if (event->type == WEvent::CHANGE_ZONE){
|
|
WEventZoneChange * e = (WEventZoneChange *) event;
|
|
MTGCardInstance * card = e->card->previous;
|
|
|
|
//when cards with affinity enter you hand from anywhere a redux is applied to them for the artifacts in play.
|
|
if(card && card->has(Constants::AFFINITYARTIFACTS)){
|
|
int ok = 0;
|
|
for (int i = 0; i < 2 ; i++){
|
|
Player * p = game->players[i];
|
|
if (e->to == p->game->hand) ok = 3;//affinity card enters hand
|
|
//---------
|
|
if(ok == 3){//enters play from anywhere
|
|
if (e->from == p->game->graveyard || e->from == p->game->hand || e->from == p->game->library || e->from == p->game->exile || e->from == p->game->stack || e->from == p->opponent()->game->battlefield || e->from == p->game->temp){
|
|
//--redux effect
|
|
MTGGameZone * z = card->controller()->game->battlefield;
|
|
int nbcards = z->nb_cards;
|
|
for (int j = 0; j < nbcards; ++j){
|
|
MTGCardInstance * c = z->cards[j];
|
|
if (c->hasSubtype("artifact")){
|
|
e->card->getManaCost()->remove(0,1);//one less colorless to cast
|
|
}
|
|
}//--end of redux bracket
|
|
}
|
|
}
|
|
//-------------
|
|
}
|
|
}//this bracket end first redux artifacts
|
|
//----------------------------------------
|
|
//the following handles redux of land affinities.
|
|
if(card && card->has(Constants::AFFINITYSWAMP)){
|
|
int ok = 0;
|
|
for (int i = 0; i < 2 ; i++){
|
|
Player * p = game->players[i];
|
|
if (e->to == p->game->hand) ok = 4;//affinity card enters hand
|
|
//---------
|
|
if(ok == 4){//enters play from anywhere
|
|
if (e->from == p->game->graveyard || e->from == p->game->hand || e->from == p->game->library || e->from == p->game->exile || e->from == p->game->stack || e->from == p->opponent()->game->battlefield || e->from == p->game->temp){
|
|
//--redux effect
|
|
MTGGameZone * z = card->controller()->game->battlefield;
|
|
int nbcards = z->nb_cards;
|
|
for (int j = 0; j < nbcards; ++j){
|
|
MTGCardInstance * c = z->cards[j];
|
|
if (c->hasSubtype("swamp")){
|
|
e->card->getManaCost()->remove(0,1);//one less colorless to cast
|
|
}
|
|
}//--end of redux bracket
|
|
}
|
|
}
|
|
//-------------
|
|
}
|
|
}//this bracket end first redux swamp
|
|
//----------------------------------------
|
|
if(card && card->has(Constants::AFFINITYMOUNTAIN)){
|
|
int ok = 0;
|
|
for (int i = 0; i < 2 ; i++){
|
|
Player * p = game->players[i];
|
|
if (e->to == p->game->hand) ok = 5;//affinity card enters hand
|
|
//---------
|
|
if(ok == 5){//enters play from anywhere
|
|
if (e->from == p->game->graveyard || e->from == p->game->hand || e->from == p->game->library || e->from == p->game->exile || e->from == p->game->stack || e->from == p->opponent()->game->battlefield || e->from == p->game->temp){
|
|
//--redux effect
|
|
MTGGameZone * z = card->controller()->game->battlefield;
|
|
int nbcards = z->nb_cards;
|
|
for (int j = 0; j < nbcards; ++j){
|
|
MTGCardInstance * c = z->cards[j];
|
|
if (c->hasSubtype("mountain")){
|
|
e->card->getManaCost()->remove(0,1);//one less colorless to cast
|
|
}
|
|
}//--end of redux bracket
|
|
}
|
|
}
|
|
//-------------
|
|
}
|
|
}//this bracket end first redux mountains
|
|
//----------------------------------------
|
|
if(card && card->has(Constants::AFFINITYPLAINS)){
|
|
int ok = 0;
|
|
for (int i = 0; i < 2 ; i++){
|
|
Player * p = game->players[i];
|
|
if (e->to == p->game->hand) ok = 6;//affinity card enters hand
|
|
//---------
|
|
if(ok == 6){//enters play from anywhere
|
|
if (e->from == p->game->graveyard || e->from == p->game->hand || e->from == p->game->library || e->from == p->game->exile || e->from == p->game->stack || e->from == p->opponent()->game->battlefield || e->from == p->game->temp){
|
|
//--redux effect
|
|
MTGGameZone * z = card->controller()->game->battlefield;
|
|
int nbcards = z->nb_cards;
|
|
for (int j = 0; j < nbcards; ++j){
|
|
MTGCardInstance * c = z->cards[j];
|
|
if (c->hasSubtype("plains")){
|
|
e->card->getManaCost()->remove(0,1);//one less colorless to cast
|
|
}
|
|
}//--end of redux bracket
|
|
}
|
|
}
|
|
//-------------
|
|
}
|
|
}//this bracket end first redux plains
|
|
//----------------------------------------
|
|
if(card && card->has(Constants::AFFINITYISLAND)){
|
|
int ok = 0;
|
|
for (int i = 0; i < 2 ; i++){
|
|
Player * p = game->players[i];
|
|
if (e->to == p->game->hand) ok = 7;//affinity card enters hand
|
|
//---------
|
|
if(ok == 7){//enters play from anywhere
|
|
if (e->from == p->game->graveyard || e->from == p->game->hand || e->from == p->game->library || e->from == p->game->exile || e->from == p->game->stack || e->from == p->opponent()->game->battlefield || e->from == p->game->temp){
|
|
//--redux effect
|
|
MTGGameZone * z = card->controller()->game->battlefield;
|
|
int nbcards = z->nb_cards;
|
|
for (int j = 0; j < nbcards; ++j){
|
|
MTGCardInstance * c = z->cards[j];
|
|
if (c->hasSubtype("island")){
|
|
e->card->getManaCost()->remove(0,1);//one less colorless to cast
|
|
}
|
|
}//--end of redux bracket
|
|
}
|
|
}
|
|
//-------------
|
|
}
|
|
}//this bracket end first redux island
|
|
//----------------------------------------
|
|
if(card && card->has(Constants::AFFINITYFOREST)){
|
|
int ok = 0;
|
|
for (int i = 0; i < 2 ; i++){
|
|
Player * p = game->players[i];
|
|
if (e->to == p->game->hand) ok = 8;//affinity card enters hand
|
|
//---------
|
|
if(ok == 8){//enters play from anywhere
|
|
if (e->from == p->game->graveyard || e->from == p->game->hand || e->from == p->game->library || e->from == p->game->exile || e->from == p->game->stack || e->from == p->opponent()->game->battlefield || e->from == p->game->temp){
|
|
//--redux effect
|
|
MTGGameZone * z = card->controller()->game->battlefield;
|
|
int nbcards = z->nb_cards;
|
|
for (int j = 0; j < nbcards; ++j){
|
|
MTGCardInstance * c = z->cards[j];
|
|
if (c->hasSubtype("forest")){
|
|
e->card->getManaCost()->remove(0,1);//one less colorless to cast
|
|
}
|
|
}//--end of redux bracket
|
|
}
|
|
}
|
|
//-------------
|
|
}
|
|
}//this bracket end first redux forest
|
|
//----------------------------------------
|
|
if(card && card->has(Constants::AFFINITYGREENCREATURES)){
|
|
int ok = 0;
|
|
for (int i = 0; i < 2 ; i++){
|
|
Player * p = game->players[i];
|
|
if (e->to == p->game->hand) ok = 21;//affinity card enters hand
|
|
//---------
|
|
if(ok == 21){//enters play from anywhere
|
|
if (e->from == p->game->graveyard || e->from == p->game->hand || e->from == p->game->library || e->from == p->game->exile || e->from == p->game->stack || e->from == p->opponent()->game->battlefield || e->from == p->game->temp){
|
|
//--redux effect
|
|
MTGGameZone * z = card->controller()->game->battlefield;
|
|
int nbcards = z->nb_cards;
|
|
for (int j = 0; j < nbcards; ++j){
|
|
MTGCardInstance * c = z->cards[j];
|
|
if (c->hasSubtype("creature") && c->hasColor(1)){
|
|
e->card->getManaCost()->remove(1,1);//one less colorless to cast
|
|
}
|
|
}//--end of redux bracket
|
|
}
|
|
}
|
|
//-------------
|
|
}
|
|
}//this bracket end first redux greencreatures
|
|
//----------------------------------------
|
|
|
|
|
|
|
|
//section 2, maintaining proper manacost
|
|
//---------this section takes care of increasing and reducing cost when artifacts enter or leave play
|
|
if (card && card->hasSubtype("artifact")){
|
|
int ok = 0;
|
|
for (int i = 0; i < 2 ; i++){
|
|
Player * p = game->players[i];
|
|
if (e->to == p->game->battlefield) ok = 1;//artifact enters play in your battlefield
|
|
if (e->to == p->game->graveyard || e->to == p->game->hand || e->to == p->game->library || e->to == p->game->exile || e->to == p->game->stack || e->to == p->opponent()->game->battlefield) ok = 2;//artifact leaves play
|
|
//---------above are the triggers "to" markers...
|
|
if(ok == 1){//enters play from anywhere
|
|
if (e->from == p->game->graveyard || e->from == p->game->hand || e->from == p->game->library || e->from == p->game->exile || e->from == p->game->stack || e->from == p->opponent()->game->battlefield || e->from == p->game->temp){
|
|
//--redux effect
|
|
MTGGameZone * z = card->controller()->game->hand;
|
|
int nbcards = z->nb_cards;
|
|
for (int j = 0; j < nbcards; ++j){
|
|
MTGCardInstance * c = z->cards[j];
|
|
if (c->has(Constants::AFFINITYARTIFACTS)){
|
|
c->getManaCost()->remove(0,1);//one less colorless to cast
|
|
}
|
|
}//--end of redux bracket
|
|
}
|
|
}
|
|
//---------
|
|
if(ok == 2){//leave play from your battlefield
|
|
if (e->from == p->game->battlefield){
|
|
//--
|
|
MTGGameZone * z = card->controller()->game->hand;
|
|
int nbcards = z->nb_cards;
|
|
//check my battlefield and opponents
|
|
for (int j = 0; j < nbcards; ++j){
|
|
MTGCardInstance * c = z->cards[j];
|
|
if (c->has(Constants::AFFINITYARTIFACTS)){
|
|
c->getManaCost()->add(0,1);
|
|
}
|
|
}
|
|
//--
|
|
}
|
|
}
|
|
//---------
|
|
}
|
|
}//this bracket ends check for artifacts
|
|
//----------------------------------------
|
|
//the following maintains cost other then artifacts
|
|
//----swamps
|
|
if (card && card->hasSubtype("swamp")){
|
|
int ok = 0;
|
|
for (int i = 0; i < 2 ; i++){
|
|
Player * p = game->players[i];
|
|
if (e->to == p->game->battlefield) ok = 9;//swamp enters play in your battlefield
|
|
if (e->to == p->game->graveyard || e->to == p->game->hand || e->to == p->game->library || e->to == p->game->exile || e->to == p->game->stack || e->to == p->opponent()->game->battlefield) ok = 10;//artifact leaves play
|
|
//---------above are the triggers "to" markers...
|
|
if(ok == 9){//enters play from anywhere
|
|
if (e->from == p->game->graveyard || e->from == p->game->hand || e->from == p->game->library || e->from == p->game->exile || e->from == p->game->stack || e->from == p->opponent()->game->battlefield || e->from == p->game->temp){
|
|
//--redux effect
|
|
MTGGameZone * z = card->controller()->game->hand;
|
|
int nbcards = z->nb_cards;
|
|
for (int j = 0; j < nbcards; ++j){
|
|
MTGCardInstance * c = z->cards[j];
|
|
if (c->has(Constants::AFFINITYSWAMP)){
|
|
c->getManaCost()->remove(0,1);//one less colorless to cast
|
|
}
|
|
}//--end of redux bracket
|
|
}
|
|
}
|
|
//---------
|
|
if(ok == 10){//leave play from your battlefield
|
|
if (e->from == p->game->battlefield){
|
|
//--
|
|
MTGGameZone * z = card->controller()->game->hand;
|
|
int nbcards = z->nb_cards;
|
|
//check my battlefield and opponents
|
|
for (int j = 0; j < nbcards; ++j){
|
|
MTGCardInstance * c = z->cards[j];
|
|
if (c->has(Constants::AFFINITYSWAMP)){
|
|
c->getManaCost()->add(0,1);
|
|
}
|
|
}
|
|
//--
|
|
}
|
|
}
|
|
//---------
|
|
}
|
|
}//this bracket ends check for swamps
|
|
//----------------------------------------
|
|
//----mountain
|
|
if (card && card->hasSubtype("mountain")){
|
|
int ok = 0;
|
|
for (int i = 0; i < 2 ; i++){
|
|
Player * p = game->players[i];
|
|
if (e->to == p->game->battlefield) ok = 11;//moutain enters play in your battlefield
|
|
if (e->to == p->game->graveyard || e->to == p->game->hand || e->to == p->game->library || e->to == p->game->exile || e->to == p->game->stack || e->to == p->opponent()->game->battlefield) ok = 12;//artifact leaves play
|
|
//---------above are the triggers "to" markers...
|
|
if(ok == 11){//enters play from anywhere
|
|
if (e->from == p->game->graveyard || e->from == p->game->hand || e->from == p->game->library || e->from == p->game->exile || e->from == p->game->stack || e->from == p->opponent()->game->battlefield || e->from == p->game->temp){
|
|
//--redux effect
|
|
MTGGameZone * z = card->controller()->game->hand;
|
|
int nbcards = z->nb_cards;
|
|
for (int j = 0; j < nbcards; ++j){
|
|
MTGCardInstance * c = z->cards[j];
|
|
if (c->has(Constants::AFFINITYMOUNTAIN)){
|
|
c->getManaCost()->remove(0,1);//one less colorless to cast
|
|
}
|
|
}//--end of redux bracket
|
|
}
|
|
}
|
|
//---------
|
|
if(ok == 12){//leave play from your battlefield
|
|
if (e->from == p->game->battlefield){
|
|
//--
|
|
MTGGameZone * z = card->controller()->game->hand;
|
|
int nbcards = z->nb_cards;
|
|
//check my battlefield and opponents
|
|
for (int j = 0; j < nbcards; ++j){
|
|
MTGCardInstance * c = z->cards[j];
|
|
if (c->has(Constants::AFFINITYMOUNTAIN)){
|
|
c->getManaCost()->add(0,1);
|
|
}
|
|
}
|
|
//--
|
|
}
|
|
}
|
|
//---------
|
|
}
|
|
}//this bracket ends check for mountains
|
|
//----------------------------------------
|
|
//----plains
|
|
if (card && card->hasSubtype("plains")){
|
|
int ok = 0;
|
|
for (int i = 0; i < 2 ; i++){
|
|
Player * p = game->players[i];
|
|
if (e->to == p->game->battlefield) ok = 13;//plains enters play in your battlefield
|
|
if (e->to == p->game->graveyard || e->to == p->game->hand || e->to == p->game->library || e->to == p->game->exile || e->to == p->game->stack || e->to == p->opponent()->game->battlefield) ok = 14;//artifact leaves play
|
|
//---------above are the triggers "to" markers...
|
|
if(ok == 13){//enters play from anywhere
|
|
if (e->from == p->game->graveyard || e->from == p->game->hand || e->from == p->game->library || e->from == p->game->exile || e->from == p->game->stack || e->from == p->opponent()->game->battlefield || e->from == p->game->temp){
|
|
//--redux effect
|
|
MTGGameZone * z = card->controller()->game->hand;
|
|
int nbcards = z->nb_cards;
|
|
for (int j = 0; j < nbcards; ++j){
|
|
MTGCardInstance * c = z->cards[j];
|
|
if (c->has(Constants::AFFINITYPLAINS)){
|
|
c->getManaCost()->remove(0,1);//one less colorless to cast
|
|
}
|
|
}//--end of redux bracket
|
|
}
|
|
}
|
|
//---------
|
|
if(ok == 14){//leave play from your battlefield
|
|
if (e->from == p->game->battlefield){
|
|
//--
|
|
MTGGameZone * z = card->controller()->game->hand;
|
|
int nbcards = z->nb_cards;
|
|
//check my battlefield and opponents
|
|
for (int j = 0; j < nbcards; ++j){
|
|
MTGCardInstance * c = z->cards[j];
|
|
if (c->has(Constants::AFFINITYPLAINS)){
|
|
c->getManaCost()->add(0,1);
|
|
}
|
|
}
|
|
//--
|
|
}
|
|
}
|
|
//---------
|
|
}
|
|
}//this bracket ends check for plains
|
|
//----------------------------------------
|
|
//----island
|
|
if (card && card->hasSubtype("island")){
|
|
int ok = 0;
|
|
for (int i = 0; i < 2 ; i++){
|
|
Player * p = game->players[i];
|
|
if (e->to == p->game->battlefield) ok = 15;//island enters play in your battlefield
|
|
|
|
if (e->to == p->game->graveyard || e->to == p->game->hand || e->to == p->game->library || e->to == p->game->exile || e->to == p->game->stack || e->to == p->opponent()->game->battlefield) ok = 16;//artifact leaves play
|
|
//---------above are the triggers "to" markers...
|
|
if(ok == 15){//enters play from anywhere
|
|
if (e->from == p->game->graveyard || e->from == p->game->hand || e->from == p->game->library || e->from == p->game->exile || e->from == p->game->stack || e->from == p->opponent()->game->battlefield || e->from == p->game->temp){
|
|
//--redux effect
|
|
MTGGameZone * z = card->controller()->game->hand;
|
|
int nbcards = z->nb_cards;
|
|
for (int j = 0; j < nbcards; ++j){
|
|
MTGCardInstance * c = z->cards[j];
|
|
if (c->has(Constants::AFFINITYISLAND)){
|
|
c->getManaCost()->remove(0,1);//one less colorless to cast
|
|
}
|
|
}//--end of redux bracket
|
|
}
|
|
}
|
|
//---------
|
|
if(ok == 16){//leave play from your battlefield
|
|
if (e->from == p->game->battlefield){
|
|
//--
|
|
MTGGameZone * z = card->controller()->game->hand;
|
|
int nbcards = z->nb_cards;
|
|
//check my battlefield and opponents
|
|
for (int j = 0; j < nbcards; ++j){
|
|
MTGCardInstance * c = z->cards[j];
|
|
if (c->has(Constants::AFFINITYISLAND)){
|
|
c->getManaCost()->add(0,1);
|
|
}
|
|
}
|
|
//--
|
|
}
|
|
}
|
|
//---------
|
|
}
|
|
}//this bracket ends check for islands
|
|
//----------------------------------------
|
|
//----forest
|
|
if (card && card->hasSubtype("forest")){
|
|
int ok = 0;
|
|
for (int i = 0; i < 2 ; i++){
|
|
Player * p = game->players[i];
|
|
if (e->to == p->game->battlefield) ok = 17;//island enters play in your battlefield
|
|
|
|
if (e->to == p->game->graveyard || e->to == p->game->hand || e->to == p->game->library || e->to == p->game->exile || e->to == p->game->stack || e->to == p->opponent()->game->battlefield) ok = 18;//artifact leaves play
|
|
//---------above are the triggers "to" markers...
|
|
if(ok == 17){//enters play from anywhere
|
|
if (e->from == p->game->graveyard || e->from == p->game->hand || e->from == p->game->library || e->from == p->game->exile || e->from == p->game->stack || e->from == p->opponent()->game->battlefield || e->from == p->game->temp){
|
|
//--redux effect
|
|
MTGGameZone * z = card->controller()->game->hand;
|
|
int nbcards = z->nb_cards;
|
|
for (int j = 0; j < nbcards; ++j){
|
|
MTGCardInstance * c = z->cards[j];
|
|
if (c->has(Constants::AFFINITYFOREST)){
|
|
c->getManaCost()->remove(0,1);//one less colorless to cast
|
|
}
|
|
}//--end of redux bracket
|
|
}
|
|
}
|
|
//---------
|
|
if(ok == 18){//leave play from your battlefield
|
|
if (e->from == p->game->battlefield){
|
|
//--
|
|
MTGGameZone * z = card->controller()->game->hand;
|
|
int nbcards = z->nb_cards;
|
|
//check my battlefield and opponents
|
|
for (int j = 0; j < nbcards; ++j){
|
|
MTGCardInstance * c = z->cards[j];
|
|
if (c->has(Constants::AFFINITYFOREST)){
|
|
c->getManaCost()->add(0,1);
|
|
}
|
|
}
|
|
//--
|
|
}
|
|
}
|
|
//---------
|
|
}
|
|
}//this bracket ends check for forest
|
|
//----------------------------------------
|
|
//----greencreatureaffinity
|
|
if (card && card->hasSubtype("creature") && card->hasColor(1)){
|
|
int ok = 0;
|
|
for (int i = 0; i < 2 ; i++){
|
|
Player * p = game->players[i];
|
|
if (e->to == p->game->battlefield) ok = 19;//island enters play in your battlefield
|
|
|
|
if (e->to == p->game->graveyard || e->to == p->game->hand || e->to == p->game->library || e->to == p->game->exile || e->to == p->game->stack || e->to == p->opponent()->game->battlefield) ok = 20;//artifact leaves play
|
|
//---------above are the triggers "to" markers...
|
|
if(ok == 19){//enters play from anywhere
|
|
if (e->from == p->game->graveyard || e->from == p->game->hand || e->from == p->game->library || e->from == p->game->exile || e->from == p->game->stack || e->from == p->opponent()->game->battlefield || e->from == p->game->temp){
|
|
//--redux effect
|
|
MTGGameZone * z = card->controller()->game->hand;
|
|
int nbcards = z->nb_cards;
|
|
for (int j = 0; j < nbcards; ++j){
|
|
MTGCardInstance * c = z->cards[j];
|
|
if (c->has(Constants::AFFINITYGREENCREATURES)){
|
|
c->getManaCost()->remove(1,1);//one less colorless to cast
|
|
}
|
|
}//--end of redux bracket
|
|
}
|
|
}
|
|
//---------
|
|
if(ok == 20){//leave play from your battlefield
|
|
if (e->from == p->game->battlefield){
|
|
//--
|
|
MTGGameZone * z = card->controller()->game->hand;
|
|
int nbcards = z->nb_cards;
|
|
//check my battlefield and opponents
|
|
for (int j = 0; j < nbcards; ++j){
|
|
MTGCardInstance * c = z->cards[j];
|
|
if (c->has(Constants::AFFINITYGREENCREATURES)){
|
|
c->getManaCost()->add(1,1);
|
|
}
|
|
}
|
|
//--
|
|
}
|
|
}
|
|
//---------
|
|
}
|
|
}//this bracket ends check for greencreatures
|
|
//----------------------------------------
|
|
}
|
|
return 0;
|
|
}
|
|
ostream& MTGAffinityRule::toString(ostream& out) const
|
|
{
|
|
out << "MTGAffinityRule ::: (";
|
|
return MTGAbility::toString(out) << ")";
|
|
}
|
|
int MTGAffinityRule::testDestroy(){return 0;}
|
|
MTGAffinityRule * MTGAffinityRule::clone() const{
|
|
MTGAffinityRule * a = NEW MTGAffinityRule(*this);
|
|
a->isClone = 1;
|
|
return a;
|
|
}
|
|
//-------------------------------------------------------------------
|
|
MTGTokensCleanup::MTGTokensCleanup(int _id):MTGAbility(_id, NULL){}
|
|
|
|
int MTGTokensCleanup::receiveEvent(WEvent * e){
|
|
if (WEventZoneChange* event = dynamic_cast<WEventZoneChange*>(e)){
|
|
if (!event->card->isToken) return 0;
|
|
if (event->to == game->players[0]->game->inPlay || event->to == game->players[1]->game->inPlay) return 0;
|
|
if (event->to == game->players[0]->game->garbage || event->to == game->players[1]->game->garbage) return 0;
|
|
list.push_back(event->card);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int MTGTokensCleanup::testDestroy(){return 0;}
|
|
|
|
void MTGTokensCleanup::Update(float dt){
|
|
MTGAbility::Update(dt);
|
|
for(size_t i= 0; i < list.size(); ++i){
|
|
MTGCardInstance * c = list[i];
|
|
c->controller()->game->putInZone(c,c->currentZone, c->controller()->game->garbage);
|
|
}
|
|
list.clear();
|
|
}
|
|
|
|
MTGTokensCleanup * MTGTokensCleanup::clone() const{
|
|
MTGTokensCleanup * a = NEW MTGTokensCleanup(*this);
|
|
a->isClone = 1;
|
|
return a;
|
|
}
|
|
|
|
/* Legend Rule */
|
|
MTGLegendRule::MTGLegendRule(int _id):ListMaintainerAbility(_id){};
|
|
|
|
int MTGLegendRule::canBeInList(MTGCardInstance * card){
|
|
if (card->hasType(Subtypes::TYPE_LEGENDARY) && game->isInPlay(card)){
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int MTGLegendRule::added(MTGCardInstance * card){
|
|
map<MTGCardInstance *,bool>::iterator it;
|
|
int destroy = 0;
|
|
for ( it=cards.begin() ; it != cards.end(); it++ ){
|
|
MTGCardInstance * comparison = (*it).first;
|
|
if (comparison != card && !(comparison->getName().compare(card->getName()))){
|
|
comparison->controller()->game->putInGraveyard(comparison);
|
|
destroy = 1;
|
|
}
|
|
}
|
|
if (destroy){
|
|
card->owner->game->putInGraveyard(card);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
int MTGLegendRule::removed(MTGCardInstance * card){return 0;}
|
|
|
|
int MTGLegendRule::testDestroy(){return 0;}
|
|
|
|
ostream& MTGLegendRule::toString(ostream& out) const
|
|
{
|
|
return out << "MTGLegendRule :::";
|
|
}
|
|
MTGLegendRule * MTGLegendRule::clone() const{
|
|
MTGLegendRule * a = NEW MTGLegendRule(*this);
|
|
a->isClone = 1;
|
|
return a;
|
|
}
|
|
|
|
/* Lifelink */
|
|
MTGLifelinkRule::MTGLifelinkRule(int _id):MTGAbility(_id,NULL){};
|
|
|
|
int MTGLifelinkRule::receiveEvent(WEvent * event){
|
|
if (event->type == WEvent::DAMAGE){
|
|
WEventDamage * e = (WEventDamage *) event;
|
|
Damage * d = e->damage;
|
|
MTGCardInstance * card = d->source;
|
|
if (d->damage>0 && card && card->basicAbilities[Constants::LIFELINK]){
|
|
card->controller()->life+= d->damage;
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int MTGLifelinkRule::testDestroy(){return 0;}
|
|
|
|
ostream& MTGLifelinkRule::toString(ostream& out) const
|
|
{
|
|
out << "MTGLifelinkRule ::: (";
|
|
return MTGAbility::toString(out) << ")";
|
|
}
|
|
MTGLifelinkRule * MTGLifelinkRule::clone() const{
|
|
MTGLifelinkRule * a = NEW MTGLifelinkRule(*this);
|
|
a->isClone = 1;
|
|
return a;
|
|
}
|
|
|
|
|
|
/* Deathtouch */
|
|
MTGDeathtouchRule::MTGDeathtouchRule(int _id):MTGAbility(_id,NULL){};
|
|
|
|
int MTGDeathtouchRule::receiveEvent(WEvent * event){
|
|
if (event->type == WEvent::DAMAGE){
|
|
WEventDamage * e = (WEventDamage *) event;
|
|
|
|
Damage * d = e->damage;
|
|
if (d->damage <= 0) return 0;
|
|
|
|
MTGCardInstance * card = d->source;
|
|
if (!card) return 0;
|
|
|
|
if (d->target->type_as_damageable != DAMAGEABLE_MTGCARDINSTANCE) return 0;
|
|
MTGCardInstance * _target = (MTGCardInstance *) (d->target);
|
|
|
|
if (card->basicAbilities[Constants::DEATHTOUCH]){
|
|
_target->destroy();
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int MTGDeathtouchRule::testDestroy(){return 0;}
|
|
|
|
|
|
MTGDeathtouchRule * MTGDeathtouchRule::clone() const{
|
|
MTGDeathtouchRule * a = NEW MTGDeathtouchRule(*this);
|
|
a->isClone = 1;
|
|
return a;
|
|
}
|