mirror of
https://github.com/correl/mage.git
synced 2024-12-25 03:00:15 +00:00
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:
parent
4604b076eb
commit
05a2e09b2a
5 changed files with 195 additions and 5 deletions
|
@ -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());
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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 players 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue