Search in sources :

Example 11 with Zone

use of mage.constants.Zone in project mage by magefree.

the class ShuffleIntoLibrarySourceEffect method apply.

@Override
public boolean apply(Game game, Ability source) {
    MageObject mageObject = source.getSourceObjectIfItStillExists(game);
    if (mageObject != null) {
        Zone fromZone = game.getState().getZone(mageObject.getId());
        Player owner;
        if (mageObject instanceof Permanent) {
            owner = game.getPlayer(((Permanent) mageObject).getOwnerId());
            if (owner != null) {
                owner.moveCardToLibraryWithInfo((Permanent) mageObject, source, game, fromZone, true, true);
                owner.shuffleLibrary(source, game);
                return true;
            }
        } else if (mageObject instanceof Card) {
            owner = game.getPlayer(((Card) mageObject).getOwnerId());
            if (owner != null) {
                owner.moveCardToLibraryWithInfo((Card) mageObject, source, game, fromZone, true, true);
                owner.shuffleLibrary(source, game);
                return true;
            }
        }
    }
    return false;
}
Also used : Player(mage.players.Player) Permanent(mage.game.permanent.Permanent) Zone(mage.constants.Zone) MageObject(mage.MageObject) Card(mage.cards.Card)

Example 12 with Zone

use of mage.constants.Zone in project mage by magefree.

the class GameState method createEventGroups.

public List<GameEvent> createEventGroups(List<GameEvent> events, Game game) {
    class ZoneChangeData {

        private final Zone fromZone;

        private final Zone toZone;

        private final UUID sourceId;

        private final UUID playerId;

        Ability source;

        public ZoneChangeData(Ability source, UUID sourceId, UUID playerId, Zone fromZone, Zone toZone) {
            this.sourceId = sourceId;
            this.playerId = playerId;
            this.fromZone = fromZone;
            this.toZone = toZone;
            this.source = source;
        }

        @Override
        public int hashCode() {
            return (this.fromZone.ordinal() + 1) * 1 + (this.toZone.ordinal() + 1) * 10 + (this.sourceId != null ? this.sourceId.hashCode() : 0) + (this.source != null ? this.source.hashCode() : 0);
        }

        @Override
        public boolean equals(Object obj) {
            if (obj instanceof ZoneChangeData) {
                ZoneChangeData data = (ZoneChangeData) obj;
                return this.fromZone == data.fromZone && this.toZone == data.toZone && Objects.equals(this.sourceId, data.sourceId) && Objects.equals(this.source, data.source);
            }
            return false;
        }
    }
    Map<ZoneChangeData, List<GameEvent>> eventsByKey = new HashMap<>();
    List<GameEvent> groupEvents = new LinkedList<>();
    for (GameEvent event : events) {
        if (event instanceof ZoneChangeEvent) {
            ZoneChangeEvent castEvent = (ZoneChangeEvent) event;
            ZoneChangeData key = new ZoneChangeData(castEvent.getSource(), castEvent.getSourceId(), castEvent.getPlayerId(), castEvent.getFromZone(), castEvent.getToZone());
            if (eventsByKey.containsKey(key)) {
                eventsByKey.get(key).add(event);
            } else {
                List<GameEvent> list = new LinkedList<>();
                list.add(event);
                eventsByKey.put(key, list);
            }
        }
    }
    for (Map.Entry<ZoneChangeData, List<GameEvent>> entry : eventsByKey.entrySet()) {
        Set<Card> movedCards = new LinkedHashSet<>();
        Set<PermanentToken> movedTokens = new LinkedHashSet<>();
        for (Iterator<GameEvent> it = entry.getValue().iterator(); it.hasNext(); ) {
            GameEvent event = it.next();
            ZoneChangeEvent castEvent = (ZoneChangeEvent) event;
            UUID targetId = castEvent.getTargetId();
            Card card = ZonesHandler.getTargetCard(game, targetId);
            if (card instanceof PermanentToken) {
                movedTokens.add((PermanentToken) card);
            } else if (game.getObject(targetId) instanceof PermanentToken) {
                movedTokens.add((PermanentToken) game.getObject(targetId));
            } else if (card != null) {
                movedCards.add(card);
            }
        }
        ZoneChangeData eventData = entry.getKey();
        if (!movedCards.isEmpty() || !movedTokens.isEmpty()) {
            ZoneChangeGroupEvent event = new ZoneChangeGroupEvent(movedCards, movedTokens, eventData.sourceId, eventData.source, eventData.playerId, eventData.fromZone, eventData.toZone);
            groupEvents.add(event);
        }
    }
    return groupEvents;
}
Also used : Zone(mage.constants.Zone) PermanentToken(mage.game.permanent.PermanentToken) PermanentCard(mage.game.permanent.PermanentCard) MageObject(mage.MageObject) StackObject(mage.game.stack.StackObject) CommandObject(mage.game.command.CommandObject) PlayerList(mage.players.PlayerList) Collections.emptyList(java.util.Collections.emptyList)

Example 13 with Zone

use of mage.constants.Zone in project mage by magefree.

the class AdventureCard method moveToExile.

@Override
public boolean moveToExile(UUID exileId, String name, Ability source, Game game, List<UUID> appliedEffects) {
    if (super.moveToExile(exileId, name, source, game, appliedEffects)) {
        Zone currentZone = game.getState().getZone(getId());
        game.getState().setZone(getSpellCard().getId(), currentZone);
        return true;
    }
    return false;
}
Also used : Zone(mage.constants.Zone)

Example 14 with Zone

use of mage.constants.Zone in project mage by magefree.

the class ZonesHandler method placeInDestinationZone.

private static void placeInDestinationZone(ZoneChangeInfo info, Game game, int createOrder) {
    // Handle unmelded cards
    if (info instanceof ZoneChangeInfo.Unmelded) {
        ZoneChangeInfo.Unmelded unmelded = (ZoneChangeInfo.Unmelded) info;
        Zone toZone = null;
        for (ZoneChangeInfo subInfo : unmelded.subInfo) {
            toZone = subInfo.event.getToZone();
            placeInDestinationZone(subInfo, game, createOrder);
        }
        // We arbitrarily prefer the bottom half card. This should never be relevant.
        if (toZone != null) {
            game.setZone(unmelded.event.getTargetId(), toZone);
        }
        return;
    }
    // Handle normal cases
    ZoneChangeEvent event = info.event;
    Zone toZone = event.getToZone();
    Card targetCard = getTargetCard(game, event.getTargetId());
    // moving real cards
    Cards cardsToMove = null;
    // updating all card's parts (must be ordered LinkedHashMap)
    Map<Zone, Cards> cardsToUpdate = new LinkedHashMap<>();
    cardsToUpdate.put(toZone, new CardsImpl());
    cardsToUpdate.put(Zone.OUTSIDE, new CardsImpl());
    // if we're moving a token it shouldn't be put into any zone as an object.
    if (!(targetCard instanceof Permanent) && targetCard != null) {
        if (targetCard instanceof MeldCard) {
            // meld/group cards must be independent (use can choose order)
            cardsToMove = ((MeldCard) targetCard).getHalves();
            cardsToUpdate.get(toZone).addAll(cardsToMove);
        } else if (targetCard instanceof ModalDoubleFacesCard || targetCard instanceof ModalDoubleFacesCardHalf) {
            // mdf cards must be moved as single object, but each half must be updated separately
            ModalDoubleFacesCard mdfCard = (ModalDoubleFacesCard) targetCard.getMainCard();
            cardsToMove = new CardsImpl(mdfCard);
            cardsToUpdate.get(toZone).add(mdfCard);
            // * right to outside (it helps to ignore all triggers and other effects from that card)
            switch(toZone) {
                case STACK:
                case BATTLEFIELD:
                    if (targetCard.getId().equals(mdfCard.getLeftHalfCard().getId())) {
                        // play left
                        cardsToUpdate.get(toZone).add(mdfCard.getLeftHalfCard());
                        cardsToUpdate.get(Zone.OUTSIDE).add(mdfCard.getRightHalfCard());
                    } else if (targetCard.getId().equals(mdfCard.getRightHalfCard().getId())) {
                        // play right
                        cardsToUpdate.get(toZone).add(mdfCard.getRightHalfCard());
                        cardsToUpdate.get(Zone.OUTSIDE).add(mdfCard.getLeftHalfCard());
                    } else {
                        // cast mdf (only on stack)
                        if (!toZone.equals(Zone.STACK)) {
                            throw new IllegalStateException("Wrong mdf card move to " + toZone + " in placeInDestinationZone");
                        }
                        cardsToUpdate.get(toZone).add(mdfCard.getLeftHalfCard());
                        cardsToUpdate.get(toZone).add(mdfCard.getRightHalfCard());
                    }
                    break;
                default:
                    // move all parts
                    cardsToUpdate.get(toZone).add(mdfCard.getLeftHalfCard());
                    cardsToUpdate.get(toZone).add(mdfCard.getRightHalfCard());
                    break;
            }
        } else {
            cardsToMove = new CardsImpl(targetCard);
            cardsToUpdate.get(toZone).addAll(cardsToMove);
        }
        Player owner = game.getPlayer(targetCard.getOwnerId());
        switch(toZone) {
            case HAND:
                for (Card card : cardsToMove.getCards(game)) {
                    game.getPlayer(card.getOwnerId()).getHand().add(card);
                }
                break;
            case GRAVEYARD:
                for (Card card : chooseOrder("order to put in graveyard (last chosen will be on top)", cardsToMove, owner, game)) {
                    game.getPlayer(card.getOwnerId()).getGraveyard().add(card);
                }
                break;
            case LIBRARY:
                if (info instanceof ZoneChangeInfo.Library && ((ZoneChangeInfo.Library) info).top) {
                    // on top
                    for (Card card : chooseOrder("order to put on top of library (last chosen will be topmost)", cardsToMove, owner, game)) {
                        game.getPlayer(card.getOwnerId()).getLibrary().putOnTop(card, game);
                    }
                } else {
                    // on bottom
                    for (Card card : chooseOrder("order to put on bottom of library (last chosen will be bottommost)", cardsToMove, owner, game)) {
                        game.getPlayer(card.getOwnerId()).getLibrary().putOnBottom(card, game);
                    }
                }
                break;
            case EXILED:
                for (Card card : cardsToMove.getCards(game)) {
                    if (info instanceof ZoneChangeInfo.Exile && ((ZoneChangeInfo.Exile) info).id != null) {
                        ZoneChangeInfo.Exile exileInfo = (ZoneChangeInfo.Exile) info;
                        game.getExile().createZone(exileInfo.id, exileInfo.name).add(card);
                    } else {
                        game.getExile().getPermanentExile().add(card);
                    }
                }
                break;
            case COMMAND:
                // There should never be more than one card here.
                for (Card card : cardsToMove.getCards(game)) {
                    game.addCommander(new Commander(card));
                }
                break;
            case STACK:
                // There should never be more than one card here.
                for (Card card : cardsToMove.getCards(game)) {
                    Spell spell;
                    if (info instanceof ZoneChangeInfo.Stack && ((ZoneChangeInfo.Stack) info).spell != null) {
                        spell = ((ZoneChangeInfo.Stack) info).spell;
                    } else {
                        spell = new Spell(card, card.getSpellAbility().copy(), card.getOwnerId(), event.getFromZone(), game);
                    }
                    spell.syncZoneChangeCounterOnStack(card, game);
                    game.getStack().push(spell);
                    game.getState().setZone(spell.getId(), Zone.STACK);
                    game.getState().setZone(card.getId(), Zone.STACK);
                }
                break;
            case BATTLEFIELD:
                Permanent permanent = event.getTarget();
                game.addPermanent(permanent, createOrder);
                game.getPermanentsEntering().remove(permanent.getId());
                break;
            default:
                throw new UnsupportedOperationException("to Zone " + toZone.toString() + " not supported yet");
        }
    }
    // update zone in main
    game.setZone(event.getTargetId(), event.getToZone());
    // update zone in other parts (meld cards, mdf half cards)
    cardsToUpdate.entrySet().forEach(entry -> {
        for (Card card : entry.getValue().getCards(game)) {
            if (!card.getId().equals(event.getTargetId())) {
                game.setZone(card.getId(), entry.getKey());
            }
        }
    });
    // reset meld status
    if (targetCard instanceof MeldCard) {
        if (event.getToZone() != Zone.BATTLEFIELD) {
            ((MeldCard) targetCard).setMelded(false, game);
        }
    }
}
Also used : Player(mage.players.Player) Permanent(mage.game.permanent.Permanent) Commander(mage.game.command.Commander) Zone(mage.constants.Zone) Spell(mage.game.stack.Spell) FilterCard(mage.filter.FilterCard) TargetCard(mage.target.TargetCard) PermanentCard(mage.game.permanent.PermanentCard) ZoneChangeEvent(mage.game.events.ZoneChangeEvent)

Example 15 with Zone

use of mage.constants.Zone in project mage by magefree.

the class ZonesHandler method maybeRemoveFromSourceZone.

private static boolean maybeRemoveFromSourceZone(ZoneChangeInfo info, Game game, Ability source) {
    ZoneChangeEvent event = info.event;
    // Handle Unmelded Cards
    if (info instanceof ZoneChangeInfo.Unmelded) {
        ZoneChangeInfo.Unmelded unmelded = (ZoneChangeInfo.Unmelded) info;
        MeldCard meld = game.getMeldCard(event.getTargetId());
        for (Iterator<ZoneChangeInfo> itr = unmelded.subInfo.iterator(); itr.hasNext(); ) {
            ZoneChangeInfo subInfo = itr.next();
            if (!maybeRemoveFromSourceZone(subInfo, game, source)) {
                itr.remove();
            } else if (Objects.equals(subInfo.event.getTargetId(), meld.getTopHalfCard().getId())) {
                meld.setTopLastZoneChangeCounter(meld.getTopHalfCard().getZoneChangeCounter(game));
            } else if (Objects.equals(subInfo.event.getTargetId(), meld.getBottomHalfCard().getId())) {
                meld.setBottomLastZoneChangeCounter(meld.getBottomHalfCard().getZoneChangeCounter(game));
            }
        }
        if (unmelded.subInfo.isEmpty()) {
            return false;
        }
        // We arbitrarily prefer the bottom half card. This should never be relevant.
        meld.updateZoneChangeCounter(game, unmelded.subInfo.get(unmelded.subInfo.size() - 1).event);
        return true;
    }
    // Handle all normal cases
    Card card = getTargetCard(game, event.getTargetId());
    if (card == null) {
        // If we can't find the card we can't remove it.
        return false;
    }
    boolean success = false;
    if (info.faceDown) {
        card.setFaceDown(true, game);
    } else if (event.getToZone().equals(Zone.BATTLEFIELD)) {
        if (!card.isPermanent(game) && (!card.isTransformable() || Boolean.FALSE.equals(game.getState().getValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + card.getId())))) {
            // Non permanents (Instants, Sorceries, ... stay in the zone they are if an abilty/effect tries to move it to the battlefield
            return false;
        }
    }
    if (!game.replaceEvent(event)) {
        Zone fromZone = event.getFromZone();
        if (event.getToZone() == Zone.BATTLEFIELD) {
            // prepare card and permanent
            // If needed take attributes from the spell (e.g. color of spell was changed)
            card = takeAttributesFromSpell(card, event, game);
            // controlling player can be replaced so use event player now
            Permanent permanent;
            if (card instanceof MeldCard) {
                permanent = new PermanentMeld(card, event.getPlayerId(), game);
            } else if (card instanceof ModalDoubleFacesCard) {
                // main mdf card must be processed before that call (e.g. only halfes can be moved to battlefield)
                throw new IllegalStateException("Unexpected trying of move mdf card to battlefield instead half");
            } else if (card instanceof Permanent) {
                throw new IllegalStateException("Unexpected trying of move permanent to battlefield instead card");
            } else {
                permanent = new PermanentCard(card, event.getPlayerId(), game);
            }
            // put onto battlefield with possible counters
            game.getPermanentsEntering().put(permanent.getId(), permanent);
            card.checkForCountersToAdd(permanent, source, game);
            permanent.setTapped(info instanceof ZoneChangeInfo.Battlefield && ((ZoneChangeInfo.Battlefield) info).tapped);
            permanent.setFaceDown(info.faceDown, game);
            if (info.faceDown) {
                card.setFaceDown(false, game);
            }
            // make sure the controller of all continuous effects of this card are switched to the current controller
            game.setScopeRelevant(true);
            game.getContinuousEffects().setController(permanent.getId(), permanent.getControllerId());
            if (permanent.entersBattlefield(source, game, fromZone, true) && card.removeFromZone(game, fromZone, source)) {
                success = true;
                event.setTarget(permanent);
            } else {
                // revert controller to owner if permanent does not enter
                game.getContinuousEffects().setController(permanent.getId(), permanent.getOwnerId());
                game.getPermanentsEntering().remove(permanent.getId());
            }
            game.setScopeRelevant(false);
        } else if (event.getTarget() != null) {
            card.setFaceDown(info.faceDown, game);
            Permanent target = event.getTarget();
            success = target.removeFromZone(game, fromZone, source) && game.getPlayer(target.getControllerId()).removeFromBattlefield(target, source, game);
        } else {
            card.setFaceDown(info.faceDown, game);
            success = card.removeFromZone(game, fromZone, source);
        }
    }
    if (success) {
        // KickerTest do many tests for token's zcc
        if (event.getToZone() == Zone.BATTLEFIELD && event.getTarget() != null) {
            event.getTarget().updateZoneChangeCounter(game, event);
        } else if (!(card instanceof Permanent)) {
            card.updateZoneChangeCounter(game, event);
        }
    }
    return success;
}
Also used : Permanent(mage.game.permanent.Permanent) Zone(mage.constants.Zone) FilterCard(mage.filter.FilterCard) TargetCard(mage.target.TargetCard) PermanentCard(mage.game.permanent.PermanentCard) ZoneChangeEvent(mage.game.events.ZoneChangeEvent) PermanentMeld(mage.game.permanent.PermanentMeld) PermanentCard(mage.game.permanent.PermanentCard)

Aggregations

Zone (mage.constants.Zone)31 Player (mage.players.Player)18 Card (mage.cards.Card)15 MageObject (mage.MageObject)13 Permanent (mage.game.permanent.Permanent)12 FilterCard (mage.filter.FilterCard)11 TargetCard (mage.target.TargetCard)9 UUID (java.util.UUID)7 Target (mage.target.Target)7 TargetOpponent (mage.target.common.TargetOpponent)6 ArrayList (java.util.ArrayList)5 CardsImpl (mage.cards.CardsImpl)5 Cards (mage.cards.Cards)4 PermanentCard (mage.game.permanent.PermanentCard)4 ZoneChangeEvent (mage.game.events.ZoneChangeEvent)3 java.util (java.util)2 HashSet (java.util.HashSet)2 LinkedHashSet (java.util.LinkedHashSet)2 Matcher (java.util.regex.Matcher)2 Ability (mage.abilities.Ability)2