/*
* Copyright 2010 BetaSteward_at_googlemail.com. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BetaSteward_at_googlemail.com ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BetaSteward_at_googlemail.com OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of BetaSteward_at_googlemail.com.
*/
package mage.cards.a;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.Condition;
import mage.abilities.costs.AlternativeCostSourceAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.counters.CounterType;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.watchers.Watcher;
/**
*
* @author stravant
*
* Note, this card is pretty hacky in its implementation due to the fact that the alternative cost system doesn't
* really support "once each turn" alternative costs in an obvious way, but it should work in all scenarios as far
* as I can see.
*/
public class AsForetold extends CardImpl {
public AsForetold(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}");
// At the beginning of your upkeep, put a time counter on As Foretold.
addAbility(
new BeginningOfUpkeepTriggeredAbility(
new AddCountersSourceEffect(CounterType.TIME.createInstance(), new StaticValue(1), true),
TargetController.YOU,
/* optional = */false));
// Once each turn, you may pay {0} rather than pay the mana cost for a spell you cast with converted mana cost X or less, where X is the number of time counters on As Foretold.
addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new AsForetoldAddAltCostEffect()), new AsForetoldAltCostUsedWatcher());
}
public AsForetold(final AsForetold card) {
super(card);
}
@Override
public AsForetold copy() {
return new AsForetold(this);
}
}
/**
* Used to determine what cast objects to apply the alternative cost to
*/
class SpellWithManaCostLessThanOrEqualToCondition implements Condition {
private int counters;
public SpellWithManaCostLessThanOrEqualToCondition(int counters) {
this.counters = counters;
}
@Override
public boolean apply(Game game, Ability source) {
MageObject object = game.getObject(source.getSourceId());
return object != null && !object.isLand() && object.getConvertedManaCost() <= counters;
}
}
/**
* Special AlternativeCostSourceAbility implementation. We wrap the call to askToActivateAlternativeCosts in order to
* tell when the alternative cost is used, and mark it as having been used this turn in the watcher
*/
class AsForetoldAlternativeCost extends AlternativeCostSourceAbility {
private UUID sourceAsForetold;
AsForetoldAlternativeCost(UUID sourceAsForetold, int timeCounters) {
super(new ManaCostsImpl("{0}"), new SpellWithManaCostLessThanOrEqualToCondition(timeCounters));
this.sourceAsForetold = sourceAsForetold;
}
AsForetoldAlternativeCost(final AsForetoldAlternativeCost ability) {
super(ability);
this.sourceAsForetold = ability.sourceAsForetold;
}
@Override
public AsForetoldAlternativeCost copy() {
return new AsForetoldAlternativeCost(this);
}
@Override
public boolean askToActivateAlternativeCosts(Ability ability, Game game) {
boolean activated = super.askToActivateAlternativeCosts(ability, game);
if (activated) {
// Get the watcher
AsForetoldAltCostUsedWatcher asForetoldAltCostUsedWatcher =
(AsForetoldAltCostUsedWatcher)game.getState().getWatchers()
.get("asForetoldAltCostUsedWatcher", sourceAsForetold);
// Mark as used
asForetoldAltCostUsedWatcher.markUsedThisTurn();
}
return activated;
}
}
/**
* The continuous effect that adds the option to pay the alternative cost if we haven't used it yet this turn
*/
class AsForetoldAddAltCostEffect extends ContinuousEffectImpl {
public AsForetoldAddAltCostEffect() {
super(Duration.WhileOnBattlefield, Outcome.Benefit);
staticText = "Once each turn, you may pay {0} rather than pay the mana cost for a spell you cast with converted mana cost X or less, where X is the number of time counters on {this}.";
}
public AsForetoldAddAltCostEffect(final AsForetoldAddAltCostEffect effect) {
super(effect);
}
@Override
public AsForetoldAddAltCostEffect copy() {
return new AsForetoldAddAltCostEffect(this);
}
@Override
public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
Permanent sourcePermanent = game.getPermanent(source.getSourceId());
if (sourcePermanent != null) {
// Get the watcher
AsForetoldAltCostUsedWatcher asForetoldAltCostUsedWatcher =
(AsForetoldAltCostUsedWatcher)game.getState().getWatchers()
.get("asForetoldAltCostUsedWatcher", sourcePermanent.getId());
// If we haven't used it yet this turn, give the option of using the zero alternative cost
if (!asForetoldAltCostUsedWatcher.hasBeenUsedThisTurn()) {
int timeCounters = sourcePermanent.getCounters(game).getCount("time");
controller.getAlternativeSourceCosts().add(new AsForetoldAlternativeCost(sourcePermanent.getId(), timeCounters));
}
// Return true even if we didn't add the alt cost. We still applied the effect
return true;
}
}
return false;
}
@Override
public boolean apply(Game game, Ability source) {
return false;
}
@Override
public boolean hasLayer(Layer layer) {
return layer == Layer.RulesEffects;
}
}
/**
* Watcher used as extra storage to record whether a given As Foretold has been used this turn.
* Technically speaking this watcher doesn't *watch* any GameEvents, but it does "watch" the
* alternative cost being used. That just isn't possible to watch through a game event. It's still
* helpfull to co-op the Watcher system for this since it automatically handles ZoneChangeCounter
* stuff and resetting the condition at the end of the turn.
*/
class AsForetoldAltCostUsedWatcher extends Watcher {
public AsForetoldAltCostUsedWatcher() {
super("asForetoldAltCostUsedWatcher", WatcherScope.CARD);
}
public AsForetoldAltCostUsedWatcher(final AsForetoldAltCostUsedWatcher watcher) {
super(watcher);
}
@Override
public void watch(GameEvent event, Game game) {
// Nothing to do, we explicitly mark used in the alternative cost
}
public boolean hasBeenUsedThisTurn() {
return conditionMet();
}
public void markUsedThisTurn() {
condition = true;
}
@Override
public AsForetoldAltCostUsedWatcher copy() {
return new AsForetoldAltCostUsedWatcher(this);
}
}