Exemplo n.º 1
0
//return true if a given ability matches a hint's description
//Eventually this will look awfully similar to the parser...any way to merge them somehow ?
bool AIHints::abilityMatches(MTGAbility * ability, AIHint * hint)
{
    string s = hint->mAction;

    MTGAbility * a = AbilityFactory::getCoreAbility(ability);

    //Here we want to check that the card reacting to the MTGAbility is the one mentioned in the hint,
    // to avoid mistaking the MTGAbility with a similar one.
    //Ideally we would find all cards with this ID, and see if the ability reacts to a click on one of these cards.
    // This is the poor man's version, based on the fact that most cards are the source of their own abilities
    if (hint->mSourceId && ((!a->source) || a->source->getMTGId() != hint->mSourceId))
        return false;

    if ( AACounter * counterAbility = dynamic_cast<AACounter *> (a) )
    {
        vector<string> splitCounter = parseBetween(s, "counter(", ")");
        if (!splitCounter.size())
            return false;

        string counterstring = counterAbility->name;
        std::transform(counterstring.begin(), counterstring.end(), counterstring.begin(), ::tolower);
        return (splitCounter[1].compare(counterstring) == 0);
    }

    if ( ATokenCreator * tokenAbility = dynamic_cast<ATokenCreator *> (a) )
    {
        vector<string> splitToken = parseBetween(s, "token(", ")");
        if (!splitToken.size())
            return false;
        return (tokenAbility->tokenId && tokenAbility->tokenId == atoi(splitToken[1].c_str()));
    }

    return false;
}
Exemplo n.º 2
0
AIHint::AIHint(string _line)
{
    string line = _line;
    if (!line.length())
    {
        DebugTrace("AIHINTS: line is empty");
        return;
    }
    std::transform(line.begin(), line.end(), line.begin(), ::tolower);
    mCondition = line;
    string action = line;
    vector<string> splitAction = parseBetween(action, "sourceid(", ")");
    if (splitAction.size())
    {
        mAction = splitAction[0];
        mSourceId = atoi(splitAction[1].c_str()); 
    }
    else
    {
        mAction = action;
        mSourceId = 0;
    }
    
    vector<string> splitDontAttack = parseBetween(action, "dontattackwith(", ")");
    if(splitDontAttack.size())
    {
        mCombatAttackTip = splitDontAttack[1];
    }

    vector<string> splitCastOrder = parseBetween(action, "castpriority(", ")");
    if(splitCastOrder.size())
    {
        castOrder = split(splitCastOrder[1],',');
    }

    if(action.find( "combo ") != string::npos)
    {
        string Combo = "";
        Combo = action.c_str() + 6;
        combos.push_back(Combo);
    }
    
}
Exemplo n.º 3
0
ManaCost * ManaCost::parseManaCost(string s, ManaCost * _manaCost, MTGCardInstance * c)
{
    ManaCost * manaCost;
    GameObserver* g = c?c->getObserver():NULL;
    if (_manaCost)
    {
        manaCost = _manaCost;
    }
    else
    {
        manaCost = NEW ManaCost();
    }
    manaCost->xColor = -1;
    int state = 0;
    size_t start = 0;
    size_t end = 0;
    while (!s.empty() && state != -1)
    {
        switch (state)
        {
        case 0:
            start = s.find_first_of("{");
            if(s.find_first_of("{") != string::npos && start > 0)
            {
                string value = s.substr(start -1,end);
                if(value == "n{")//"restrictio n{m orbid} would read the n{m as {m} millcost
                    return manaCost;
            }
            if (start == string::npos)
            {
                return manaCost;
            }
            else
            {
                state = 1;
            }
            break;
        case 1:
            end = s.find_first_of("}");
            if (end == string::npos)
            {
                state = -1;
            }
            else
            {
                string value = s.substr(start + 1, end - 1 - start);

                if (value == "u")
                {
                    manaCost->add(Constants::MTG_COLOR_BLUE, 1);
                }
                else if (value == "b")
                {
                    manaCost->add(Constants::MTG_COLOR_BLACK, 1);
                }
                else if (value == "w")
                {
                    manaCost->add(Constants::MTG_COLOR_WHITE, 1);
                }
                else if (value == "g")
                {
                    manaCost->add(Constants::MTG_COLOR_GREEN, 1);
                }
                else if (value == "r")
                {
                    manaCost->add(Constants::MTG_COLOR_RED, 1);

                }
                else
                {
                    //Parse target for extraCosts
                    TargetChooserFactory tcf(g);
                    TargetChooser * tc = NULL;
                    size_t target_start = value.find("(");
                    size_t target_end = value.find(")");
                    if (target_start != string::npos && target_end != string::npos)
                    {
                        string target = value.substr(target_start + 1, target_end - 1 - target_start);
                        tc = tcf.createTargetChooser(target, c);
                    }

                    //switch on the first letter. If two costs share their first letter, add an "if" within the switch
                    std::transform(value.begin(), value.end(), value.begin(), ::tolower);
                    switch (value[0])
                    {
                    case 'x':
                        if(value == "x")
                        {
                            manaCost->x();
                        }
                        else
                        {
                            vector<string>colorSplit = parseBetween(value,"x:"," ",false);
                            if(colorSplit.size())
                            {
                                int color = -1;
                                const string ColorStrings[] = { Constants::kManaColorless, Constants::kManaGreen, Constants::kManaBlue, Constants::kManaRed, Constants::kManaBlack, Constants::kManaWhite };
                                for (unsigned int i = 0; i < sizeof(ColorStrings)/sizeof(ColorStrings[0]); ++i)
                                {
                                    if (s.find(ColorStrings[i]) != string::npos)
                                    {
                                        color = i;
                                    }
                                }
                                manaCost->specificX(color);
                            }
                        }
                        break;
                    case 'v':
                        if (value.find("value:") != string::npos) {
                            vector<string> splitParsedVar = parseBetween(value, "value:", " ", false);
                            WParsedInt* res = NEW WParsedInt(splitParsedVar[1], NULL, c);
                            manaCost->add(Constants::MTG_COLOR_ARTIFACT, res->getValue());
                            SAFE_DELETE(res);
                        }
                        break;
                    case 't': //Tap
                        if (value == "t")
                        {
                            manaCost->addExtraCost(NEW TapCost);
                        }
                        else
                        {
                            manaCost->addExtraCost(NEW TapTargetCost(tc));
                        }
                        break;
                    case 's':
                        if (value.find("s2l") != string::npos)
                        { //Send To Library Cost (move from anywhere to Library)
                            manaCost->addExtraCost(NEW ToLibraryCost(tc));
                        }
                        else if (value.find("s2g") != string::npos)
                        { //Send to Graveyard Cost (move from anywhere to Graveyard)
                            manaCost->addExtraCost(NEW ToGraveCost(tc));
                        }
                        else
                        { //Sacrifice
                            manaCost->addExtraCost(NEW SacrificeCost(tc));
                        }
                        break;
                    case 'e': 
                        //Exile
                        manaCost->addExtraCost(NEW ExileTargetCost(tc));
                        break;
                    case 'h': //bounce (move to Hand)
                        manaCost->addExtraCost(NEW BounceTargetCost(tc));
                        break;
                    case 'l':
                        if (value == "l2e")
                        { //Mill to exile yourself as a cost (Library 2 Exile)
                            manaCost->addExtraCost(NEW MillExileCost(tc));
                        }
                        else if (value == "l")
                        { //Life cost
                            manaCost->addExtraCost(NEW LifeCost(tc));
                        }
                        else
                        { //Specific Life cost
                            vector<string>valSplit = parseBetween(value,"l:"," ",false);
                            if (valSplit.size()) {
                                WParsedInt* lifetopay = NEW WParsedInt(valSplit[1], NULL, c);
                                manaCost->addExtraCost(NEW SpecificLifeCost(tc,lifetopay->getValue()));
                                SAFE_DELETE(lifetopay);
                            }
                        }
                        break;
                    case 'd': //DiscardRandom cost
                        if (value.find("delve") != string::npos)
                        {
                            if(!tc)
                                tc = tcf.createTargetChooser("*|mygraveyard", c);
                            manaCost->addExtraCost(NEW Delve(tc));
                        }
                        else if (value == "d")
                        {
                            manaCost->addExtraCost(NEW DiscardRandomCost(tc));
                        }
                        else
                        {
                            manaCost->addExtraCost(NEW DiscardCost(tc));
                        }
                        break;
                    case 'm': //Mill yourself as a cost
                        manaCost->addExtraCost(NEW MillCost(tc));
                        break;
                    case 'n': //return unblocked attacker cost
                        {
                            TargetChooserFactory tcf(g);
                            tc = tcf.createTargetChooser("creature|myBattlefield", c);
                            manaCost->addExtraCost(NEW Ninja(tc));
                            break;
                        }
                    case 'k': //kill offering
                        {
                            TargetChooserFactory tcf(g);
                            if (value == "kgoblin")
                            {
                                tc = tcf.createTargetChooser("creature[goblin]|myBattlefield", c);
                            }
                            else if (value == "kfox")
                            {
                                tc = tcf.createTargetChooser("creature[fox]|myBattlefield", c);
                            }
                            else if (value == "kmoonfolk")
                            {
                                tc = tcf.createTargetChooser("creature[moonfolk]|myBattlefield", c);
                            }
                            else if (value == "krat")
                            {
                                tc = tcf.createTargetChooser("creature[rat]|myBattlefield", c);
                            }
                            else if (value == "ksnake")
                            {
                                tc = tcf.createTargetChooser("creature[snake]|myBattlefield", c);
                            }
                            //TODO iterate subtypes of creatures
                            manaCost->addExtraCost(NEW Offering(tc));
                            break;
                        }
                    case 'p' :
                        {
                            SAFE_DELETE(tc);
                            size_t start = value.find("(");
                            size_t end = value.rfind(")");
                            string manaType = value.substr(start + 1, end - start - 1);
                            manaCost->addExtraCost(NEW LifeorManaCost(NULL,manaType));
                            break;
                        }
                    case 'i' :
                        {
                            SAFE_DELETE(tc);
                            manaCost->add(0,1);
                            manaCost->addExtraCost(NEW SnowCost);
                            break;
                        }
                    case 'q':
                        if(value == "q")
                        {
                            manaCost->addExtraCost(NEW UnTapCost);
                        }
                        else
                        {
                            manaCost->addExtraCost(NEW UnTapTargetCost(tc));
                        }
                        break;
                    case 'c': //Counters or cycle
                        {
                            if (value.find("convoke") != string::npos)
                            {
                                if (!tc)
                                    tc = tcf.createTargetChooser("creature|mybattlefield", c);
                                manaCost->addExtraCost(NEW Convoke(tc));
                            }
                            else if(value == "chosencolor")
                            {
                                if(c)
                                manaCost->add(c->chooseacolor, 1);
                            }
                            else if(value == "cycle")
                            {
                                manaCost->addExtraCost(NEW CycleCost(tc));
                            }
                            else if(value.find("(") != string::npos)
                            {
                                size_t counter_start = value.find("(");
                                size_t counter_end = value.find(")", counter_start);
                                AbilityFactory abf(g);
                                string counterString = value.substr(counter_start + 1, counter_end - counter_start - 1);
                                Counter * counter = abf.parseCounter(counterString, c);
                                size_t separator = value.find(",", counter_start);
                                size_t separator2 = string::npos;
                                if (separator != string::npos)
                                {
                                    separator2 = value.find(",", counter_end + 1);
                                }
                                SAFE_DELETE(tc);
                                size_t target_start = string::npos;
                                if (separator2 != string::npos)
                                {
                                    target_start = value.find(",", counter_end + 1);
                                }
                                size_t target_end = value.length();
                                if (target_start != string::npos && target_end != string::npos)
                                {
                                    string target = value.substr(target_start + 1, target_end - 1 - target_start);
                                    tc = tcf.createTargetChooser(target, c);
                                }
                                manaCost->addExtraCost(NEW CounterCost(counter, tc));
                                break;
                            }
                            else if(value == "c")
                            {
                                manaCost->add(Constants::MTG_COLOR_WASTE, 1);
                                break;
                            }
                        break;
                    }
                    default: //uncolored cost and hybrid costs and special cost
                    {
                        if(value == "unattach")
                        {
                            manaCost->addExtraCost(NEW UnattachCost(c));
                            break;
                        }
                        int intvalue = atoi(value.c_str());
                        int colors[2];
                        int values[2];
                        if (intvalue < 10 && value.size() > 1)
                        {
                            for (int i = 0; i < 2; i++)
                            {
                                char c = value[i];
                                if (c >= '0' && c <= '9')
                                {
                                    colors[i] = Constants::MTG_COLOR_ARTIFACT;
                                    values[i] = c - '0';
                                }
                                else
                                {
                                    for (int j = 0; j < Constants::NB_Colors; j++)
                                    {
                                        if (c == Constants::MTGColorChars[j])
                                        {
                                            colors[i] = j;
                                            values[i] = 1;
                                        }
                                    }
                                }
                            }
                            if (values[0] > 0 || values[1] > 0)
                                manaCost->addHybrid(colors[0], values[0], colors[1], values[1]);
                        }
                        else
                        {
                            manaCost->add(Constants::MTG_COLOR_ARTIFACT, intvalue);
                        }
                        break;
                    }
                    }
                }
                s = s.substr(end + 1);
                state = 0;
            }
            break;
        default:
            break;
        }
    }
    return manaCost;
}
Exemplo n.º 4
0
//MTGAllCards
int MTGAllCards::processConfLine(string &s, MTGCard *card, CardPrimitive * primitive)
{
    if ('#' == s[0]) return 1; // a comment shouldn't be treated as an error condition
    size_t del_pos = s.find_first_of('=');
    if (del_pos == string::npos || 0 == del_pos)
        return 0;

    s[del_pos] = '\0';
    const string key = s.substr(0, del_pos);
    const string val = s.substr(del_pos + 1);

    switch (key[0])
    {
    case 'a':
        if (key == "auto")
        {
            if (!primitive) primitive = NEW CardPrimitive();
            primitive->addMagicText(val);
        }
        else if (StartsWith(key, "auto"))
        {
            if (!primitive) primitive = NEW CardPrimitive();
            primitive->addMagicText(val, key.substr(4));
        }
        else if (key == "alias")
        {
            if (!primitive) primitive = NEW CardPrimitive();
            primitive->alias = atoi(val.c_str());
        }
        else if (key == "abilities")
        {
            if (!primitive) primitive = NEW CardPrimitive();
            string value = val;
            //Specific Abilities
            std::transform(value.begin(), value.end(), value.begin(), ::tolower);
            vector<string> values = split(value, ',');
            for (size_t values_i = 0; values_i < values.size(); ++values_i)
            {

                for (int j = Constants::NB_BASIC_ABILITIES - 1; j >= 0; --j)
                {
                    if (values[values_i].find(Constants::MTGBasicAbilities[j]) != string::npos)
                    {
                        primitive->basicAbilities[j] = 1;
                        break;
                    }
                }
            }
        }
        break;

    case 'b': //buyback
        if (!primitive) primitive = NEW CardPrimitive();
        if (ManaCost * cost = primitive->getManaCost())
        {
            string value = val;
            std::transform(value.begin(), value.end(), value.begin(), ::tolower);
            cost->setBuyback(ManaCost::parseManaCost(value));
        }
        break;

    case 'c': //color
        if (!primitive) primitive = NEW CardPrimitive();
        {
            string value = val;
            std::transform(value.begin(), value.end(), value.begin(), ::tolower);
            vector<string> values = split(value, ',');
            int removeAllOthers = 1;
            for (size_t values_i = 0; values_i < values.size(); ++values_i)
            {
                primitive->setColor(values[values_i], removeAllOthers);
                removeAllOthers = 0;
            }
        }
        break;
    case 'd'://dredge
        if (!primitive) primitive = NEW CardPrimitive();
        {
            string value = val;
            std::transform(value.begin(), value.end(), value.begin(), ::tolower);
            vector<string> values = parseBetween(value,"dredge(",")");
            if(values.size())
                primitive->dredgeAmount = atoi(values[1].c_str());

            break;
        }
    case 'f': //flashback//morph
    {
        if (!primitive) primitive = NEW CardPrimitive();
        if(ManaCost * cost = primitive->getManaCost())
        {
            if( s.find("facedown") != string::npos)//morph
            {
                string value = val;
                std::transform(value.begin(), value.end(), value.begin(), ::tolower);
                cost->setMorph(ManaCost::parseManaCost(value));
            }
            else
            {
                string value = val;
                std::transform(value.begin(), value.end(), value.begin(), ::tolower);
                cost->setFlashback(ManaCost::parseManaCost(value));
            }
        }
        break;
    }

    case 'g': //grade
        if (s.size() - del_pos - 1 > 2) currentGrade = getGrade(val[2]);
        break;

    case 'i': //id
        if (!card) card = NEW MTGCard();
        card->setMTGId(atoi(val.c_str()));
        break;

    case 'k': //kicker
        if (!primitive) primitive = NEW CardPrimitive();
        if (ManaCost * cost = primitive->getManaCost())
        {
            string value = val;
            std::transform(value.begin(), value.end(), value.begin(), ::tolower);
            size_t multikick = value.find("multi");
            bool isMultikicker = false;
            if(multikick != string::npos)
            {
                size_t endK = value.find("{",multikick);
                value.erase(multikick, endK - multikick);
                isMultikicker = true;
            }
            cost->setKicker(ManaCost::parseManaCost(value));
            cost->getKicker()->isMulti = isMultikicker;
        }
        break;

    case 'm': //mana
        if (!primitive) primitive = NEW CardPrimitive();
        {
            string value = val;
            std::transform(value.begin(), value.end(), value.begin(), ::tolower);
            primitive->setManaCost(value);
        }
        break;

    case 'n': //name
        if (!primitive) primitive = NEW CardPrimitive();
        primitive->setName(val);
        break;

    case 'o': //othercost/otherrestriction
        if (!primitive) primitive = NEW CardPrimitive();
        if(key[5] == 'r')//otherrestrictions
        {
            string value = val;
            primitive->setOtherRestrictions(value);
        }
        else
        {
            if (ManaCost * cost = primitive->getManaCost())
            {
                string value = val;
                std::transform(value.begin(), value.end(), value.begin(), ::tolower);
                size_t name = value.find("name(");
                string theName = "";
                if(name != string::npos)
                {
                    size_t endName = value.find(")",name);
                    theName = value.substr(name + 5,endName - name - 5);
                    value.erase(name, endName - name + 1);
                }
                cost->setAlternative(ManaCost::parseManaCost(value));
                if(theName.size())
                    cost->getAlternative()->alternativeName.append(theName);
            }
        }
        break;

    case 'p':
        if (key[1] == 'r')
        {   // primitive
            if (!card) card = NEW MTGCard();
            map<string, CardPrimitive*>::iterator it = primitives.find(val);
            if (it != primitives.end()) card->setPrimitive(it->second);
        }
        else
        {   //power
            if (!primitive) primitive = NEW CardPrimitive();
            primitive->setPower(atoi(val.c_str()));
        }
        break;

    case 'r': //retrace/rarity//restrictions
        if(key[2] == 's' && key[3] == 't')//restrictions
        {
            if (!primitive) primitive = NEW CardPrimitive();
            string value = val;
            primitive->setRestrictions(value);
        }
        else if (key[1] == 'e' && key[2] == 't')
        {   //retrace
            if (!primitive) primitive = NEW CardPrimitive();
            if (ManaCost * cost = primitive->getManaCost())
            {
                string value = val;
                std::transform(value.begin(), value.end(), value.begin(), ::tolower);
                cost->setRetrace(ManaCost::parseManaCost(value));
            }
        }
        else if (s.find("rar") != string::npos)
        {   //rarity
            if (!card) card = NEW MTGCard();
            card->setRarity(val[0]);
        }
        break;

    case 's': //subtype, suspend
    {
        if (s.find("suspend") != string::npos)
        {
            size_t time = s.find("suspend(");
            size_t end = s.find(")=");
            int suspendTime = atoi(s.substr(time + 8,end - 2).c_str());
            if (!primitive) primitive = NEW CardPrimitive();
            if (ManaCost * cost = primitive->getManaCost())
            {
                string value = val;
                std::transform(value.begin(), value.end(), value.begin(), ::tolower);
                cost->setSuspend(ManaCost::parseManaCost(value));
                primitive->suspendedTime = suspendTime;
            }

        }
        else
        {
            if (!primitive) primitive = NEW CardPrimitive();
            vector<string> values = split(val.c_str(), ' ');
            for (size_t values_i = 0; values_i < values.size(); ++values_i)
                primitive->setSubtype(values[values_i]);
        }
        break;
    }

    case 't':
        if (!primitive) primitive = NEW CardPrimitive();
        if (key == "target")
        {
            string value = val;
            std::transform(value.begin(), value.end(), value.begin(), ::tolower);
            primitive->spellTargetType = value;
        }
        else if (key == "text")
            primitive->setText(val);
        else if (key == "type")
        {
            vector<string> values = split(val, ' ');
            for (size_t values_i = 0; values_i < values.size(); ++values_i)
                primitive->setType(values[values_i]);
        }
        else if (key == "toughness") primitive->setToughness(atoi(val.c_str()));
        break;

    default:
        if(primitive) {
            DebugTrace( endl << "MTGDECK Parsing Error: " << " [" << primitive->getName() << "]" << s << std::endl);
        } else {
            DebugTrace( endl << "MTGDECK Parsing Generic Error: " << s << std::endl);
        }
        break;
    }

    tempPrimitive = primitive;
    tempCard = card;

    return del_pos;

}
Exemplo n.º 5
0
bool AIHints::HintSaysItsForCombo(GameObserver* observer,MTGCardInstance * card)
{
    TargetChooserFactory tfc(observer);
    TargetChooser * hintTc = NULL;
    bool forCombo = false;
    for(unsigned int i = 0; i < hints.size();i++)
    {
        if (hints[i]->combos.size())
        {
            //time to find the parts and condiations of the combo.
            string part = "";
            if(!hints[i]->partOfCombo.size() && hints[i]->combos.size())
            {
                for(unsigned int cPart = 0; cPart < hints[i]->combos.size(); cPart++)
                {
                    //here we disect the different parts of a given combo
                    part = hints[i]->combos[cPart];
                    hints[i]->partOfCombo = split(part,'^');
                    for(unsigned int dPart = 0; dPart < hints[i]->partOfCombo.size(); dPart++)
                    {
                        vector<string>asTc;
                        asTc = parseBetween(hints[i]->partOfCombo[dPart],"hold(",")");
                        if(asTc.size())
                        {
                            hints[i]->hold.push_back(asTc[1]);
                            asTc.clear();
                        }
                        asTc = parseBetween(hints[i]->partOfCombo[dPart],"until(",")");
                        if(asTc.size())
                        {
                            hints[i]->until.push_back(asTc[1]);
                            asTc.clear();
                        }
                        asTc = parseBetween(hints[i]->partOfCombo[dPart],"restriction{","}");
                        if(asTc.size())
                        {
                            hints[i]->restrict.push_back(asTc[1]);
                            asTc.clear();
                        }
                        asTc = parseBetween(hints[i]->partOfCombo[dPart],"cast(",")");
                        if(asTc.size())
                        {
                            hints[i]->cardTargets[asTc[1]] = parseBetween(hints[i]->partOfCombo[dPart],"targeting(",")")[1];
                        }
                        asTc = parseBetween(hints[i]->partOfCombo[dPart],"totalmananeeded(",")");
                        if(asTc.size())
                        {
                            hints[i]->manaNeeded = asTc[1];
                            asTc.clear();
                        }
                    }
                }
            }//we collect the peices of a combo on first run.
            for(unsigned int hPart = 0; hPart < hints[i]->hold.size(); hPart++)
            {
                hintTc = tfc.createTargetChooser(hints[i]->hold[hPart],card);
                if(hintTc && hintTc->canTarget(card,true) && hintTc->countValidTargets() <= hintTc->maxtargets)
                {
                    forCombo = true;
                }
                SAFE_DELETE(hintTc);
            }
        }
    }
    return forCombo;//return forCombo that way all hints that are combos are predisected.
}