Beispiel #1
0
int AIPlayer::clickMultiTarget(TargetChooser * tc, vector<Targetable*>& potentialTargets)
{
    vector<Targetable*>::iterator ite = potentialTargets.begin();
    while(ite != potentialTargets.end())
    {
        MTGCardInstance * card = dynamic_cast<MTGCardInstance *>(*ite);
        if(card && card == tc->source)//if the source is part of the targetting deal with it first. second click is "confirming click".
        {
            clickstream.push(NEW AIAction(this, card));
            DebugTrace("Ai clicked source as a target: " << (card ? card->name : "None" ) << endl );
            ite = potentialTargets.erase(ite);
            continue;
        }
        else if(Player * pTarget = dynamic_cast<Player *>(*ite))
        {
            clickstream.push(NEW AIAction(this, pTarget));
            DebugTrace("Ai clicked Player as a target");
            ite = potentialTargets.erase(ite);
            continue;
        }
        ++ite;
    }

    randomGenerator.random_shuffle(potentialTargets.begin(), potentialTargets.end());
    if(potentialTargets.size())
        clickstream.push(NEW AIAction(this, NULL,tc->source,potentialTargets));
    while(clickstream.size())
    {
        AIAction * action = clickstream.front();
        action->Act();
        SAFE_DELETE(action);
        clickstream.pop();
    }
    return 1;
}
Beispiel #2
0
int AIPlayer::clickSingleTarget(TargetChooser *, vector<Targetable*>& potentialTargets, MTGCardInstance * chosenCard)
{
    int i = randomGenerator.random() % potentialTargets.size();

    if(MTGCardInstance * card = dynamic_cast<MTGCardInstance *>(potentialTargets[i]))
    {
        if (!chosenCard)
            clickstream.push(NEW AIAction(this, card));
    }
    else if(Player * player = dynamic_cast<Player *>(potentialTargets[i]))
    {
        clickstream.push(NEW AIAction(this, player));
    }

    return 1;
}
Beispiel #3
0
AIAction * AIHints::findAbilityRecursive(AIHint * hint, ManaCost * potentialMana)
{
        RankingContainer ranking = findActions(hint);

        AIAction * a = NULL;
        if (ranking.size())
        {
            a = NEW AIAction(ranking.begin()->first);
        }

        string s = constraintsNotFulfilled(a, hint, potentialMana);
        if (hint->mCombatAttackTip.size() || hint->castOrder.size())
            return NULL;
        if (s.size())
        {
            SAFE_DELETE(a);
            AIHint * nextHint = getByCondition(s);
            DebugTrace("**I Need " << s << ", this can be provided by " << (nextHint ? nextHint->mAction : "NULL") << "\n\n");
            if (nextHint && nextHint != hint)
                return findAbilityRecursive(nextHint, potentialMana);
            return NULL;
        }

        return a;

}
    AIAction &GOAPlanner::AddAction(const std::string &name, ActionHandler func)
    {
        auto itr = _actions.find(name);

        UAssert(itr == _actions.end(), "The action \"%s\" has already been added.", name.c_str());

        // add the action to the actions map
        _actions.emplace(std::make_pair(name, AIAction(name, func)));

        return _actions[name];
    }
Beispiel #5
0
int AIMomirPlayer::momir()
{
    if (!game->hand->nb_cards) return 0; //nothing to discard :/
    int result = 0;
    int opponentCreatures = getCreaturesInfo(opponent(), INFO_NBCREATURES);
    int myCreatures = getCreaturesInfo(this, INFO_NBCREATURES );
    ManaCost * potentialMana = getPotentialMana();
    int converted = potentialMana->getConvertedCost();
    SAFE_DELETE(potentialMana);
    int efficiency = 100;
    int chance = 1 + (randomGenerator.random() % 100);
    if (converted == 5 && myCreatures > opponentCreatures && game->hand->nb_cards < 4) efficiency = 5; //Strategy: skip 5 drop
    if (converted == 7 && myCreatures > opponentCreatures && game->hand->nb_cards < 2) efficiency = 50; //Strategy: 7 drops have bad upkeep costs and the AI doesn't handle those right now...
    if (converted > 8) converted = 8;
    if (converted == 8) efficiency = 100 - (myCreatures - opponentCreatures);

    if (efficiency >= chance)
    {

        std::vector<int16_t> _cost;
        _cost.push_back(Constants::MTG_COLOR_ARTIFACT);
        _cost.push_back(converted);
        ManaCost * cost = NEW ManaCost(_cost);
        MTGAbility * ability = getMomirAbility();
        MTGCardInstance * card = game->hand->cards[0];
        if (ability->isReactingToClick(card, cost))
        {
            payTheManaCost(cost);
            AIAction * a = NEW AIAction(this, ability, card);
            clickstream.push(a);
            result = 1;
        }
        delete cost;
    }
    return result;
}
Beispiel #6
0
int AIMomirPlayer::computeActions()
{
    //Part of the strategy goes here. When should we put a land into play ?
    /*
     Another gift from Alex Majlaton on my first day playing Momir, and it has served me well ever since. It goes a little something like this: (a) if you are on the play, hit your Two through Four, skip your Five, and then hit all the way to Eight; (b) if you are on the draw and your opponent skips his One, you make Two through Eight; (c) if you are on the draw and your opponent hits a One, you match him drop-for-drop for the rest of the game.

     You skip your Five on the play because it is the weakest drop. There are plenty of serviceable guys there, but very few bombs compared to other drops
     the general rule is this: if you want to get to Eight, you have to skip two drops on the play and one drop on the draw.
     */

    Player * p = observer->currentPlayer;
    if (!(observer->currentlyActing() == this)) return 0;
    if (chooseTarget()) return 1;
    int currentGamePhase = observer->getCurrentGamePhase();
    if (observer->isInterrupting == this)
    {   // interrupting
        selectAbility();
        return 1;
    }
    else if (p == this && observer->mLayers->stackLayer()->count(0, NOT_RESOLVED) == 0)
    {   //standard actions
        CardDescriptor cd;
        MTGCardInstance * card = NULL;

        switch (currentGamePhase)
        {
        case MTG_PHASE_FIRSTMAIN:
        {
            ManaCost * potentialMana = getPotentialMana();
            int converted = potentialMana->getConvertedCost();
            SAFE_DELETE(potentialMana);

            if (converted < 8 || game->hand->nb_cards > 1)
            {
                //Attempt to put land into play
                cd.init();
                cd.setColor(Constants::MTG_COLOR_LAND);
                card = cd.match(game->hand);
                int canPutLandsIntoPlay = game->playRestrictions->canPutIntoZone(card, game->inPlay);
                if (card && (canPutLandsIntoPlay == PlayRestriction::CAN_PLAY))
                {
                    MTGAbility * putIntoPlay = observer->mLayers->actionLayer()->getAbility(MTGAbility::PUT_INTO_PLAY);
                    AIAction * a = NEW AIAction(this, putIntoPlay, card); //TODO putinplay action
                    clickstream.push(a);
                    return 1;
                }
            }
            momir();
            return 1;
            break;
        }
        case MTG_PHASE_SECONDMAIN:
            selectAbility();
            return 1;
            break;
        default:
            return AIPlayerBaka::computeActions();
            break;
        }
    }
    return AIPlayerBaka::computeActions();
}
Beispiel #7
0
AIAction SimpleAI::Tick(float _timespan, std::vector<Core_ptr>& /*_allies*/, std::vector<Core_ptr>& _enemies, Core_ptr _self)
{
	AIAction a = AIAction(0, 0, 0, false, false); 

	sum_time_ += _timespan;
	focus_time_ += _timespan;
	strafe_time_ += _timespan;
	if(strafe_time_ > SimpleAIStrafeTime)
	{
		strafe_time_ = 0;
		if(Random::RandomChance(0.4f))
			strafe_clockwise_ = !strafe_clockwise_;
		if(Random::RandomChance(0.8f))
			preferred_minimum_range_ = SimpleAIMinimumRange * 1.5f;
		else
			preferred_minimum_range_ = SimpleAIMinimumRange * 1.0f;
	}

	if(focus_time_ > max_focus_time_ || target_ == NULL)
	{
		focus_time_ = 0;
		//Pick a new target
		if(_enemies.size() > 0)
		{
			if(target_ != NULL)
				target_->RemoveSubscriber(this);
			int index = Random::RandomIndex(static_cast<int>(_enemies.size()));

			target_ = _enemies[index];
			target_->AddSubscriber(this);
		}
	}	

	if(target_ != NULL)
	{
		Vector3f relative_position = (target_->GetPosition() - _self->GetPosition());
		float range = relative_position.length();
		float angle = atan2f(relative_position.x, relative_position.y);
		if(relative_position.lengthSq() > 0)
			relative_position.normalize();
		if(range > preferred_minimum_range_ * 2) //Close on target
		{
			a.dx_ = sinf(angle);
			a.dy_ = cosf(angle);
		}else if(range < preferred_minimum_range_) //Back off target
		{
			a.dx_ = -sinf(angle);
			a.dy_ = -cosf(angle);
		} else //Circle strafe
		{
			//Add sideways movement
			if(strafe_clockwise_)
			{
				a.dx_ = -cosf(angle) * 0.2f;
				a.dy_ = sinf(angle) * 0.2f;
			} else
			{
				a.dx_ = cosf(angle) * 0.2f;
				a.dy_ = -sinf(angle) * 0.2f;
			}
			//Reduce range movement
			float movement_in_range_dimension;
			Vector3f self_velocity = _self->GetVelocity();
			if(self_velocity.lengthSq() > 0)
			{
				self_velocity.normalize();
				movement_in_range_dimension = self_velocity.dotProduct(relative_position);
				a.dx_ -= 0.8f * sinf(angle) * movement_in_range_dimension;
				a.dy_ -= 0.8f * cosf(angle) * movement_in_range_dimension;
			}
		}
		TurnData td = GetTurnDirection(_self->GetAngle(), relative_position);
		td.turn_factor = ClampTurnDirection(td.turn_factor, 0.1f);
		//td.turn_factor *= 0.2f;
		a.dtheta_ = td.turn_factor;
		a.firing_ = true;
		a.target_ = target_;
	}

	return a;
}