Adeded ContinuousRuleModifyingEffect and handling for it. This effects will also be taken into account when checking if a spell gets yellow frame if it can be cast.

This commit is contained in:
LevelX2 2014-07-25 13:09:48 +02:00
parent 4604b076eb
commit 05a2e09b2a
5 changed files with 195 additions and 5 deletions

View file

@ -39,6 +39,7 @@ import mage.constants.SpellAbilityType;
import mage.constants.TimingRule; import mage.constants.TimingRule;
import mage.constants.Zone; import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent;
/** /**
* *
@ -97,6 +98,14 @@ public class SpellAbility extends ActivatedAbilityImpl {
if (this.getManaCosts().isEmpty() && this.getCosts().isEmpty()) { if (this.getManaCosts().isEmpty() && this.getCosts().isEmpty()) {
return false; return false;
} }
// Check if rule modifying events prevent to cast the spell in check playable mode
if (this.isCheckPlayableMode()) {
if (game.getContinuousEffects().preventedByRuleModification(
GameEvent.getEvent(GameEvent.EventType.CAST_SPELL, this.getId(), this.getSourceId(), playerId), game, true)) {
return false;
}
}
if (costs.canPay(sourceId, controllerId, game)) { if (costs.canPay(sourceId, controllerId, game)) {
if (getSpellAbilityType().equals(SpellAbilityType.SPLIT_FUSED)) { if (getSpellAbilityType().equals(SpellAbilityType.SPLIT_FUSED)) {
SplitCard splitCard = (SplitCard) game.getCard(getSourceId()); SplitCard splitCard = (SplitCard) game.getCard(getSourceId());

View file

@ -80,6 +80,7 @@ public class ContinuousEffects implements Serializable {
//transient Continuous effects //transient Continuous effects
private ContinuousEffectsList<ContinuousEffect> layeredEffects = new ContinuousEffectsList<>(); private ContinuousEffectsList<ContinuousEffect> layeredEffects = new ContinuousEffectsList<>();
private ContinuousEffectsList<ContinuousRuleModifiyingEffect> continuousRuleModifyingEffects = new ContinuousEffectsList<>();
private ContinuousEffectsList<ReplacementEffect> replacementEffects = new ContinuousEffectsList<>(); private ContinuousEffectsList<ReplacementEffect> replacementEffects = new ContinuousEffectsList<>();
private ContinuousEffectsList<PreventionEffect> preventionEffects = new ContinuousEffectsList<>(); private ContinuousEffectsList<PreventionEffect> preventionEffects = new ContinuousEffectsList<>();
private ContinuousEffectsList<RequirementEffect> requirementEffects = new ContinuousEffectsList<>(); private ContinuousEffectsList<RequirementEffect> requirementEffects = new ContinuousEffectsList<>();
@ -111,6 +112,7 @@ public class ContinuousEffects implements Serializable {
this.planeswalkerRedirectionEffect = effect.planeswalkerRedirectionEffect.copy(); this.planeswalkerRedirectionEffect = effect.planeswalkerRedirectionEffect.copy();
this.auraReplacementEffect = effect.auraReplacementEffect.copy(); this.auraReplacementEffect = effect.auraReplacementEffect.copy();
layeredEffects = effect.layeredEffects.copy(); layeredEffects = effect.layeredEffects.copy();
continuousRuleModifyingEffects = effect.continuousRuleModifyingEffects.copy();
replacementEffects = effect.replacementEffects.copy(); replacementEffects = effect.replacementEffects.copy();
preventionEffects = effect.preventionEffects.copy(); preventionEffects = effect.preventionEffects.copy();
requirementEffects = effect.requirementEffects.copy(); requirementEffects = effect.requirementEffects.copy();
@ -130,7 +132,8 @@ public class ContinuousEffects implements Serializable {
} }
private void collectAllEffects() { private void collectAllEffects() {
allEffectsLists.add(layeredEffects); allEffectsLists.add(layeredEffects);
allEffectsLists.add(continuousRuleModifyingEffects);
allEffectsLists.add(replacementEffects); allEffectsLists.add(replacementEffects);
allEffectsLists.add(preventionEffects); allEffectsLists.add(preventionEffects);
allEffectsLists.add(requirementEffects); allEffectsLists.add(requirementEffects);
@ -157,6 +160,7 @@ public class ContinuousEffects implements Serializable {
public void removeEndOfCombatEffects() { public void removeEndOfCombatEffects() {
layeredEffects.removeEndOfCombatEffects(); layeredEffects.removeEndOfCombatEffects();
continuousRuleModifyingEffects.removeEndOfCombatEffects();
replacementEffects.removeEndOfCombatEffects(); replacementEffects.removeEndOfCombatEffects();
preventionEffects.removeEndOfCombatEffects(); preventionEffects.removeEndOfCombatEffects();
requirementEffects.removeEndOfCombatEffects(); requirementEffects.removeEndOfCombatEffects();
@ -170,6 +174,7 @@ public class ContinuousEffects implements Serializable {
public void removeEndOfTurnEffects() { public void removeEndOfTurnEffects() {
layeredEffects.removeEndOfTurnEffects(); layeredEffects.removeEndOfTurnEffects();
continuousRuleModifyingEffects.removeEndOfTurnEffects();
replacementEffects.removeEndOfTurnEffects(); replacementEffects.removeEndOfTurnEffects();
preventionEffects.removeEndOfTurnEffects(); preventionEffects.removeEndOfTurnEffects();
requirementEffects.removeEndOfTurnEffects(); requirementEffects.removeEndOfTurnEffects();
@ -183,6 +188,7 @@ public class ContinuousEffects implements Serializable {
public void removeInactiveEffects(Game game) { public void removeInactiveEffects(Game game) {
layeredEffects.removeInactiveEffects(game); layeredEffects.removeInactiveEffects(game);
continuousRuleModifyingEffects.removeInactiveEffects(game);
replacementEffects.removeInactiveEffects(game); replacementEffects.removeInactiveEffects(game);
preventionEffects.removeInactiveEffects(game); preventionEffects.removeInactiveEffects(game);
requirementEffects.removeInactiveEffects(game); requirementEffects.removeInactiveEffects(game);
@ -320,8 +326,7 @@ public class ContinuousEffects implements Serializable {
* @param game * @param game
* @return a list of all {@link ReplacementEffect} that apply to the current event * @return a list of all {@link ReplacementEffect} that apply to the current event
*/ */
private HashMap<ReplacementEffect, HashSet<Ability>> getApplicableReplacementEffects(GameEvent event, Game game) { private HashMap<ReplacementEffect, HashSet<Ability>> getApplicableReplacementEffects(GameEvent event, Game game) {
// List<ReplacementEffect> replaceEffects = new ArrayList<ReplacementEffect>();
HashMap<ReplacementEffect, HashSet<Ability>> replaceEffects = new HashMap<>(); HashMap<ReplacementEffect, HashSet<Ability>> replaceEffects = new HashMap<>();
if (planeswalkerRedirectionEffect.applies(event, null, game)) { if (planeswalkerRedirectionEffect.applies(event, null, game)) {
replaceEffects.put(planeswalkerRedirectionEffect, null); replaceEffects.put(planeswalkerRedirectionEffect, null);
@ -588,8 +593,34 @@ public class ContinuousEffects implements Serializable {
} }
} }
public boolean preventedByRuleModification(GameEvent event, Game game, boolean checkPlayableMode) {
for (ContinuousRuleModifiyingEffect effect: continuousRuleModifyingEffects) {
for (Ability ability : continuousRuleModifyingEffects.getAbility(effect.getId())) {
if (!(ability instanceof StaticAbility) || ability.isInUseableZone(game, null, false)) {
if (effect.getDuration() != Duration.OneUse || !effect.isUsed()) {
if (effect.applies(event, ability, checkPlayableMode, game)) {
if (!checkPlayableMode) {
String message = effect.getInfoMessage(ability, game);
if (message != null && !message.isEmpty()) {
Player player = game.getPlayer(event.getPlayerId());
if (player != null) {
game.informPlayer(player, message);
}
}
}
return true;
}
}
}
}
}
return false;
}
public boolean replaceEvent(GameEvent event, Game game) { public boolean replaceEvent(GameEvent event, Game game) {
if (preventedByRuleModification(event, game, false)) {
return true;
}
boolean caught = false; boolean caught = false;
HashMap<UUID, HashSet<UUID>> consumed = new HashMap<>(); HashMap<UUID, HashSet<UUID>> consumed = new HashMap<>();
do { do {
@ -860,6 +891,10 @@ public class ContinuousEffects implements Serializable {
SpliceCardEffect newSpliceCardEffect = (SpliceCardEffect)effect; SpliceCardEffect newSpliceCardEffect = (SpliceCardEffect)effect;
spliceCardEffects.addEffect(newSpliceCardEffect, source); spliceCardEffects.addEffect(newSpliceCardEffect, source);
break; break;
case CONTINUOUS_RULE_MODIFICATION:
ContinuousRuleModifiyingEffect newContinuousRuleModifiyingEffect = (ContinuousRuleModifiyingEffect)effect;
continuousRuleModifyingEffects.addEffect(newContinuousRuleModifiyingEffect, source);
break;
default: default:
layeredEffects.addEffect(effect, source); layeredEffects.addEffect(effect, source);
break; break;

View file

@ -0,0 +1,59 @@
/*
* 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;
import mage.game.events.GameEvent;
/**
*
* @author LevelX2
*/
public interface ContinuousRuleModifiyingEffect extends ContinuousEffect {
/**
*
* @param event the event to check if it may happen
* @param source the ability of the effect
* @param checkPlayableMode is the call for checking playables or to prevent a real event
* @param game the game
* @return
*/
boolean applies(GameEvent event, Ability source, boolean checkPlayableMode, Game game);
/**
* Returns a message text that informs the player why he can't do something.
*
* @param source the ability of the effect
* @param game the game
* @return
*/
String getInfoMessage(Ability source, Game game);
}

View file

@ -0,0 +1,86 @@
/*
* 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.MageObject;
import mage.abilities.Ability;
import mage.constants.Duration;
import mage.constants.EffectType;
import mage.constants.Outcome;
import mage.game.Game;
/**
*
* @author LevelX2
*/
public abstract class ContinuousRuleModifiyingEffectImpl extends ContinuousEffectImpl implements ContinuousRuleModifiyingEffect {
protected final String infoMessage;
// 613.10
// Some continuous effects affect game rules rather than objects. For example, effects may modify
// a player’s maximum hand size, or say that a creature must attack this turn if able. These effects
// are applied after all other continuous effects have been applied. Continuous effects that affect
// the costs of spells or abilities are applied according to the order specified in rule 601.2e.
// All other such effects are applied in timestamp order. See also the rules for timestamp order
// and dependency (rules 613.6 and 613.7).
// Some of this rule modifying effects are implemented as normal CONTINUOUS effects using the Layer.RulesEffects.
// But if the rule change can be implemented simply by preventing an event from happening, CONTINUOUS_RULE_MODIFICATION effects can be used.
// They work technical like a replacement effect that replaces the event completely.
// But player isn't asked to choose order of effects if multiple are applied to the same event.
public ContinuousRuleModifiyingEffectImpl(Duration duration, Outcome outcome) {
super(duration, outcome);
this.effectType = EffectType.CONTINUOUS_RULE_MODIFICATION;
this.infoMessage = null;
}
public ContinuousRuleModifiyingEffectImpl(final ContinuousRuleModifiyingEffectImpl effect) {
super(effect);
this.infoMessage = effect.infoMessage;
}
@Override
public String getInfoMessage(Ability source, Game game) {
if (infoMessage == null) {
String message = null;
MageObject object = game.getObject(source.getSourceId());
if (object != null) {
message = source.getRule(object.getLogName());
} else {
message = source.getRule();
}
return message;
} else {
return infoMessage;
}
}
}

View file

@ -8,6 +8,7 @@ public enum EffectType {
ONESHOT("One Shot Effect"), ONESHOT("One Shot Effect"),
CONTINUOUS("Continuous Effect"), CONTINUOUS("Continuous Effect"),
CONTINUOUS_RULE_MODIFICATION("Layered rule modification"),
REPLACEMENT("Replacement Effect"), REPLACEMENT("Replacement Effect"),
PREVENTION("Prevention Effect"), PREVENTION("Prevention Effect"),
REDIRECTION("Redirection Effect"), REDIRECTION("Redirection Effect"),
@ -18,7 +19,7 @@ public enum EffectType {
COSTMODIFICATION("Cost Modification Effect"), COSTMODIFICATION("Cost Modification Effect"),
SPLICE("Splice Card Effect"); SPLICE("Splice Card Effect");
private String text; private final String text;
EffectType(String text) { EffectType(String text) {
this.text = text; this.text = text;