package magic.model.event; import magic.data.GeneralConfig; import magic.model.MagicAbility; import magic.model.MagicGame; import magic.model.MagicPermanent; import magic.model.MagicPlayer; import magic.model.MagicPlayerState; import magic.model.MagicSource; import magic.model.stack.MagicItemOnStack; import magic.model.choice.MagicChoice; import magic.model.condition.MagicCondition; public abstract class MagicActivation<T extends MagicSource> implements MagicEventAction, Comparable<MagicActivation<?>> { public static final MagicCondition[] NO_COND = new MagicCondition[0]; protected static final String ActivationRestriction = " Activate this ability "; private final int priority; private final long id; private final String text; private final MagicCondition[] conditions; private final MagicActivationHints hints; MagicActivation(final MagicCondition[] conditions, final MagicActivationHints hints, final String txt) { this.text = txt; this.conditions=conditions; this.hints=hints; this.priority=hints.getTiming().getPriority(); //randomly assigned, used for ordering activations this.id = hashCode(); } public final MagicActivationHints getActivationHints() { return hints; } public final String getText() { return text; } private final boolean checkActivationPriority(final MagicSource source) { final MagicActivationPriority actpri = source.getController().getActivationPriority(); final int priorityDif = priority - actpri.getPriority(); if (priorityDif > 0) { return true; } else if (priorityDif < 0) { return false; } return id >= actpri.getActivationId(); } void changeActivationPriority(final MagicPlayer player) { final MagicActivationPriority actpri = player.getActivationPriority(); actpri.setPriority(priority); actpri.setActivationId(id); // reset activation/priority of opponent player.getOpponent().getActivationPriority().clear(); } public boolean canPlay(final MagicGame game, final MagicPlayer player, final T source, final boolean isAI) { if (isAI && game.getHintPriority() && !checkActivationPriority(source)) { return false; } if (isAI && game.getHintTiming() && !hints.getTiming().canPlay(game, source)) { return false; } if (source.isPermanent() && ((MagicPermanent)source).hasAbility(MagicAbility.CantActivateAbilities)) { return false; } if (source.isPermanent() && player.hasState(MagicPlayerState.CantActivateAbilities)) { return false; } if (source.isSpell() && player.hasState(MagicPlayerState.CantCastSpells)) { return false; } // Handling of split second for (final MagicItemOnStack item : game.getStack()) { if (item.hasAbility(MagicAbility.SplitSecond)) { return false; } } // Check conditions for activation for (final MagicCondition condition : conditions) { if (condition.accept(source) == false) { return false; } } // Check able to pay costs // // Current method of using MagicCondition could lead to unpayable costs in certain cases: // * self needed to tap to pay mana cost, but self must tap as part of cost // Ideally execute each event with the first choice, if all events have choices then cost can be paid // * execute tap self event // * execute pay mana cost event // for (final MagicEvent event : getCostEvent(source)) { if (event.isSatisfied() == false) { return false; } } // Check for options for choice final boolean useTargetHints = (isAI && game.getHintTarget()) || GeneralConfig.getInstance().getSmartTarget(); final MagicChoice choice = getChoice(source); return choice.hasOptions(game, player, source, useTargetHints); } @Override public int compareTo(final MagicActivation<?> other) { return Long.signum(id-other.id); } abstract boolean usesStack(); abstract Iterable<? extends MagicEvent> getCostEvent(final T source); public abstract MagicEvent getEvent(final MagicSource source); abstract MagicChoice getChoice(final T source); }