package net.demilich.metastone.game.logic; import java.util.ArrayList; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.demilich.metastone.game.Attribute; import net.demilich.metastone.game.Environment; import net.demilich.metastone.game.GameContext; import net.demilich.metastone.game.Player; import net.demilich.metastone.game.actions.ActionType; import net.demilich.metastone.game.actions.GameAction; import net.demilich.metastone.game.cards.Card; import net.demilich.metastone.game.entities.Actor; import net.demilich.metastone.game.entities.Entity; import net.demilich.metastone.game.entities.heroes.Hero; import net.demilich.metastone.game.entities.minions.Minion; import net.demilich.metastone.game.entities.minions.Summon; import net.demilich.metastone.game.targeting.EntityReference; import net.demilich.metastone.game.targeting.TargetSelection; public class TargetLogic { private static Logger logger = LoggerFactory.getLogger(TargetLogic.class); private static List<Entity> singleTargetAsList(Entity target) { ArrayList<Entity> list = new ArrayList<>(1); list.add(target); return list; } private boolean containsTaunters(List<Minion> minions) { for (Entity entity : minions) { if (entity.hasAttribute(Attribute.TAUNT) && !entity.hasAttribute(Attribute.STEALTH) && !entity.hasAttribute(Attribute.IMMUNE)) { return true; } } return false; } private List<Entity> filterTargets(GameContext context, Player player, GameAction action, List<Entity> potentialTargets) { List<Entity> validTargets = new ArrayList<>(); for (Entity entity : potentialTargets) { // special case for 'SYSTEM' action, which are used in Sandbox Mode // we do not want to restrict those actions by STEALTH or // UNTARGETABLE_BY_SPELLS if (action.getActionType() == ActionType.SYSTEM && action.canBeExecutedOn(context, player, entity)) { validTargets.add(entity); continue; } if ((action.getActionType() == ActionType.SPELL || action.getActionType() == ActionType.HERO_POWER) && (entity.hasAttribute(Attribute.UNTARGETABLE_BY_SPELLS) || (entity.hasAttribute(Attribute.AURA_UNTARGETABLE_BY_SPELLS)))) { continue; } if (entity.getOwner() != player.getId() && (entity.hasAttribute(Attribute.STEALTH) || entity.hasAttribute(Attribute.IMMUNE))) { continue; } if (entity.getOwner() != player.getId() && entity instanceof Hero && context.getLogic().hasAttribute(context.getPlayer(entity.getOwner()), Attribute.IMMUNE_HERO)) { continue; } if (action.canBeExecutedOn(context, player, entity)) { validTargets.add(entity); } } return validTargets; } public Entity findEntity(GameContext context, EntityReference targetKey) { int targetId = targetKey.getId(); Entity environmentResult = findInEnvironment(context, targetKey); if (environmentResult != null) { return environmentResult; } for (Player player : context.getPlayers()) { if (player.getId() == targetId) { return player; } if (player.getHero().getId() == targetId) { return player.getHero(); } else if (player.getHero().getWeapon() != null && player.getHero().getWeapon().getId() == targetId) { return player.getHero().getWeapon(); } for (Summon summon : player.getSummons()) { if (summon.getId() == targetId) { return summon; } } for (Entity entity : player.getGraveyard()) { if (entity.getId() == targetId) { return entity; } } for (Entity entity : player.getSetAsideZone()) { if (entity.getId() == targetId) { return entity; } } } Entity cardResult = findInCards(context.getPlayer1(), targetId); if (cardResult == null) { cardResult = findInCards(context.getPlayer2(), targetId); } if (cardResult != null) { return cardResult; } logger.error("Id " + targetId + " not found!"); logger.error(context.toString()); logger.error(context.getEnvironment().toString()); throw new RuntimeException("Target not found exception: " + targetKey); } private Entity findInCards(Player player, int targetId) { if (player.getHero().getHeroPower().getId() == targetId) { return player.getHero().getHeroPower(); } for (Card card : player.getHand()) { if (card.getId() == targetId) { return card; } } for (Card card : player.getDeck()) { if (card.getId() == targetId) { return card; } } return null; } private Entity findInEnvironment(GameContext context, EntityReference targetKey) { if (!context.getEventTargetStack().isEmpty() && targetKey == EntityReference.EVENT_TARGET) { return context.resolveSingleTarget(context.getEventTargetStack().peek()); } return null; } private List<Entity> getEntities(GameContext context, Player player, TargetSelection targetRequirement) { Player opponent = context.getOpponent(player); List<Entity> entities = new ArrayList<>(); if (targetRequirement == TargetSelection.ENEMY_HERO || targetRequirement == TargetSelection.ENEMY_CHARACTERS || targetRequirement == TargetSelection.ANY || targetRequirement == TargetSelection.HEROES) { entities.add(opponent.getHero()); } if (targetRequirement == TargetSelection.ENEMY_MINIONS || targetRequirement == TargetSelection.ENEMY_CHARACTERS || targetRequirement == TargetSelection.MINIONS || targetRequirement == TargetSelection.ANY) { entities.addAll(opponent.getMinions()); } if (targetRequirement == TargetSelection.FRIENDLY_HERO || targetRequirement == TargetSelection.FRIENDLY_CHARACTERS || targetRequirement == TargetSelection.ANY || targetRequirement == TargetSelection.HEROES) { entities.add(player.getHero()); } if (targetRequirement == TargetSelection.FRIENDLY_MINIONS || targetRequirement == TargetSelection.FRIENDLY_CHARACTERS || targetRequirement == TargetSelection.MINIONS || targetRequirement == TargetSelection.ANY) { entities.addAll(player.getMinions()); } List<Entity> destroyedEntities = new ArrayList<Entity>(); for (Entity entity : entities) { if (entity != null && entity.hasAttribute(Attribute.PENDING_DESTROY)) { destroyedEntities.add(entity); } } entities.removeAll(destroyedEntities); return entities; } private List<Entity> getTaunters(List<Minion> entities) { List<Entity> taunters = new ArrayList<>(); for (Actor entity : entities) { if (entity.hasAttribute(Attribute.TAUNT) && !entity.hasAttribute(Attribute.STEALTH) && !entity.hasAttribute(Attribute.IMMUNE)) { taunters.add(entity); } } return taunters; } public List<Entity> getValidTargets(GameContext context, Player player, GameAction action) { TargetSelection targetRequirement = action.getTargetRequirement(); ActionType actionType = action.getActionType(); Player opponent = context.getOpponent(player); // if there is a minion with TAUNT and the action is of type physical // attack only allow corresponding minions as targets if (actionType == ActionType.PHYSICAL_ATTACK && (targetRequirement == TargetSelection.ENEMY_CHARACTERS || targetRequirement == TargetSelection.ENEMY_MINIONS) && containsTaunters(opponent.getMinions())) { return getTaunters(opponent.getMinions()); } if (actionType == ActionType.SUMMON) { // you can summon next to any friendly minion or provide no target // (=null) // in which case the minion will appear to the very right of your // board List<Entity> summonTargets = getEntities(context, player, targetRequirement); summonTargets.add(null); return summonTargets; } List<Entity> potentialTargets = getEntities(context, player, targetRequirement); return filterTargets(context, player, action, potentialTargets); } public List<Entity> resolveTargetKey(GameContext context, Player player, Entity source, EntityReference targetKey) { if (targetKey == null || targetKey == EntityReference.NONE) { return null; } if (targetKey == EntityReference.ALL_CHARACTERS) { return getEntities(context, player, TargetSelection.ANY); } else if (targetKey == EntityReference.ALL_MINIONS) { return getEntities(context, player, TargetSelection.MINIONS); } else if (targetKey == EntityReference.ENEMY_CHARACTERS) { return getEntities(context, player, TargetSelection.ENEMY_CHARACTERS); } else if (targetKey == EntityReference.ENEMY_HERO) { return getEntities(context, player, TargetSelection.ENEMY_HERO); } else if (targetKey == EntityReference.ENEMY_MINIONS) { return getEntities(context, player, TargetSelection.ENEMY_MINIONS); } else if (targetKey == EntityReference.FRIENDLY_CHARACTERS) { return getEntities(context, player, TargetSelection.FRIENDLY_CHARACTERS); } else if (targetKey == EntityReference.FRIENDLY_HERO) { return getEntities(context, player, TargetSelection.FRIENDLY_HERO); } else if (targetKey == EntityReference.FRIENDLY_MINIONS) { return getEntities(context, player, TargetSelection.FRIENDLY_MINIONS); } else if (targetKey == EntityReference.OTHER_FRIENDLY_MINIONS) { List<Entity> targets = getEntities(context, player, TargetSelection.FRIENDLY_MINIONS); targets.remove(source); return targets; } else if (targetKey == EntityReference.ALL_OTHER_CHARACTERS) { List<Entity> targets = getEntities(context, player, TargetSelection.ANY); targets.remove(source); return targets; } else if (targetKey == EntityReference.ALL_OTHER_MINIONS) { List<Entity> targets = getEntities(context, player, TargetSelection.MINIONS); targets.remove(source); return targets; } else if (targetKey == EntityReference.ADJACENT_MINIONS) { return new ArrayList<>(context.getAdjacentSummons(player, source.getReference())); } else if (targetKey == EntityReference.OPPOSITE_MINIONS) { return new ArrayList<>(context.getOppositeSummons(player, source.getReference())); } else if (targetKey == EntityReference.MINIONS_TO_LEFT) { return new ArrayList<>(context.getLeftSummons(player, source.getReference())); } else if (targetKey == EntityReference.MINIONS_TO_RIGHT) { return new ArrayList<>(context.getRightSummons(player, source.getReference())); } else if (targetKey == EntityReference.SELF) { return singleTargetAsList(source); } else if (targetKey == EntityReference.EVENT_TARGET) { return singleTargetAsList(context.resolveSingleTarget(context.getEventTargetStack().peek())); } else if (targetKey == EntityReference.TARGET) { return singleTargetAsList(context.resolveSingleTarget((EntityReference) context.getEnvironment().get(Environment.TARGET))); } else if (targetKey == EntityReference.SPELL_TARGET) { return singleTargetAsList(context.resolveSingleTarget((EntityReference) context.getEnvironment().get(Environment.SPELL_TARGET))); } else if (targetKey == EntityReference.KILLED_MINION) { return singleTargetAsList(context.resolveSingleTarget((EntityReference) context.getEnvironment().get(Environment.KILLED_MINION))); } else if (targetKey == EntityReference.ATTACKER_REFERENCE) { return singleTargetAsList(context.resolveSingleTarget((EntityReference) context.getEnvironment().get(Environment.ATTACKER_REFERENCE))); } else if (targetKey == EntityReference.PENDING_CARD) { return singleTargetAsList((Entity) context.getPendingCard()); } else if (targetKey == EntityReference.EVENT_CARD) { return singleTargetAsList((Entity) context.getEventCard()); } else if (targetKey == EntityReference.FRIENDLY_WEAPON) { if (player.getHero().getWeapon() != null) { return singleTargetAsList(player.getHero().getWeapon()); } else { return new ArrayList<>(); } } else if (targetKey == EntityReference.ENEMY_WEAPON) { Player opponent = context.getOpponent(player); if (opponent.getHero().getWeapon() != null) { return singleTargetAsList(opponent.getHero().getWeapon()); } else { return new ArrayList<>(); } } else if (targetKey == EntityReference.FRIENDLY_HAND) { return new ArrayList<>(player.getHand().toList()); } else if (targetKey == EntityReference.ENEMY_HAND) { return new ArrayList<>(context.getOpponent(player).getHand().toList()); } else if (targetKey == EntityReference.FRIENDLY_PLAYER) { return singleTargetAsList(player); } else if (targetKey == EntityReference.ENEMY_PLAYER) { return singleTargetAsList(context.getOpponent(player)); } return singleTargetAsList(findEntity(context, targetKey)); } }