public UUID getControllerOfSourceId(UUID sourceId) { UUID controllerFound = null; for (PreventionEffect effect : preventionEffects) { HashSet<Ability> abilities = preventionEffects.getAbility(effect.getId()); for (Ability ability : abilities) { if (ability.getSourceId().equals(sourceId)) { if (controllerFound == null || controllerFound == ability.getControllerId()) { controllerFound = ability.getControllerId(); } else { // not unique controller - No solution yet return null; } } } } for (ReplacementEffect effect : replacementEffects) { HashSet<Ability> abilities = replacementEffects.getAbility(effect.getId()); for (Ability ability : abilities) { if (ability.getSourceId().equals(sourceId)) { if (controllerFound == null || controllerFound == ability.getControllerId()) { controllerFound = ability.getControllerId(); } else { // not unique controller - No solution yet return null; } } } } return controllerFound; }
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; } }
public void removeEndOfTurnEffects() { layeredEffects.removeEndOfTurnEffects(); continuousRuleModifyingEffects.removeEndOfTurnEffects(); replacementEffects.removeEndOfTurnEffects(); preventionEffects.removeEndOfTurnEffects(); requirementEffects.removeEndOfTurnEffects(); restrictionEffects.removeEndOfTurnEffects(); for (ContinuousEffectsList asThoughtlist : asThoughEffectsMap.values()) { asThoughtlist.removeEndOfTurnEffects(); } costModificationEffects.removeEndOfTurnEffects(); spliceCardEffects.removeEndOfTurnEffects(); }
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; }
/** * Checks all available splice effects to be applied. * * @param abilityToModify * @param game */ public void applySpliceEffects(Ability abilityToModify, Game game) { if (((SpellAbility) abilityToModify).getSpellAbilityType().equals(SpellAbilityType.SPLICE)) { // on a spliced ability of a spell can't be spliced again return; } List<SpliceCardEffect> spliceEffects = getApplicableSpliceCardEffects(game, abilityToModify.getControllerId()); // get the applyable splice abilities List<SpliceOntoArcaneAbility> spliceAbilities = new ArrayList<>(); for (SpliceCardEffect effect : spliceEffects) { HashSet<Ability> abilities = spliceCardEffects.getAbility(effect.getId()); for (Ability ability : abilities) { if (effect.applies(abilityToModify, ability, game)) { spliceAbilities.add((SpliceOntoArcaneAbility) ability); } } } // check if player wants to use splice if (spliceAbilities.size() > 0) { Player controller = game.getPlayer(abilityToModify.getControllerId()); if (controller.chooseUse(Outcome.Benefit, "Splice a card?", game)) { Cards cardsToReveal = new CardsImpl(); do { FilterCard filter = new FilterCard("a card to splice"); ArrayList<Predicate<MageObject>> idPredicates = new ArrayList<>(); for (SpliceOntoArcaneAbility ability : spliceAbilities) { idPredicates.add(new CardIdPredicate((ability.getSourceId()))); } filter.add(Predicates.or(idPredicates)); TargetCardInHand target = new TargetCardInHand(filter); controller.chooseTarget(Outcome.Benefit, target, abilityToModify, game); UUID cardId = target.getFirstTarget(); if (cardId != null) { SpliceOntoArcaneAbility selectedAbility = null; for (SpliceOntoArcaneAbility ability : spliceAbilities) { if (ability.getSourceId().equals(cardId)) { selectedAbility = ability; break; } } if (selectedAbility != null) { SpliceCardEffect spliceEffect = (SpliceCardEffect) selectedAbility.getEffects().get(0); spliceEffect.apply(game, selectedAbility, abilityToModify); cardsToReveal.add(game.getCard(cardId)); spliceAbilities.remove(selectedAbility); } } } while (!spliceAbilities.isEmpty() && controller.chooseUse(Outcome.Benefit, "Splice another card?", game)); controller.revealCards("Spliced cards", cardsToReveal, game); } } }
public void removeAllTemporaryEffects() { for (Map.Entry<ContinuousEffect, Set<Ability>> entry : temporaryEffects.entrySet()) { switch (entry.getKey().getEffectType()) { case REPLACEMENT: case REDIRECTION: replacementEffects.removeEffects(entry.getKey().getId(), entry.getValue()); break; case PREVENTION: preventionEffects.removeEffects(entry.getKey().getId(), entry.getValue()); break; case RESTRICTION: restrictionEffects.removeEffects(entry.getKey().getId(), entry.getValue()); break; case RESTRICTION_UNTAP_NOT_MORE_THAN: restrictionUntapNotMoreThanEffects.removeEffects( entry.getKey().getId(), entry.getValue()); break; case REQUIREMENT: requirementEffects.removeEffects(entry.getKey().getId(), entry.getValue()); break; case ASTHOUGH: AsThoughEffect newAsThoughEffect = (AsThoughEffect) entry.getKey(); if (!asThoughEffectsMap.containsKey(newAsThoughEffect.getAsThoughEffectType())) { break; } asThoughEffectsMap .get(newAsThoughEffect.getAsThoughEffectType()) .removeEffects(entry.getKey().getId(), entry.getValue()); break; case COSTMODIFICATION: costModificationEffects.removeEffects(entry.getKey().getId(), entry.getValue()); break; case SPLICE: spliceCardEffects.removeEffects(entry.getKey().getId(), entry.getValue()); break; case CONTINUOUS_RULE_MODIFICATION: continuousRuleModifyingEffects.removeEffects(entry.getKey().getId(), entry.getValue()); break; default: layeredEffects.removeEffects(entry.getKey().getId(), entry.getValue()); break; } } temporaryEffects.clear(); }
/** * Inspects all {@link Permanent permanent's} {@link Ability abilities} on the battlefield for * {@link CostModificationEffect cost modification effects} and applies them if necessary. * * @param abilityToModify * @param game */ public void costModification(Ability abilityToModify, Game game) { List<CostModificationEffect> costEffects = getApplicableCostModificationEffects(game); for (CostModificationEffect effect : costEffects) { if (effect.getModificationType() == CostModificationType.INCREASE_COST) { HashSet<Ability> abilities = costModificationEffects.getAbility(effect.getId()); for (Ability ability : abilities) { if (effect.applies(abilityToModify, ability, game)) { effect.apply(game, ability, abilityToModify); } } } } for (CostModificationEffect effect : costEffects) { if (effect.getModificationType() == CostModificationType.REDUCE_COST) { HashSet<Ability> abilities = costModificationEffects.getAbility(effect.getId()); for (Ability ability : abilities) { if (effect.applies(abilityToModify, ability, game)) { effect.apply(game, ability, abilityToModify); } } } } for (CostModificationEffect effect : costEffects) { if (effect.getModificationType() == CostModificationType.SET_COST) { HashSet<Ability> abilities = costModificationEffects.getAbility(effect.getId()); for (Ability ability : abilities) { if (effect.applies(abilityToModify, ability, game)) { effect.apply(game, ability, abilityToModify); } } } } }
private void setControllerForEffect( ContinuousEffectsList<?> effects, UUID cardId, UUID controllerId) { for (Effect effect : effects) { HashSet<Ability> abilities = effects.getAbility(effect.getId()); for (Ability ability : abilities) { if (ability.getSourceId() != null) { if (ability.getSourceId().equals(cardId)) { ability.setControllerId(controllerId); } } else { if (!ability.getZone().equals(Zone.COMMAND)) { logger.fatal(new StringBuilder("No sourceId Ability: ").append(ability)); } } } } }
/** * Filters out cost modification effects that are not active. * * @param game * @return */ private List<CostModificationEffect> getApplicableCostModificationEffects(Game game) { List<CostModificationEffect> costEffects = new ArrayList<>(); for (CostModificationEffect effect : costModificationEffects) { HashSet<Ability> abilities = costModificationEffects.getAbility(effect.getId()); for (Ability ability : abilities) { if (!(ability instanceof StaticAbility) || ability.isInUseableZone(game, null, null)) { if (effect.getDuration() != Duration.OneUse || !effect.isUsed()) { costEffects.add(effect); break; } } } } return costEffects; }
/** * Filters out splice effects that are not active. * * @param game * @return */ private List<SpliceCardEffect> getApplicableSpliceCardEffects(Game game, UUID playerId) { List<SpliceCardEffect> spliceEffects = new ArrayList<>(); for (SpliceCardEffect effect : spliceCardEffects) { HashSet<Ability> abilities = spliceCardEffects.getAbility(effect.getId()); for (Ability ability : abilities) { if (ability.getControllerId().equals(playerId) && (!(ability instanceof StaticAbility) || ability.isInUseableZone(game, null, null))) { if (effect.getDuration() != Duration.OneUse || !effect.isUsed()) { spliceEffects.add(effect); break; } } } } return spliceEffects; }
public HashMap<RestrictionUntapNotMoreThanEffect, HashSet<Ability>> getApplicableRestrictionUntapNotMoreThanEffects(Player player, Game game) { HashMap<RestrictionUntapNotMoreThanEffect, HashSet<Ability>> effects = new HashMap<>(); for (RestrictionUntapNotMoreThanEffect effect : restrictionUntapNotMoreThanEffects) { HashSet<Ability> abilities = restrictionUntapNotMoreThanEffects.getAbility(effect.getId()); HashSet<Ability> applicableAbilities = new HashSet<>(); for (Ability ability : abilities) { if (!(ability instanceof StaticAbility) || ability.isInUseableZone(game, null, null)) { if (effect.applies(player, ability, game)) { applicableAbilities.add(ability); } } } if (!applicableAbilities.isEmpty()) { effects.put(effect, abilities); } } return effects; }
public HashMap<RestrictionEffect, HashSet<Ability>> getApplicableRestrictionEffects( Permanent permanent, Game game) { HashMap<RestrictionEffect, HashSet<Ability>> effects = new HashMap<>(); for (RestrictionEffect effect : restrictionEffects) { HashSet<Ability> abilities = restrictionEffects.getAbility(effect.getId()); HashSet<Ability> applicableAbilities = new HashSet<>(); for (Ability ability : abilities) { if (!(ability instanceof StaticAbility) || ability.isInUseableZone( game, ability instanceof MageSingleton ? permanent : null, null)) { if (effect.applies(permanent, ability, game)) { applicableAbilities.add(ability); } } } if (!applicableAbilities.isEmpty()) { effects.put(effect, abilities); } } return effects; }
/** * 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 game * @param checkPlayableMode true if the event does not really happen but it's checked if the event * would be replaced * @return */ public boolean preventedByRuleModification( GameEvent event, Ability targetAbility, Game game, boolean checkPlayableMode) { for (ContinuousRuleModifyingEffect effect : continuousRuleModifyingEffects) { if (!effect.checksEventType(event, game)) { continue; } for (Ability sourceAbility : continuousRuleModifyingEffects.getAbility(effect.getId())) { if (!(sourceAbility instanceof StaticAbility) || sourceAbility.isInUseableZone(game, null, event)) { if (checkAbilityStillExists(sourceAbility, effect, event, game)) { if (effect.getDuration() != Duration.OneUse || !effect.isUsed()) { effect.setValue("targetAbility", targetAbility); if (effect.applies(event, sourceAbility, game)) { if (!checkPlayableMode) { String message = effect.getInfoMessage(sourceAbility, event, game); if (message != null && !message.isEmpty()) { if (effect.sendMessageToUser()) { Player player = game.getPlayer(event.getPlayerId()); if (player != null && !game.isSimulation()) { game.informPlayer(player, message); } } if (effect.sendMessageToGameLog() && !game.isSimulation()) { game.informPlayers(message); } } } return true; } } } } } } return false; }
// 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 boolean replaceEvent(GameEvent event, Game game) { boolean caught = false; HashMap<UUID, HashSet<UUID>> consumed = new HashMap<>(); do { 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 (rEffects.get(entry) == null || consumedAbilitiesIds.size() == rEffects.get(entry).size()) { it1.remove(); } else { Iterator it = 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) { ReplacementEffect effect = rEffects.keySet().iterator().next(); HashSet<Ability> abilities; if (effect.getEffectType().equals(EffectType.REPLACEMENT)) { abilities = replacementEffects.getAbility(effect.getId()); } else { abilities = preventionEffects.getAbility(effect.getId()); } if (abilities == null || abilities.size() == 1) { onlyOne = true; } } if (onlyOne) { index = 0; } else { // 20100716 - 616.1c Player player = game.getPlayer(event.getPlayerId()); index = player.chooseReplacementEffect(getReplacementEffectsTexts(rEffects, game), game); } // get the selected effect int checked = 0; ReplacementEffect rEffect = null; Ability rAbility = null; for (Map.Entry<ReplacementEffect, HashSet<Ability>> entry : rEffects.entrySet()) { if (entry.getValue() == null) { if (checked == index) { rEffect = entry.getKey(); break; } else { checked++; } } else { HashSet<Ability> abilities = entry.getValue(); int size = abilities.size(); if (index > (checked + size - 1)) { checked += size; } else { rEffect = entry.getKey(); Iterator it = abilities.iterator(); while (it.hasNext() && rAbility == null) { if (checked == index) { rAbility = (Ability) it.next(); } else { it.next(); checked++; } } break; } } } if (rEffect != null) { event.getAppliedEffects().add(rEffect.getId()); caught = rEffect.replaceEvent(event, rAbility, game); } if (caught) { // Event was completely replaced -> stop applying effects to it break; } // add the applied effect to the 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<>(); if (rAbility != null) { // in case of AuraReplacementEffect or PlaneswalkerReplacementEffect there // is no Ability set.add(rAbility.getId()); } consumed.put(rEffect.getId(), set); } } // Must be called here for some effects to be able to work correctly // TODO: add info which effects need that call game.applyEffects(); } while (true); return caught; }
public void clear() { for (ContinuousEffectsList effectsList : allEffectsLists) { effectsList.clear(); } temporaryEffects.clear(); }
public boolean existRequirementEffects() { return !requirementEffects.isEmpty(); }
public void removeInactiveEffects(Game game) { layeredEffects.removeInactiveEffects(game); continuousRuleModifyingEffects.removeInactiveEffects(game); replacementEffects.removeInactiveEffects(game); preventionEffects.removeInactiveEffects(game); requirementEffects.removeInactiveEffects(game); restrictionEffects.removeInactiveEffects(game); restrictionUntapNotMoreThanEffects.removeInactiveEffects(game); for (ContinuousEffectsList asThoughtlist : asThoughEffectsMap.values()) { asThoughtlist.removeInactiveEffects(game); } costModificationEffects.removeInactiveEffects(game); spliceCardEffects.removeInactiveEffects(game); }
/** * @param event * @param game * @return a list of all {@link ReplacementEffect} that apply to the current event */ private HashMap<ReplacementEffect, HashSet<Ability>> getApplicableReplacementEffects( GameEvent event, Game game) { HashMap<ReplacementEffect, HashSet<Ability>> replaceEffects = new HashMap<>(); if (planeswalkerRedirectionEffect.checksEventType(event, game) && planeswalkerRedirectionEffect.applies(event, null, game)) { replaceEffects.put(planeswalkerRedirectionEffect, null); } if (auraReplacementEffect.checksEventType(event, game) && auraReplacementEffect.applies(event, null, game)) { replaceEffects.put(auraReplacementEffect, null); } // boolean checkLKI = event.getType().equals(EventType.ZONE_CHANGE) || // event.getType().equals(EventType.DESTROYED_PERMANENT); // get all applicable transient Replacement effects for (ReplacementEffect effect : replacementEffects) { if (!effect.checksEventType(event, game)) { continue; } if (event.getAppliedEffects() != null && event.getAppliedEffects().contains(effect.getId())) { // Effect already applied to this event, ignore it // TODO: Handle also gained effect that are connected to different abilities. continue; } HashSet<Ability> abilities = replacementEffects.getAbility(effect.getId()); HashSet<Ability> applicableAbilities = new HashSet<>(); for (Ability ability : abilities) { // for replacment effects of static abilities do not use LKI to check if to apply if (ability.getAbilityType() != AbilityType.STATIC || ability.isInUseableZone(game, null, event)) { 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(effect, applicableAbilities); } } for (PreventionEffect effect : preventionEffects) { if (!effect.checksEventType(event, game)) { continue; } if (event.getAppliedEffects() != null && event.getAppliedEffects().contains(effect.getId())) { // Effect already applied to this event, ignore it // TODO: Handle also gained effect that are connected to different abilities. continue; } HashSet<Ability> abilities = preventionEffects.getAbility(effect.getId()); HashSet<Ability> applicableAbilities = new HashSet<>(); for (Ability ability : abilities) { if (ability.getAbilityType() != AbilityType.STATIC || ability.isInUseableZone(game, null, event)) { 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; }