From 4e9d4bfaf66a693a4b6535f19383629783f3f8c0 Mon Sep 17 00:00:00 2001 From: zethfoxster Date: Sun, 17 Jul 2016 02:19:58 -0400 Subject: [PATCH 1/6] minor changes to ai --- projects/mtg/src/AIPlayerBaka.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/projects/mtg/src/AIPlayerBaka.cpp b/projects/mtg/src/AIPlayerBaka.cpp index a4d437c08..c7f679fb3 100644 --- a/projects/mtg/src/AIPlayerBaka.cpp +++ b/projects/mtg/src/AIPlayerBaka.cpp @@ -62,8 +62,9 @@ int OrderedAIAction::getEfficiency(AADamager * aad) // I can't remember as I type this in which condition we use one or the other for this function, if you find out please replace this comment int OrderedAIAction::getEfficiency() { - if (efficiency > -1) - return efficiency; + //commented out the below becuase I noticed it prevented ai from updating the given abilities with new eff %. + //if (efficiency > -1) + // return efficiency; if (!ability) return 0; GameObserver * g = owner->getObserver(); @@ -335,6 +336,16 @@ int OrderedAIAction::getEfficiency() } case MTGAbility::MANA_PRODUCER://only way to hit this condition is nested manaabilities, ai skips manaproducers by defualt when finding an ability to use. { + AManaProducer * manamaker = dynamic_cast(a); + GenericActivatedAbility * GAA = dynamic_cast(ability); + AForeach * forMana = dynamic_cast(GAA->ability); + if (manamaker && forMana) + { + int outPut = forMana->checkActivation(); + if (ability->getCost() && outPut > int(ability->getCost()->getConvertedCost() +1) && currentPhase == MTG_PHASE_FIRSTMAIN && ability->source->controller()->game->hand->nb_cards > 1) + efficiency = 90;//might be a bit random, but better than never using them. + } + else efficiency = 0; break; } @@ -635,6 +646,10 @@ int OrderedAIAction::getEfficiency() { efficiency += 55; } + else if (dynamic_cast(a)) + { + efficiency += 55; + } SAFE_DELETE(transAbility); return efficiency; } From 9e73dc9c00e9e123bf5cc0747be5c70a9c824784 Mon Sep 17 00:00:00 2001 From: zethfoxster Date: Sun, 17 Jul 2016 22:24:53 -0400 Subject: [PATCH 2/6] add support for repeater deplete cards. Scalpelexis Sphinx's Tutelage Grindstone normally I aim for much bigger card groups, but this was requested by one of the only 2 active members we have on the forum. I'll have the card code for these cards ready when I code eldrich moon set. to use, use it like any normal depelte except add name color to the front, name deplete:4 targetsZone(player) this will repeat this until the player depletes cards that dont have atleast 2 with the same name. color deplete:2 target(player) this will continue to deplete until the player depletes a set of cards that dont share a color with each other lands not included when checking colors. enjoy. --- projects/mtg/include/AllAbilities.h | 4 +- projects/mtg/src/AllAbilities.cpp | 124 ++++++++++++++++++++++++++-- projects/mtg/src/MTGAbility.cpp | 16 +++- 3 files changed, 133 insertions(+), 11 deletions(-) diff --git a/projects/mtg/include/AllAbilities.h b/projects/mtg/include/AllAbilities.h index 5681d7994..e1d7fb45d 100644 --- a/projects/mtg/include/AllAbilities.h +++ b/projects/mtg/include/AllAbilities.h @@ -6195,8 +6195,10 @@ class AADepleter: public ActivatedAbilityTP public: string nbcardsStr; bool toexile; + bool namerepeat; + bool colorrepeat; AADepleter(GameObserver* observer, int _id, MTGCardInstance * card, Targetable * _target,string nbcardsStr, ManaCost * _cost = NULL, - int who = TargetChooser::UNSET, bool toexile = false); + int who = TargetChooser::UNSET, bool toexile = false, bool colorrepeat = false, bool namerepeat = false); int resolve(); const string getMenuText(); AADepleter * clone() const; diff --git a/projects/mtg/src/AllAbilities.cpp b/projects/mtg/src/AllAbilities.cpp index e5ced563c..4cf600791 100644 --- a/projects/mtg/src/AllAbilities.cpp +++ b/projects/mtg/src/AllAbilities.cpp @@ -1099,8 +1099,8 @@ AADamager * AADamager::clone() const //AADepleter -AADepleter::AADepleter(GameObserver* observer, int _id, MTGCardInstance * card, Targetable * _target,string nbcardsStr, ManaCost * _cost, int who, bool toexile) : - ActivatedAbilityTP(observer, _id, card, _target, _cost, who),nbcardsStr(nbcardsStr),toexile(toexile) +AADepleter::AADepleter(GameObserver* observer, int _id, MTGCardInstance * card, Targetable * _target,string nbcardsStr, ManaCost * _cost, int who, bool toexile, bool colorrepeat, bool namerepeat) : + ActivatedAbilityTP(observer, _id, card, _target, _cost, who),nbcardsStr(nbcardsStr),toexile(toexile), colorrepeat(colorrepeat), namerepeat(namerepeat) { } int AADepleter::resolve() @@ -1110,16 +1110,124 @@ AADepleter::AADepleter(GameObserver* observer, int _id, MTGCardInstance * card, { WParsedInt numCards(nbcardsStr, NULL, source); MTGLibrary * library = player->game->library; - for (int i = 0; i < numCards.getValue(); i++) + if (colorrepeat && library->nb_cards) { - if (library->nb_cards) + bool repeating = false; + do { - if(toexile) - player->game->putInZone(library->cards[library->nb_cards - 1], library, player->game->exile); - else - player->game->putInZone(library->cards[library->nb_cards - 1], library, player->game->graveyard); + repeating = false; + vectorfound; + for (int i = 0; i < numCards.getValue(); i++) + { + if (library->nb_cards) + { + if(library->nb_cards > i) + found.push_back(library->cards[(library->nb_cards - 1) - i]); + } + } + + for (vector::iterator it = found.begin(); it != found.end(); it++) + { + MTGCardInstance * cardFirst = *it; + if (cardFirst->isLand()) + continue; + for (int i = Constants::MTG_COLOR_GREEN; i <= Constants::MTG_COLOR_WHITE; ++i) + { + if (cardFirst->hasColor(i)) + { + for (vector::iterator secondit = found.begin(); secondit != found.end(); secondit++) + { + MTGCardInstance * cardSecond = *secondit; + if (cardSecond->isLand()) + continue; + if (cardSecond->hasColor(i) && cardFirst != cardSecond) + { + repeating = true; + } + } + } + } + } + + do + { + if (found.size()) + { + MTGCardInstance * toMove = found.back(); + if (toMove) + { + if (toexile) + player->game->putInZone(toMove, library, player->game->exile); + else + player->game->putInZone(toMove, library, player->game->graveyard); + found.pop_back(); + } + } + } while (found.size()); + + } while (repeating); + } + else if (namerepeat && library->nb_cards) + { + bool repeating = false; + do + { + repeating = false; + vectorfound; + for (int i = 0; i < numCards.getValue(); i++) + { + if (library->nb_cards) + { + if (library->nb_cards > i) + found.push_back(library->cards[(library->nb_cards - 1) - i]); + } + } + + for (vector::iterator it = found.begin(); it != found.end(); it++) + { + MTGCardInstance * cardFirst = *it; + for (vector::iterator secondit = found.begin(); secondit != found.end(); secondit++) + { + MTGCardInstance * cardSecond = *secondit; + if (cardSecond->name == cardFirst->name && cardFirst != cardSecond) + { + repeating = true; + } + } + + } + + do + { + if (found.size()) + { + MTGCardInstance * toMove = found.back(); + if (toMove) + { + if (toexile) + player->game->putInZone(toMove, library, player->game->exile); + else + player->game->putInZone(toMove, library, player->game->graveyard); + found.pop_back(); + } + } + } while (found.size()); + } while (repeating); + } + else + { + for (int i = 0; i < numCards.getValue(); i++) + { + if (library->nb_cards) + { + if (toexile) + player->game->putInZone(library->cards[library->nb_cards - 1], library, player->game->exile); + else + player->game->putInZone(library->cards[library->nb_cards - 1], library, player->game->graveyard); + } } } + } return 1; } diff --git a/projects/mtg/src/MTGAbility.cpp b/projects/mtg/src/MTGAbility.cpp index 005b028c6..ea7def80b 100644 --- a/projects/mtg/src/MTGAbility.cpp +++ b/projects/mtg/src/MTGAbility.cpp @@ -2820,8 +2820,14 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG vector splitDeplete = parseBetween(s, "deplete:", " ", false); if (splitDeplete.size()) { + bool namerepeat = false; + bool colorrepeat = false; + if (splitDeplete[0].find("color") != string::npos) + colorrepeat = true; + if (splitDeplete[0].find("name") != string::npos) + namerepeat = true; Targetable * t = spell ? spell->getNextTarget() : NULL; - MTGAbility * a = NEW AADepleter(observer, id, card, t , splitDeplete[1], NULL, who, false); + MTGAbility * a = NEW AADepleter(observer, id, card, t , splitDeplete[1], NULL, who, false, colorrepeat, namerepeat); a->oneShot = 1; return a; } @@ -2830,8 +2836,14 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG vector splitIngest = parseBetween(s, "ingest:", " ", false); if (splitIngest.size()) { + bool namerepeat = false; + bool colorrepeat = false; + if (splitIngest[0].find("coloringest") != string::npos) + colorrepeat = true; + if (splitIngest[0].find("nameingest") != string::npos) + namerepeat = true; Targetable * t = spell ? spell->getNextTarget() : NULL; - MTGAbility * a = NEW AADepleter(observer, id, card, t , splitIngest[1], NULL, who, true); + MTGAbility * a = NEW AADepleter(observer, id, card, t , splitIngest[1], NULL, who, true, colorrepeat, namerepeat); a->oneShot = 1; return a; } From bfaaf7d8936052a5e34b01a4c5cb2b4e70e13855 Mon Sep 17 00:00:00 2001 From: zethfoxster Date: Sun, 17 Jul 2016 22:37:32 -0400 Subject: [PATCH 3/6] travis int order --- projects/mtg/include/AllAbilities.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/mtg/include/AllAbilities.h b/projects/mtg/include/AllAbilities.h index e1d7fb45d..bbc45f076 100644 --- a/projects/mtg/include/AllAbilities.h +++ b/projects/mtg/include/AllAbilities.h @@ -6195,8 +6195,8 @@ class AADepleter: public ActivatedAbilityTP public: string nbcardsStr; bool toexile; - bool namerepeat; bool colorrepeat; + bool namerepeat; AADepleter(GameObserver* observer, int _id, MTGCardInstance * card, Targetable * _target,string nbcardsStr, ManaCost * _cost = NULL, int who = TargetChooser::UNSET, bool toexile = false, bool colorrepeat = false, bool namerepeat = false); int resolve(); From 37fd0ebbd28ec4dd1bc278bd8684efb2a3f74fa7 Mon Sep 17 00:00:00 2001 From: zethfoxster Date: Mon, 18 Jul 2016 19:02:03 -0400 Subject: [PATCH 4/6] readded the "fakebar" size adjustments based on string lengths. in debug there is a strange line drawn sometimes on screen, like the buttons on main screen, this is not present in release builds, I'm guessing its some kind of debug related thing with JGE and quads. --- projects/mtg/src/GuiPhaseBar.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/projects/mtg/src/GuiPhaseBar.cpp b/projects/mtg/src/GuiPhaseBar.cpp index 9f879ecbb..c96fc78ab 100644 --- a/projects/mtg/src/GuiPhaseBar.cpp +++ b/projects/mtg/src/GuiPhaseBar.cpp @@ -151,10 +151,11 @@ void GuiPhaseBar::Render() sprintf(buf, _("(%s%s) %s").c_str(), currentP.c_str(), interrupt.c_str(),phaseNameToTranslate.c_str()); if(phaseinfo.get()) { - phaseinfo->SetHotSpot(phaseinfo->mWidth-2.f,0); - //phaseinfo->mWidth = font->GetStringWidth(buf)+12.f; + + phaseinfo->mWidth = font->GetStringWidth(buf)+12.f; + phaseinfo->SetHotSpot(phaseinfo->mWidth -4, 0); //phaseinfo->mHeight = font->GetHeight()+5.f; - JRenderer::GetInstance()->RenderQuad(phaseinfo.get(),SCREEN_WIDTH_F,0,0,SCREEN_WIDTH_F / phaseinfo->mWidth, SCREEN_HEIGHT_F / phaseinfo->mHeight); + JRenderer::GetInstance()->RenderQuad(phaseinfo.get(),SCREEN_WIDTH_F,0,0,2.2f, SCREEN_HEIGHT_F / phaseinfo->mHeight); } font->DrawString(buf, SCREEN_WIDTH - 5, 2, JGETEXT_RIGHT); } From 61cd74fcd0f34c710aba5cb0c55a878a29898a4b Mon Sep 17 00:00:00 2001 From: Anthony Calosa Date: Tue, 19 Jul 2016 09:52:18 +0800 Subject: [PATCH 5/6] revert psp cache --- projects/mtg/include/WResourceManagerImpl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/projects/mtg/include/WResourceManagerImpl.h b/projects/mtg/include/WResourceManagerImpl.h index b44da2728..c460be262 100644 --- a/projects/mtg/include/WResourceManagerImpl.h +++ b/projects/mtg/include/WResourceManagerImpl.h @@ -11,7 +11,7 @@ #include #if defined (PSP) -#define HUGE_CACHE_LIMIT 28000000 // Size of the cache for PSP (in bytes) - old value is 20mb increased to 28mb +#define HUGE_CACHE_LIMIT 20000000 // Size of the cache for PSP (in bytes) - old value is 20mb - reverted #else #define HUGE_CACHE_LIMIT 60000000 // Size of the cache for Windows and Linux (in bytes) - old value is 20mb increased to 60mb #endif From 6316577ec7c5fd1963448ff6a1a25c004164e0af Mon Sep 17 00:00:00 2001 From: zethfoxster Date: Mon, 18 Jul 2016 22:03:16 -0400 Subject: [PATCH 6/6] taught AI basic attack and block cost. added functionality to send specific abilities to AI "selectAbility" to have it find mana, targets, and use a selected ability at our command. --- projects/mtg/include/AIPlayerBaka.h | 2 +- projects/mtg/src/AIPlayerBaka.cpp | 103 ++++++++++++++++++++++++++-- projects/mtg/src/MTGRules.cpp | 18 +++-- 3 files changed, 113 insertions(+), 10 deletions(-) diff --git a/projects/mtg/include/AIPlayerBaka.h b/projects/mtg/include/AIPlayerBaka.h index 65816c015..e2275ce7b 100644 --- a/projects/mtg/include/AIPlayerBaka.h +++ b/projects/mtg/include/AIPlayerBaka.h @@ -107,7 +107,7 @@ class AIPlayerBaka: public AIPlayer{ virtual bool payTheManaCost(ManaCost * cost, MTGCardInstance * card = NULL,vector gotPayment = vector()); virtual int getCreaturesInfo(Player * player, int neededInfo = INFO_NBCREATURES , int untapMode = 0, int canAttack = 0); virtual ManaCost * getPotentialMana(MTGCardInstance * card = NULL); - virtual int selectAbility(); + virtual int selectAbility(MTGAbility * Specific = NULL); public: enum { diff --git a/projects/mtg/src/AIPlayerBaka.cpp b/projects/mtg/src/AIPlayerBaka.cpp index c7f679fb3..1b2595510 100644 --- a/projects/mtg/src/AIPlayerBaka.cpp +++ b/projects/mtg/src/AIPlayerBaka.cpp @@ -1369,7 +1369,7 @@ int AIPlayerBaka::selectHintAbility() return 0; } -int AIPlayerBaka::selectAbility() +int AIPlayerBaka::selectAbility(MTGAbility * Specific) { if(observer->mExtraPayment && observer->mExtraPayment->source && observer->mExtraPayment->source->controller() == this) { @@ -1410,12 +1410,14 @@ int AIPlayerBaka::selectAbility() for (size_t i = 1; i < observer->mLayers->actionLayer()->mObjects.size(); i++) { //0 is not a mtgability...hackish MTGAbility * a = ((MTGAbility *) observer->mLayers->actionLayer()->mObjects[i]); + if (Specific && Specific != a) + continue; //Skip mana abilities for performance if (dynamic_cast (a)) continue; //Make sure we can use the ability for (int j = 0; j < game->inPlay->nb_cards; j++) - { + {//zeth fox: note to self, this is where I can teach it suspend and other cost types. MTGCardInstance * card = game->inPlay->cards[j]; if(a->getCost() && !a->isReactingToClick(card, totalPotentialMana))//for performance reason only look for specific mana if the payment couldnt be made with potential. { @@ -1444,7 +1446,32 @@ int AIPlayerBaka::selectAbility() ManaCost * pMana = getPotentialMana(card); pMana->add(this->getManaPool()); if (a->isReactingToClick(card, pMana)) + { createAbilityTargets(a, card, ranking); + if (Specific) + { + if (!Specific->getCost()) + { + //attackcost, blockcost + if (a->aType == MTGAbility::ATTACK_COST) + { + ManaCost * specificCost = NEW ManaCost(ManaCost::parseManaCost("{0}", NULL, NULL)); + specificCost->add(0, card->attackCostBackup); + abilityPayment = canPayMana(card, specificCost); + SAFE_DELETE(specificCost); + } + else if (a->aType == MTGAbility::BLOCK_COST) + { + ManaCost * specificCost = NEW ManaCost(ManaCost::parseManaCost("{0}", NULL, NULL)); + specificCost->add(0, card->blockCostBackup); + abilityPayment = canPayMana(card, specificCost); + SAFE_DELETE(specificCost); + } + } + delete (pMana); + break; + } + } delete (pMana); } } @@ -1458,6 +1485,8 @@ int AIPlayerBaka::selectAbility() if (!forceBestAbilityUse) chance = 1 + randomGenerator.random() % 100; int actionScore = action.getEfficiency(); + if (Specific) + actionScore = 95; if(action.ability->getCost() && action.ability->getCost()->hasX() && this->game->hand->cards.size()) actionScore = actionScore/int(this->game->hand->cards.size());//reduce chance for "x" abilities if cards are in hand. if (actionScore >= chance) @@ -1469,6 +1498,35 @@ int AIPlayerBaka::selectAbility() DebugTrace(" Ai knows exactly what mana to use for this ability."); } DebugTrace("AIPlayer:Using Activated ability"); + if (Specific) + { + if (!Specific->getCost()) + { + //attackcost, blockcost + if (action.ability->aType == MTGAbility::ATTACK_COST) + { + ManaCost * specificCost = NEW ManaCost(ManaCost::parseManaCost("{0}", NULL, NULL)); + specificCost->add(0, action.click->attackCostBackup); + if (payTheManaCost(specificCost, action.click, abilityPayment)) + clickstream.push(NEW AIAction(action)); + SAFE_DELETE(specificCost); + } + else if (action.ability->aType == MTGAbility::BLOCK_COST) + { + ManaCost * specificCost = NEW ManaCost(ManaCost::parseManaCost("{0}", NULL, NULL)); + specificCost->add(0, action.click->blockCostBackup); + if (payTheManaCost(specificCost, action.click, abilityPayment)) + clickstream.push(NEW AIAction(action)); + SAFE_DELETE(specificCost); + } + } + else + { + if (payTheManaCost(action.ability->getCost(), action.click, abilityPayment)) + clickstream.push(NEW AIAction(action)); + } + } + else if (payTheManaCost(action.ability->getCost(), action.click,abilityPayment)) clickstream.push(NEW AIAction(action)); } @@ -2624,8 +2682,19 @@ int AIPlayerBaka::chooseAttackers() MTGCardInstance * card = NULL; while ((card = cd.nextmatch(game->inPlay, card))) { - if(hints && hints->HintSaysAlwaysAttack(observer,card)) - observer->cardClick(card, MTGAbility::MTG_ATTACK_RULE); + if (hints && hints->HintSaysAlwaysAttack(observer, card)) + { + if (!card->isAttacker()) + { + if (card->attackCost) + { + MTGAbility * a = observer->mLayers->actionLayer()->getAbility(MTGAbility::ATTACK_COST); + selectAbility(a); + observer->cardClick(card, MTGAbility::ATTACK_COST); + } + } + observer->cardClick(card, MTGAbility::MTG_ATTACK_RULE); + } } if (attack) @@ -2638,8 +2707,16 @@ int AIPlayerBaka::chooseAttackers() { if(hints && hints->HintSaysDontAttack(observer,card)) continue; - if(!card->isAttacker()) + if (!card->isAttacker()) + { + if (card->attackCost) + { + MTGAbility * a = observer->mLayers->actionLayer()->getAbility(MTGAbility::ATTACK_COST); + selectAbility(a); + observer->cardClick(card, MTGAbility::ATTACK_COST); + } observer->cardClick(card, MTGAbility::MTG_ATTACK_RULE); + } } } return 1; @@ -2716,6 +2793,12 @@ int AIPlayerBaka::chooseBlockers() } else { + if (card->blockCost) + { + MTGAbility * a = observer->mLayers->actionLayer()->getAbility(MTGAbility::BLOCK_COST); + selectAbility(a); + observer->cardClick(card, MTGAbility::BLOCK_COST); + } observer->cardClick(card, MTGAbility::MTG_BLOCK_RULE); } } @@ -2746,6 +2829,11 @@ int AIPlayerBaka::chooseBlockers() continue; if (!card->defenser) { + if (card->blockCost) + { + MTGAbility * a = observer->mLayers->actionLayer()->getAbility(MTGAbility::BLOCK_COST); + selectAbility(a); + } observer->cardClick(card, MTGAbility::MTG_BLOCK_RULE); int set = 0; while (!set) @@ -2760,6 +2848,11 @@ int AIPlayerBaka::chooseBlockers() if (opponentsToughness[attacker] <= 0 || (card->toughness <= attacker->power && opponentForce * 2 < life && !canFirstStrikeKill(card, attacker)) || attacker->nbOpponents() > 1) { + if (card->blockCost) + { + MTGAbility * a = observer->mLayers->actionLayer()->getAbility(MTGAbility::BLOCK_COST); + selectAbility(a); + } observer->cardClick(card, MTGAbility::MTG_BLOCK_RULE); } else diff --git a/projects/mtg/src/MTGRules.cpp b/projects/mtg/src/MTGRules.cpp index 2cab2b17f..995fb30bb 100644 --- a/projects/mtg/src/MTGRules.cpp +++ b/projects/mtg/src/MTGRules.cpp @@ -1553,7 +1553,7 @@ MTGAttackCostRule::MTGAttackCostRule(GameObserver* observer, int _id) : scost = "Pay to attack"; } -int MTGAttackCostRule::isReactingToClick(MTGCardInstance * card, ManaCost *) +int MTGAttackCostRule::isReactingToClick(MTGCardInstance * card, ManaCost * aiCheck) { if (currentPhase == MTG_PHASE_COMBATATTACKERS && card->controller() == game->currentPlayer && card->controller() == game->currentlyActing())//on my turn and when I am the acting player. @@ -1571,8 +1571,12 @@ int MTGAttackCostRule::isReactingToClick(MTGCardInstance * card, ManaCost *) attackcost->extraCosts->costs[i]->setSource(card); } scost = attackcost->getConvertedCost(); - if (playerMana->canAfford(attackcost)) + if ((aiCheck && aiCheck->canAfford(attackcost)) || playerMana->canAfford(attackcost)) + { + SAFE_DELETE(attackcost); return 1; + } + SAFE_DELETE(attackcost); } return 0; } @@ -1588,6 +1592,7 @@ int MTGAttackCostRule::reactToClick(MTGCardInstance * card) playerMana->pay(attackcost);//I think you can't pay partial cost to attack cost so you pay full (508.1i) card->attackCost = 0; card->attackPlaneswalkerCost = 0; + SAFE_DELETE(attackcost); return 1; /* 508.1g: If any of the chosen creatures require paying costs to attack, the active player determines the total cost to attack. @@ -1622,7 +1627,7 @@ MTGBlockCostRule::MTGBlockCostRule(GameObserver* observer, int _id) : aType = MTGAbility::BLOCK_COST; scost = "Pay to block"; } -int MTGBlockCostRule::isReactingToClick(MTGCardInstance * card, ManaCost *) +int MTGBlockCostRule::isReactingToClick(MTGCardInstance * card, ManaCost * aiCheck) { if (currentPhase == MTG_PHASE_COMBATBLOCKERS && !game->isInterrupting && card->controller() != game->currentPlayer @@ -1642,8 +1647,12 @@ int MTGBlockCostRule::isReactingToClick(MTGCardInstance * card, ManaCost *) blockcost->extraCosts->costs[i]->setSource(card); } scost = blockcost->getConvertedCost(); - if (playerMana->canAfford(blockcost)) + if ((aiCheck && aiCheck->canAfford(blockcost)) || playerMana->canAfford(blockcost)) + { + SAFE_DELETE(blockcost); return 1; + } + SAFE_DELETE(blockcost); } return 0; } @@ -1658,6 +1667,7 @@ int MTGBlockCostRule::reactToClick(MTGCardInstance * card) 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; + SAFE_DELETE(blockcost); return 1; /* 509.1d: If any of the chosen creatures require paying costs to block, the defending player determines the total cost to block.