Search in sources :

Example 1 with RestrictionUntapNotMoreThanEffect

use of mage.abilities.effects.RestrictionUntapNotMoreThanEffect in project mage by magefree.

the class PlayerImpl method untap.

@Override
public void untap(Game game) {
    // create list of all "notMoreThan" effects to track which one are consumed
    Map<Entry<RestrictionUntapNotMoreThanEffect, Set<Ability>>, Integer> notMoreThanEffectsUsage = new HashMap<>();
    for (Entry<RestrictionUntapNotMoreThanEffect, Set<Ability>> restrictionEffect : game.getContinuousEffects().getApplicableRestrictionUntapNotMoreThanEffects(this, game).entrySet()) {
        notMoreThanEffectsUsage.put(restrictionEffect, restrictionEffect.getKey().getNumber());
    }
    if (!notMoreThanEffectsUsage.isEmpty()) {
        // create list of all permanents that can be untapped generally
        List<Permanent> canBeUntapped = new ArrayList<>();
        for (Permanent permanent : game.getBattlefield().getAllActivePermanents(playerId)) {
            boolean untap = true;
            for (RestrictionEffect effect : game.getContinuousEffects().getApplicableRestrictionEffects(permanent, game).keySet()) {
                untap &= effect.canBeUntapped(permanent, null, game, true);
            }
            if (untap) {
                canBeUntapped.add(permanent);
            }
        }
        // selected permanents to untap
        List<Permanent> selectedToUntap = new ArrayList<>();
        // player can cancel the selection of an effect to use a preferred order of restriction effects
        boolean playerCanceledSelection;
        do {
            playerCanceledSelection = false;
            // select permanents to untap to consume the "notMoreThan" effects
            for (Map.Entry<Entry<RestrictionUntapNotMoreThanEffect, Set<Ability>>, Integer> handledEntry : notMoreThanEffectsUsage.entrySet()) {
                // select a permanent to untap for this entry
                int numberToUntap = handledEntry.getValue();
                if (numberToUntap > 0) {
                    List<Permanent> leftForUntap = getPermanentsThatCanBeUntapped(game, canBeUntapped, handledEntry.getKey().getKey(), notMoreThanEffectsUsage);
                    FilterControlledPermanent filter = handledEntry.getKey().getKey().getFilter().copy();
                    String message = filter.getMessage();
                    // omit already from other untap effects selected permanents
                    for (Permanent permanent : selectedToUntap) {
                        filter.add(Predicates.not(new PermanentIdPredicate(permanent.getId())));
                    }
                    // while targets left and there is still allowed to untap
                    while (canRespond() && !leftForUntap.isEmpty() && numberToUntap > 0) {
                        // player has to select the permanent they want to untap for this restriction
                        Ability ability = handledEntry.getKey().getValue().iterator().next();
                        if (ability != null) {
                            StringBuilder sb = new StringBuilder(message).append(" to untap").append(" (").append(Math.min(leftForUntap.size(), numberToUntap)).append(" in total");
                            MageObject effectSource = game.getObject(ability.getSourceId());
                            if (effectSource != null) {
                                sb.append(" from ").append(effectSource.getLogName());
                            }
                            sb.append(')');
                            filter.setMessage(sb.toString());
                            Target target = new TargetPermanent(1, 1, filter, true);
                            if (!this.chooseTarget(Outcome.Untap, target, ability, game)) {
                                // player canceled, go on with the next effect (if no other effect available, this effect will be active again)
                                playerCanceledSelection = true;
                                break;
                            }
                            Permanent selectedPermanent = game.getPermanent(target.getFirstTarget());
                            if (leftForUntap.contains(selectedPermanent)) {
                                selectedToUntap.add(selectedPermanent);
                                numberToUntap--;
                                // don't allow to select same permanent twice
                                filter.add(Predicates.not(new PermanentIdPredicate(selectedPermanent.getId())));
                                // reduce available untap numbers from other "UntapNotMoreThan" effects if selected permanent applies to their filter too
                                for (Entry<Entry<RestrictionUntapNotMoreThanEffect, Set<Ability>>, Integer> notMoreThanEffect : notMoreThanEffectsUsage.entrySet()) {
                                    if (notMoreThanEffect.getValue() > 0 && notMoreThanEffect.getKey().getKey().getFilter().match(selectedPermanent, game)) {
                                        notMoreThanEffect.setValue(notMoreThanEffect.getValue() - 1);
                                    }
                                }
                                // update the left for untap list
                                leftForUntap = getPermanentsThatCanBeUntapped(game, canBeUntapped, handledEntry.getKey().getKey(), notMoreThanEffectsUsage);
                                // remove already selected permanents
                                for (Permanent permanent : selectedToUntap) {
                                    leftForUntap.remove(permanent);
                                }
                            } else {
                                // player selected an permanent that is restricted by another effect, disallow it (so AI can select another one)
                                filter.add(Predicates.not(new PermanentIdPredicate(selectedPermanent.getId())));
                                if (this.isHuman() && !game.isSimulation()) {
                                    game.informPlayer(this, "This permanent can't be untapped because of other restricting effect.");
                                }
                            }
                        }
                    }
                }
            }
        } while (canRespond() && playerCanceledSelection);
        if (!game.isSimulation()) {
            // show in log which permanents were selected to untap
            for (Permanent permanent : selectedToUntap) {
                game.informPlayers(this.getLogName() + " untapped " + permanent.getLogName());
            }
        }
        // untap if permanent is not concerned by notMoreThan effects or is included in the selectedToUntapList
        for (Permanent permanent : canBeUntapped) {
            boolean doUntap = true;
            if (!selectedToUntap.contains(permanent)) {
                // if the permanent is covered by one of the restriction effects, don't untap it
                for (Entry<Entry<RestrictionUntapNotMoreThanEffect, Set<Ability>>, Integer> notMoreThanEffect : notMoreThanEffectsUsage.entrySet()) {
                    if (notMoreThanEffect.getKey().getKey().getFilter().match(permanent, game)) {
                        doUntap = false;
                        break;
                    }
                }
            }
            if (permanent != null && doUntap) {
                permanent.untap(game);
            }
        }
    } else {
        for (Permanent permanent : game.getBattlefield().getAllActivePermanents(playerId)) {
            boolean untap = true;
            for (RestrictionEffect effect : game.getContinuousEffects().getApplicableRestrictionEffects(permanent, game).keySet()) {
                untap &= effect.canBeUntapped(permanent, null, game, true);
            }
            if (untap) {
                permanent.untap(game);
            }
        }
    }
}
Also used : AlternateManaPaymentAbility(mage.abilities.costs.mana.AlternateManaPaymentAbility) StackAbility(mage.game.stack.StackAbility) WhileSearchingPlayFromLibraryAbility(mage.abilities.common.WhileSearchingPlayFromLibraryAbility) AtTheEndOfTurnStepPostDelayedTriggeredAbility(mage.abilities.common.delayed.AtTheEndOfTurnStepPostDelayedTriggeredAbility) PassAbility(mage.abilities.common.PassAbility) PlayLandAsCommanderAbility(mage.abilities.common.PlayLandAsCommanderAbility) PermanentIdPredicate(mage.filter.predicate.permanent.PermanentIdPredicate) Permanent(mage.game.permanent.Permanent) FilterPermanent(mage.filter.FilterPermanent) FilterControlledPermanent(mage.filter.common.FilterControlledPermanent) TargetPermanent(mage.target.TargetPermanent) FilterControlledPermanent(mage.filter.common.FilterControlledPermanent) RestrictionUntapNotMoreThanEffect(mage.abilities.effects.RestrictionUntapNotMoreThanEffect) Entry(java.util.Map.Entry) Target(mage.target.Target) TargetPermanent(mage.target.TargetPermanent) RestrictionEffect(mage.abilities.effects.RestrictionEffect) ImmutableMap(com.google.common.collect.ImmutableMap)

Aggregations

ImmutableMap (com.google.common.collect.ImmutableMap)1 Entry (java.util.Map.Entry)1 PassAbility (mage.abilities.common.PassAbility)1 PlayLandAsCommanderAbility (mage.abilities.common.PlayLandAsCommanderAbility)1 WhileSearchingPlayFromLibraryAbility (mage.abilities.common.WhileSearchingPlayFromLibraryAbility)1 AtTheEndOfTurnStepPostDelayedTriggeredAbility (mage.abilities.common.delayed.AtTheEndOfTurnStepPostDelayedTriggeredAbility)1 AlternateManaPaymentAbility (mage.abilities.costs.mana.AlternateManaPaymentAbility)1 RestrictionEffect (mage.abilities.effects.RestrictionEffect)1 RestrictionUntapNotMoreThanEffect (mage.abilities.effects.RestrictionUntapNotMoreThanEffect)1 FilterPermanent (mage.filter.FilterPermanent)1 FilterControlledPermanent (mage.filter.common.FilterControlledPermanent)1 PermanentIdPredicate (mage.filter.predicate.permanent.PermanentIdPredicate)1 Permanent (mage.game.permanent.Permanent)1 StackAbility (mage.game.stack.StackAbility)1 Target (mage.target.Target)1 TargetPermanent (mage.target.TargetPermanent)1