示例#1
0
  @Override
  public boolean activate(Game game, boolean noMana) {
    Player controller = game.getPlayer(this.getControllerId());
    if (controller == null) {
      return false;
    }
    game.applyEffects();

    /* 20130201 - 601.2b
     * If the spell is modal the player announces the mode choice (see rule 700.2).
     */
    if (!getModes().choose(game, this)) {
      return false;
    }
    if (controller.isTestMode()) {
      if (!controller.addTargets(this, game)) {
        return false;
      }
    }

    getSourceObject(game);

    /* 20130201 - 601.2b
     * If the player wishes to splice any cards onto the spell (see rule 702.45), he
     * or she reveals those cards in his or her hand.
     */
    if (this.abilityType.equals(AbilityType.SPELL)) {
      game.getContinuousEffects().applySpliceEffects(this, game);
    }

    // if ability can be cast for no mana, clear the mana costs now, because additional mana costs
    // must be paid.
    // For Flashback ability can be set X before, so the X costs have to be restored for the
    // flashbacked ability
    if (noMana) {
      if (this.getManaCostsToPay().getVariableCosts().size() > 0) {
        int xValue = this.getManaCostsToPay().getX();
        this.getManaCostsToPay().clear();
        VariableManaCost xCosts = new VariableManaCost();
        xCosts.setAmount(xValue);
        this.getManaCostsToPay().add(xCosts);
      } else {
        this.getManaCostsToPay().clear();
      }
    }
    // 20130201 - 601.2b
    // If the spell has alternative or additional costs that will be paid as it's being cast such
    // as buyback, kicker, or convoke costs (see rules 117.8 and 117.9), the player announces his
    // or her intentions to pay any or all of those costs (see rule 601.2e).
    // A player can't apply two alternative methods of casting or two alternative costs to a single
    // spell.
    if (!activateAlternateOrAdditionalCosts(sourceObject, noMana, controller, game)) {
      if (getAbilityType().equals(AbilityType.SPELL)
          && ((SpellAbility) this)
              .getSpellAbilityType()
              .equals(SpellAbilityType.FACE_DOWN_CREATURE)) {
        return false;
      }
    }

    // 20121001 - 601.2b
    // If the spell has a variable cost that will be paid as it's being cast (such as an {X} in
    // its mana cost; see rule 107.3), the player announces the value of that variable.
    VariableManaCost variableManaCost = handleManaXCosts(game, noMana, controller);
    String announceString = handleOtherXCosts(game, controller);
    // For effects from cards like Void Winnower x costs have to be set
    if (this.getAbilityType().equals(AbilityType.SPELL)
        && game.replaceEvent(
            GameEvent.getEvent(
                GameEvent.EventType.CAST_SPELL_LATE, getId(), getSourceId(), getControllerId()),
            this)) {
      return false;
    }
    for (Mode mode : this.getModes().getSelectedModes()) {
      this.getModes().setActiveMode(mode);
      // 20121001 - 601.2c
      // 601.2c The player announces his or her choice of an appropriate player, object, or zone for
      // each target the spell requires. A spell may require some targets only if an alternative or
      // additional cost (such as a buyback or kicker cost), or a particular mode, was chosen for
      // it;
      // otherwise, the spell is cast as though it did not require those targets. If the spell has a
      // variable number of targets, the player announces how many targets he or she will choose
      // before
      // he or she announces those targets. The same target can't be chosen multiple times for any
      // one
      // instance of the word "target" on the spell. However, if the spell uses the word "target" in
      // multiple places, the same object, player, or zone can be chosen once for each instance of
      // the
      // word "target" (as long as it fits the targeting criteria). If any effects say that an
      // object
      // or player must be chosen as a target, the player chooses targets so that he or she obeys
      // the
      // maximum possible number of such effects without violating any rules or effects that say
      // that
      // an object or player can't be chosen as a target. The chosen players, objects, and/or zones
      // each become a target of that spell. (Any abilities that trigger when those players,
      // objects,
      // and/or zones become the target of a spell trigger at this point; they'll wait to be put on
      // the stack until the spell has finished being cast.)

      if (sourceObject != null
          && !this.getAbilityType()
              .equals(AbilityType.TRIGGERED)) { // triggered abilities check this already in
        // playerImpl.triggerAbility
        sourceObject.adjustTargets(this, game);
      }
      if (mode.getTargets().size() > 0
          && mode.getTargets()
                  .chooseTargets(
                      getEffects().get(0).getOutcome(), this.controllerId, this, noMana, game)
              == false) {
        if ((variableManaCost != null || announceString != null) && !game.isSimulation()) {
          game.informPlayer(
              controller,
              (sourceObject != null ? sourceObject.getIdName() : "")
                  + ": no valid targets with this value of X");
        }
        return false; // when activation of ability is canceled during target selection
      }
    } // end modes

    // TODO: Handle optionalCosts at the same time as already OptionalAdditionalSourceCosts are
    // handled.
    for (Cost cost : optionalCosts) {
      if (cost instanceof ManaCost) {
        cost.clearPaid();
        if (controller.chooseUse(
            Outcome.Benefit, "Pay optional cost " + cost.getText() + "?", this, game)) {
          manaCostsToPay.add((ManaCost) cost);
        }
      }
    }
    // 20100716 - 601.2e
    if (sourceObject != null) {
      sourceObject.adjustCosts(this, game);
      if (sourceObject instanceof Card) {
        for (Ability ability : ((Card) sourceObject).getAbilities(game)) {
          if (ability instanceof AdjustingSourceCosts) {
            ((AdjustingSourceCosts) ability).adjustCosts(this, game);
          }
        }
      } else {
        for (Ability ability : sourceObject.getAbilities()) {
          if (ability instanceof AdjustingSourceCosts) {
            ((AdjustingSourceCosts) ability).adjustCosts(this, game);
          }
        }
      }
    }

    // this is a hack to prevent mana abilities with mana costs from causing endless loops - pay
    // other costs first
    if (this instanceof ManaAbility
        && !costs.pay(this, game, sourceId, controllerId, noMana, null)) {
      logger.debug("activate mana ability failed - non mana costs");
      return false;
    }

    // 20101001 - 601.2e
    if (costModificationActive) {
      game.getContinuousEffects().costModification(this, game);
    } else {
      costModificationActive = true;
    }

    UUID activatorId = controllerId;
    if ((this instanceof ActivatedAbilityImpl)
        && ((ActivatedAbilityImpl) this).getActivatorId() != null) {
      activatorId = ((ActivatedAbilityImpl) this).getActivatorId();
    }

    // 20100716 - 601.2f  (noMana is not used here, because mana costs were cleared for this ability
    // before adding additional costs and applying cost modification effects)
    if (!manaCostsToPay.pay(this, game, sourceId, activatorId, false, null)) {
      return false; // cancel during mana payment
    }

    // 20100716 - 601.2g
    if (!costs.pay(this, game, sourceId, activatorId, noMana, null)) {
      logger.debug("activate failed - non mana costs");
      return false;
    }
    if (!game.isSimulation()) {
      // inform about x costs now, so canceled announcements are not shown in the log
      if (announceString != null) {
        game.informPlayers(announceString);
      }
      if (variableManaCost != null) {
        int xValue = getManaCostsToPay().getX();
        game.informPlayers(
            controller.getLogName()
                + " announces a value of "
                + xValue
                + " for "
                + variableManaCost.getText());
      }
    }
    activated = true;
    // fire if tapped for mana (may only fire now because else costs of ability itself can be payed
    // with mana of abilities that trigger for that event
    if (this.getAbilityType().equals(AbilityType.MANA)) {
      for (Cost cost : costs) {
        if (cost instanceof TapSourceCost) {
          Mana mana = null;
          Effect effect = getEffects().get(0);
          if (effect instanceof DynamicManaEffect) {
            mana = ((DynamicManaEffect) effect).getMana(game, this);
          } else if (effect instanceof BasicManaEffect) {
            mana = ((BasicManaEffect) effect).getMana(game, this);
          }
          if (mana != null
              && mana.getAny()
                  == 0) { // if mana == null or Any > 0 the event has to be fired in the mana effect
            // to know which mana was produced
            ManaEvent event =
                new ManaEvent(
                    GameEvent.EventType.TAPPED_FOR_MANA, sourceId, sourceId, controllerId, mana);
            if (!game.replaceEvent(event)) {
              game.fireEvent(event);
            }
          }
          break;
        }
      }
    }
    return true;
  }