Improved implementation for isCommander and RingBearer card status (now they are no longer basic abilities but inner card properties in order to avoid conflicts with abilitiy modificators), added a white border on commanders to highlight them during match in the various game zones.

This commit is contained in:
Vittorio Alfieri
2023-07-01 16:28:19 +02:00
parent 6731251d07
commit 617ce45dbc
14 changed files with 101 additions and 49 deletions

View File

@@ -97,6 +97,8 @@ public:
bool turningOver;
bool isMorphed;
int isFlipped;
int isCommander;
int isRingBearer;
bool isDefeated;
string MeldedFrom;
bool isPhased;

View File

@@ -291,7 +291,7 @@ class Constants
HASOTHERKICKER = 163,
PARTNER = 164,
CANBECOMMANDER = 165,
ISCOMMANDER = 166,
POISONFOURTOXIC = 166,
THREEBLOCKERS = 167,
HANDDEATH = 168,
INPLAYDEATH = 169,
@@ -319,7 +319,7 @@ class Constants
PERPETUALDEATHTOUCH = 191,
NONCOMBATVIGOR = 192,
NOMOVETRIGGER = 193,
WASCOMMANDER = 194,
CANLOYALTYTWICE = 194,
SHOWOPPONENTHAND = 195,
SHOWCONTROLLERHAND = 196,
HASREPLICATE = 197,
@@ -354,16 +354,13 @@ class Constants
AFFINITYGRAVECREATURES = 226,
AFFINITYATTACKINGCREATURES = 227,
AFFINITYGRAVEINSTSORC = 228,
CANLOYALTYTWICE = 229,
POISONFOURTOXIC = 230,
POISONFIVETOXIC = 231,
POISONSIXTOXIC = 232,
POISONSEVENTOXIC = 233,
POISONEIGHTTOXIC = 234,
POISONNINETOXIC = 235,
POISONTENTOXIC = 236,
RINGBEARER = 237,
NB_BASIC_ABILITIES = 238,
POISONFIVETOXIC = 229,
POISONSIXTOXIC = 230,
POISONSEVENTOXIC = 231,
POISONEIGHTTOXIC = 232,
POISONNINETOXIC = 233,
POISONTENTOXIC = 234,
NB_BASIC_ABILITIES = 235,
RARITY_S = 'S', //Special Rarity
RARITY_M = 'M', //Mythics

View File

@@ -2750,7 +2750,7 @@ MTGCardInstance * AIPlayerBaka::FindCardToPlay(ManaCost * pMana, const char * ty
CardDescriptor cd;
cd.init();
if(!strcmp(type,"commander")) //Added to allow the casting priority for commanders
cd.basicAbilities[Constants::ISCOMMANDER] = 1;
cd.isCommander = 1;
else if(strcmp(type,"*")) //Added to allow the wildcard in casting priority
cd.setType(type);
card = NULL;

View File

@@ -1081,13 +1081,13 @@ int AARingBearerChosen::resolve()
{
MTGCardInstance * currentBearer = NULL;
for (int j = _target->controller()->game->inPlay->nb_cards - 1; j >= 0; --j){
if(_target->controller()->game->inPlay->cards[j]->basicAbilities[Constants::RINGBEARER] == 1){
if(_target->controller()->game->inPlay->cards[j]->isRingBearer == 1){
currentBearer = _target->controller()->game->inPlay->cards[j];
_target->controller()->game->inPlay->cards[j]->basicAbilities[Constants::RINGBEARER] = 0;
_target->controller()->game->inPlay->cards[j]->isRingBearer = 0;
break;
}
}
_target->basicAbilities[Constants::RINGBEARER] = 1;
_target->isRingBearer = 1;
bool bearerChanged = false;
if(currentBearer == NULL || currentBearer != _target){
for (int j = _target->controller()->game->inPlay->nb_cards - 1; j >= 0; --j){
@@ -5147,12 +5147,8 @@ int AAFlip::resolve()
}
SAFE_DELETE(myOrig);
} else{
if(_target->has(Constants::ISCOMMANDER)){
_target->basicAbilities[Constants::WASCOMMANDER] = 1;
_target->basicAbilities[Constants::ISCOMMANDER] = 0;
}
for(size_t i = 0; i < _target->basicAbilities.size(); i++) {
if(i != Constants::WASCOMMANDER && i != Constants::GAINEDEXILEDEATH && i != Constants::GAINEDHANDDEATH && i != Constants::GAINEDDOUBLEFACEDEATH &&
if(i != Constants::GAINEDEXILEDEATH && i != Constants::GAINEDHANDDEATH && i != Constants::GAINEDDOUBLEFACEDEATH &&
i != Constants::DUNGEONCOMPLETED && i != Constants::PERPETUALDEATHTOUCH && i != Constants::PERPETUALLIFELINK)
_target->basicAbilities[i] = myFlip->model->data->basicAbilities[i]; // Try to keep the original special abilities on card flip.
}

View File

@@ -393,6 +393,16 @@ MTGCardInstance * CardDescriptor::match(MTGCardInstance * card)
match = NULL;
}
if ((isCommander == -1 && card->isCommander > 0) || (isCommander == 1 && card->isCommander == 0))
{
match = NULL;
}
if ((isRingBearer == -1 && card->isRingBearer > 0) || (isRingBearer == 1 && card->isRingBearer == 0))
{
match = NULL;
}
if ((tapped == -1 && card->isTapped()) || (tapped == 1 && !card->isTapped()))
{
match = NULL;

View File

@@ -257,9 +257,11 @@ void CardGui::Render()
if(game)
{
if(card->has(Constants::PAYZERO) ||
((card->has(Constants::CANPLAYFROMGRAVEYARD) || card->has(Constants::TEMPFLASHBACK) || card->getManaCost()->getFlashback() || card->getManaCost()->getRetrace()) && game->isInGrave(card)) ||
(((card->has(Constants::FORETELL) && card->foretellTurn > -1 && game->turn > card->foretellTurn) || card->has(Constants::CANPLAYFROMEXILE)) && game->isInExile(card)))
fakeborder->SetColor(ARGB((int)(actA),7,235,7));//green border
((card->has(Constants::CANPLAYFROMGRAVEYARD) || card->has(Constants::TEMPFLASHBACK) || card->getManaCost()->getFlashback() || card->getManaCost()->getRetrace()) && game->isInGrave(card)) ||
(((card->has(Constants::FORETELL) && card->foretellTurn > -1 && game->turn > card->foretellTurn) || card->has(Constants::CANPLAYFROMEXILE)) && game->isInExile(card)))
fakeborder->SetColor(ARGB((int)(actA),7,235,7)); //green border
else if(card->isCommander)
fakeborder->SetColor(ARGB((int)(actA),255,255,255)); //white border for commanders
else
fakeborder->SetColor(ARGB((int)(actA),15,15,15));
}
@@ -1616,6 +1618,30 @@ bool CardGui::FilterCard(MTGCard * _card,string filter)
cd.isFlipped = 1;
}
}
//Card is commander
else if (attribute.find("iscommander") != string::npos)
{
if (minus)
{
cd.isCommander = -1;
}
else
{
cd.isCommander = 1;
}
}
//Card is Ring bearer
else if (attribute.find("ringbearer") != string::npos)
{
if (minus)
{
cd.isRingBearer = -1;
}
else
{
cd.isRingBearer = 1;
}
}
//Has x in cost
else if (attribute.find("hasx") != string::npos)
{

View File

@@ -266,7 +266,7 @@ int Damage::resolve()
else
{
((MTGCardInstance*)source)->damageToOpponent += damage;
if(((MTGCardInstance*)source)->basicAbilities[Constants::ISCOMMANDER])
if(((MTGCardInstance*)source)->isCommander > 0)
((MTGCardInstance*)source)->damageInflictedAsCommander += damage;
}
target->lifeLostThisTurn += damage;

View File

@@ -6165,12 +6165,8 @@ int AbilityFactory::getAbilities(vector<MTGAbility *> * v, Spell * spell, MTGCar
card->types.clear();
string cre = "Creature";
card->setType(cre.c_str());
if(card->has(Constants::ISCOMMANDER)){
card->basicAbilities[Constants::WASCOMMANDER] = 1;
card->basicAbilities[Constants::ISCOMMANDER] = 0;
}
for(size_t i = 0; i < card->basicAbilities.size(); i++) {
if(i != Constants::WASCOMMANDER && i != Constants::GAINEDEXILEDEATH && i != Constants::GAINEDHANDDEATH && i != Constants::GAINEDDOUBLEFACEDEATH &&
if(i != Constants::GAINEDEXILEDEATH && i != Constants::GAINEDHANDDEATH && i != Constants::GAINEDDOUBLEFACEDEATH &&
i != Constants::DUNGEONCOMPLETED && i != Constants::PERPETUALDEATHTOUCH && i != Constants::PERPETUALLIFELINK)
card->basicAbilities[i] = 0; // Try to keep the original special abilities on card morph.
}
@@ -6186,8 +6182,6 @@ int AbilityFactory::getAbilities(vector<MTGAbility *> * v, Spell * spell, MTGCar
card->types = card->model->data->types;
card->colors = card->model->data->colors;
card->basicAbilities |= card->model->data->basicAbilities;
card->basicAbilities[Constants::ISCOMMANDER] = card->basicAbilities[Constants::WASCOMMANDER];
card->basicAbilities[Constants::WASCOMMANDER] = 0;
ManaCost * copyCost = card->model->data->getManaCost();
card->getManaCost()->copy(copyCost);
magicText = card->model->data->magicText;

View File

@@ -238,6 +238,8 @@ void MTGCardInstance::initMTGCI()
isMorphed = false;
MeldedFrom = "";
isFlipped = 0;
isCommander = 0;
isRingBearer = 0;
isDefeated = false;
isPhased = false;
isCascaded = false;

View File

@@ -197,7 +197,7 @@ const char* Constants::MTGBasicAbilities[] = {
"hasotherkicker", //Kicker cost is expressed with "other" keyword (eg. not mana kicker such as life and/or tap a creature)
"partner", //Has partner ability
"canbecommander", //Can be a commander (eg. some planeswalkers can)
"iscommander", //It's the current commander
"poisonfourtoxic", // Card has toxic 4
"threeblockers", //It can be blocked just by 3 creatures or more.
"handdeath", //It goes in hand after death.
"inplaydeath", //It goes back in play untapped after death.
@@ -225,7 +225,7 @@ const char* Constants::MTGBasicAbilities[] = {
"perpetualdeathtouch", //It gains deathtouch perpetually
"noncombatvigor", //instead of taking non-combat damage the source gains +1/+1 counters (e.g. Stormwild Capridor)
"nomovetrigger", //no trigger when playing these cards (e.g. fake ability cards such as Davriel Conditions, Davriel Offers, Annihilation Rooms)
"wascommander", //It was the current commander (e.g. after it flipped or morphed)
"canloyaltytwice", //Planeswalker can activate its loyalty abilities twice in a turn (e.g. "Urza, Planeswalker").
"showopponenthand", //opponent plays with his hand revealed.
"showcontrollerhand", //controller plays with his hand revealed.
"hasreplicate", //Kicker cost is a replicate cost (e.g. "Vacuumelt")
@@ -260,15 +260,12 @@ const char* Constants::MTGBasicAbilities[] = {
"affinitygravecreatures", //Cost 1 less for each creature in your graveyard.
"affinityattackingcreatures", //Cost 1 less for each attacking creature in your battlefield.
"affinitygraveinstsorc", //Cost 1 less for each instant or sorcery in your graveyard.
"canloyaltytwice", //Planeswalker can activate its loyalty abilities twice in a turn (e.g. "Urza, Planeswalker").
"poisonfourtoxic", // Card has toxic 4
"poisonfivetoxic", // Card has toxic 5
"poisonsixtoxic", // Card has toxic 6
"poisonseventoxic", // Card has toxic 7
"poisoneighttoxic", // Card has toxic 8
"poisonninetoxic", // Card has toxic 9
"poisontentoxic", // Card has toxic 10
"ringbearer" // The creature is The Ring bearer.
"poisontentoxic" // Card has toxic 10
};
map<string,int> Constants::MTGBasicAbilitiesMap;

View File

@@ -61,7 +61,7 @@ void MTGPlayerCards::initDeck(MTGDeck * deck)
{
MTGCardInstance * newCard = NEW MTGCardInstance(card, this);
//the card is marked as commander ad added to library.
newCard->basicAbilities[Constants::ISCOMMANDER] = 1;
newCard->isCommander = 1;
library->addCard(newCard);
}
}
@@ -946,7 +946,7 @@ MTGCardInstance * MTGGameZone::removeCard(MTGCardInstance * card, int createCopy
copy->storedSourceCard = card->storedSourceCard;
copy->lastController = card->controller();
copy->previousController = card->controller();
copy->basicAbilities[Constants::ISCOMMANDER] = (card->basicAbilities[Constants::ISCOMMANDER] | card->basicAbilities[Constants::WASCOMMANDER]);
copy->isCommander = card->isCommander;
copy->basicAbilities[Constants::GAINEDEXILEDEATH] = card->basicAbilities[Constants::GAINEDEXILEDEATH];
copy->basicAbilities[Constants::GAINEDHANDDEATH] = card->basicAbilities[Constants::GAINEDHANDDEATH];
copy->basicAbilities[Constants::GAINEDDOUBLEFACEDEATH] = card->basicAbilities[Constants::GAINEDDOUBLEFACEDEATH];

View File

@@ -1561,18 +1561,18 @@ int MTGMorphCostRule::reactToClick(MTGCardInstance * card)
card->getManaCost()->setManaUsedToCast(NEW ManaCost());
card->getManaCost()->getManaUsedToCast()->copy(spellCost);
}
int iscommander = card->has(Constants::ISCOMMANDER);
card->basicAbilities[Constants::ISCOMMANDER] = 0;//Morph is not a commander on stack
int iscommander = card->isCommander;
card->isCommander = 0;//Morph is not a commander on stack
MTGCardInstance * copy = player->game->putInZone(card, card->currentZone, player->game->stack);
if(iscommander > 0)
copy->basicAbilities[Constants::ISCOMMANDER] = 1;
copy->isCommander = 1;
copy->getManaCost()->resetCosts();//Morph has no ManaCost on stack
copy->setColor(0,1);
copy->types.clear();
string cre = "Creature";
copy->setType(cre.c_str());
for(size_t i = 0; i < copy->basicAbilities.size(); i++) {
if(i != Constants::ISCOMMANDER && i != Constants::GAINEDEXILEDEATH && i != Constants::GAINEDHANDDEATH && i != Constants::GAINEDDOUBLEFACEDEATH &&
if(i != Constants::GAINEDEXILEDEATH && i != Constants::GAINEDHANDDEATH && i != Constants::GAINEDDOUBLEFACEDEATH &&
i != Constants::DUNGEONCOMPLETED && i != Constants::PERPETUALDEATHTOUCH && i != Constants::PERPETUALLIFELINK)
copy->basicAbilities[i] = 0; // Try to keep the original special abilities on card morph.
}

View File

@@ -713,6 +713,30 @@ TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInsta
cd->isFlipped = 1;
}
}
//Card is commander
else if (attribute.find("iscommander") != string::npos)
{
if (minus)
{
cd->isCommander = -1;
}
else
{
cd->isCommander = 1;
}
}
//Card is Ring bearer
else if (attribute.find("ringbearer") != string::npos)
{
if (minus)
{
cd->isRingBearer = -1;
}
else
{
cd->isRingBearer = 1;
}
}
//Has x in cost
else if (attribute.find("hasx") != string::npos)
{

View File

@@ -514,23 +514,23 @@ void WParsedInt::init(string s, Spell * spell, MTGCardInstance * card)
MTGGameZone * zones[] = { p->game->inPlay, p->game->graveyard, p->game->hand, p->game->library, p->game->exile, p->game->commandzone, p->game->sideboard };
for(int i = 0; i < 7; i++){
for(int j = 0; j < zones[i]->nb_cards; j++){
if(zones[i]->cards[j]->has(Constants::ISCOMMANDER) && zones[i]->cards[j]->hasColor(Constants::MTG_COLOR_RED) && !redFound){
if(zones[i]->cards[j]->isCommander && zones[i]->cards[j]->hasColor(Constants::MTG_COLOR_RED) && !redFound){
intValue++;
redFound = true;
}
if(zones[i]->cards[j]->has(Constants::ISCOMMANDER) && zones[i]->cards[j]->hasColor(Constants::MTG_COLOR_BLACK) && !blackFound){
if(zones[i]->cards[j]->isCommander && zones[i]->cards[j]->hasColor(Constants::MTG_COLOR_BLACK) && !blackFound){
intValue++;
blackFound = true;
}
if(zones[i]->cards[j]->has(Constants::ISCOMMANDER) && zones[i]->cards[j]->hasColor(Constants::MTG_COLOR_BLUE) && !blueFound){
if(zones[i]->cards[j]->isCommander && zones[i]->cards[j]->hasColor(Constants::MTG_COLOR_BLUE) && !blueFound){
intValue++;
blueFound = true;
}
if(zones[i]->cards[j]->has(Constants::ISCOMMANDER) && zones[i]->cards[j]->hasColor(Constants::MTG_COLOR_GREEN) && !greenFound){
if(zones[i]->cards[j]->isCommander && zones[i]->cards[j]->hasColor(Constants::MTG_COLOR_GREEN) && !greenFound){
intValue++;
greenFound = true;
}
if(zones[i]->cards[j]->has(Constants::ISCOMMANDER) && zones[i]->cards[j]->hasColor(Constants::MTG_COLOR_WHITE) && !whiteFound){
if(zones[i]->cards[j]->isCommander && zones[i]->cards[j]->hasColor(Constants::MTG_COLOR_WHITE) && !whiteFound){
intValue++;
whiteFound = true;
}
@@ -1646,6 +1646,10 @@ void WParsedInt::extendedParse(string s, Spell * spell, MTGCardInstance * card)
{
intValue = (s == "pringtemptations")?card->controller()->ringTemptations:card->controller()->opponent()->ringTemptations;
}
else if (s == "iscommander" || s == "ringbearer") // Return 1 if card is the commander -- Return 1 if card is the Ring bearer
{
intValue = (s == "iscommander")?card->isCommander:card->isRingBearer;
}
else if(!intValue)//found nothing, try parsing a atoi
{
intValue = atoi(s.c_str());