mirror of
https://github.com/correl/mage.git
synced 2024-12-27 03:00:13 +00:00
Added effect type and logic to handle multiple untap restriction effects.
This commit is contained in:
parent
ae44981cfa
commit
0cf7ca3fca
5 changed files with 298 additions and 9 deletions
|
@ -67,6 +67,7 @@ public class ContinuousEffects implements Serializable {
|
||||||
private ContinuousEffectsList<PreventionEffect> preventionEffects = new ContinuousEffectsList<PreventionEffect>();
|
private ContinuousEffectsList<PreventionEffect> preventionEffects = new ContinuousEffectsList<PreventionEffect>();
|
||||||
private ContinuousEffectsList<RequirementEffect> requirementEffects = new ContinuousEffectsList<RequirementEffect>();
|
private ContinuousEffectsList<RequirementEffect> requirementEffects = new ContinuousEffectsList<RequirementEffect>();
|
||||||
private ContinuousEffectsList<RestrictionEffect> restrictionEffects = new ContinuousEffectsList<RestrictionEffect>();
|
private ContinuousEffectsList<RestrictionEffect> restrictionEffects = new ContinuousEffectsList<RestrictionEffect>();
|
||||||
|
private ContinuousEffectsList<RestrictionUntapNotMoreThanEffect> restrictionUntapNotMoreThanEffects = new ContinuousEffectsList<RestrictionUntapNotMoreThanEffect>();
|
||||||
private ContinuousEffectsList<AsThoughEffect> asThoughEffects = new ContinuousEffectsList<AsThoughEffect>();
|
private ContinuousEffectsList<AsThoughEffect> asThoughEffects = new ContinuousEffectsList<AsThoughEffect>();
|
||||||
private ContinuousEffectsList<CostModificationEffect> costModificationEffects = new ContinuousEffectsList<CostModificationEffect>();
|
private ContinuousEffectsList<CostModificationEffect> costModificationEffects = new ContinuousEffectsList<CostModificationEffect>();
|
||||||
private ContinuousEffectsList<SpliceCardEffect> spliceCardEffects = new ContinuousEffectsList<SpliceCardEffect>();
|
private ContinuousEffectsList<SpliceCardEffect> spliceCardEffects = new ContinuousEffectsList<SpliceCardEffect>();
|
||||||
|
@ -98,6 +99,7 @@ public class ContinuousEffects implements Serializable {
|
||||||
preventionEffects = effect.preventionEffects.copy();
|
preventionEffects = effect.preventionEffects.copy();
|
||||||
requirementEffects = effect.requirementEffects.copy();
|
requirementEffects = effect.requirementEffects.copy();
|
||||||
restrictionEffects = effect.restrictionEffects.copy();
|
restrictionEffects = effect.restrictionEffects.copy();
|
||||||
|
restrictionUntapNotMoreThanEffects = effect.restrictionUntapNotMoreThanEffects.copy();
|
||||||
asThoughEffects = effect.asThoughEffects.copy();
|
asThoughEffects = effect.asThoughEffects.copy();
|
||||||
costModificationEffects = effect.costModificationEffects.copy();
|
costModificationEffects = effect.costModificationEffects.copy();
|
||||||
spliceCardEffects = effect.spliceCardEffects.copy();
|
spliceCardEffects = effect.spliceCardEffects.copy();
|
||||||
|
@ -114,6 +116,7 @@ public class ContinuousEffects implements Serializable {
|
||||||
allEffectsLists.add(preventionEffects);
|
allEffectsLists.add(preventionEffects);
|
||||||
allEffectsLists.add(requirementEffects);
|
allEffectsLists.add(requirementEffects);
|
||||||
allEffectsLists.add(restrictionEffects);
|
allEffectsLists.add(restrictionEffects);
|
||||||
|
allEffectsLists.add(restrictionUntapNotMoreThanEffects);
|
||||||
allEffectsLists.add(asThoughEffects);
|
allEffectsLists.add(asThoughEffects);
|
||||||
allEffectsLists.add(costModificationEffects);
|
allEffectsLists.add(costModificationEffects);
|
||||||
allEffectsLists.add(spliceCardEffects);
|
allEffectsLists.add(spliceCardEffects);
|
||||||
|
@ -159,6 +162,7 @@ public class ContinuousEffects implements Serializable {
|
||||||
preventionEffects.removeInactiveEffects(game);
|
preventionEffects.removeInactiveEffects(game);
|
||||||
requirementEffects.removeInactiveEffects(game);
|
requirementEffects.removeInactiveEffects(game);
|
||||||
restrictionEffects.removeInactiveEffects(game);
|
restrictionEffects.removeInactiveEffects(game);
|
||||||
|
restrictionUntapNotMoreThanEffects.removeInactiveEffects(game);
|
||||||
asThoughEffects.removeInactiveEffects(game);
|
asThoughEffects.removeInactiveEffects(game);
|
||||||
costModificationEffects.removeInactiveEffects(game);
|
costModificationEffects.removeInactiveEffects(game);
|
||||||
spliceCardEffects.removeInactiveEffects(game);
|
spliceCardEffects.removeInactiveEffects(game);
|
||||||
|
@ -251,7 +255,7 @@ public class ContinuousEffects implements Serializable {
|
||||||
HashSet<Ability> abilities = restrictionEffects.getAbility(effect.getId());
|
HashSet<Ability> abilities = restrictionEffects.getAbility(effect.getId());
|
||||||
HashSet<Ability> applicableAbilities = new HashSet<Ability>();
|
HashSet<Ability> applicableAbilities = new HashSet<Ability>();
|
||||||
for (Ability ability : abilities) {
|
for (Ability ability : abilities) {
|
||||||
if (!(ability instanceof StaticAbility) || ability.isInUseableZone(game, permanent, false)) {
|
if (!(ability instanceof StaticAbility) || ability.isInUseableZone(game, null, false)) {
|
||||||
if (effect.applies(permanent, ability, game)) {
|
if (effect.applies(permanent, ability, game)) {
|
||||||
applicableAbilities.add(ability);
|
applicableAbilities.add(ability);
|
||||||
}
|
}
|
||||||
|
@ -264,6 +268,25 @@ public class ContinuousEffects implements Serializable {
|
||||||
return effects;
|
return effects;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public HashMap<RestrictionUntapNotMoreThanEffect, HashSet<Ability>> getApplicableRestrictionUntapNotMoreThanEffects(Player player, Game game) {
|
||||||
|
HashMap<RestrictionUntapNotMoreThanEffect, HashSet<Ability>> effects = new HashMap<RestrictionUntapNotMoreThanEffect, HashSet<Ability>>();
|
||||||
|
for (RestrictionUntapNotMoreThanEffect effect: restrictionUntapNotMoreThanEffects) {
|
||||||
|
HashSet<Ability> abilities = restrictionUntapNotMoreThanEffects.getAbility(effect.getId());
|
||||||
|
HashSet<Ability> applicableAbilities = new HashSet<Ability>();
|
||||||
|
for (Ability ability : abilities) {
|
||||||
|
if (!(ability instanceof StaticAbility) || ability.isInUseableZone(game, null, false)) {
|
||||||
|
if (effect.applies(player, ability, game)) {
|
||||||
|
applicableAbilities.add(ability);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!applicableAbilities.isEmpty()) {
|
||||||
|
effects.put(effect, abilities);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return effects;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param event
|
* @param event
|
||||||
|
@ -708,6 +731,10 @@ public class ContinuousEffects implements Serializable {
|
||||||
RestrictionEffect newRestrictionEffect = (RestrictionEffect)effect;
|
RestrictionEffect newRestrictionEffect = (RestrictionEffect)effect;
|
||||||
restrictionEffects.addEffect(newRestrictionEffect, source);
|
restrictionEffects.addEffect(newRestrictionEffect, source);
|
||||||
break;
|
break;
|
||||||
|
case RESTRICTION_UNTAP_NOT_MORE_THAN:
|
||||||
|
RestrictionUntapNotMoreThanEffect newRestrictionUntapNotMoreThanEffect = (RestrictionUntapNotMoreThanEffect)effect;
|
||||||
|
restrictionUntapNotMoreThanEffects.addEffect(newRestrictionUntapNotMoreThanEffect, source);
|
||||||
|
break;
|
||||||
case REQUIREMENT:
|
case REQUIREMENT:
|
||||||
RequirementEffect newRequirementEffect = (RequirementEffect)effect;
|
RequirementEffect newRequirementEffect = (RequirementEffect)effect;
|
||||||
requirementEffects.addEffect(newRequirementEffect, source);
|
requirementEffects.addEffect(newRequirementEffect, source);
|
||||||
|
|
|
@ -28,12 +28,14 @@
|
||||||
|
|
||||||
package mage.abilities.effects;
|
package mage.abilities.effects;
|
||||||
|
|
||||||
|
import mage.abilities.Ability;
|
||||||
import mage.constants.Duration;
|
import mage.constants.Duration;
|
||||||
import mage.constants.EffectType;
|
import mage.constants.EffectType;
|
||||||
import mage.constants.Outcome;
|
import mage.constants.Outcome;
|
||||||
import mage.abilities.Ability;
|
import mage.filter.FilterPermanent;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
|
import mage.players.Player;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -41,13 +43,28 @@ import mage.game.permanent.Permanent;
|
||||||
*/
|
*/
|
||||||
public abstract class RestrictionEffect<T extends RestrictionEffect<T>> extends ContinuousEffectImpl<T> {
|
public abstract class RestrictionEffect<T extends RestrictionEffect<T>> extends ContinuousEffectImpl<T> {
|
||||||
|
|
||||||
|
private boolean notMoreThanRestriction;
|
||||||
|
private int notMoreThanNumber;
|
||||||
|
private FilterPermanent notMoreThanNumberFilter;
|
||||||
|
|
||||||
public RestrictionEffect(Duration duration) {
|
public RestrictionEffect(Duration duration) {
|
||||||
|
this(duration, false, 0, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RestrictionEffect(Duration duration, boolean notMoreThanRestriction, int notMoreThanNumber, FilterPermanent notMoreThanNumberFilter) {
|
||||||
super(duration, Outcome.Detriment);
|
super(duration, Outcome.Detriment);
|
||||||
this.effectType = EffectType.RESTRICTION;
|
this.effectType = EffectType.RESTRICTION;
|
||||||
|
this.notMoreThanRestriction = notMoreThanRestriction;
|
||||||
|
this.notMoreThanNumber = notMoreThanNumber;
|
||||||
|
this.notMoreThanNumberFilter = notMoreThanNumberFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RestrictionEffect(final RestrictionEffect effect) {
|
public RestrictionEffect(final RestrictionEffect effect) {
|
||||||
super(effect);
|
super(effect);
|
||||||
|
this.notMoreThanRestriction = effect.notMoreThanRestriction;
|
||||||
|
if (this.notMoreThanNumberFilter != null) {
|
||||||
|
this.notMoreThanNumberFilter = effect.notMoreThanNumberFilter.copy();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -57,6 +74,15 @@ public abstract class RestrictionEffect<T extends RestrictionEffect<T>> extends
|
||||||
|
|
||||||
public abstract boolean applies(Permanent permanent, Ability source, Game game);
|
public abstract boolean applies(Permanent permanent, Ability source, Game game);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* only used for the notMoreThanRestrictions, called to check if the effect shall be applied for a player
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public boolean appliesNotMoreThan(Player player, Ability source, Game game) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean canAttack(Game game) {
|
public boolean canAttack(Game game) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -77,5 +103,16 @@ public abstract class RestrictionEffect<T extends RestrictionEffect<T>> extends
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isNotMoreThanRestriction() {
|
||||||
|
return notMoreThanRestriction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNotMoreThanNumber() {
|
||||||
|
return notMoreThanNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FilterPermanent getNotMoreThanNumberFilter() {
|
||||||
|
return notMoreThanNumberFilter;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
/*
|
||||||
|
* 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.constants.Duration;
|
||||||
|
import mage.constants.EffectType;
|
||||||
|
import mage.constants.Outcome;
|
||||||
|
import mage.filter.common.FilterControlledPermanent;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.players.Player;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author LevelX2
|
||||||
|
*/
|
||||||
|
public abstract class RestrictionUntapNotMoreThanEffect<T extends RestrictionUntapNotMoreThanEffect<T>> extends ContinuousEffectImpl<T> {
|
||||||
|
|
||||||
|
private int number;
|
||||||
|
private FilterControlledPermanent filter;
|
||||||
|
|
||||||
|
public RestrictionUntapNotMoreThanEffect(Duration duration, int number, FilterControlledPermanent filter) {
|
||||||
|
super(duration, Outcome.Detriment);
|
||||||
|
this.effectType = EffectType.RESTRICTION_UNTAP_NOT_MORE_THAN;
|
||||||
|
this.number = number;
|
||||||
|
this.filter = filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RestrictionUntapNotMoreThanEffect(final RestrictionUntapNotMoreThanEffect effect) {
|
||||||
|
super(effect);
|
||||||
|
this.number = effect.number;
|
||||||
|
if (effect.filter != null) {
|
||||||
|
this.filter = effect.filter.copy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
throw new UnsupportedOperationException("Not supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract boolean applies(Player player, Ability source, Game game);
|
||||||
|
|
||||||
|
public int getNumber() {
|
||||||
|
return number;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FilterControlledPermanent getFilter() {
|
||||||
|
return filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -13,6 +13,7 @@ public enum EffectType {
|
||||||
REDIRECTION("Redirection Effect"),
|
REDIRECTION("Redirection Effect"),
|
||||||
ASTHOUGH("As Though Effect"),
|
ASTHOUGH("As Though Effect"),
|
||||||
RESTRICTION("Restriction Effect"),
|
RESTRICTION("Restriction Effect"),
|
||||||
|
RESTRICTION_UNTAP_NOT_MORE_THAN("Restriction untap not more than Effect"),
|
||||||
REQUIREMENT("Requirement Effect"),
|
REQUIREMENT("Requirement Effect"),
|
||||||
COSTMODIFICATION("Cost Modification Effect"),
|
COSTMODIFICATION("Cost Modification Effect"),
|
||||||
SPLICE("Splice Card Effect");
|
SPLICE("Splice Card Effect");
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
package mage.players;
|
package mage.players;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.security.InvalidParameterException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
@ -36,6 +37,7 @@ import java.util.Iterator;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
@ -56,6 +58,7 @@ import mage.abilities.common.delayed.AtTheEndOfTurnStepPostDelayedTriggeredAbili
|
||||||
import mage.abilities.costs.AdjustingSourceCosts;
|
import mage.abilities.costs.AdjustingSourceCosts;
|
||||||
import mage.abilities.costs.AlternativeCost;
|
import mage.abilities.costs.AlternativeCost;
|
||||||
import mage.abilities.effects.RestrictionEffect;
|
import mage.abilities.effects.RestrictionEffect;
|
||||||
|
import mage.abilities.effects.RestrictionUntapNotMoreThanEffect;
|
||||||
import mage.abilities.effects.common.LoseControlOnOtherPlayersControllerEffect;
|
import mage.abilities.effects.common.LoseControlOnOtherPlayersControllerEffect;
|
||||||
import mage.abilities.keyword.FlashbackAbility;
|
import mage.abilities.keyword.FlashbackAbility;
|
||||||
import mage.abilities.keyword.HexproofAbility;
|
import mage.abilities.keyword.HexproofAbility;
|
||||||
|
@ -82,8 +85,11 @@ import mage.counters.Counter;
|
||||||
import mage.counters.CounterType;
|
import mage.counters.CounterType;
|
||||||
import mage.counters.Counters;
|
import mage.counters.Counters;
|
||||||
import mage.filter.FilterCard;
|
import mage.filter.FilterCard;
|
||||||
|
import mage.filter.common.FilterControlledPermanent;
|
||||||
import mage.filter.common.FilterCreatureForCombat;
|
import mage.filter.common.FilterCreatureForCombat;
|
||||||
import mage.filter.common.FilterCreatureForCombatBlock;
|
import mage.filter.common.FilterCreatureForCombatBlock;
|
||||||
|
import mage.filter.predicate.Predicates;
|
||||||
|
import mage.filter.predicate.permanent.PermanentIdPredicate;
|
||||||
import mage.game.ExileZone;
|
import mage.game.ExileZone;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.combat.CombatGroup;
|
import mage.game.combat.CombatGroup;
|
||||||
|
@ -99,10 +105,12 @@ import mage.players.net.UserData;
|
||||||
import mage.target.Target;
|
import mage.target.Target;
|
||||||
import mage.target.TargetAmount;
|
import mage.target.TargetAmount;
|
||||||
import mage.target.TargetCard;
|
import mage.target.TargetCard;
|
||||||
|
import mage.target.TargetPermanent;
|
||||||
import mage.target.common.TargetCardInLibrary;
|
import mage.target.common.TargetCardInLibrary;
|
||||||
import mage.target.common.TargetDiscard;
|
import mage.target.common.TargetDiscard;
|
||||||
import mage.watchers.common.BloodthirstWatcher;
|
import mage.watchers.common.BloodthirstWatcher;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
import org.omg.CORBA.DynAnyPackage.Invalid;
|
||||||
|
|
||||||
|
|
||||||
public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Serializable {
|
public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Serializable {
|
||||||
|
@ -999,6 +1007,122 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void untap(Game game) {
|
public void untap(Game game) {
|
||||||
|
// create list of all "notMoreThan" effects to track which one are consumed
|
||||||
|
HashMap<Entry<RestrictionUntapNotMoreThanEffect, HashSet<Ability>>, Integer> notMoreThanEffectsUsage = new HashMap<Entry<RestrictionUntapNotMoreThanEffect, HashSet<Ability>>, Integer>();
|
||||||
|
for (Entry<RestrictionUntapNotMoreThanEffect, HashSet<Ability>> restrictionEffect: game.getContinuousEffects().getApplicableRestrictionUntapNotMoreThanEffects(this, game).entrySet()) {
|
||||||
|
notMoreThanEffectsUsage.put(restrictionEffect, new Integer(restrictionEffect.getKey().getNumber()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!notMoreThanEffectsUsage.isEmpty()) {
|
||||||
|
// create list of all permanents that can be untapped generally
|
||||||
|
List<Permanent> canBeUntapped = new ArrayList<Permanent>();
|
||||||
|
for (Permanent permanent: game.getBattlefield().getAllActivePermanents(playerId)) {
|
||||||
|
boolean untap = true;
|
||||||
|
for (RestrictionEffect effect: game.getContinuousEffects().getApplicableRestrictionEffects(permanent, game).keySet()) {
|
||||||
|
untap &= effect.canBeUntapped(permanent, game);
|
||||||
|
}
|
||||||
|
if (untap) {
|
||||||
|
canBeUntapped.add(permanent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// selected permanents to untap
|
||||||
|
List<Permanent> selectedToUntap = new ArrayList<Permanent>();
|
||||||
|
|
||||||
|
// player can cancel the seletion of an effect to use a prefered order of restriction effects
|
||||||
|
boolean playerCanceledSelection;
|
||||||
|
do {
|
||||||
|
playerCanceledSelection = false;
|
||||||
|
// select permanents to untap to consume the "notMoreThan" effects
|
||||||
|
for(Map.Entry<Entry<RestrictionUntapNotMoreThanEffect, HashSet<Ability>>, Integer> handledEntry: notMoreThanEffectsUsage.entrySet()) {
|
||||||
|
// select a permanent to untap for this entry
|
||||||
|
int numberToUntap = handledEntry.getValue().intValue();
|
||||||
|
if (numberToUntap > 0) {
|
||||||
|
|
||||||
|
List<Permanent> leftForUntap = getPermanentsThatCanBeUntapped(game, canBeUntapped, handledEntry.getKey().getKey(), notMoreThanEffectsUsage);
|
||||||
|
|
||||||
|
FilterControlledPermanent filter = handledEntry.getKey().getKey().getFilter().copy();
|
||||||
|
String message = filter.getMessage();
|
||||||
|
// omitt already from other untap effects selected permanents
|
||||||
|
for (Permanent permanent: selectedToUntap) {
|
||||||
|
filter.add(Predicates.not(new PermanentIdPredicate(permanent.getId())));
|
||||||
|
}
|
||||||
|
// while targets left and there is still allowed to untap
|
||||||
|
while (leftForUntap.size() > 0 && numberToUntap > 0) {
|
||||||
|
// player has to select the permanent he wants to untap for this restriction
|
||||||
|
Ability ability = handledEntry.getKey().getValue().iterator().next();
|
||||||
|
if (ability != null) {
|
||||||
|
StringBuilder sb = new StringBuilder(message).append(" to untap").append(" (").append(Math.min(leftForUntap.size(), numberToUntap)).append(" in total");
|
||||||
|
MageObject effectSource = game.getObject(ability.getSourceId());
|
||||||
|
if (effectSource != null) {
|
||||||
|
sb.append(" from ").append(effectSource.getName()).toString();
|
||||||
|
}
|
||||||
|
sb.append(")");
|
||||||
|
filter.setMessage(sb.toString());
|
||||||
|
Target target = new TargetPermanent(filter);
|
||||||
|
if (!this.chooseTarget(Outcome.Untap, target, ability, game)) {
|
||||||
|
// player canceled, go on with the next effect (if no other effect available, this effect will be active again)
|
||||||
|
playerCanceledSelection = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Permanent selectedPermanent = game.getPermanent(target.getFirstTarget());
|
||||||
|
if (leftForUntap.contains(selectedPermanent)) {
|
||||||
|
selectedToUntap.add(selectedPermanent);
|
||||||
|
numberToUntap--;
|
||||||
|
// don't allow to select same permanent twice
|
||||||
|
filter.add(Predicates.not(new PermanentIdPredicate(selectedPermanent.getId())));
|
||||||
|
// reduce available untap numbers from other "UntapNotMoreThan" effects if selected permanent applies to their filter too
|
||||||
|
for (Entry<Entry<RestrictionUntapNotMoreThanEffect, HashSet<Ability>>, Integer> notMoreThanEffect : notMoreThanEffectsUsage.entrySet()) {
|
||||||
|
if (notMoreThanEffect.getValue().intValue() > 0 && notMoreThanEffect.getKey().getKey().getFilter().match(selectedPermanent, game)) {
|
||||||
|
notMoreThanEffect.setValue(new Integer(notMoreThanEffect.getValue().intValue() - 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// update the left for untap list
|
||||||
|
leftForUntap = getPermanentsThatCanBeUntapped(game, canBeUntapped, handledEntry.getKey().getKey(), notMoreThanEffectsUsage);
|
||||||
|
// remove already selected permanents
|
||||||
|
for (Permanent permanent :selectedToUntap) {
|
||||||
|
if (leftForUntap.contains(permanent)) {
|
||||||
|
leftForUntap.remove(permanent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// player selected an permanent that is restricted by another effect, disallow it (so AI can select another one)
|
||||||
|
filter.add(Predicates.not(new PermanentIdPredicate(selectedPermanent.getId())));
|
||||||
|
if (this.isHuman()) {
|
||||||
|
game.informPlayer(this, "This permanent can't be untapped because of other restricting effect.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (playerCanceledSelection);
|
||||||
|
|
||||||
|
// show in log which permanents were selected to untap
|
||||||
|
for(Permanent permanent :selectedToUntap) {
|
||||||
|
game.informPlayers(new StringBuilder(this.getName()).append(" untapped ").append(permanent.getName()).toString());
|
||||||
|
}
|
||||||
|
// untap if permanent is not concerned by notMoreThan effects or is included in the selectedToUntapList
|
||||||
|
for (Permanent permanent: canBeUntapped) {
|
||||||
|
boolean doUntap = true;
|
||||||
|
if (!selectedToUntap.contains(permanent)) {
|
||||||
|
// if the permanent is covered by one of the restriction effects, don't untap it
|
||||||
|
for (Entry<Entry<RestrictionUntapNotMoreThanEffect, HashSet<Ability>>, Integer> notMoreThanEffect : notMoreThanEffectsUsage.entrySet()) {
|
||||||
|
if (notMoreThanEffect.getKey().getKey().getFilter().match(permanent, game)) {
|
||||||
|
doUntap = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (permanent != null && doUntap) {
|
||||||
|
permanent.untap(game);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} else {
|
||||||
//20091005 - 502.2
|
//20091005 - 502.2
|
||||||
for (Permanent permanent: game.getBattlefield().getAllActivePermanents(playerId)) {
|
for (Permanent permanent: game.getBattlefield().getAllActivePermanents(playerId)) {
|
||||||
boolean untap = true;
|
boolean untap = true;
|
||||||
|
@ -1010,6 +1134,28 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Permanent> getPermanentsThatCanBeUntapped(Game game, List<Permanent> canBeUntapped, RestrictionUntapNotMoreThanEffect handledEffect, HashMap<Entry<RestrictionUntapNotMoreThanEffect, HashSet<Ability>>, Integer> notMoreThanEffectsUsage) {
|
||||||
|
List<Permanent> leftForUntap = new ArrayList<Permanent>();
|
||||||
|
// select permanents that can still be untapped
|
||||||
|
for (Permanent permanent: canBeUntapped) {
|
||||||
|
if (handledEffect.getFilter().match(permanent, game)) { // matches the restricted permanents of handled entry
|
||||||
|
boolean canBeSelected = true;
|
||||||
|
// check if the permanent is restriced by another restriction that has left no permanent
|
||||||
|
for (Entry<Entry<RestrictionUntapNotMoreThanEffect, HashSet<Ability>>, Integer> notMoreThanEffect : notMoreThanEffectsUsage.entrySet()) {
|
||||||
|
if (notMoreThanEffect.getKey().getKey().getFilter().match(permanent, game) && notMoreThanEffect.getValue().intValue() == 0) {
|
||||||
|
canBeSelected = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (canBeSelected) {
|
||||||
|
leftForUntap.add(permanent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return leftForUntap;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UUID getId() {
|
public UUID getId() {
|
||||||
|
|
Loading…
Reference in a new issue