forked from External/mage
* Fixed a problem with check playable methods causing e.g. endless loop if Shared Fate was on the battlefield.
This commit is contained in:
parent
32bd88a6c0
commit
133cc7342d
19 changed files with 227 additions and 230 deletions
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
package mage.abilities;
|
||||
|
||||
import java.util.UUID;
|
||||
|
|
@ -62,14 +61,6 @@ public interface ActivatedAbility extends Ability {
|
|||
@Override
|
||||
ActivatedAbility copy();
|
||||
|
||||
/**
|
||||
* Set a flag to know, that the ability is only created adn used to check
|
||||
* what's playbable for the player.
|
||||
*/
|
||||
void setCheckPlayableMode();
|
||||
|
||||
boolean isCheckPlayableMode();
|
||||
|
||||
void setMaxActivationsPerTurn(int maxActivationsPerTurn);
|
||||
|
||||
int getMaxActivationsPerTurn(Game game);
|
||||
|
|
|
|||
|
|
@ -46,11 +46,9 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa
|
|||
protected TimingRule timing = TimingRule.INSTANT;
|
||||
protected TargetController mayActivate = TargetController.YOU;
|
||||
protected UUID activatorId;
|
||||
protected boolean checkPlayableMode;
|
||||
|
||||
protected ActivatedAbilityImpl(AbilityType abilityType, Zone zone) {
|
||||
super(abilityType, zone);
|
||||
this.checkPlayableMode = false;
|
||||
}
|
||||
|
||||
public ActivatedAbilityImpl(final ActivatedAbilityImpl ability) {
|
||||
|
|
@ -58,7 +56,6 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa
|
|||
timing = ability.timing;
|
||||
mayActivate = ability.mayActivate;
|
||||
activatorId = ability.activatorId;
|
||||
checkPlayableMode = ability.checkPlayableMode;
|
||||
maxActivationsPerTurn = ability.maxActivationsPerTurn;
|
||||
condition = ability.condition;
|
||||
}
|
||||
|
|
@ -262,16 +259,6 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa
|
|||
this.timing = timing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCheckPlayableMode() {
|
||||
checkPlayableMode = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCheckPlayableMode() {
|
||||
return checkPlayableMode;
|
||||
}
|
||||
|
||||
protected boolean hasMoreActivationsThisTurn(Game game) {
|
||||
if (getMaxActivationsPerTurn(game) == Integer.MAX_VALUE) {
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package mage.abilities;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import mage.MageObject;
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.costs.Cost;
|
||||
|
|
@ -15,9 +17,6 @@ import mage.game.events.GameEvent;
|
|||
import mage.game.stack.Spell;
|
||||
import mage.players.Player;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
|
|
@ -91,7 +90,7 @@ public class SpellAbility extends ActivatedAbilityImpl {
|
|||
}
|
||||
}
|
||||
// Check if rule modifying events prevent to cast the spell in check playable mode
|
||||
if (this.isCheckPlayableMode()) {
|
||||
if (game.inCheckPlayableState()) {
|
||||
if (game.getContinuousEffects().preventedByRuleModification(
|
||||
GameEvent.getEvent(GameEvent.EventType.CAST_SPELL, this.getId(), this.getSourceId(), playerId), this, game, true)) {
|
||||
return ActivationStatus.getFalse();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
package mage.abilities.effects;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.stream.Collectors;
|
||||
import mage.MageObject;
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.*;
|
||||
|
|
@ -23,11 +27,6 @@ import mage.players.Player;
|
|||
import mage.target.common.TargetCardInHand;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author BetaSteward_at_googlemail.com
|
||||
*/
|
||||
|
|
@ -333,7 +332,7 @@ public class ContinuousEffects implements Serializable {
|
|||
}
|
||||
// boolean checkLKI = event.getType().equals(EventType.ZONE_CHANGE) || event.getType().equals(EventType.DESTROYED_PERMANENT);
|
||||
//get all applicable transient Replacement effects
|
||||
for (Iterator<ReplacementEffect> iterator = replacementEffects.iterator(); iterator.hasNext(); ) {
|
||||
for (Iterator<ReplacementEffect> iterator = replacementEffects.iterator(); iterator.hasNext();) {
|
||||
ReplacementEffect effect = iterator.next();
|
||||
if (!effect.checksEventType(event, game)) {
|
||||
continue;
|
||||
|
|
@ -366,7 +365,7 @@ public class ContinuousEffects implements Serializable {
|
|||
}
|
||||
}
|
||||
|
||||
for (Iterator<PreventionEffect> iterator = preventionEffects.iterator(); iterator.hasNext(); ) {
|
||||
for (Iterator<PreventionEffect> iterator = preventionEffects.iterator(); iterator.hasNext();) {
|
||||
PreventionEffect effect = iterator.next();
|
||||
if (!effect.checksEventType(event, game)) {
|
||||
continue;
|
||||
|
|
@ -720,10 +719,10 @@ public class ContinuousEffects implements Serializable {
|
|||
* Checks if an event won't happen because of an rule modifying effect
|
||||
*
|
||||
* @param event
|
||||
* @param targetAbility ability the event is attached to. can be null.
|
||||
* @param targetAbility ability the event is attached to. can be null.
|
||||
* @param game
|
||||
* @param checkPlayableMode true if the event does not really happen but
|
||||
* it's checked if the event would be replaced
|
||||
* it's checked if the event would be replaced
|
||||
* @return
|
||||
*/
|
||||
public boolean preventedByRuleModification(GameEvent event, Ability targetAbility, Game game, boolean checkPlayableMode) {
|
||||
|
|
@ -737,10 +736,7 @@ public class ContinuousEffects implements Serializable {
|
|||
if (effect.getDuration() != Duration.OneUse || !effect.isUsed()) {
|
||||
effect.setValue("targetAbility", targetAbility);
|
||||
if (effect.applies(event, sourceAbility, game)) {
|
||||
if (targetAbility instanceof ActivatedAbility && ((ActivatedAbility) targetAbility).isCheckPlayableMode()) {
|
||||
checkPlayableMode = true;
|
||||
}
|
||||
if (!checkPlayableMode) {
|
||||
if (!game.inCheckPlayableState()) {
|
||||
String message = effect.getInfoMessage(sourceAbility, event, game);
|
||||
if (message != null && !message.isEmpty()) {
|
||||
if (effect.sendMessageToUser()) {
|
||||
|
|
@ -770,7 +766,7 @@ public class ContinuousEffects implements Serializable {
|
|||
do {
|
||||
Map<ReplacementEffect, Set<Ability>> rEffects = getApplicableReplacementEffects(event, game);
|
||||
// Remove all consumed effects (ability dependant)
|
||||
for (Iterator<ReplacementEffect> it1 = rEffects.keySet().iterator(); it1.hasNext(); ) {
|
||||
for (Iterator<ReplacementEffect> it1 = rEffects.keySet().iterator(); it1.hasNext();) {
|
||||
ReplacementEffect entry = it1.next();
|
||||
if (consumed.containsKey(entry.getId()) /*&& !(entry instanceof CommanderReplacementEffect) */) { // 903.9.
|
||||
Set<UUID> consumedAbilitiesIds = consumed.get(entry.getId());
|
||||
|
|
@ -961,7 +957,7 @@ public class ContinuousEffects implements Serializable {
|
|||
|
||||
if (!waitingEffects.isEmpty()) {
|
||||
// check if waiting effects can be applied now
|
||||
for (Iterator<Map.Entry<ContinuousEffect, Set<UUID>>> iterator = waitingEffects.entrySet().iterator(); iterator.hasNext(); ) {
|
||||
for (Iterator<Map.Entry<ContinuousEffect, Set<UUID>>> iterator = waitingEffects.entrySet().iterator(); iterator.hasNext();) {
|
||||
Map.Entry<ContinuousEffect, Set<UUID>> entry = iterator.next();
|
||||
if (appliedEffects.containsAll(entry.getValue())) { // all dependent to effects are applied now so apply the effect itself
|
||||
appliedAbilities = appliedEffectAbilities.get(entry.getKey());
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
package mage.abilities.effects.common.cost;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
|
|
@ -6,7 +5,6 @@ import java.util.Set;
|
|||
import java.util.UUID;
|
||||
import mage.Mana;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.ActivatedAbility;
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.choices.ChoiceImpl;
|
||||
|
|
@ -70,11 +68,9 @@ public class SpellsCostReductionAllEffect extends CostModificationEffectImpl {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source, Ability abilityToModify) {
|
||||
if (upTo) {
|
||||
if (abilityToModify instanceof ActivatedAbility) {
|
||||
if (((ActivatedAbility) abilityToModify).isCheckPlayableMode()) {
|
||||
CardUtil.reduceCost(abilityToModify, this.amount);
|
||||
return true;
|
||||
}
|
||||
if (game.inCheckPlayableState()) {
|
||||
CardUtil.reduceCost(abilityToModify, this.amount);
|
||||
return true;
|
||||
}
|
||||
Mana mana = abilityToModify.getManaCostsToPay().getMana();
|
||||
int reduceMax = mana.getGeneric();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
package mage.abilities.effects.common.cost;
|
||||
|
||||
import java.util.LinkedHashSet;
|
||||
|
|
@ -6,7 +5,6 @@ import java.util.Set;
|
|||
import mage.MageObject;
|
||||
import mage.Mana;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.ActivatedAbility;
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.abilities.costs.mana.ManaCost;
|
||||
import mage.abilities.costs.mana.ManaCosts;
|
||||
|
|
@ -85,7 +83,7 @@ public class SpellsCostReductionControllerEffect extends CostModificationEffectI
|
|||
return false;
|
||||
}
|
||||
int reduce = reduceMax;
|
||||
if (!(abilityToModify instanceof ActivatedAbility) || !((ActivatedAbility) abilityToModify).isCheckPlayableMode()) {
|
||||
if (!game.inCheckPlayableState()) {
|
||||
ChoiceImpl choice = new ChoiceImpl(false);
|
||||
Set<String> set = new LinkedHashSet<>();
|
||||
for (int i = 0; i <= amount; i++) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package mage.abilities.keyword;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.StaticAbility;
|
||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||
|
|
@ -23,8 +24,6 @@ import mage.players.Player;
|
|||
import mage.target.TargetCard;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author LevelX2
|
||||
* <p>
|
||||
|
|
@ -122,7 +121,7 @@ class HideawayLookAtFaceDownCardEffect extends AsThoughEffectImpl {
|
|||
|
||||
public HideawayLookAtFaceDownCardEffect() {
|
||||
super(AsThoughEffectType.LOOK_AT_FACE_DOWN, Duration.EndOfGame, Outcome.Benefit);
|
||||
staticText = "You may look at cards exiled with {this}";
|
||||
staticText = "You may look at the cards exiled with {this}";
|
||||
}
|
||||
|
||||
private HideawayLookAtFaceDownCardEffect(final HideawayLookAtFaceDownCardEffect effect) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package mage.abilities.keyword;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.SpellAbility;
|
||||
|
|
@ -17,8 +18,6 @@ import mage.target.Target;
|
|||
import mage.target.common.TargetControlledCreaturePermanent;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* 702.46. Offering # 702.46a Offering is a static ability of a card that
|
||||
* functions in any zone from which the card can be cast. "[Subtype] offering"
|
||||
|
|
@ -121,7 +120,7 @@ class OfferingAsThoughEffect extends AsThoughEffectImpl {
|
|||
|
||||
if (game.getBattlefield().count(((OfferingAbility) source).getFilter(), source.getSourceId(), source.getControllerId(), game) > 0) {
|
||||
|
||||
if (CardUtil.isCheckPlayableMode(affectedAbility)) {
|
||||
if (game.inCheckPlayableState()) {
|
||||
return true;
|
||||
}
|
||||
FilterControlledCreaturePermanent filter = ((OfferingAbility) source).getFilter();
|
||||
|
|
@ -130,7 +129,7 @@ class OfferingAsThoughEffect extends AsThoughEffectImpl {
|
|||
return false;
|
||||
}
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
if (player != null && !CardUtil.isCheckPlayableMode(affectedAbility)
|
||||
if (player != null && !game.inCheckPlayableState()
|
||||
&& player.chooseUse(Outcome.Benefit, "Offer a " + filter.getMessage() + " to cast " + spellToCast.getName() + '?', source, game)) {
|
||||
Target target = new TargetControlledCreaturePermanent(1, 1, filter, true);
|
||||
player.chooseTarget(Outcome.Sacrifice, target, source, game);
|
||||
|
|
@ -193,7 +192,7 @@ class OfferingCostReductionEffect extends CostModificationEffectImpl {
|
|||
|
||||
@Override
|
||||
public boolean applies(Ability abilityToModify, Ability source, Game game) {
|
||||
if (CardUtil.isCheckPlayableMode(abilityToModify)) { // Cost modifaction does not work correctly for checking available spells
|
||||
if (game.inCheckPlayableState()) { // Cost modifaction does not work correctly for checking available spells
|
||||
return false;
|
||||
}
|
||||
if (abilityToModify.getId().equals(spellAbilityId) && abilityToModify instanceof SpellAbility) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue