Search in sources :

Example 1 with SagaAbility

use of mage.abilities.common.SagaAbility in project mage by magefree.

the class GameImpl method checkStateBasedActions.

/**
 * 116.5. Each time a player would get priority, the game first performs all
 * applicable state-based actions as a single event (see rule 704,
 * “State-Based Actions”), then repeats this process until no state-based
 * actions are performed. Then triggered abilities are put on the stack (see
 * rule 603, “Handling Triggered Abilities”). These steps repeat in order
 * until no further state-based actions are performed and no abilities
 * trigger. Then the player who would have received priority does so.
 *
 * @return
 */
protected boolean checkStateBasedActions() {
    boolean somethingHappened = false;
    // 20091005 - 704.5a/704.5b/704.5c
    for (Player player : state.getPlayers().values()) {
        if (!player.hasLost() && ((player.getLife() <= 0 && player.canLoseByZeroOrLessLife()) || player.getLibrary().isEmptyDraw() || player.getCounters().getCount(CounterType.POISON) >= 10)) {
            player.lost(this);
        }
    }
    // If a Dungeon is on its last room and is not the source of any triggered abilities, it is removed
    Set<Dungeon> dungeonsToRemove = new HashSet<>();
    for (CommandObject commandObject : state.getCommand()) {
        if (!(commandObject instanceof Dungeon)) {
            continue;
        }
        Dungeon dungeon = (Dungeon) commandObject;
        boolean removeDungeon = !dungeon.hasNextRoom() && this.getStack().stream().filter(DungeonRoom::isRoomTrigger).map(StackObject::getSourceId).noneMatch(dungeon.getId()::equals) && this.state.getTriggered(dungeon.getControllerId()).stream().filter(DungeonRoom::isRoomTrigger).map(Ability::getSourceId).noneMatch(dungeon.getId()::equals);
        if (removeDungeon) {
            dungeonsToRemove.add(dungeon);
        }
    }
    for (Dungeon dungeon : dungeonsToRemove) {
        this.removeDungeon(dungeon);
        somethingHappened = true;
    }
    // signature spells goes to command zone all the time
    for (Player player : state.getPlayers().values()) {
        Set<UUID> commanderIds = getCommandersIds(player, CommanderCardType.COMMANDER_OR_OATHBREAKER, false);
        if (commanderIds.isEmpty()) {
            continue;
        }
        Set<Card> commanders = new HashSet<>();
        Cards toMove = new CardsImpl();
        player.getGraveyard().stream().filter(commanderIds::contains).map(this::getCard).filter(Objects::nonNull).forEach(commanders::add);
        commanderIds.stream().map(uuid -> getExile().getCard(uuid, this)).filter(Objects::nonNull).forEach(commanders::add);
        commanders.removeIf(card -> state.checkCommanderShouldStay(card, this));
        for (Card card : commanders) {
            Zone currentZone = this.getState().getZone(card.getId());
            String currentZoneInfo = (currentZone == null ? "(error)" : "(" + currentZone.name() + ")");
            if (player.chooseUse(Outcome.Benefit, "Move " + card.getIdName() + " to the command zone or leave it in current zone " + currentZoneInfo + "?", "You can only make this choice once per object", "Move to command", "Leave in current zone " + currentZoneInfo, null, this)) {
                toMove.add(card);
            } else {
                state.setCommanderShouldStay(card, this);
            }
        }
        if (toMove.isEmpty()) {
            continue;
        }
        player.moveCards(toMove, Zone.COMMAND, null, this);
        somethingHappened = true;
    }
    // 704.5e
    // If a copy of a spell is in a zone other than the stack, it ceases to exist.
    // If a copy of a card is in any zone other than the stack or the battlefield, it ceases to exist.
    // (Isochron Scepter) 12/1/2004: If you don't want to cast the copy, you can choose not to; the copy ceases
    // to exist the next time state-based actions are checked.
    // 
    // Copied cards can be stored in GameState.copiedCards or in game state value (until LKI rework)
    // Copied cards list contains all parts of split/adventure/mdfc
    Set<Card> allCopiedCards = new HashSet<>();
    allCopiedCards.addAll(this.getState().getCopiedCards());
    Map<String, Object> stateSavedCopiedCards = this.getState().getValues(GameState.COPIED_CARD_KEY);
    allCopiedCards.addAll(stateSavedCopiedCards.values().stream().map(object -> (Card) object).filter(Objects::nonNull).collect(Collectors.toList()));
    Set<Card> copiedCardsToRemove = new HashSet<>();
    for (Card copiedCard : allCopiedCards) {
        // 1. Zone must be checked from main card only cause mdf parts can have different zones
        // (one side on battlefield, another side on outside)
        // 2. Copied card creates in OUTSIDE zone and put to stack manually in the same code,
        // so no SBA calls before real zone change (you will see here only unused cards like Isochron Scepter)
        // (Isochron Scepter) 12/1/2004: If you don't want to cast the copy, you can choose not to; the copy ceases
        // to exist the next time state-based actions are checked.
        Zone zone = state.getZone(copiedCard.getMainCard().getId());
        // TODO: remember LKI of copied cards here after LKI rework
        switch(zone) {
            case OUTSIDE:
            case BATTLEFIELD:
                {
                    // keep in outside (it's a final zone for all copied cards)
                    continue;
                }
            case STACK:
                {
                    // copied cards aren't moves and keeps in Stack zone after resolve,
                    // so it must be moved manually as SBA (see Outside zone change at the end)
                    MageObject object = getStack().getStackObject(copiedCard.getId());
                    if (object != null) {
                        // keep in stack until resolve
                        continue;
                    }
                    break;
                }
            case GRAVEYARD:
                {
                    for (Player player : getPlayers().values()) {
                        if (player.getGraveyard().contains(copiedCard.getId())) {
                            player.getGraveyard().remove(copiedCard);
                            break;
                        }
                    }
                    break;
                }
            case HAND:
                {
                    for (Player player : getPlayers().values()) {
                        if (player.getHand().contains(copiedCard.getId())) {
                            player.getHand().remove(copiedCard);
                            break;
                        }
                    }
                    break;
                }
            case LIBRARY:
                {
                    for (Player player : getPlayers().values()) {
                        if (player.getLibrary().getCard(copiedCard.getId(), this) != null) {
                            player.getLibrary().remove(copiedCard.getId(), this);
                            break;
                        }
                    }
                    break;
                }
            case EXILED:
                {
                    getExile().removeCard(copiedCard, this);
                    break;
                }
            case COMMAND:
            default:
                {
                    break;
                }
        }
        // copied card can be removed to Outside
        copiedCardsToRemove.add(copiedCard);
    }
    // real remove
    copiedCardsToRemove.forEach(card -> {
        card.setZone(Zone.OUTSIDE, this);
        this.getState().getCopiedCards().remove(card);
    // must keep card in game state as LKI alternative until LKI rework, so don't remove from it
    // TODO: change after LKI rework
    // this.getState().removeValue(GameState.COPIED_CARD_KEY + copiedCard.getId().toString());
    });
    List<Permanent> legendary = new ArrayList<>();
    List<Permanent> worldEnchantment = new ArrayList<>();
    List<FilterCreaturePermanent> usePowerInsteadOfToughnessForDamageLethalityFilters = getState().getActivePowerInsteadOfToughnessForDamageLethalityFilters();
    for (Permanent perm : getBattlefield().getAllActivePermanents()) {
        if (perm.isCreature(this)) {
            // 20091005 - 704.5f
            if (perm.getToughness().getValue() <= 0) {
                if (movePermanentToGraveyardWithInfo(perm)) {
                    somethingHappened = true;
                    continue;
                }
            } else // 20091005 - 704.5g/704.5h
            {
                /*
                     * for handling Zilortha, Strength Incarnate:
                     * 2020-04-17: Any time the game is checking whether damage is lethal or if a creature should be destroyed for having lethal damage marked on it, use the power of your creatures rather than their toughness to check the damage against. This includes being assigned trample damage, damage from Flame Spill, and so on.
                     */
                boolean usePowerInsteadOfToughnessForDamageLethality = usePowerInsteadOfToughnessForDamageLethalityFilters.stream().anyMatch(filter -> filter.match(perm, this));
                int lethalDamageThreshold = usePowerInsteadOfToughnessForDamageLethality ? // Zilortha, Strength Incarnate, 2020-04-17: A creature with 0 power isn’t destroyed unless it has at least 1 damage marked on it.
                Math.max(perm.getPower().getValue(), 1) : perm.getToughness().getValue();
                if (lethalDamageThreshold <= perm.getDamage() || perm.isDeathtouched()) {
                    if (perm.destroy(null, this, false)) {
                        somethingHappened = true;
                        continue;
                    }
                }
            }
            if (perm.getPairedCard() != null) {
                // 702.93e.: ...another player gains control
                // ...or the creature it's paired with leaves the battlefield.
                Permanent paired = perm.getPairedCard().getPermanent(this);
                if (paired == null || !perm.isControlledBy(paired.getControllerId()) || paired.getPairedCard() == null) {
                    perm.setPairedCard(null);
                    if (paired != null && paired.getPairedCard() != null) {
                        paired.setPairedCard(null);
                    }
                    somethingHappened = true;
                }
            }
            if (perm.getBandedCards() != null && !perm.getBandedCards().isEmpty()) {
                for (UUID bandedId : new ArrayList<>(perm.getBandedCards())) {
                    Permanent banded = getPermanent(bandedId);
                    if (banded == null || !perm.isControlledBy(banded.getControllerId()) || !banded.getBandedCards().contains(perm.getId())) {
                        perm.removeBandedCard(bandedId);
                        if (banded != null && banded.getBandedCards().contains(perm.getId())) {
                            banded.removeBandedCard(perm.getId());
                        }
                        somethingHappened = true;
                    }
                }
            }
        } else if (perm.getPairedCard() != null) {
            // 702.93e.: ...stops being a creature
            Permanent paired = perm.getPairedCard().getPermanent(this);
            perm.setPairedCard(null);
            if (paired != null) {
                paired.setPairedCard(null);
            }
            somethingHappened = true;
        } else if (perm.getBandedCards() != null && !perm.getBandedCards().isEmpty()) {
            perm.clearBandedCards();
            for (UUID bandedId : perm.getBandedCards()) {
                Permanent banded = getPermanent(bandedId);
                if (banded != null) {
                    banded.removeBandedCard(perm.getId());
                }
                somethingHappened = true;
            }
        }
        if (perm.isPlaneswalker(this)) {
            // 20091005 - 704.5i
            if (perm.getCounters(this).getCount(CounterType.LOYALTY) == 0) {
                if (movePermanentToGraveyardWithInfo(perm)) {
                    somethingHappened = true;
                    continue;
                }
            }
        }
        if (perm.isWorld()) {
            worldEnchantment.add(perm);
        }
        if (perm.hasSubtype(SubType.AURA, this)) {
            // 20091005 - 704.5n, 702.14c
            if (perm.getAttachedTo() == null) {
                if (!perm.isCreature(this) && !perm.getAbilities(this).containsClass(BestowAbility.class)) {
                    if (movePermanentToGraveyardWithInfo(perm)) {
                        somethingHappened = true;
                    }
                }
            } else {
                Ability spellAbility = perm.getSpellAbility();
                if (spellAbility == null) {
                    if (!perm.getAbilities().isEmpty()) {
                        // Can happen for created tokens (e.g. Estrid, the Masked)
                        spellAbility = perm.getAbilities().get(0);
                    }
                }
                if (spellAbility.getTargets().isEmpty()) {
                    for (Ability ability : perm.getAbilities(this)) {
                        if ((ability instanceof SpellAbility) && SpellAbilityType.BASE_ALTERNATE == ((SpellAbility) ability).getSpellAbilityType() && !ability.getTargets().isEmpty()) {
                            spellAbility = ability;
                            break;
                        }
                    }
                }
                if (spellAbility.getTargets().isEmpty()) {
                    Permanent enchanted = this.getPermanent(perm.getAttachedTo());
                    logger.error("Aura without target: " + perm.getName() + " attached to " + (enchanted == null ? " null" : enchanted.getName()));
                } else {
                    Target target = spellAbility.getTargets().get(0);
                    if (target instanceof TargetPermanent) {
                        Permanent attachedTo = getPermanent(perm.getAttachedTo());
                        if (attachedTo == null || !attachedTo.getAttachments().contains(perm.getId())) {
                            // handle bestow unattachment
                            Card card = this.getCard(perm.getId());
                            if (card != null && card.isCreature(this)) {
                                UUID wasAttachedTo = perm.getAttachedTo();
                                perm.attachTo(null, null, this);
                                fireEvent(new UnattachedEvent(wasAttachedTo, perm.getId(), perm, null));
                            } else if (movePermanentToGraveyardWithInfo(perm)) {
                                somethingHappened = true;
                            }
                        } else {
                            Filter auraFilter = spellAbility.getTargets().get(0).getFilter();
                            if (auraFilter instanceof FilterPermanent) {
                                if (!((FilterPermanent) auraFilter).match(attachedTo, perm.getId(), perm.getControllerId(), this) || attachedTo.cantBeAttachedBy(perm, null, this, true)) {
                                    Card card = this.getCard(perm.getId());
                                    if (card != null && card.isCreature(this)) {
                                        UUID wasAttachedTo = perm.getAttachedTo();
                                        perm.attachTo(null, null, this);
                                        BestowAbility.becomeCreature(perm, this);
                                        fireEvent(new UnattachedEvent(wasAttachedTo, perm.getId(), perm, null));
                                    } else if (movePermanentToGraveyardWithInfo(perm)) {
                                        somethingHappened = true;
                                    }
                                }
                            } else if (!auraFilter.match(attachedTo, this) || attachedTo.cantBeAttachedBy(perm, null, this, true)) {
                                // handle bestow unattachment
                                Card card = this.getCard(perm.getId());
                                if (card != null && card.isCreature(this)) {
                                    UUID wasAttachedTo = perm.getAttachedTo();
                                    perm.attachTo(null, null, this);
                                    BestowAbility.becomeCreature(perm, this);
                                    fireEvent(new UnattachedEvent(wasAttachedTo, perm.getId(), perm, null));
                                } else if (movePermanentToGraveyardWithInfo(perm)) {
                                    somethingHappened = true;
                                }
                            }
                        }
                    } else if (target instanceof TargetPlayer) {
                        Player attachedToPlayer = getPlayer(perm.getAttachedTo());
                        if (attachedToPlayer == null || attachedToPlayer.hasLost()) {
                            if (movePermanentToGraveyardWithInfo(perm)) {
                                somethingHappened = true;
                            }
                        } else {
                            Filter auraFilter = spellAbility.getTargets().get(0).getFilter();
                            if (!auraFilter.match(attachedToPlayer, this) || attachedToPlayer.hasProtectionFrom(perm, this)) {
                                if (movePermanentToGraveyardWithInfo(perm)) {
                                    somethingHappened = true;
                                }
                            }
                        }
                    } else if (target instanceof TargetCard) {
                        Card attachedTo = getCard(perm.getAttachedTo());
                        if (attachedTo == null || !(spellAbility.getTargets().get(0)).canTarget(perm.getControllerId(), perm.getAttachedTo(), spellAbility, this)) {
                            if (movePermanentToGraveyardWithInfo(perm)) {
                                if (attachedTo != null) {
                                    attachedTo.removeAttachment(perm.getId(), null, this);
                                }
                                somethingHappened = true;
                            }
                        }
                    }
                }
            }
        }
        // and it isn't the source of a chapter ability that has triggered but not yet left the stack, that Saga's controller sacrifices it.
        if (perm.hasSubtype(SubType.SAGA, this)) {
            int maxChapter = perm.getAbilities(this).stream().filter(SagaAbility.class::isInstance).map(SagaAbility.class::cast).map(SagaAbility::getMaxChapter).mapToInt(SagaChapter::getNumber).max().orElse(0);
            boolean sacSaga = maxChapter <= perm.getCounters(this).getCount(CounterType.LORE) && this.getStack().stream().filter(SagaAbility::isChapterAbility).map(StackObject::getSourceId).noneMatch(perm.getId()::equals) && this.state.getTriggered(perm.getControllerId()).stream().filter(SagaAbility::isChapterAbility).map(Ability::getSourceId).noneMatch(perm.getId()::equals);
            if (sacSaga) {
                // After the last chapter ability has left the stack, you'll sacrifice the Saga
                perm.sacrifice(null, this);
                somethingHappened = true;
            }
        }
        if (this.getState().isLegendaryRuleActive() && StaticFilters.FILTER_PERMANENT_LEGENDARY.match(perm, this)) {
            legendary.add(perm);
        }
        if (StaticFilters.FILTER_PERMANENT_EQUIPMENT.match(perm, this)) {
            // 20091005 - 704.5p, 702.14d
            if (perm.getAttachedTo() != null) {
                Permanent attachedTo = getPermanent(perm.getAttachedTo());
                if (attachedTo != null) {
                    for (Ability ability : perm.getAbilities(this)) {
                        if (ability instanceof AttachableToRestrictedAbility) {
                            if (!((AttachableToRestrictedAbility) ability).canEquip(attachedTo, null, this)) {
                                attachedTo = null;
                                break;
                            }
                        }
                    }
                }
                if (attachedTo == null || !attachedTo.getAttachments().contains(perm.getId())) {
                    UUID wasAttachedTo = perm.getAttachedTo();
                    perm.attachTo(null, null, this);
                    fireEvent(new UnattachedEvent(wasAttachedTo, perm.getId(), perm, null));
                } else if (!attachedTo.isCreature(this) || attachedTo.hasProtectionFrom(perm, this)) {
                    if (attachedTo.removeAttachment(perm.getId(), null, this)) {
                        somethingHappened = true;
                    }
                }
            }
        }
        if (StaticFilters.FILTER_PERMANENT_FORTIFICATION.match(perm, this)) {
            if (perm.getAttachedTo() != null) {
                Permanent land = getPermanent(perm.getAttachedTo());
                if (land == null || !land.getAttachments().contains(perm.getId())) {
                    perm.attachTo(null, null, this);
                } else if (!land.isLand(this) || land.hasProtectionFrom(perm, this)) {
                    if (land.removeAttachment(perm.getId(), null, this)) {
                        somethingHappened = true;
                    }
                }
            }
        }
        // it becomes unattached and remains on the battlefield.
        if (!perm.getAttachments().isEmpty()) {
            for (UUID attachmentId : perm.getAttachments()) {
                Permanent attachment = getPermanent(attachmentId);
                if (attachment != null && (attachment.isCreature(this) || !(attachment.hasSubtype(SubType.AURA, this) || attachment.hasSubtype(SubType.EQUIPMENT, this) || attachment.hasSubtype(SubType.FORTIFICATION, this)))) {
                    if (perm.removeAttachment(attachment.getId(), null, this)) {
                        somethingHappened = true;
                        break;
                    }
                }
            }
        }
        // 20110501 - 704.5r
        if (perm.getCounters(this).containsKey(CounterType.P1P1) && perm.getCounters(this).containsKey(CounterType.M1M1)) {
            int p1p1 = perm.getCounters(this).getCount(CounterType.P1P1);
            int m1m1 = perm.getCounters(this).getCount(CounterType.M1M1);
            int min = Math.min(p1p1, m1m1);
            perm.getCounters(this).removeCounter(CounterType.P1P1, min);
            perm.getCounters(this).removeCounter(CounterType.M1M1, min);
        }
        // has more than N counters of that kind on it, all but N of those counters are removed from it.
        for (Ability ability : perm.getAbilities(this)) {
            if (ability instanceof CantHaveMoreThanAmountCountersSourceAbility) {
                CantHaveMoreThanAmountCountersSourceAbility counterAbility = (CantHaveMoreThanAmountCountersSourceAbility) ability;
                int count = perm.getCounters(this).getCount(counterAbility.getCounterType());
                if (count > counterAbility.getAmount()) {
                    perm.removeCounters(counterAbility.getCounterType().getName(), count - counterAbility.getAmount(), counterAbility, this);
                    somethingHappened = true;
                }
            }
        }
    }
    if (legendary.size() > 1) {
        // don't bother checking if less than 2 legends in play
        for (Permanent legend : legendary) {
            FilterPermanent filterLegendName = new FilterPermanent();
            filterLegendName.add(SuperType.LEGENDARY.getPredicate());
            filterLegendName.add(new NamePredicate(legend.getName()));
            filterLegendName.add(new ControllerIdPredicate(legend.getControllerId()));
            if (getBattlefield().contains(filterLegendName, null, legend.getControllerId(), this, 2)) {
                if (!replaceEvent(GameEvent.getEvent(GameEvent.EventType.DESTROY_PERMANENT_BY_LEGENDARY_RULE, legend.getId(), legend.getControllerId()))) {
                    Player controller = this.getPlayer(legend.getControllerId());
                    if (controller != null) {
                        Target targetLegendaryToKeep = new TargetPermanent(filterLegendName);
                        targetLegendaryToKeep.setTargetName(legend.getName() + " to keep (Legendary Rule)?");
                        controller.chooseTarget(Outcome.Benefit, targetLegendaryToKeep, null, this);
                        for (Permanent dupLegend : getBattlefield().getActivePermanents(filterLegendName, legend.getControllerId(), this)) {
                            if (!targetLegendaryToKeep.getTargets().contains(dupLegend.getId())) {
                                movePermanentToGraveyardWithInfo(dupLegend);
                            }
                        }
                    }
                    return true;
                }
            }
        }
    }
    // 704.5k  - World Enchantments
    if (worldEnchantment.size() > 1) {
        int newestCard = -1;
        Set<UUID> controllerIdOfNewest = new HashSet<>();
        Permanent newestPermanent = null;
        for (Permanent permanent : worldEnchantment) {
            if (newestCard == -1) {
                newestCard = permanent.getCreateOrder();
                newestPermanent = permanent;
                controllerIdOfNewest.clear();
                controllerIdOfNewest.add(permanent.getControllerId());
            } else if (newestCard < permanent.getCreateOrder()) {
                newestCard = permanent.getCreateOrder();
                newestPermanent = permanent;
                controllerIdOfNewest.clear();
                controllerIdOfNewest.add(permanent.getControllerId());
            } else if (newestCard == permanent.getCreateOrder()) {
                // In the event of a tie for the shortest amount of time, all are put into their owners’ graveyards. This is called the “world rule.”
                newestPermanent = null;
                controllerIdOfNewest.add(permanent.getControllerId());
            }
        }
        for (UUID controllerId : controllerIdOfNewest) {
            PlayerList newestPermanentControllerRange = state.getPlayersInRange(controllerId, this);
            // 801.12 The "world rule" applies to a permanent only if other world permanents are within its controller's range of influence.
            for (Permanent permanent : worldEnchantment) {
                if (newestPermanentControllerRange.contains(permanent.getControllerId()) && !Objects.equals(newestPermanent, permanent)) {
                    movePermanentToGraveyardWithInfo(permanent);
                    somethingHappened = true;
                }
            }
        }
    }
    // This is not a state-based action but it's unclear where else to put it
    if (hasDayNight()) {
        for (Permanent permanent : getBattlefield().getAllActivePermanents()) {
            if ((permanent.getAbilities(this).containsClass(DayboundAbility.class) && !state.isDaytime()) || (permanent.getAbilities(this).containsClass(NightboundAbility.class) && state.isDaytime())) {
                somethingHappened = permanent.transform(null, this, true) || somethingHappened;
            }
        }
    }
    // TODO: implement the rest
    return somethingHappened;
}
Also used : SagaAbility(mage.abilities.common.SagaAbility) ReflexiveTriggeredAbility(mage.abilities.common.delayed.ReflexiveTriggeredAbility) Turn(mage.game.turn.Turn) Mulligan(mage.game.mulligan.Mulligan) Counters(mage.counters.Counters) AttachableToRestrictedAbility(mage.abilities.common.AttachableToRestrictedAbility) TriggeredManaAbility(mage.abilities.mana.TriggeredManaAbility) ContinuousEffect(mage.abilities.effects.ContinuousEffect) Logger(org.apache.log4j.Logger) mage.watchers.common(mage.watchers.common) StackObject(mage.game.stack.StackObject) mage.constants(mage.constants) NamePredicate(mage.filter.predicate.mageobject.NamePredicate) mage.abilities(mage.abilities) MageAction(mage.actions.impl.MageAction) Choice(mage.choices.Choice) FilterCard(mage.filter.FilterCard) StaticFilters(mage.filter.StaticFilters) Monarch(mage.designations.Monarch) GameLog(mage.util.GameLog) mage.abilities.keyword(mage.abilities.keyword) mage.game.command(mage.game.command) mage.cards(mage.cards) Battlefield(mage.game.permanent.Battlefield) DelayedTriggeredManaAbility(mage.abilities.mana.DelayedTriggeredManaAbility) CardUtil(mage.util.CardUtil) TargetPlayer(mage.target.TargetPlayer) Collectors(java.util.stream.Collectors) Filter(mage.filter.Filter) Phase(mage.game.turn.Phase) Serializable(java.io.Serializable) Watcher(mage.watchers.Watcher) PreventionEffectData(mage.abilities.effects.PreventionEffectData) Effect(mage.abilities.effects.Effect) InfoEffect(mage.abilities.effects.common.InfoEffect) Permanent(mage.game.permanent.Permanent) Entry(java.util.Map.Entry) CounterType(mage.counters.CounterType) Target(mage.target.Target) SimpleStaticAbility(mage.abilities.common.SimpleStaticAbility) java.util(java.util) Combat(mage.game.combat.Combat) mage.game.events(mage.game.events) ControllerIdPredicate(mage.filter.predicate.permanent.ControllerIdPredicate) PlayerList(mage.players.PlayerList) FilterPermanent(mage.filter.FilterPermanent) Player(mage.players.Player) SpellStack(mage.game.stack.SpellStack) Step(mage.game.turn.Step) Designation(mage.designations.Designation) TargetCard(mage.target.TargetCard) MageObject(mage.MageObject) FilterCreaturePermanent(mage.filter.common.FilterCreaturePermanent) Players(mage.players.Players) Spell(mage.game.stack.Spell) RandomUtil(mage.util.RandomUtil) CopyApplier(mage.util.functions.CopyApplier) Deck(mage.cards.decks.Deck) EventType(mage.game.events.TableEvent.EventType) IOException(java.io.IOException) MageException(mage.MageException) CopyEffect(mage.abilities.effects.common.CopyEffect) ContinuousEffects(mage.abilities.effects.ContinuousEffects) PermanentCard(mage.game.permanent.PermanentCard) MessageToClient(mage.util.MessageToClient) CantHaveMoreThanAmountCountersSourceAbility(mage.abilities.common.CantHaveMoreThanAmountCountersSourceAbility) TurnMod(mage.game.turn.TurnMod) TargetPermanent(mage.target.TargetPermanent) FilterPermanent(mage.filter.FilterPermanent) Permanent(mage.game.permanent.Permanent) FilterPermanent(mage.filter.FilterPermanent) FilterCreaturePermanent(mage.filter.common.FilterCreaturePermanent) TargetPermanent(mage.target.TargetPermanent) PlayerList(mage.players.PlayerList) TargetPlayer(mage.target.TargetPlayer) Target(mage.target.Target) CantHaveMoreThanAmountCountersSourceAbility(mage.abilities.common.CantHaveMoreThanAmountCountersSourceAbility) FilterCreaturePermanent(mage.filter.common.FilterCreaturePermanent) ControllerIdPredicate(mage.filter.predicate.permanent.ControllerIdPredicate) TargetPermanent(mage.target.TargetPermanent) SagaAbility(mage.abilities.common.SagaAbility) ReflexiveTriggeredAbility(mage.abilities.common.delayed.ReflexiveTriggeredAbility) AttachableToRestrictedAbility(mage.abilities.common.AttachableToRestrictedAbility) TriggeredManaAbility(mage.abilities.mana.TriggeredManaAbility) DelayedTriggeredManaAbility(mage.abilities.mana.DelayedTriggeredManaAbility) SimpleStaticAbility(mage.abilities.common.SimpleStaticAbility) CantHaveMoreThanAmountCountersSourceAbility(mage.abilities.common.CantHaveMoreThanAmountCountersSourceAbility) TargetPlayer(mage.target.TargetPlayer) Player(mage.players.Player) NamePredicate(mage.filter.predicate.mageobject.NamePredicate) MageObject(mage.MageObject) TargetCard(mage.target.TargetCard) AttachableToRestrictedAbility(mage.abilities.common.AttachableToRestrictedAbility) FilterCard(mage.filter.FilterCard) TargetCard(mage.target.TargetCard) PermanentCard(mage.game.permanent.PermanentCard) Filter(mage.filter.Filter) StackObject(mage.game.stack.StackObject) MageObject(mage.MageObject) SagaAbility(mage.abilities.common.SagaAbility)

Aggregations

IOException (java.io.IOException)1 Serializable (java.io.Serializable)1 java.util (java.util)1 Entry (java.util.Map.Entry)1 Collectors (java.util.stream.Collectors)1 MageException (mage.MageException)1 MageObject (mage.MageObject)1 mage.abilities (mage.abilities)1 AttachableToRestrictedAbility (mage.abilities.common.AttachableToRestrictedAbility)1 CantHaveMoreThanAmountCountersSourceAbility (mage.abilities.common.CantHaveMoreThanAmountCountersSourceAbility)1 SagaAbility (mage.abilities.common.SagaAbility)1 SimpleStaticAbility (mage.abilities.common.SimpleStaticAbility)1 ReflexiveTriggeredAbility (mage.abilities.common.delayed.ReflexiveTriggeredAbility)1 ContinuousEffect (mage.abilities.effects.ContinuousEffect)1 ContinuousEffects (mage.abilities.effects.ContinuousEffects)1 Effect (mage.abilities.effects.Effect)1 PreventionEffectData (mage.abilities.effects.PreventionEffectData)1 CopyEffect (mage.abilities.effects.common.CopyEffect)1 InfoEffect (mage.abilities.effects.common.InfoEffect)1 mage.abilities.keyword (mage.abilities.keyword)1