@Override public boolean apply(Game game, Ability source) { Player player = getPayingPlayer(game, source); MageObject mageObject = game.getObject(source.getSourceId()); if (player != null && mageObject != null) { String message; if (chooseUseText == null) { message = new StringBuilder(getCostText()) .append(" and ") .append(executingEffect.getText(source.getModes().getMode())) .append("?") .toString(); } else { message = chooseUseText; } message = CardUtil.replaceSourceName(message, mageObject.getName()); if (cost.canPay(source, source.getSourceId(), player.getId(), game) && player.chooseUse(executingEffect.getOutcome(), message, game)) { cost.clearPaid(); if (cost.pay(source, game, source.getSourceId(), player.getId(), false)) { executingEffect.setTargetPointer(this.targetPointer); if (executingEffect instanceof OneShotEffect) { if (!(executingEffect instanceof PostResolveEffect)) { return executingEffect.apply(game, source); } } else { game.addEffect((ContinuousEffect) executingEffect, source); } } } return true; } return false; }
@Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(targetPointer.getFirst(game, source)); MageObject mageObject = game.getObject(source.getSourceId()); if (player != null && mageObject != null) { String message = userMessage; if (message == null) { message = getCostText() + " to prevent " + executingEffect.getText(source.getModes().getMode()) + "?"; } message = CardUtil.replaceSourceName(message, mageObject.getLogName()); cost.clearPaid(); if (cost.canPay(source, source.getSourceId(), player.getId(), game) && player.chooseUse(executingEffect.getOutcome(), message, source, game)) { cost.pay(source, game, source.getSourceId(), player.getId(), false, null); } if (!cost.isPaid()) { executingEffect.setTargetPointer(this.targetPointer); return executingEffect.apply(game, source); } return true; } return false; }
@Override public boolean apply(Game game, Ability source) { Cost cost = new GenericManaCost(1); cost.clearPaid(); if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) { super.apply(game, source); } return true; }
private void checkPaid(UUID uuid, Spell spell) { for (Cost cost : spell.getSpellAbility().getManaCostsToPay()) { if (!cost.isPaid()) { return; } } CardView cardView = stack.get(uuid); cardView.paid = true; }
/** * Handles the setting of non mana X costs * * @param controller * @param game * @return announce message */ protected String handleOtherXCosts(Game game, Player controller) { String announceString = null; for (VariableCost variableCost : this.costs.getVariableCosts()) { if (!(variableCost instanceof VariableManaCost)) { int xValue = variableCost.announceXValue(this, game); costs.add(variableCost.getFixedCostsFromAnnouncedValue(xValue)); // set the xcosts to paid variableCost.setAmount(xValue); ((Cost) variableCost).setPaid(); String message = controller.getLogName() + " announces a value of " + xValue + " (" + variableCost.getActionText() + ")"; if (announceString == null) { announceString = message; } else { announceString = announceString + " " + message; } } } return announceString; }
@Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); Permanent permanent = game.getPermanent(source.getSourceId()); if (player != null && permanent != null) { if (player.chooseUse( Outcome.Benefit, "Pay " + cost.getText() /* + " or sacrifice " + permanent.getName() */ + "?", game)) { cost.clearPaid(); if (cost.pay(source, game, source.getId(), source.getControllerId(), false)) return true; } permanent.sacrifice(source.getSourceId(), game); return true; } return false; }
@Override public boolean apply(Game game, Ability source) { Cost cost = new GenericManaCost(1); cost.clearPaid(); if (cost.pay(source, game, source.getId(), source.getControllerId(), false)) { Permanent permanent = game.getPermanent(source.getFirstTarget()); if (permanent != null) { permanent.damage(1, source.getId(), game, true, false); return true; } Player player = game.getPlayer(source.getFirstTarget()); if (player != null) { player.damage(1, source.getSourceId(), game, false, true); return true; } return false; } return false; }
protected String getCostText() { StringBuilder sb = new StringBuilder(); String costText = cost.getText(); if (costText != null && !costText.toLowerCase().startsWith("discard") && !costText.toLowerCase().startsWith("sacrifice") && !costText.toLowerCase().startsWith("remove")) { sb.append("pay "); } return sb.append(costText).toString(); }
protected static int playerPaysXGenericMana(Player player, Ability source, Game game) { int xValue = 0; boolean payed = false; while (player.canRespond() && !payed) { xValue = player.announceXMana(0, Integer.MAX_VALUE, "How much mana will you pay?", game, source); if (xValue > 0) { Cost cost = new GenericManaCost(xValue); payed = cost.pay(source, game, source.getSourceId(), player.getId(), false, null); } else { payed = true; } } game.informPlayers( new StringBuilder(player.getLogName()) .append(" pays {") .append(xValue) .append("}.") .toString()); return xValue; }
@Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { boolean costPaid = false; for (UUID playerId : controller.getInRange()) { Cost cost = new SacrificeTargetCost( new TargetControlledPermanent(new FilterControlledLandPermanent())); Player player = game.getPlayer(playerId); if (player != null && cost.canPay(source, source.getSourceId(), playerId, game) && player.chooseUse(Outcome.Sacrifice, "Sacrifice a land?", game) && cost.pay(source, game, source.getSourceId(), playerId, true)) { costPaid = true; } } if (costPaid) { super.apply(game, source); } return true; } return false; }
@Override public String getText(Mode mode) { StringBuilder sb = new StringBuilder("sacrifice {this} unless you "); String costText = cost.getText(); if (costText.toLowerCase().startsWith("discard") || costText.toLowerCase().startsWith("remove") || costText.toLowerCase().startsWith("return")) { sb.append(costText.substring(0, 1).toLowerCase()); sb.append(costText.substring(1)); } else { sb.append("pay ").append(costText); } return sb.toString(); }
/** * As we have ability in the stack, we need to update optional costs in original card. This * information will be used later by effects, e.g. to determine whether card was kicked or not. * E.g. Desolation Angel */ private void updateOptionalCosts(int index) { Ability abilityOrig = spellCards.get(index).getAbilities().get(spellAbilities.get(index).getId()); if (abilityOrig != null) { for (Object object : spellAbilities.get(index).getOptionalCosts()) { Cost cost = (Cost) object; for (Cost costOrig : abilityOrig.getOptionalCosts()) { if (cost.getId().equals(costOrig.getId())) { if (cost.isPaid()) { costOrig.setPaid(); } else { costOrig.clearPaid(); } break; } } } } }
@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; }