Much better than revision 4e7269ad70

This commit is contained in:
maurer.it 2011-01-17 23:03:40 -05:00
parent 2fb0b267bf
commit 31fedb27a6
6 changed files with 220 additions and 29 deletions

View file

@ -31,10 +31,8 @@ package mage.sets.worldwake;
import java.util.UUID;
import mage.Constants.CardType;
import mage.Constants.Duration;
import mage.Constants.Layer;
import mage.Constants.Outcome;
import mage.Constants.Rarity;
import mage.Constants.SubLayer;
import mage.Constants.Zone;
import mage.abilities.Ability;
import mage.abilities.SpellAbility;
@ -42,14 +40,12 @@ import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.effects.CostModificationEffectImpl;
import mage.abilities.effects.common.SearchLibraryRevealPutInHandEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.filter.common.FilterCreatureCard;
import mage.game.Game;
import mage.game.stack.Spell;
import mage.game.stack.SpellStack;
import mage.game.stack.StackObject;
import mage.target.common.TargetCardInLibrary;
/**
@ -89,12 +85,12 @@ public class EyeofUgin extends CardImpl<EyeofUgin> {
}
}
class EyeofUginCostReductionEffect extends ContinuousEffectImpl<EyeofUginCostReductionEffect> {
class EyeofUginCostReductionEffect extends CostModificationEffectImpl<EyeofUginCostReductionEffect> {
private static final String effectText = "Colorless Eldrazi spells you cast cost {2} less to cast";
EyeofUginCostReductionEffect ( ) {
super(Duration.WhileOnBattlefield, Layer.TextChangingEffects_3, SubLayer.NA, Outcome.Benefit);
super(Duration.WhileOnBattlefield, Outcome.Benefit);
}
EyeofUginCostReductionEffect(EyeofUginCostReductionEffect effect) {
@ -102,28 +98,27 @@ class EyeofUginCostReductionEffect extends ContinuousEffectImpl<EyeofUginCostRed
}
@Override
public boolean apply(Game game, Ability source) {
SpellStack stack = game.getStack();
boolean applied = false;
public boolean apply(Game game, Ability source, Ability abilityToModify) {
SpellAbility spellAbility = (SpellAbility)abilityToModify;
int previousCost = spellAbility.getManaCostsToPay().convertedManaCost();
int adjustedCost = 0;
if ( (previousCost - 2) > 0 ) {
adjustedCost = previousCost - 2;
}
spellAbility.getManaCostsToPay().load("{" + adjustedCost + "}");
for ( int idx = 0; idx < stack.size(); idx++ ) {
StackObject stackObject = stack.get(idx);
if ( stackObject instanceof Spell &&
((Spell)stackObject).getSubtype().contains("Eldrazi"))
{
SpellAbility spell = ((Spell)stackObject).getSpellAbility();
int previousCost = spell.getManaCosts().convertedManaCost();
int adjustedCost = 0;
if ( (previousCost - 2) > 0 ) {
adjustedCost = previousCost - 2;
}
spell.getManaCosts().load("{" + adjustedCost + "}");
applied = true;
return true;
}
@Override
public boolean applies(Ability abilityToModify, Ability source, Game game) {
if ( abilityToModify instanceof SpellAbility ) {
Card sourceCard = game.getCard(((SpellAbility)abilityToModify).getSourceId());
if ( sourceCard != null && sourceCard.getSubtype().contains("Eldrazi") && sourceCard.getOwnerId().equals(source.getControllerId()) ) {
return true;
}
}
return applied;
return false;
}
@Override

View file

@ -153,7 +153,8 @@ public final class Constants {
REDIRECTION("Redirection Effect"),
ASTHOUGH("As Though Effect"),
RESTRICTION("Restriction Effect"),
REQUIREMENT("Requirement Effect");
REQUIREMENT("Requirement Effect"),
COSTMODIFICATION("Cost Modification Effect");
private String text;

View file

@ -68,6 +68,7 @@ public abstract class AbilityImpl<T extends AbilityImpl<T>> implements Ability {
protected UUID controllerId;
protected UUID sourceId;
protected ManaCosts<ManaCost> manaCosts;
protected ManaCosts<ManaCost> manaCostsToPay;
protected Costs<Cost> costs;
protected ArrayList<AlternativeCost> alternativeCosts = new ArrayList<AlternativeCost>();
protected Costs<Cost> optionalCosts;
@ -87,6 +88,7 @@ public abstract class AbilityImpl<T extends AbilityImpl<T>> implements Ability {
this.abilityType = abilityType;
this.zone = zone;
this.manaCosts = new ManaCostsImpl<ManaCost>();
this.manaCostsToPay = new ManaCostsImpl<ManaCost>();
this.costs = new CostsImpl<Cost>();
this.optionalCosts = new CostsImpl<Cost>();
this.effects = new Effects();
@ -104,6 +106,7 @@ public abstract class AbilityImpl<T extends AbilityImpl<T>> implements Ability {
this.name = ability.name;
this.usesStack = ability.usesStack;
this.manaCosts = ability.manaCosts.copy();
this.manaCostsToPay = ability.manaCostsToPay.copy();
this.costs = ability.costs.copy();
this.optionalCosts = ability.optionalCosts.copy();
for (AlternativeCost cost: ability.alternativeCosts) {
@ -162,8 +165,11 @@ public abstract class AbilityImpl<T extends AbilityImpl<T>> implements Ability {
if (game.getObject(sourceId) != null)
game.getObject(sourceId).adjustCosts(this, game);
if (!useAlternativeCost(game)) {
//20101001 - 601.2e
game.getContinuousEffects().costModification(this, game);
//20100716 - 601.2f
if (!manaCosts.pay(game, sourceId, controllerId, noMana)) {
if (!manaCostsToPay.pay(game, sourceId, controllerId, noMana)) {
logger.fine("activate failed - mana");
return false;
}
@ -225,6 +231,16 @@ public abstract class AbilityImpl<T extends AbilityImpl<T>> implements Ability {
return manaCosts;
}
/**
* Should be used by {@link mage.abilities.effects.CostModificationEffect cost modification effects}
* to manipulate what is actually paid before resolution.
*
* @return
*/
public ManaCosts<ManaCost> getManaCostsToPay ( ) {
return manaCostsToPay;
}
@Override
public List<AlternativeCost> getAlternativeCosts() {
return alternativeCosts;
@ -324,6 +340,7 @@ public abstract class AbilityImpl<T extends AbilityImpl<T>> implements Ability {
public void addManaCost(ManaCost cost) {
if (cost != null) {
this.manaCosts.add(cost);
this.manaCostsToPay.add(cost);
}
}

View file

@ -65,6 +65,7 @@ public class ContinuousEffects implements Serializable {
private final List<RequirementEffect> requirementEffects = new ArrayList<RequirementEffect>();
private final List<RestrictionEffect> restrictionEffects = new ArrayList<RestrictionEffect>();
private final List<AsThoughEffect> asThoughEffects = new ArrayList<AsThoughEffect>();
private final List<CostModificationEffect> costModificationEffects = new ArrayList<CostModificationEffect>();
//map Abilities to Continuous effects
private final Map<UUID, Ability> abilityMap = new HashMap<UUID, Ability>();
@ -98,6 +99,9 @@ public class ContinuousEffects implements Serializable {
for (AsThoughEffect entry: effect.asThoughEffects) {
asThoughEffects.add((AsThoughEffect)entry.copy());
}
for ( CostModificationEffect entry : effect.costModificationEffects ) {
costModificationEffects.add(entry);
}
for (Entry<UUID, Ability> entry: effect.abilityMap.entrySet()) {
abilityMap.put(entry.getKey(), entry.getValue().copy());
}
@ -150,6 +154,11 @@ public class ContinuousEffects implements Serializable {
if (entry.getDuration() == Duration.EndOfTurn)
i.remove();
}
for (Iterator<CostModificationEffect> i = costModificationEffects.iterator(); i.hasNext();) {
ContinuousEffect entry = i.next();
if (entry.getDuration() == Duration.EndOfTurn)
i.remove();
}
}
public void removeInactiveEffects(Game game) {
@ -177,6 +186,10 @@ public class ContinuousEffects implements Serializable {
if (isInactive(i.next(), game))
i.remove();
}
for (Iterator<CostModificationEffect> i = costModificationEffects.iterator(); i.hasNext();) {
if (isInactive(i.next(), game))
i.remove();
}
}
private boolean isInactive(ContinuousEffect effect, Game game) {
@ -357,6 +370,33 @@ public class ContinuousEffects implements Serializable {
return false;
}
/**
* Inspects all {@link Permanent permanent's} {@link Ability abilities} on the battlefied
* for {@link CostModificationEffect cost modification effects} and applies them if necessary.
*
* @param objectId
* @param abilityToModify
* @param game
* @return
*/
public void costModification ( Ability abilityToModify, Game game ) {
for ( Permanent permanent : game.getBattlefield().getAllPermanents() ) {
for ( Ability ability : permanent.getAbilities().getStaticAbilities(Zone.BATTLEFIELD) ) {
for ( Effect effect : ability.getEffects(EffectType.COSTMODIFICATION) ) {
CostModificationEffect rEffect = (CostModificationEffect)effect;
if ( rEffect.applies(abilityToModify, ability, game) ) {
rEffect.apply(game, ability, abilityToModify);
}
}
}
}
for ( CostModificationEffect effect : costModificationEffects ) {
if ( effect.applies(abilityToModify, abilityMap.get(effect.getId()), game) ) {
effect.apply(game, abilityMap.get(effect.getId()), abilityToModify);
}
}
}
public boolean replaceEvent(GameEvent event, Game game) {
boolean caught = false;
List<ReplacementEffect> rEffects = getApplicableReplacementEffects(event, game);
@ -474,6 +514,11 @@ public class ContinuousEffects implements Serializable {
asThoughEffects.add(newAsThoughEffect);
abilityMap.put(newAsThoughEffect.getId(), source);
break;
case COSTMODIFICATION:
CostModificationEffect newCostModificationEffect = (CostModificationEffect)effect;
costModificationEffects.add(newCostModificationEffect);
abilityMap.put(newCostModificationEffect.getId(), source);
break;
default:
ContinuousEffect newEffect = (ContinuousEffect)effect;
layeredEffects.add(newEffect);

View file

@ -0,0 +1,67 @@
/*
* 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.abilities.effects;
import mage.abilities.Ability;
import mage.game.Game;
/**
* Represents a {@link ContinuousEffect} that will modify the cost of a spell or
* ability on the stack. {@link mage.abilities.Ability Abilities} with this type
* of effect will be called once and only once from the
* {@link mage.abilities.AbilityImpl#activate(mage.game.Game, boolean) Ability.activate}
* method before costs are paid. After this time the costs are locked in and
* should not be modified further.
*
* @author maurer.it_at_gmail.com
*/
//20101001 - 601.2e/613.10
public interface CostModificationEffect<T extends CostModificationEffect<T>> extends ContinuousEffect<T> {
/**
* Called by the {@link ContinuousEffects#costModification(java.util.UUID, mage.abilities.Ability, mage.game.Game) ContinuousEffects.costModification}
* method.
*
* @param game The game for which this effect should be applied to.
* @param source The source ability of this effect.
* @param abilityToModify The {@link mage.abilities.SpellAbility} or {@link Ability} which should be modified.
* @return
*/
public boolean apply ( Game game, Ability source, Ability abilityToModify );
/**
* Called by the {@link ContinuousEffects#costModification(mage.abilities.Ability, mage.game.Game) ContinuousEffects.costModification}
* method.
*
* @param objectId The ability
* @param source
* @param game
* @return
*/
public boolean applies(Ability abilityToModify, Ability source, Game game);
}

View file

@ -0,0 +1,66 @@
/*
* 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.abilities.effects;
import mage.Constants.Duration;
import mage.Constants.EffectType;
import mage.Constants.Outcome;
import mage.abilities.Ability;
import mage.game.Game;
/**
* Simple implementation of a {@link CostModificationEffect} offering simplified
* construction to setup the object for use by the mage framework.
* @author maurer.it_at_gmail.com
*/
public abstract class CostModificationEffectImpl<T extends CostModificationEffectImpl<T>> extends ContinuousEffectImpl<T> implements CostModificationEffect<T> {
public CostModificationEffectImpl ( Duration duration, Outcome outcome ) {
super(duration, outcome);
this.effectType = EffectType.COSTMODIFICATION;
}
public CostModificationEffectImpl(final CostModificationEffectImpl<T> effect) {
super(effect);
this.effectType = effect.effectType;
}
/**
* Overridden and 'no-op' implementation put in place.
*
* @see #apply(mage.game.Game, mage.abilities.Ability, mage.abilities.Ability)
*
* @param game
* @param source
* @return
*/
@Override
public final boolean apply ( Game game, Ability source ) { return false; }
}