diff --git a/projects/mtg/include/MTGAbility.h b/projects/mtg/include/MTGAbility.h index 23270482e..997716c79 100644 --- a/projects/mtg/include/MTGAbility.h +++ b/projects/mtg/include/MTGAbility.h @@ -520,6 +520,9 @@ public: int TapAll(TargetChooser * tc); int UntapAll(TargetChooser * tc); void addAbilities(int _id, Spell * spell); + MTGAbility * parseUpkeepAbility(string s = "", MTGCardInstance * card = NULL, Spell * spell = NULL, int restrictions = 0, int id = -1); + MTGAbility * parsePhaseActionAbility(string s = "", MTGCardInstance * card = NULL, Spell * spell = NULL,MTGCardInstance * target = NULL, int restrictions = 0, int id = -1); + }; diff --git a/projects/mtg/src/AIPlayer.cpp b/projects/mtg/src/AIPlayer.cpp index ae0d4985a..bd1bdacf0 100644 --- a/projects/mtg/src/AIPlayer.cpp +++ b/projects/mtg/src/AIPlayer.cpp @@ -665,7 +665,6 @@ int AIAction::getEfficiency() if (s->has(ability)) return 0; MTGAbility * a = AbilityFactory::getCoreAbility(ability); - if (!a) { DebugTrace("FATAL: Ability is NULL in AIAction::getEfficiency()"); @@ -941,40 +940,29 @@ int AIAction::getEfficiency() } break; } - - case MTGAbility::UPCOST: - { - //hello, Ai pay your upcost please :P, this entices Ai into paying upcost, the conditional isAi() is required strangely ai is able to pay upcost during YOUR upkeep. - if (g->getCurrentGamePhase() == Constants::MTG_PHASE_UPKEEP && g->currentPlayer == p && p == a->source->controller()) - { - efficiency = 100; - } - break; - } - case MTGAbility::FOREACH: case MTGAbility::MANA_PRODUCER://only way to hit this condition is nested manaabilities, ai skips manaproducers by defualt when finding an ability to use. { MTGCardInstance * _target = (MTGCardInstance *) (a->target); MTGAbility * a = AbilityFactory::getCoreAbility(ability); - + AManaProducer * amp = dynamic_cast(a); efficiency = 0; //trying to encourage Ai to use his foreach manaproducers in first main - if (a->getCost() && a->getCost()->getConvertedCost() && a->aType == MTGAbility::MANA_PRODUCER && (g->getCurrentGamePhase() == Constants::MTG_PHASE_FIRSTMAIN + if (amp && amp->output && amp->output->getConvertedCost() && (g->getCurrentGamePhase() == Constants::MTG_PHASE_FIRSTMAIN || g->getCurrentGamePhase() == Constants::MTG_PHASE_SECONDMAIN) && _target->controller()->game->hand->nb_cards > 0) { efficiency = 0; for (int i = Constants::MTG_NB_COLORS - 1; i > 0; i--) { if ((p->game->hand->hasColor(i) || p->game->hand->hasColor(0)) - && (dynamic_cast (a)->output->hasColor(i))) + && amp->output->hasColor(i)) { efficiency = 100; } } - if (a->getCost() && a->getCost()->getConvertedCost() && p->game->hand->hasX()) + if (amp->getCost() && amp->getCost()->getConvertedCost() && p->game->hand->hasX()) efficiency = 100; } @@ -1196,6 +1184,14 @@ int AIAction::getEfficiency() } break; } + if(AUpkeep * auk = dynamic_cast(ability)) + { + //hello, Ai pay your upcost please :P, this entices Ai into paying upcost, the conditional isAi() is required strangely ai is able to pay upcost during YOUR upkeep. + if (auk && g->getCurrentGamePhase() == Constants::MTG_PHASE_UPKEEP && g->currentPlayer == p && p == a->source->controller()) + { + efficiency = 100; + } + } if (AAMover * aam = dynamic_cast(a)) { MTGGameZone * z = aam->destinationZone(target); diff --git a/projects/mtg/src/ExtraCost.cpp b/projects/mtg/src/ExtraCost.cpp index 912a9f87b..c80138da7 100644 --- a/projects/mtg/src/ExtraCost.cpp +++ b/projects/mtg/src/ExtraCost.cpp @@ -621,16 +621,17 @@ int CounterCost::isPaymentSet() int CounterCost::canPay() { // if target needs to be chosen, then move on. - if(!target) - return 0; if (tc) return 1; if (counter->nb >= 0) return 1; //add counters always possible // otherwise, move on only if target has enough counters - Counter * targetCounter = target->counters->hasCounter(counter->name.c_str(), counter->power, counter->toughness); - if (targetCounter && targetCounter->nb >= -counter->nb) - return 1; + if(target) + { + Counter * targetCounter = target->counters->hasCounter(counter->name.c_str(), counter->power, counter->toughness); + if (targetCounter && targetCounter->nb >= -counter->nb) + return 1; + } return 0; } diff --git a/projects/mtg/src/MTGAbility.cpp b/projects/mtg/src/MTGAbility.cpp index 23965bac2..3f4f9e58b 100644 --- a/projects/mtg/src/MTGAbility.cpp +++ b/projects/mtg/src/MTGAbility.cpp @@ -977,6 +977,7 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG string cond = sWithoutTc.substr(ifKeywords[i].length(),ifKeywords[i].length() + sWithoutTc.find(" then ")-6); string s1 = s.substr(s.find(" then ")+6); MTGAbility * a1 = parseMagicLine(s1, id, spell, card); + if(!a1) return NULL; MTGAbility * a = NEW IfThenAbility(id, a1, card,checkIf[i],cond); a->canBeInterrupted = false; a->oneShot = true; @@ -1022,89 +1023,14 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG found = s.find("upcostmulti"); if (found != string::npos) { - bool Cumulative = false; - size_t cumulative = s.find("cumulativeupcost"); - if(cumulative != string::npos) - Cumulative = true; - size_t start = s.find("["); - size_t end = s.find("]", start); - string s1 = s.substr(start + 1, end - start - 1); - size_t seperator = s1.find(";"); - int phase = Constants::MTG_PHASE_UPKEEP; - int once = 0; - if (seperator != string::npos) - { - for (int i = 0; i < Constants::NB_MTG_PHASES; i++) - { - if (s1.find("next") != string::npos) - once = 1; - string phaseStr = Constants::MTGPhaseCodeNames[i]; - if (s1.find(phaseStr) != string::npos) - { - phase = PhaseRing::phaseStrToInt(phaseStr); - break; - } - } - s1 = s1.substr(0, seperator - 1); - } - ManaCost * cost = ManaCost::parseManaCost(s1); - - if (!cost) - { - DebugTrace("MTGABILITY: Parsing Error: " << s); - return NULL; - } - - string sAbility = s.substr(end + 1); - MTGAbility * a = parseMagicLine(sAbility, id, spell, card); - - if (!a) - { - DebugTrace("MTGABILITY: Parsing Error: " << s); - delete (cost); - return NULL; - } - - return NEW AUpkeep(id, card, a, cost, restrictions, phase, once,Cumulative); + return AbilityFactory::parseUpkeepAbility(s,card,spell,restrictions,id); } - //Phase based actions found = s.find("phaseactionmulti"); if (found != string::npos) { - vector splitActions = parseBetween(s, "[", "]"); - if (!splitActions.size()) - { - DebugTrace("MTGABILITY:Parsing Error " << s); - return NULL; - } - string s1 = splitActions[1]; - int phase = Constants::MTG_PHASE_UPKEEP; - for (int i = 0; i < Constants::NB_MTG_PHASES; i++) - { - string phaseStr = Constants::MTGPhaseCodeNames[i]; - if (s1.find(phaseStr) != string::npos) - { - phase = PhaseRing::phaseStrToInt(phaseStr); - break; - } - } - - bool opponentturn = (s1.find("my") == string::npos); - bool myturn = (s1.find("opponent") == string::npos); - - bool sourceinPlay = (s1.find("sourceinplay") != string::npos); - bool next = (s1.find("next") == string::npos); //Why is this one the opposite of the two others? That's completely inconsistent - bool once = (s1.find("once") != string::npos); - - MTGCardInstance * _target = NULL; - if (spell) - _target = spell->getNextCardTarget(); - if(!_target) - _target = target; - return NEW APhaseActionGeneric(id, card,_target, splitActions[2], restrictions, phase,sourceinPlay,next,myturn,opponentturn,once); + return parsePhaseActionAbility(s,card,spell,target,restrictions,id); } - //Multiple abilities for ONE cost found = s.find("&&"); if (found != string::npos) @@ -1440,98 +1366,18 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG return a; } - //Phase based actions - //TODO: This is 100% the same code as phaseActionMulti, can't these 2 be merged somehow? + //Phase based actions found = s.find("phaseaction"); if (found != string::npos) { - vector splitActions = parseBetween(s, "[", "]"); - if (!splitActions.size()) - { - DebugTrace("MTGABILITY:Parsing Error " << s); - return NULL; - } - string s1 = splitActions[1]; - int phase = Constants::MTG_PHASE_UPKEEP; - for (int i = 0; i < Constants::NB_MTG_PHASES; i++) - { - string phaseStr = Constants::MTGPhaseCodeNames[i]; - if (s1.find(phaseStr) != string::npos) - { - phase = PhaseRing::phaseStrToInt(phaseStr); - break; - } - } - - bool opponentturn = (s1.find("my") == string::npos); - bool myturn = (s1.find("opponent") == string::npos); - - bool sourceinPlay = (s1.find("sourceinplay") != string::npos); - bool next = (s1.find("next") == string::npos); //Why is this one the opposite of the two others? That's completely inconsistent - bool once = (s1.find("once") != string::npos); - - MTGCardInstance * _target = NULL; - if (spell) - _target = spell->getNextCardTarget(); - if(!_target) - _target = target; - return NEW APhaseActionGeneric(id, card,_target, trim(splitActions[2]), restrictions, phase,sourceinPlay,next,myturn,opponentturn,once); + return parsePhaseActionAbility(s,card,spell,target,restrictions,id); } - //Upkeep Cost - //TODO: This is 100% the same code as upkeepCostMulti, can't these 2 be merged somehow? - //also see phaseActionMulti found = s.find("upcost"); if (found != string::npos) { - bool Cumulative = false; - size_t cumulative = s.find("cumulativeupcost"); - if(cumulative != string::npos) - Cumulative = true; - size_t start = s.find("["); - size_t end = s.find("]", start); - string s1 = s.substr(start + 1, end - start - 1); - size_t seperator = s1.find(";"); - int phase = Constants::MTG_PHASE_UPKEEP; - int once = 0; - if (seperator != string::npos) - { - for (int i = 0; i < Constants::NB_MTG_PHASES; i++) - { - if (s1.find("next") != string::npos) - once = 1; - - string phaseStr = Constants::MTGPhaseCodeNames[i]; - if (s1.find(phaseStr) != string::npos) - { - phase = PhaseRing::phaseStrToInt(phaseStr); - break; - } - - } - s1 = s1.substr(0, seperator - 1); - } - ManaCost * cost = ManaCost::parseManaCost(s1); - - if (!cost) - { - DebugTrace("MTGABILITY: Parsing Error: " << s); - return NULL; - } - - string sAbility = s.substr(end + 1); - MTGAbility * a = parseMagicLine(sAbility, id, spell, card); - - if (!a) - { - DebugTrace("MTGABILITY: Parsing Error: " << s); - delete (cost); - return NULL; - } - - return NEW AUpkeep(id, card, a, cost, restrictions, phase, once,Cumulative); + return AbilityFactory::parseUpkeepAbility(s,card,spell,restrictions,id); } - //Cycling found = s.find("cycling"); if (found != string::npos) @@ -2455,6 +2301,90 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG return NULL; } +MTGAbility * AbilityFactory::parseUpkeepAbility(string s,MTGCardInstance * card,Spell * spell,int restrictions,int id) +{ + MTGAbility * a1 = NULL; + bool Cumulative = false; + size_t cumulative = s.find("cumulativeupcost"); + if(cumulative != string::npos) + Cumulative = true; + size_t start = s.find("["); + size_t end = s.find("]", start); + string s1 = s.substr(start + 1, end - start - 1); + size_t seperator = s1.find(";"); + int phase = Constants::MTG_PHASE_UPKEEP; + int once = 0; + if (seperator != string::npos) + { + for (int i = 0; i < Constants::NB_MTG_PHASES; i++) + { + if (s1.find("next") != string::npos) + once = 1; + + string phaseStr = Constants::MTGPhaseCodeNames[i]; + if (s1.find(phaseStr) != string::npos) + { + phase = PhaseRing::phaseStrToInt(phaseStr); + break; + } + + } + s1 = s1.substr(0, seperator); + } + ManaCost * cost = ManaCost::parseManaCost(s1); + + if (!cost) + { + DebugTrace("MTGABILITY: Parsing Error: " << s); + return NULL; + } + + string sAbility = s.substr(end + 1); + MTGAbility * a = parseMagicLine(sAbility, id, spell, card); + + if (!a) + { + DebugTrace("MTGABILITY: Parsing Error: " << s); + delete (cost); + return NULL; + } + return NEW AUpkeep(id, card, a, cost, restrictions, phase, once,Cumulative);; +} + +MTGAbility * AbilityFactory::parsePhaseActionAbility(string s,MTGCardInstance * card,Spell * spell,MTGCardInstance * target, int restrictions,int id) +{ + vector splitActions = parseBetween(s, "[", "]"); + if (!splitActions.size()) + { + DebugTrace("MTGABILITY:Parsing Error " << s); + return NULL; + } + string s1 = splitActions[1]; + int phase = Constants::MTG_PHASE_UPKEEP; + for (int i = 0; i < Constants::NB_MTG_PHASES; i++) + { + string phaseStr = Constants::MTGPhaseCodeNames[i]; + if (s1.find(phaseStr) != string::npos) + { + phase = PhaseRing::phaseStrToInt(phaseStr); + break; + } + } + + bool opponentturn = (s1.find("my") == string::npos); + bool myturn = (s1.find("opponent") == string::npos); + bool sourceinPlay = (s1.find("sourceinplay") != string::npos); + bool next = (s1.find("next") == string::npos); //Why is this one the opposite of the two others? That's completely inconsistent + bool once = (s1.find("once") != string::npos); + + MTGCardInstance * _target = NULL; + if (spell) + _target = spell->getNextCardTarget(); + if(!_target) + _target = target; + return NEW APhaseActionGeneric(id, card,_target, trim(splitActions[2]), restrictions, phase,sourceinPlay,next,myturn,opponentturn,once); +} + //Tells the AI if the ability should target itself or an ennemy int AbilityFactory::abilityEfficiency(MTGAbility * a, Player * p, int mode, TargetChooser * tc,Targetable * target) {