mirror of
https://github.com/magefree/mage.git
synced 2026-01-10 12:52:06 -08:00
Added the logic, that one continious effect in game state can be connected to multiple abilities. This fixes issue #198 and #196.
This commit is contained in:
parent
e0bd0e3ffe
commit
1e5100e0d6
12 changed files with 402 additions and 206 deletions
|
|
@ -550,7 +550,8 @@ public class HumanPlayer extends PlayerImpl<HumanPlayer> {
|
|||
}
|
||||
|
||||
private void removeAttackerIfPossible(Game game, Permanent attacker) {
|
||||
for (RequirementEffect effect : game.getContinuousEffects().getApplicableRequirementEffects(attacker, game)) {
|
||||
for (Map.Entry entry : game.getContinuousEffects().getApplicableRequirementEffects(attacker, game).entrySet()) {
|
||||
RequirementEffect effect = (RequirementEffect)entry.getKey();
|
||||
if (effect.mustAttack(game)) {
|
||||
return; // we can't cancel attacking
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
*/
|
||||
package mage.sets.newphyrexia;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import mage.Constants.CardType;
|
||||
import mage.Constants.Duration;
|
||||
|
|
@ -97,7 +98,7 @@ class UnwindingClockEffect extends ContinuousEffectImpl<UnwindingClockEffect> {
|
|||
game.getState().setValue(source.getSourceId() + "applied", true);
|
||||
for (Permanent artifact: game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) {
|
||||
boolean untap = true;
|
||||
for (RestrictionEffect effect : game.getContinuousEffects().getApplicableRestrictionEffects(artifact, game)) {
|
||||
for (RestrictionEffect effect: game.getContinuousEffects().getApplicableRestrictionEffects(artifact, game).keySet()) {
|
||||
untap &= effect.canBeUntapped(artifact, game);
|
||||
}
|
||||
if (untap) artifact.untap(game);
|
||||
|
|
|
|||
|
|
@ -18,6 +18,12 @@ public class CastThroughTimeTest extends CardTestPlayerBase {
|
|||
@Test
|
||||
public void testCastWithRebound() {
|
||||
addCard(Constants.Zone.BATTLEFIELD, playerA, "Mountain", 1);
|
||||
/*
|
||||
* Instant and sorcery spells you control have rebound. (Exile the spell as
|
||||
* it resolves if you cast it from your hand. At the beginning of your next
|
||||
* upkeep, you may cast that card from exile without paying its mana cost.)
|
||||
*
|
||||
*/
|
||||
addCard(Constants.Zone.BATTLEFIELD, playerA, "Cast Through Time");
|
||||
addCard(Constants.Zone.HAND, playerA, "Lightning Bolt");
|
||||
|
||||
|
|
|
|||
|
|
@ -66,8 +66,9 @@ public class ContinuousEffects implements Serializable {
|
|||
private final AuraReplacementEffect auraReplacementEffect;
|
||||
|
||||
private List<ContinuousEffect> previous = new ArrayList<ContinuousEffect>();
|
||||
|
||||
private Map<Effect, UUID> sources = new HashMap<Effect, UUID>();
|
||||
|
||||
// effect.id -> sourceId - which effect was added by which sourceId
|
||||
private Map<UUID, UUID> sources = new HashMap<UUID, UUID>();
|
||||
|
||||
public ContinuousEffects() {
|
||||
applyCounters = new ApplyCountersEffect();
|
||||
|
|
@ -87,7 +88,7 @@ public class ContinuousEffects implements Serializable {
|
|||
restrictionEffects = effect.restrictionEffects.copy();
|
||||
asThoughEffects = effect.asThoughEffects.copy();
|
||||
costModificationEffects = effect.costModificationEffects.copy();
|
||||
for (Map.Entry<Effect, UUID> entry : effect.sources.entrySet()) {
|
||||
for (Map.Entry<UUID, UUID> entry : effect.sources.entrySet()) {
|
||||
sources.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
collectAllEffects();
|
||||
|
|
@ -116,29 +117,6 @@ public class ContinuousEffects implements Serializable {
|
|||
return restrictionEffects;
|
||||
}
|
||||
|
||||
public Ability getAbility(UUID effectId) {
|
||||
Ability ability = layeredEffects.getAbility(effectId);
|
||||
if (ability == null) {
|
||||
ability = replacementEffects.getAbility(effectId);
|
||||
}
|
||||
if (ability == null) {
|
||||
ability = preventionEffects.getAbility(effectId);
|
||||
}
|
||||
if (ability == null) {
|
||||
ability = requirementEffects.getAbility(effectId);
|
||||
}
|
||||
if (ability == null) {
|
||||
ability = restrictionEffects.getAbility(effectId);
|
||||
}
|
||||
if (ability == null) {
|
||||
ability = asThoughEffects.getAbility(effectId);
|
||||
}
|
||||
if (ability == null) {
|
||||
ability = costModificationEffects.getAbility(effectId);
|
||||
}
|
||||
return ability;
|
||||
}
|
||||
|
||||
public void removeEndOfTurnEffects() {
|
||||
layeredEffects.removeEndOfTurnEffects();
|
||||
replacementEffects.removeEndOfTurnEffects();
|
||||
|
|
@ -166,9 +144,12 @@ public class ContinuousEffects implements Serializable {
|
|||
case WhileOnBattlefield:
|
||||
case WhileOnStack:
|
||||
case WhileInGraveyard:
|
||||
Ability ability = layeredEffects.getAbility(effect.getId());
|
||||
if (ability.isInUseableZone(game, null, false)) {
|
||||
layerEffects.add(effect);
|
||||
HashSet<Ability> abilities = layeredEffects.getAbility(effect.getId());
|
||||
for (Ability ability: abilities) {
|
||||
if (ability.isInUseableZone(game, null, false)) {
|
||||
layerEffects.add(effect);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
@ -217,28 +198,40 @@ public class ContinuousEffects implements Serializable {
|
|||
return layerEffects;
|
||||
}
|
||||
|
||||
public List<RequirementEffect> getApplicableRequirementEffects(Permanent permanent, Game game) {
|
||||
List<RequirementEffect> effects = new ArrayList<RequirementEffect>();
|
||||
public HashMap<RequirementEffect, HashSet<Ability>> getApplicableRequirementEffects(Permanent permanent, Game game) {
|
||||
HashMap<RequirementEffect, HashSet<Ability>> effects = new HashMap<RequirementEffect, HashSet<Ability>>();
|
||||
for (RequirementEffect effect: requirementEffects) {
|
||||
Ability ability = requirementEffects.getAbility(effect.getId());
|
||||
if (!(ability instanceof StaticAbility) || ability.isInUseableZone(game, null, false)) {
|
||||
if (effect.applies(permanent, ability, game)) {
|
||||
effects.add(effect);
|
||||
HashSet<Ability> abilities = requirementEffects.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(permanent, ability, game)) {
|
||||
applicableAbilities.add(ability);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!applicableAbilities.isEmpty()) {
|
||||
effects.put(effect, abilities);
|
||||
}
|
||||
}
|
||||
return effects;
|
||||
}
|
||||
|
||||
public List<RestrictionEffect> getApplicableRestrictionEffects(Permanent permanent, Game game) {
|
||||
List<RestrictionEffect> effects = new ArrayList<RestrictionEffect>();
|
||||
public HashMap<RestrictionEffect, HashSet<Ability>> getApplicableRestrictionEffects(Permanent permanent, Game game) {
|
||||
HashMap<RestrictionEffect, HashSet<Ability>> effects = new HashMap<RestrictionEffect, HashSet<Ability>>();
|
||||
for (RestrictionEffect effect: restrictionEffects) {
|
||||
Ability ability = restrictionEffects.getAbility(effect.getId());
|
||||
if (!(ability instanceof StaticAbility) || ability.isInUseableZone(game, permanent, false)) {
|
||||
if (effect.applies(permanent, ability, game)) {
|
||||
effects.add(effect);
|
||||
HashSet<Ability> abilities = restrictionEffects.getAbility(effect.getId());
|
||||
HashSet<Ability> applicableAbilities = new HashSet<Ability>();
|
||||
for (Ability ability : abilities) {
|
||||
if (!(ability instanceof StaticAbility) || ability.isInUseableZone(game, permanent, false)) {
|
||||
if (effect.applies(permanent, ability, game)) {
|
||||
applicableAbilities.add(ability);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!applicableAbilities.isEmpty()) {
|
||||
effects.put(effect, abilities);
|
||||
}
|
||||
}
|
||||
return effects;
|
||||
}
|
||||
|
|
@ -249,36 +242,49 @@ public class ContinuousEffects implements Serializable {
|
|||
* @param game
|
||||
* @return a list of all {@link ReplacementEffect} that apply to the current event
|
||||
*/
|
||||
private List<ReplacementEffect> getApplicableReplacementEffects(GameEvent event, Game game) {
|
||||
List<ReplacementEffect> replaceEffects = new ArrayList<ReplacementEffect>();
|
||||
private HashMap<ReplacementEffect, HashSet<Ability>> getApplicableReplacementEffects(GameEvent event, Game game) {
|
||||
// List<ReplacementEffect> replaceEffects = new ArrayList<ReplacementEffect>();
|
||||
HashMap<ReplacementEffect, HashSet<Ability>> replaceEffects = new HashMap<ReplacementEffect, HashSet<Ability>>();
|
||||
if (planeswalkerRedirectionEffect.applies(event, null, game)) {
|
||||
replaceEffects.add(planeswalkerRedirectionEffect);
|
||||
replaceEffects.put(planeswalkerRedirectionEffect, null);
|
||||
}
|
||||
if(auraReplacementEffect.applies(event, null, game)){
|
||||
replaceEffects.add(auraReplacementEffect);
|
||||
replaceEffects.put(auraReplacementEffect, null);
|
||||
}
|
||||
//get all applicable transient Replacement effects
|
||||
for (ReplacementEffect effect: replacementEffects) {
|
||||
Ability ability = replacementEffects.getAbility(effect.getId());
|
||||
if (!(ability instanceof StaticAbility) || ability.isInUseableZone(game, null, false)) {
|
||||
if (effect.getDuration() != Duration.OneUse || !effect.isUsed()) {
|
||||
if (!game.getScopeRelevant() || effect.hasSelfScope() || !event.getTargetId().equals(this.replacementEffects.getAbility(effect.getId()).getSourceId())) {
|
||||
if (effect.applies(event, ability, game)) {
|
||||
replaceEffects.add(effect);
|
||||
HashSet<Ability> abilities = replacementEffects.getAbility(effect.getId());
|
||||
HashSet<Ability> applicableAbilities = new HashSet<Ability>();
|
||||
for (Ability ability : abilities) {
|
||||
if (!(ability instanceof StaticAbility) || ability.isInUseableZone(game, null, false)) {
|
||||
if (effect.getDuration() != Duration.OneUse || !effect.isUsed()) {
|
||||
if (!game.getScopeRelevant() || effect.hasSelfScope() || !event.getTargetId().equals(ability.getSourceId())) {
|
||||
if (effect.applies(event, ability, game)) {
|
||||
applicableAbilities.add(ability);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!applicableAbilities.isEmpty()) {
|
||||
replaceEffects.put((ReplacementEffect) effect, applicableAbilities);
|
||||
}
|
||||
}
|
||||
for (PreventionEffect effect: preventionEffects) {
|
||||
Ability ability = preventionEffects.getAbility(effect.getId());
|
||||
if (!(ability instanceof StaticAbility) || ability.isInUseableZone(game, null, false)) {
|
||||
if (effect.getDuration() != Duration.OneUse || !effect.isUsed()) {
|
||||
if (effect.applies(event, ability, game)) {
|
||||
replaceEffects.add(effect);
|
||||
HashSet<Ability> abilities = preventionEffects.getAbility(effect.getId());
|
||||
HashSet<Ability> applicableAbilities = new HashSet<Ability>();
|
||||
for (Ability ability : abilities) {
|
||||
if (!(ability instanceof StaticAbility) || ability.isInUseableZone(game, null, false)) {
|
||||
if (effect.getDuration() != Duration.OneUse || !effect.isUsed()) {
|
||||
if (effect.applies(event, ability, game)) {
|
||||
applicableAbilities.add(ability);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!applicableAbilities.isEmpty()) {
|
||||
replaceEffects.put((ReplacementEffect) effect, applicableAbilities);
|
||||
}
|
||||
}
|
||||
return replaceEffects;
|
||||
}
|
||||
|
|
@ -293,10 +299,13 @@ public class ContinuousEffects implements Serializable {
|
|||
List<CostModificationEffect> costEffects = new ArrayList<CostModificationEffect>();
|
||||
|
||||
for (CostModificationEffect effect: costModificationEffects) {
|
||||
Ability ability = costModificationEffects.getAbility(effect.getId());
|
||||
if (!(ability instanceof StaticAbility) || ability.isInUseableZone(game, null, false)) {
|
||||
if (effect.getDuration() != Duration.OneUse || !effect.isUsed()) {
|
||||
costEffects.add(effect);
|
||||
HashSet<Ability> abilities = costModificationEffects.getAbility(effect.getId());
|
||||
for (Ability ability : abilities) {
|
||||
if (!(ability instanceof StaticAbility) || ability.isInUseableZone(game, null, false)) {
|
||||
if (effect.getDuration() != Duration.OneUse || !effect.isUsed()) {
|
||||
costEffects.add(effect);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -309,8 +318,11 @@ public class ContinuousEffects implements Serializable {
|
|||
|
||||
for (AsThoughEffect effect: asThoughEffectsList) {
|
||||
if (effect.getAsThoughEffectType() == type) {
|
||||
if (effect.applies(objectId, asThoughEffects.getAbility(effect.getId()), game)) {
|
||||
return true;
|
||||
HashSet<Ability> abilities = asThoughEffects.getAbility(effect.getId());
|
||||
for (Ability ability : abilities) {
|
||||
if (effect.applies(objectId, ability, game)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -327,10 +339,13 @@ public class ContinuousEffects implements Serializable {
|
|||
List<AsThoughEffect> asThoughEffectsList = new ArrayList<AsThoughEffect>();
|
||||
|
||||
for (AsThoughEffect effect: asThoughEffects) {
|
||||
Ability ability = asThoughEffects.getAbility(effect.getId());
|
||||
if (!(ability instanceof StaticAbility) || ability.isInUseableZone(game, null, false)) {
|
||||
if (effect.getDuration() != Duration.OneUse || !effect.isUsed()) {
|
||||
asThoughEffectsList.add(effect);
|
||||
HashSet<Ability> abilities = asThoughEffects.getAbility(effect.getId());
|
||||
for (Ability ability : abilities) {
|
||||
if (!(ability instanceof StaticAbility) || ability.isInUseableZone(game, null, false)) {
|
||||
if (effect.getDuration() != Duration.OneUse || !effect.isUsed()) {
|
||||
asThoughEffectsList.add(effect);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -350,41 +365,115 @@ public class ContinuousEffects implements Serializable {
|
|||
List<CostModificationEffect> costEffects = getApplicableCostModificationEffects(game);
|
||||
|
||||
for ( CostModificationEffect effect : costEffects) {
|
||||
if ( effect.applies(abilityToModify, costModificationEffects.getAbility(effect.getId()), game) ) {
|
||||
effect.apply(game, costModificationEffects.getAbility(effect.getId()), abilityToModify);
|
||||
HashSet<Ability> abilities = costModificationEffects.getAbility(effect.getId());
|
||||
for (Ability ability : abilities) {
|
||||
if ( effect.applies(abilityToModify, ability, game) ) {
|
||||
effect.apply(game, ability, abilityToModify);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean replaceEvent(GameEvent event, Game game) {
|
||||
boolean caught = false;
|
||||
List<UUID> consumed = new ArrayList<UUID>();
|
||||
HashMap<UUID, HashSet<UUID>> consumed = new HashMap<UUID, HashSet<UUID>>();
|
||||
do {
|
||||
List<ReplacementEffect> rEffects = getApplicableReplacementEffects(event, game);
|
||||
for (Iterator<ReplacementEffect> i = rEffects.iterator(); i.hasNext();) {
|
||||
ReplacementEffect entry = i.next();
|
||||
if (consumed.contains(entry.getId())) {
|
||||
i.remove();
|
||||
HashMap<ReplacementEffect, HashSet<Ability>> rEffects = getApplicableReplacementEffects(event, game);
|
||||
// Remove all consumed effects (ability dependant)
|
||||
for (Iterator<ReplacementEffect> it1 = rEffects.keySet().iterator(); it1.hasNext();){
|
||||
ReplacementEffect entry = it1.next();
|
||||
if (consumed.containsKey(entry.getId())) {
|
||||
HashSet<UUID> consumedAbilitiesIds = consumed.get(entry.getId());
|
||||
if (consumedAbilitiesIds.size() == ((HashSet<Ability>) rEffects.get(entry)).size()) {
|
||||
it1.remove();
|
||||
} else {
|
||||
Iterator it = ((HashSet<Ability>) rEffects.get(entry)).iterator();
|
||||
while (it.hasNext()) {
|
||||
Ability ability = (Ability) it.next();
|
||||
if (consumedAbilitiesIds.contains(ability.getId())) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// no effects left, quit
|
||||
if (rEffects.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
int index;
|
||||
boolean onlyOne = false;
|
||||
if (rEffects.size() == 1) {
|
||||
index = 0;
|
||||
ReplacementEffect effect = (ReplacementEffect) rEffects.keySet().iterator().next();
|
||||
HashSet<Ability> abilities = replacementEffects.getAbility(effect.getId());
|
||||
if (abilities == null || abilities.size() == 1) {
|
||||
onlyOne = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (onlyOne) {
|
||||
index = 0;
|
||||
} else {
|
||||
//20100716 - 616.1c
|
||||
Player player = game.getPlayer(event.getPlayerId());
|
||||
index = player.chooseEffect(getReplacementEffectsTexts(rEffects, game), game);
|
||||
}
|
||||
ReplacementEffect rEffect = rEffects.get(index);
|
||||
caught = rEffect.replaceEvent(event, this.getAbility(rEffect.getId()), game);
|
||||
if (caught) {
|
||||
// get the selected effect
|
||||
int checked = 0;
|
||||
ReplacementEffect rEffect = null;
|
||||
Ability rAbility = null;
|
||||
for (Map.Entry entry : rEffects.entrySet()) {
|
||||
if (entry.getValue() == null) {
|
||||
if (checked == index) {
|
||||
rEffect = (ReplacementEffect) entry.getKey();
|
||||
break;
|
||||
} else {
|
||||
checked++;
|
||||
}
|
||||
} else {
|
||||
HashSet<Ability> abilities = (HashSet<Ability>) entry.getValue();
|
||||
int size = abilities.size();
|
||||
if (index > (checked + size - 1)) {
|
||||
checked += size;
|
||||
} else {
|
||||
rEffect = (ReplacementEffect) entry.getKey();
|
||||
Iterator it = abilities.iterator();
|
||||
while (it.hasNext() && rAbility == null) {
|
||||
if (checked == index) {
|
||||
rAbility = (Ability) it.next();
|
||||
} else {
|
||||
it.next();
|
||||
checked++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rEffect != null) {
|
||||
caught = rEffect.replaceEvent(event, rAbility, game);
|
||||
}
|
||||
if (caught) { // Event was completely replaced -> stop applying effects to it
|
||||
break;
|
||||
}
|
||||
consumed.add(rEffect.getId());
|
||||
|
||||
// add used effect to consumed effects
|
||||
if (rEffect != null) {
|
||||
if (consumed.containsKey(rEffect.getId())) {
|
||||
HashSet<UUID> set = consumed.get(rEffect.getId());
|
||||
if (rAbility != null) {
|
||||
if (!set.contains(rAbility.getId())) {
|
||||
set.add(rAbility.getId());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
HashSet<UUID> set = new HashSet<UUID>();
|
||||
if (rAbility != null) { // in case of AuraReplacementEffect or PlaneswalkerReplacementEffect there is no Ability
|
||||
set.add(rAbility.getId());
|
||||
}
|
||||
consumed.put(rEffect.getId(), set);
|
||||
}
|
||||
}
|
||||
|
||||
game.applyEffects();
|
||||
} while (true);
|
||||
return caught;
|
||||
|
|
@ -396,7 +485,10 @@ public class ContinuousEffects implements Serializable {
|
|||
List<ContinuousEffect> layerEffects = getLayeredEffects(game);
|
||||
List<ContinuousEffect> layer = filterLayeredEffects(layerEffects, Layer.CopyEffects_1);
|
||||
for (ContinuousEffect effect: layer) {
|
||||
effect.apply(Layer.CopyEffects_1, SubLayer.NA, layeredEffects.getAbility(effect.getId()), game);
|
||||
HashSet<Ability> abilities = layeredEffects.getAbility(effect.getId());
|
||||
for (Ability ability : abilities) {
|
||||
effect.apply(Layer.CopyEffects_1, SubLayer.NA, ability, game);
|
||||
}
|
||||
}
|
||||
//Reload layerEffect if copy effects were applied
|
||||
if (layer.size()>0) {
|
||||
|
|
@ -405,51 +497,81 @@ public class ContinuousEffects implements Serializable {
|
|||
|
||||
layer = filterLayeredEffects(layerEffects, Layer.ControlChangingEffects_2);
|
||||
for (ContinuousEffect effect: layer) {
|
||||
effect.apply(Layer.ControlChangingEffects_2, SubLayer.NA, layeredEffects.getAbility(effect.getId()), game);
|
||||
HashSet<Ability> abilities = layeredEffects.getAbility(effect.getId());
|
||||
for (Ability ability : abilities) {
|
||||
effect.apply(Layer.ControlChangingEffects_2, SubLayer.NA, ability, game);
|
||||
}
|
||||
}
|
||||
layer = filterLayeredEffects(layerEffects, Layer.TextChangingEffects_3);
|
||||
for (ContinuousEffect effect: layer) {
|
||||
effect.apply(Layer.TextChangingEffects_3, SubLayer.NA, layeredEffects.getAbility(effect.getId()), game);
|
||||
HashSet<Ability> abilities = layeredEffects.getAbility(effect.getId());
|
||||
for (Ability ability : abilities) {
|
||||
effect.apply(Layer.TextChangingEffects_3, SubLayer.NA, ability, game);
|
||||
}
|
||||
}
|
||||
layer = filterLayeredEffects(layerEffects, Layer.TypeChangingEffects_4);
|
||||
for (ContinuousEffect effect: layer) {
|
||||
effect.apply(Layer.TypeChangingEffects_4, SubLayer.NA, layeredEffects.getAbility(effect.getId()), game);
|
||||
HashSet<Ability> abilities = layeredEffects.getAbility(effect.getId());
|
||||
for (Ability ability : abilities) {
|
||||
effect.apply(Layer.TypeChangingEffects_4, SubLayer.NA, ability, game);
|
||||
}
|
||||
}
|
||||
layer = filterLayeredEffects(layerEffects, Layer.ColorChangingEffects_5);
|
||||
for (ContinuousEffect effect: layer) {
|
||||
effect.apply(Layer.ColorChangingEffects_5, SubLayer.NA, layeredEffects.getAbility(effect.getId()), game);
|
||||
HashSet<Ability> abilities = layeredEffects.getAbility(effect.getId());
|
||||
for (Ability ability : abilities) {
|
||||
effect.apply(Layer.ColorChangingEffects_5, SubLayer.NA, ability, game);
|
||||
}
|
||||
}
|
||||
layer = filterLayeredEffects(layerEffects, Layer.AbilityAddingRemovingEffects_6);
|
||||
for (ContinuousEffect effect: layer) {
|
||||
if (layerEffects.contains(effect)) {
|
||||
effect.apply(Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, layeredEffects.getAbility(effect.getId()), game);
|
||||
HashSet<Ability> abilities = layeredEffects.getAbility(effect.getId());
|
||||
for (Ability ability : abilities) {
|
||||
effect.apply(Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, ability, game);
|
||||
}
|
||||
}
|
||||
layerEffects = getLayeredEffects(game);
|
||||
}
|
||||
layer = filterLayeredEffects(layerEffects, Layer.PTChangingEffects_7);
|
||||
for (ContinuousEffect effect: layer) {
|
||||
effect.apply(Layer.PTChangingEffects_7, SubLayer.SetPT_7b, layeredEffects.getAbility(effect.getId()), game);
|
||||
HashSet<Ability> abilities = layeredEffects.getAbility(effect.getId());
|
||||
for (Ability ability : abilities) {
|
||||
effect.apply(Layer.PTChangingEffects_7, SubLayer.SetPT_7b, ability, game);
|
||||
}
|
||||
}
|
||||
for (ContinuousEffect effect: layer) {
|
||||
effect.apply(Layer.PTChangingEffects_7, SubLayer.ModifyPT_7c, layeredEffects.getAbility(effect.getId()), game);
|
||||
HashSet<Ability> abilities = layeredEffects.getAbility(effect.getId());
|
||||
for (Ability ability : abilities) {
|
||||
effect.apply(Layer.PTChangingEffects_7, SubLayer.ModifyPT_7c, ability, game);
|
||||
}
|
||||
}
|
||||
applyCounters.apply(Layer.PTChangingEffects_7, SubLayer.Counters_7d, null, game);
|
||||
for (ContinuousEffect effect: layer) {
|
||||
effect.apply(Layer.PTChangingEffects_7, SubLayer.SwitchPT_e, layeredEffects.getAbility(effect.getId()), game);
|
||||
HashSet<Ability> abilities = layeredEffects.getAbility(effect.getId());
|
||||
for (Ability ability : abilities) {
|
||||
effect.apply(Layer.PTChangingEffects_7, SubLayer.SwitchPT_e, ability, game);
|
||||
}
|
||||
}
|
||||
layer = filterLayeredEffects(layerEffects, Layer.PlayerEffects);
|
||||
for (ContinuousEffect effect: layer) {
|
||||
effect.apply(Layer.PlayerEffects, SubLayer.NA, layeredEffects.getAbility(effect.getId()), game);
|
||||
HashSet<Ability> abilities = layeredEffects.getAbility(effect.getId());
|
||||
for (Ability ability : abilities) {
|
||||
effect.apply(Layer.PlayerEffects, SubLayer.NA, ability, game);
|
||||
}
|
||||
}
|
||||
layer = filterLayeredEffects(layerEffects, Layer.RulesEffects);
|
||||
for (ContinuousEffect effect: layer) {
|
||||
effect.apply(Layer.RulesEffects, SubLayer.NA, layeredEffects.getAbility(effect.getId()), game);
|
||||
HashSet<Ability> abilities = layeredEffects.getAbility(effect.getId());
|
||||
for (Ability ability : abilities) {
|
||||
effect.apply(Layer.RulesEffects, SubLayer.NA, ability, game);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addEffect(ContinuousEffect effect, UUID sourceId, Ability source) {
|
||||
addEffect(effect, source);
|
||||
sources.put(effect, sourceId);
|
||||
sources.put(effect.getId(), sourceId);
|
||||
}
|
||||
|
||||
public void addEffect(ContinuousEffect effect, Ability source) {
|
||||
|
|
@ -493,9 +615,11 @@ public class ContinuousEffects implements Serializable {
|
|||
|
||||
private void setControllerForEffect(ContinuousEffectsList<?> effects, UUID cardId, UUID controllerId) {
|
||||
for (Effect effect : effects) {
|
||||
Ability ability = effects.getAbility(effect.getId());
|
||||
if (ability.getSourceId().equals(cardId)) {
|
||||
ability.setControllerId(controllerId);
|
||||
HashSet<Ability> abilities = effects.getAbility(effect.getId());
|
||||
for (Ability ability : abilities) {
|
||||
if (ability.getSourceId().equals(cardId)) {
|
||||
ability.setControllerId(controllerId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -507,19 +631,6 @@ public class ContinuousEffects implements Serializable {
|
|||
sources.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all granted effects
|
||||
*/
|
||||
public void removeGainedEffects() {
|
||||
for (Map.Entry<Effect, UUID> source : sources.entrySet()) {
|
||||
for (ContinuousEffectsList effectsList : allEffectsLists) {
|
||||
Ability ability = effectsList.getAbility(source.getKey().getId());
|
||||
if (ability != null && !ability.getSourceId().equals(source.getValue())) {
|
||||
effectsList.removeEffect((ContinuousEffect) source.getKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes effects granted by sourceId
|
||||
|
|
@ -528,30 +639,40 @@ public class ContinuousEffects implements Serializable {
|
|||
*/
|
||||
public List<Effect> removeGainedEffectsForSource(UUID sourceId) {
|
||||
List<Effect> effects = new ArrayList<Effect>();
|
||||
for (Map.Entry<Effect, UUID> source : sources.entrySet()) {
|
||||
Set<UUID> effectsToRemove = new HashSet<UUID>();
|
||||
for (Map.Entry<UUID, UUID> source : sources.entrySet()) {
|
||||
if (sourceId.equals(source.getValue())) {
|
||||
for (ContinuousEffectsList effectsList : allEffectsLists) {
|
||||
Ability ability = effectsList.getAbility(source.getKey().getId());
|
||||
if (ability != null && !ability.getSourceId().equals(source.getValue())) {
|
||||
effectsList.removeEffect((ContinuousEffect) source.getKey());
|
||||
effects.add(source.getKey());
|
||||
Iterator it = effectsList.iterator();
|
||||
while (it.hasNext()) {
|
||||
ContinuousEffect effect = (ContinuousEffect) it.next();
|
||||
if (source.getKey().equals(effect.getId())) {
|
||||
effectsToRemove.add(effect.getId());
|
||||
effectsList.removeEffectAbilityMap(effect.getId());
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (UUID effectId: effectsToRemove) {
|
||||
sources.remove(effectId);
|
||||
}
|
||||
return effects;
|
||||
}
|
||||
|
||||
public List<String> getReplacementEffectsTexts(List<ReplacementEffect> rEffects, Game game) {
|
||||
public List<String> getReplacementEffectsTexts(HashMap<ReplacementEffect, HashSet<Ability>> rEffects, Game game) {
|
||||
List<String> texts = new ArrayList<String>();
|
||||
for (ReplacementEffect effect: rEffects) {
|
||||
Ability ability = replacementEffects.getAbility(effect.getId());
|
||||
MageObject object = game.getObject(ability.getSourceId());
|
||||
if (object != null) {
|
||||
texts.add(ability.getRule(object.getName()));
|
||||
} else {
|
||||
texts.add(effect.getText(null));
|
||||
for (Map.Entry entry : rEffects.entrySet()) {
|
||||
for (Ability ability :(HashSet<Ability>) entry.getValue()) {
|
||||
MageObject object = game.getObject(ability.getSourceId());
|
||||
if (object != null) {
|
||||
texts.add(ability.getRule(object.getName()));
|
||||
} else {
|
||||
texts.add(((ReplacementEffect)entry.getKey()).getText(null));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return texts;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,9 @@ import mage.abilities.Ability;
|
|||
import mage.game.Game;
|
||||
|
||||
import java.util.*;
|
||||
import static mage.Constants.Duration.Custom;
|
||||
import static mage.Constants.Duration.OneUse;
|
||||
import static mage.Constants.Duration.WhileOnBattlefield;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -39,7 +42,8 @@ import java.util.*;
|
|||
*/
|
||||
public class ContinuousEffectsList<T extends ContinuousEffect> extends ArrayList<T> {
|
||||
|
||||
private final Map<UUID, Ability> abilityMap = new HashMap<UUID, Ability>();
|
||||
// the effectAbilityMap holds for each effect all abilities that are connected (used) with this effect
|
||||
private final Map<UUID, HashSet<Ability>> effectAbilityMap = new HashMap<UUID, HashSet<Ability>>();
|
||||
|
||||
public ContinuousEffectsList() { }
|
||||
|
||||
|
|
@ -48,8 +52,12 @@ public class ContinuousEffectsList<T extends ContinuousEffect> extends ArrayList
|
|||
for (ContinuousEffect cost: effects) {
|
||||
this.add((T)cost.copy());
|
||||
}
|
||||
for (Map.Entry<UUID, Ability> entry: effects.abilityMap.entrySet()) {
|
||||
abilityMap.put(entry.getKey(), entry.getValue().copy());
|
||||
for (Map.Entry<UUID, HashSet<Ability>> entry: effects.effectAbilityMap.entrySet()) {
|
||||
HashSet<Ability> newSet = new HashSet<Ability>();
|
||||
for (Ability ability :(HashSet<Ability>)entry.getValue()) {
|
||||
newSet.add(ability.copy());
|
||||
}
|
||||
effectAbilityMap.put(entry.getKey(), newSet);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -62,7 +70,7 @@ public class ContinuousEffectsList<T extends ContinuousEffect> extends ArrayList
|
|||
T entry = i.next();
|
||||
if (entry.getDuration() == Constants.Duration.EndOfTurn) {
|
||||
i.remove();
|
||||
abilityMap.remove(entry.getId());
|
||||
effectAbilityMap.remove(entry.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -72,58 +80,100 @@ public class ContinuousEffectsList<T extends ContinuousEffect> extends ArrayList
|
|||
T entry = i.next();
|
||||
if (isInactive(entry, game)) {
|
||||
i.remove();
|
||||
abilityMap.remove(entry.getId());
|
||||
effectAbilityMap.remove(entry.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isInactive(T effect, Game game) {
|
||||
Ability ability = abilityMap.get(effect.getId());
|
||||
if (ability == null)
|
||||
return true;
|
||||
|
||||
if (effect.isDiscarded())
|
||||
return true;
|
||||
|
||||
switch(effect.getDuration()) {
|
||||
case WhileOnBattlefield:
|
||||
if (game.getObject(ability.getSourceId()) == null) {//TODO: does this really works?? object is returned across the game
|
||||
return (true); // LevelX2: I guess it's not used, because effects stay the whole game
|
||||
HashSet<Ability> set = effectAbilityMap.get(effect.getId());
|
||||
Iterator it = set.iterator();
|
||||
while (it.hasNext()) {
|
||||
Ability ability = (Ability)it.next();
|
||||
if (ability == null) {
|
||||
it.remove();
|
||||
} else if (effect.isDiscarded()) {
|
||||
it.remove();
|
||||
} else {
|
||||
switch(effect.getDuration()) {
|
||||
case WhileOnBattlefield:
|
||||
if (game.getObject(ability.getSourceId()) == null) {//TODO: does this really works?? object is returned across the game
|
||||
it.remove();
|
||||
}
|
||||
case OneUse:
|
||||
if (effect.isUsed()) {
|
||||
it.remove();
|
||||
}
|
||||
case Custom:
|
||||
if (effect.isInactive(ability , game)) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
case OneUse:
|
||||
return effect.isUsed();
|
||||
case Custom:
|
||||
return effect.isInactive(abilityMap.get(effect.getId()), game);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return set.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an effect and its connected ability to the list.
|
||||
* For each effect will be stored, which abilities are connected to the effect.
|
||||
* So an effect can be connected to multiple abilities.
|
||||
*
|
||||
* @param effect - effect to add
|
||||
* @param source - connected ability
|
||||
*/
|
||||
public void addEffect(T effect, Ability source) {
|
||||
if (abilityMap.containsKey(effect.getId()))
|
||||
if (effectAbilityMap.containsKey(effect.getId())) {
|
||||
HashSet<Ability> set = effectAbilityMap.get(effect.getId());
|
||||
for (Ability ability: set) {
|
||||
if (ability.getId().equals(source.getId()) && ability.getSourceId().equals(source.getSourceId()) ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
set.add(source);
|
||||
return;
|
||||
}
|
||||
HashSet<Ability> set = new HashSet<Ability>();
|
||||
set.add(source);
|
||||
this.effectAbilityMap.put(effect.getId(), set);
|
||||
this.add(effect);
|
||||
this.abilityMap.put(effect.getId(), source);
|
||||
}
|
||||
|
||||
public Ability getAbility(UUID effectId) {
|
||||
return abilityMap.get(effectId);
|
||||
public HashSet<Ability> getAbility(UUID effectId) {
|
||||
return effectAbilityMap.get(effectId);
|
||||
}
|
||||
|
||||
public void removeEffect(T effect) {
|
||||
/**
|
||||
* Removes an effect and / or a connected ability.
|
||||
* If no ability for this effect is left in the effectAbilityMap, the effect will be removed.
|
||||
* Otherwise the effect won't be removed.
|
||||
*
|
||||
* @param effect - effect to remove if all abilities are removed
|
||||
* @param ability - ability to remove
|
||||
*/
|
||||
|
||||
public void removeEffect(T effect, Ability ability) {
|
||||
for (Iterator<T> i = this.iterator(); i.hasNext();) {
|
||||
T entry = i.next();
|
||||
if (entry.equals(effect)) {
|
||||
i.remove();
|
||||
if (abilityMap.containsKey(effect.getId())) {
|
||||
abilityMap.remove(effect.getId());
|
||||
HashSet<Ability> abilities = effectAbilityMap.get(effect.getId());
|
||||
if (!abilities.isEmpty()) {
|
||||
abilities.remove(ability);
|
||||
}
|
||||
if (abilities.isEmpty()) {
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeEffectAbilityMap(UUID effectId) {
|
||||
effectAbilityMap.remove(effectId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
super.clear();
|
||||
abilityMap.clear();
|
||||
effectAbilityMap.clear();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1642,7 +1642,7 @@ public abstract class GameImpl<T extends GameImpl<T>> implements Game, Serializa
|
|||
}
|
||||
getContinuousEffects().removeGainedEffectsForSource(sourceId);
|
||||
// remove gained triggered abilities
|
||||
getState().resetForSourceId(sourceId);
|
||||
getState().resetTriggersForSourceId(sourceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -567,7 +567,7 @@ public class GameState implements Serializable, Copyable<GameState> {
|
|||
*
|
||||
* @param sourceId
|
||||
*/
|
||||
public void resetForSourceId(UUID sourceId) {
|
||||
public void resetTriggersForSourceId(UUID sourceId) {
|
||||
List<String> keysToRemove = triggers.removeGainedAbilitiesForSource(sourceId);
|
||||
for (String key : keysToRemove) {
|
||||
triggers.remove(key);
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ package mage.game.combat;
|
|||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
import mage.Constants.Outcome;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.RequirementEffect;
|
||||
import mage.abilities.keyword.CantAttackAloneAbility;
|
||||
import mage.abilities.keyword.VigilanceAbility;
|
||||
|
|
@ -176,21 +177,24 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
protected void checkAttackRequirements(Player player, Game game) {
|
||||
//20101001 - 508.1d
|
||||
for (Permanent creature : player.getAvailableAttackers(game)) {
|
||||
for (RequirementEffect effect : game.getContinuousEffects().getApplicableRequirementEffects(creature, game)) {
|
||||
for (Map.Entry entry : game.getContinuousEffects().getApplicableRequirementEffects(creature, game).entrySet()) {
|
||||
RequirementEffect effect = (RequirementEffect)entry.getKey();
|
||||
if (effect.mustAttack(game)) {
|
||||
UUID defenderId = effect.mustAttackDefender(game.getContinuousEffects().getAbility(effect.getId()), game);
|
||||
if (defenderId == null) {
|
||||
if (defenders.size() == 1) {
|
||||
player.declareAttacker(creature.getId(), defenders.iterator().next(), game);
|
||||
} else {
|
||||
TargetDefender target = new TargetDefender(defenders, creature.getId());
|
||||
target.setRequired(true);
|
||||
if (player.chooseTarget(Outcome.Damage, target, null, game)) {
|
||||
player.declareAttacker(creature.getId(), target.getFirstTarget(), game);
|
||||
for (Ability ability: (HashSet<Ability>)entry.getValue()) {
|
||||
UUID defenderId = effect.mustAttackDefender(ability, game);
|
||||
if (defenderId == null) {
|
||||
if (defenders.size() == 1) {
|
||||
player.declareAttacker(creature.getId(), defenders.iterator().next(), game);
|
||||
} else {
|
||||
TargetDefender target = new TargetDefender(defenders, creature.getId());
|
||||
target.setRequired(true);
|
||||
if (player.chooseTarget(Outcome.Damage, target, null, game)) {
|
||||
player.declareAttacker(creature.getId(), target.getFirstTarget(), game);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
player.declareAttacker(creature.getId(), defenderId, game);
|
||||
}
|
||||
} else {
|
||||
player.declareAttacker(creature.getId(), defenderId, game);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -269,12 +273,15 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
//20101001 - 509.1c
|
||||
for (Permanent creature : game.getBattlefield().getActivePermanents(filterBlockers, player.getId(), game)) {
|
||||
if (game.getOpponents(attackerId).contains(creature.getControllerId())) {
|
||||
for (RequirementEffect effect : game.getContinuousEffects().getApplicableRequirementEffects(creature, game)) {
|
||||
for (Map.Entry entry : game.getContinuousEffects().getApplicableRequirementEffects(creature, game).entrySet()) {
|
||||
RequirementEffect effect = (RequirementEffect)entry.getKey();
|
||||
if (effect.mustBlock(game)) {
|
||||
UUID attackId = effect.mustBlockAttacker(game.getContinuousEffects().getAbility(effect.getId()), game);
|
||||
Player defender = game.getPlayer(creature.getControllerId());
|
||||
if (attackId != null && defender != null) {
|
||||
defender.declareBlocker(creature.getId(), attackId, game);
|
||||
for (Ability ability: (HashSet<Ability>)entry.getValue()) {
|
||||
UUID attackId = effect.mustBlockAttacker(ability, game);
|
||||
Player defender = game.getPlayer(creature.getControllerId());
|
||||
if (attackId != null && defender != null) {
|
||||
defender.declareBlocker(creature.getId(), attackId, game);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -286,7 +293,7 @@ public class Combat implements Serializable, Copyable<Combat> {
|
|||
//20101001 - 509.1c
|
||||
for (Permanent creature : game.getBattlefield().getActivePermanents(new FilterControlledCreaturePermanent(), player.getId(), game)) {
|
||||
if (creature.getBlocking() == 0 && game.getOpponents(attackerId).contains(creature.getControllerId())) {
|
||||
for (RequirementEffect effect : game.getContinuousEffects().getApplicableRequirementEffects(creature, game)) {
|
||||
for (RequirementEffect effect : game.getContinuousEffects().getApplicableRequirementEffects(creature, game).keySet()) {
|
||||
if (effect.mustBlockAny(game)) {
|
||||
// check that it can block an attacker
|
||||
boolean mayBlock = false;
|
||||
|
|
|
|||
|
|
@ -79,6 +79,8 @@ public class PermanentCard extends PermanentImpl<PermanentCard> {
|
|||
public void reset(Game game) {
|
||||
// when the permanent is reset copy all original values from the card
|
||||
// must copy card each reset so that the original values don't get modified
|
||||
// game.getState().getContinuousEffects().removeGainedEffectsForSource(objectId);
|
||||
// game.getState().resetTriggersForSourceId(this.getId());
|
||||
copyFromCard(card, game);
|
||||
super.reset(game);
|
||||
}
|
||||
|
|
@ -126,6 +128,7 @@ public class PermanentCard extends PermanentImpl<PermanentCard> {
|
|||
|
||||
protected void copyFromCard(Card card, Game game) {
|
||||
this.name = card.getName();
|
||||
// this.removeAllAbilities(objectId, game);
|
||||
this.abilities.clear();
|
||||
this.abilities.addAll(card.getAbilities());
|
||||
this.abilities.setControllerId(this.controllerId);
|
||||
|
|
|
|||
|
|
@ -187,7 +187,6 @@ public abstract class PermanentImpl<T extends PermanentImpl<T>> extends CardImpl
|
|||
public void addAbility(Ability ability, UUID sourceId, Game game) {
|
||||
if (!abilities.containsKey(ability.getId())) {
|
||||
Ability copyAbility = ability.copy();
|
||||
copyAbility.newId(); // needed e.g. if a gainAll ability gives Forestwalk to multiple creatures
|
||||
copyAbility.setControllerId(controllerId);
|
||||
copyAbility.setSourceId(objectId);
|
||||
game.getState().addAbility(copyAbility, sourceId, this);
|
||||
|
|
@ -201,7 +200,7 @@ public abstract class PermanentImpl<T extends PermanentImpl<T>> extends CardImpl
|
|||
// removes abilities that were gained from abilities of this permanent
|
||||
game.getContinuousEffects().removeGainedEffectsForSource(this.getId());
|
||||
// remove gained triggered abilities
|
||||
game.getState().resetForSourceId(this.getId());
|
||||
game.getState().resetTriggersForSourceId(this.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -836,7 +835,7 @@ public abstract class PermanentImpl<T extends PermanentImpl<T>> extends CardImpl
|
|||
return false;
|
||||
}
|
||||
//20101001 - 508.1c
|
||||
for (RestrictionEffect effect : game.getContinuousEffects().getApplicableRestrictionEffects(this, game)) {
|
||||
for (RestrictionEffect effect: game.getContinuousEffects().getApplicableRestrictionEffects(this, game).keySet()) {
|
||||
if (!effect.canAttack(game)) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -854,19 +853,24 @@ public abstract class PermanentImpl<T extends PermanentImpl<T>> extends CardImpl
|
|||
}
|
||||
Permanent attacker = game.getPermanent(attackerId);
|
||||
//20101001 - 509.1b
|
||||
for (RestrictionEffect effect : game.getContinuousEffects().getApplicableRestrictionEffects(this, game)) {
|
||||
if (!effect.canBlock(attacker, this, game.getContinuousEffects().getAbility(effect.getId()), game)) {
|
||||
return false;
|
||||
for (Map.Entry entry: game.getContinuousEffects().getApplicableRestrictionEffects(this, game).entrySet()) {
|
||||
RestrictionEffect effect = (RestrictionEffect)entry.getKey();
|
||||
for (Ability ability : (HashSet<Ability>) entry.getValue()) {
|
||||
if (!effect.canBlock(attacker, this, ability, game)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// check also attacker's restriction effects
|
||||
for (RestrictionEffect effect : game.getContinuousEffects().getApplicableRestrictionEffects(attacker, game)) {
|
||||
/*if (!effect.canBlock(attacker, this, game))
|
||||
return false;*/
|
||||
if (!effect.canBeBlocked(attacker, this, game.getContinuousEffects().getAbility(effect.getId()), game)) {
|
||||
return false;
|
||||
for (Map.Entry entry: game.getContinuousEffects().getApplicableRestrictionEffects(attacker, game).entrySet()) {
|
||||
RestrictionEffect effect = (RestrictionEffect)entry.getKey();
|
||||
for (Ability ability : (HashSet<Ability>) entry.getValue()) {
|
||||
if (!effect.canBeBlocked(attacker, this, ability, game)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (attacker != null && attacker.hasProtectionFrom(this, game)) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -880,9 +884,12 @@ public abstract class PermanentImpl<T extends PermanentImpl<T>> extends CardImpl
|
|||
}
|
||||
|
||||
//20101001 - 509.1b
|
||||
for (RestrictionEffect effect : game.getContinuousEffects().getApplicableRestrictionEffects(this, game)) {
|
||||
if (!effect.canBlock(null, this, game.getContinuousEffects().getAbility(effect.getId()), game)) {
|
||||
return false;
|
||||
for (Map.Entry entry: game.getContinuousEffects().getApplicableRestrictionEffects(this, game).entrySet()) {
|
||||
RestrictionEffect effect = (RestrictionEffect)entry.getKey();
|
||||
for (Ability ability : (HashSet<Ability>) entry.getValue()) {
|
||||
if (!effect.canBlock(null, this, ability, game)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -801,7 +801,7 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
|
|||
//20091005 - 502.2
|
||||
for (Permanent permanent: game.getBattlefield().getAllActivePermanents(playerId)) {
|
||||
boolean untap = true;
|
||||
for (RestrictionEffect effect : game.getContinuousEffects().getApplicableRestrictionEffects(permanent, game)) {
|
||||
for (RestrictionEffect effect: game.getContinuousEffects().getApplicableRestrictionEffects(permanent, game).keySet()) {
|
||||
untap &= effect.canBeUntapped(permanent, game);
|
||||
}
|
||||
if (untap) {
|
||||
|
|
@ -944,7 +944,7 @@ public abstract class PlayerImpl<T extends PlayerImpl<T>> implements Player, Ser
|
|||
Permanent source = game.getPermanent(sourceId);
|
||||
if(source == null){
|
||||
MageObject lastKnownInformation = game.getLastKnownInformation(sourceId, Zone.BATTLEFIELD);
|
||||
if(lastKnownInformation instanceof Permanent){
|
||||
if(lastKnownInformation != null && lastKnownInformation instanceof Permanent){
|
||||
source = (Permanent) lastKnownInformation;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -130,25 +130,25 @@ public class TraceUtil {
|
|||
}
|
||||
|
||||
private static void traceForPermanent(Game game, Permanent permanent, String uuid, ContinuousEffectsList<RestrictionEffect> restrictionEffects) {
|
||||
Ability ability;
|
||||
for (RestrictionEffect effect: restrictionEffects) {
|
||||
ability = restrictionEffects.getAbility(effect.getId());
|
||||
if (!(ability instanceof StaticAbility) || ability.isInUseableZone(game, permanent, false)) {
|
||||
log.error(uuid+" ability=" + ability + ", applies_to_attacker=" + effect.applies(permanent, ability, game));
|
||||
} else {
|
||||
boolean usable = ability.isInUseableZone(game, permanent, false);
|
||||
log.error(uuid+" instanceof: " + (ability instanceof StaticAbility) + ", ability=" + ability);
|
||||
log.error(uuid+" usable: " + usable + ", ability=" + ability);
|
||||
if (!usable) {
|
||||
Constants.Zone zone = ability.getZone();
|
||||
log.error(uuid+" zone: " + zone);
|
||||
MageObject object = game.getObject(ability.getSourceId());
|
||||
log.error(uuid+" object: " + object);
|
||||
if (object != null) {
|
||||
log.error(uuid + " contains:" + object.getAbilities().contains(ability));
|
||||
for (Ability ability : restrictionEffects.getAbility(effect.getId())) {
|
||||
if (!(ability instanceof StaticAbility) || ability.isInUseableZone(game, permanent, false)) {
|
||||
log.error(uuid+" ability=" + ability + ", applies_to_attacker=" + effect.applies(permanent, ability, game));
|
||||
} else {
|
||||
boolean usable = ability.isInUseableZone(game, permanent, false);
|
||||
log.error(uuid+" instanceof: " + (ability instanceof StaticAbility) + ", ability=" + ability);
|
||||
log.error(uuid+" usable: " + usable + ", ability=" + ability);
|
||||
if (!usable) {
|
||||
Constants.Zone zone = ability.getZone();
|
||||
log.error(uuid+" zone: " + zone);
|
||||
MageObject object = game.getObject(ability.getSourceId());
|
||||
log.error(uuid+" object: " + object);
|
||||
if (object != null) {
|
||||
log.error(uuid + " contains:" + object.getAbilities().contains(ability));
|
||||
}
|
||||
Constants.Zone test = game.getState().getZone(ability.getSourceId());
|
||||
log.error(uuid+" test_zone: " + test);
|
||||
}
|
||||
Constants.Zone test = game.getState().getZone(ability.getSourceId());
|
||||
log.error(uuid+" test_zone: " + test);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue