package net.demilich.metastone.game.spells.aura; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import net.demilich.metastone.game.GameContext; import net.demilich.metastone.game.Player; import net.demilich.metastone.game.entities.Actor; import net.demilich.metastone.game.entities.Entity; import net.demilich.metastone.game.events.GameEvent; import net.demilich.metastone.game.spells.desc.SpellDesc; import net.demilich.metastone.game.spells.desc.aura.AuraDesc; import net.demilich.metastone.game.spells.desc.filter.EntityFilter; import net.demilich.metastone.game.spells.trigger.BoardChangedTrigger; import net.demilich.metastone.game.spells.trigger.GameEventTrigger; import net.demilich.metastone.game.spells.trigger.SpellTrigger; import net.demilich.metastone.game.targeting.EntityReference; public class Aura extends SpellTrigger { private EntityReference targets; private SpellDesc applyAuraEffect; private SpellDesc removeAuraEffect; private EntityFilter entityFilter; private HashSet<Integer> affectedEntities = new HashSet<>(); public Aura(AuraDesc desc) { this(desc.getApplyEffect(), desc.getRemoveEffect(), desc.getTarget()); setEntityFilter(desc.getFilter()); } public Aura(GameEventTrigger secondaryTrigger, SpellDesc applyAuraEffect, SpellDesc removeAuraEffect, EntityReference targetSelection, EntityFilter entityFilter) { super(new BoardChangedTrigger(), secondaryTrigger, applyAuraEffect, false); this.applyAuraEffect = applyAuraEffect; this.removeAuraEffect = removeAuraEffect; this.targets = targetSelection; this.entityFilter = entityFilter; } public Aura(GameEventTrigger secondaryTrigger, SpellDesc applyAuraEffect, SpellDesc removeAuraEffect, EntityReference targetSelection) { this(secondaryTrigger, applyAuraEffect, removeAuraEffect, targetSelection, null); } public Aura(SpellDesc applyAuraEffect, SpellDesc removeAuraEffect, EntityReference targetSelection) { this(null, applyAuraEffect, removeAuraEffect, targetSelection); } protected boolean affects(GameContext context, Player player, Entity target, List<Entity> resolvedTargets) { if (getEntityFilter() != null && !getEntityFilter().matches(context, player, target)) { return false; } return resolvedTargets.contains(target); } @Override public Aura clone() { Aura clone = (Aura) super.clone(); clone.targets = this.targets; clone.applyAuraEffect = this.applyAuraEffect.clone(); clone.removeAuraEffect = this.removeAuraEffect.clone(); clone.affectedEntities = new HashSet<>(this.affectedEntities); return clone; } @Override public void onAdd(GameContext context) { super.onAdd(context); affectedEntities.clear(); } public void onGameEvent(GameEvent event) { GameContext context = event.getGameContext(); Player owner = context.getPlayer(getOwner()); Actor sourceActor = (Actor) context.resolveSingleTarget(getHostReference()); List<Entity> resolvedTargets = context.resolveTarget(owner, sourceActor, targets); List<Entity> relevantTargets = new ArrayList<Entity>(resolvedTargets); for (Iterator<Integer> iterator = affectedEntities.iterator(); iterator.hasNext();) { int entityId = iterator.next(); EntityReference entityReference = new EntityReference(entityId); Entity affectedEntity = context.tryFind(entityReference); if (affectedEntity == null) { iterator.remove(); } else { relevantTargets.add(affectedEntity); } } for (Entity target : relevantTargets) { if (affects(context, owner, target, resolvedTargets) && !affectedEntities.contains(target.getId())) { context.getLogic().castSpell(getOwner(), applyAuraEffect, getHostReference(), target.getReference(), true); affectedEntities.add(target.getId()); // target is not affected anymore, remove effect } else if (!affects(context, owner, target, resolvedTargets) && affectedEntities.contains(target.getId())) { context.getLogic().castSpell(getOwner(), removeAuraEffect, getHostReference(), target.getReference(), true); affectedEntities.remove(target.getId()); } } } @Override public void onRemove(GameContext context) { for (int targetId : affectedEntities) { EntityReference targetKey = new EntityReference(targetId); Entity target = context.resolveSingleTarget(targetKey); context.getLogic().castSpell(getOwner(), removeAuraEffect, getHostReference(), target.getReference(), true); } affectedEntities.clear(); } public EntityFilter getEntityFilter() { return entityFilter; } public void setEntityFilter(EntityFilter entityFilter) { this.entityFilter = entityFilter; } }