public List<ContinuousEffect> getLayeredEffects(Game game) { List<ContinuousEffect> layerEffects = new ArrayList<>(); for (ContinuousEffect effect : layeredEffects) { switch (effect.getDuration()) { case WhileOnBattlefield: case WhileOnStack: case WhileInGraveyard: HashSet<Ability> abilities = layeredEffects.getAbility(effect.getId()); for (Ability ability : abilities) { // If e.g. triggerd abilities (non static) created the effect, the ability must not be // in usable zone (e.g. Unearth giving Haste effect) if (!(ability instanceof StaticAbility) || ability.isInUseableZone(game, null, null)) { layerEffects.add(effect); break; } } break; default: layerEffects.add(effect); } } updateTimestamps(layerEffects); Collections.sort(layerEffects, sorter); return layerEffects; }
public void addEffect(ContinuousEffect effect, Ability source) { if (effect == null) { logger.error("Effect is null: " + source.toString()); return; } else if (source == null) { logger.warn("Adding effect without ability : " + effect.toString()); } switch (effect.getEffectType()) { case REPLACEMENT: case REDIRECTION: ReplacementEffect newReplacementEffect = (ReplacementEffect) effect; replacementEffects.addEffect(newReplacementEffect, source); break; case PREVENTION: PreventionEffect newPreventionEffect = (PreventionEffect) effect; preventionEffects.addEffect(newPreventionEffect, source); break; case RESTRICTION: RestrictionEffect newRestrictionEffect = (RestrictionEffect) effect; restrictionEffects.addEffect(newRestrictionEffect, source); break; case RESTRICTION_UNTAP_NOT_MORE_THAN: RestrictionUntapNotMoreThanEffect newRestrictionUntapNotMoreThanEffect = (RestrictionUntapNotMoreThanEffect) effect; restrictionUntapNotMoreThanEffects.addEffect(newRestrictionUntapNotMoreThanEffect, source); break; case REQUIREMENT: RequirementEffect newRequirementEffect = (RequirementEffect) effect; requirementEffects.addEffect(newRequirementEffect, source); break; case ASTHOUGH: AsThoughEffect newAsThoughEffect = (AsThoughEffect) effect; if (!asThoughEffectsMap.containsKey(newAsThoughEffect.getAsThoughEffectType())) { ContinuousEffectsList<AsThoughEffect> list = new ContinuousEffectsList<>(); allEffectsLists.add(list); asThoughEffectsMap.put(newAsThoughEffect.getAsThoughEffectType(), list); } asThoughEffectsMap .get(newAsThoughEffect.getAsThoughEffectType()) .addEffect(newAsThoughEffect, source); break; case COSTMODIFICATION: CostModificationEffect newCostModificationEffect = (CostModificationEffect) effect; costModificationEffects.addEffect(newCostModificationEffect, source); break; case SPLICE: SpliceCardEffect newSpliceCardEffect = (SpliceCardEffect) effect; spliceCardEffects.addEffect(newSpliceCardEffect, source); break; case CONTINUOUS_RULE_MODIFICATION: ContinuousRuleModifyingEffect newContinuousRuleModifiyingEffect = (ContinuousRuleModifyingEffect) effect; continuousRuleModifyingEffects.addEffect(newContinuousRuleModifiyingEffect, source); break; default: layeredEffects.addEffect(effect, source); break; } }
private List<ContinuousEffect> filterLayeredEffects(List<ContinuousEffect> effects, Layer layer) { List<ContinuousEffect> layerEffects = new ArrayList<>(); for (ContinuousEffect effect : effects) { if (effect.hasLayer(layer)) { layerEffects.add(effect); } } return layerEffects; }
private boolean checkAbilityStillExists( Ability ability, ContinuousEffect effect, GameEvent event, Game game) { switch (effect .getDuration()) { // effects with fixed duration don't need an object with the source // ability (e.g. a silence cast with isochronic Scepter has no more a card // object case EndOfCombat: case EndOfGame: case EndOfStep: case EndOfTurn: case OneUse: case Custom: // custom duration means the effect ends itself if needed return true; } if (ability.getSourceId() == null) { // commander replacement effect return true; } MageObject object; if (event.getType().equals(EventType.ZONE_CHANGE) && ((ZoneChangeEvent) event).getFromZone().equals(Zone.BATTLEFIELD) && event.getTargetId().equals(ability.getSourceId())) { object = ((ZoneChangeEvent) event).getTarget(); } else { object = game.getObject(ability.getSourceId()); } if (object == null) { return false; } boolean exists = true; if (!object.getAbilities().contains(ability)) { exists = false; if (object instanceof PermanentCard) { PermanentCard permanent = (PermanentCard) object; if (permanent.canTransform() && event.getType() == GameEvent.EventType.TRANSFORMED) { exists = permanent.getCard().getAbilities().contains(ability); } } } else { if (object instanceof PermanentCard) { PermanentCard permanent = (PermanentCard) object; if (permanent.isFaceDown(game) && !ability.getWorksFaceDown()) { return false; } } else if (object instanceof Spell) { Spell spell = (Spell) object; if (spell.isFaceDown(game) && !ability.getWorksFaceDown()) { return false; } } } return exists; }
/** * Adds a continuous ability with a reference to a sourceId. It's used for effects that cease to * exist again So this effects were removed again before each applyEffecs * * @param effect * @param sourceId * @param source */ public void addEffect(ContinuousEffect effect, UUID sourceId, Ability source) { if (!(source instanceof MageSingleton)) { // because MageSingletons may never be removed by removing the temporary // effecs they are not added to the temporaryEffects to prevent this effect.setTemporary(true); Set abilities = temporaryEffects.get(effect); if (abilities == null) { abilities = new HashSet<>(); temporaryEffects.put(effect, abilities); } else { if (abilities.contains(source)) { // this ability (for the continuous effect) is already added return; } } abilities.add(source); // add the effect itself } addEffect(effect, source); }
// 20091005 - 613 public void apply(Game game) { removeInactiveEffects(game); List<ContinuousEffect> layerEffects = getLayeredEffects(game); List<ContinuousEffect> layer = filterLayeredEffects(layerEffects, Layer.CopyEffects_1); for (ContinuousEffect effect : layer) { 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) { layerEffects = getLayeredEffects(game); } layer = filterLayeredEffects(layerEffects, Layer.ControlChangingEffects_2); // apply control changing effects multiple times if it's needed // for cases when control over permanents with change control abilities is changed // e.g. Mind Control is controlled by Steal Enchantment while (true) { for (ContinuousEffect effect : layer) { HashSet<Ability> abilities = layeredEffects.getAbility(effect.getId()); for (Ability ability : abilities) { effect.apply(Layer.ControlChangingEffects_2, SubLayer.NA, ability, game); } } // if control over all permanent has not changed, we can no longer reapply control changing // effects if (!game.getBattlefield().fireControlChangeEvents(game)) { break; } // reset control before reapplying control changing effects game.getBattlefield().resetPermanentsControl(); } layer = filterLayeredEffects(layerEffects, Layer.TextChangingEffects_3); for (ContinuousEffect effect : layer) { 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) { 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) { HashSet<Ability> abilities = layeredEffects.getAbility(effect.getId()); for (Ability ability : abilities) { effect.apply(Layer.ColorChangingEffects_5, SubLayer.NA, ability, game); } } Map<ContinuousEffect, List<Ability>> appliedEffects = new HashMap<>(); boolean done = false; while (!done) { // loop needed if a added effect adds again an effect (e.g. Level 5- of Joraga // Treespeaker) done = true; layer = filterLayeredEffects(layerEffects, Layer.AbilityAddingRemovingEffects_6); for (ContinuousEffect effect : layer) { if (layerEffects.contains(effect)) { List<Ability> appliedAbilities = appliedEffects.get(effect); HashSet<Ability> abilities = layeredEffects.getAbility(effect.getId()); for (Ability ability : abilities) { if (appliedAbilities == null || !appliedAbilities.contains(ability)) { if (appliedAbilities == null) { appliedAbilities = new ArrayList<>(); appliedEffects.put(effect, appliedAbilities); } appliedAbilities.add(ability); effect.apply(Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, ability, game); done = false; // list must be updated after each applied effect (eg. if "Turn to Frog" removes // abilities) layerEffects = getLayeredEffects(game); } } } } } layer = filterLayeredEffects(layerEffects, Layer.PTChangingEffects_7); for (ContinuousEffect effect : layer) { 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) { 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) { 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) { 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) { HashSet<Ability> abilities = layeredEffects.getAbility(effect.getId()); for (Ability ability : abilities) { effect.apply(Layer.RulesEffects, SubLayer.NA, ability, game); } } }
public void setOrder(ContinuousEffect effect) { effect.setOrder(order++); }
@Override public int compare(ContinuousEffect one, ContinuousEffect two) { return Long.compare(one.getOrder(), two.getOrder()); }