package net.demilich.metastone.game.spells;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.Predicate;
import net.demilich.metastone.game.Attribute;
import net.demilich.metastone.game.GameContext;
import net.demilich.metastone.game.Player;
import net.demilich.metastone.game.actions.DiscoverAction;
import net.demilich.metastone.game.actions.GameAction;
import net.demilich.metastone.game.cards.Card;
import net.demilich.metastone.game.cards.CardCatalogue;
import net.demilich.metastone.game.cards.CardCollection;
import net.demilich.metastone.game.cards.CardType;
import net.demilich.metastone.game.entities.Actor;
import net.demilich.metastone.game.entities.Entity;
import net.demilich.metastone.game.entities.EntityType;
import net.demilich.metastone.game.entities.heroes.HeroClass;
import net.demilich.metastone.game.entities.minions.Race;
import net.demilich.metastone.game.entities.minions.RelativeToSource;
import net.demilich.metastone.game.entities.minions.Summon;
import net.demilich.metastone.game.spells.desc.SpellArg;
import net.demilich.metastone.game.spells.desc.SpellDesc;
import net.demilich.metastone.game.spells.desc.filter.EntityFilter;
import net.demilich.metastone.game.spells.desc.filter.Operation;
import net.demilich.metastone.game.targeting.EntityReference;
public class SpellUtils {
public static void castChildSpell(GameContext context, Player player, SpellDesc spell, Entity source, Entity target) {
EntityReference sourceReference = source != null ? source.getReference() : null;
EntityReference targetReference = spell.getTarget();
if (targetReference == null && target != null) {
targetReference = target.getReference();
}
context.getLogic().castSpell(player.getId(), spell, sourceReference, targetReference, true);
}
public static boolean evaluateOperation(Operation operation, int actualValue, int targetValue) {
switch (operation) {
case EQUAL:
return actualValue == targetValue;
case GREATER:
return actualValue > targetValue;
case GREATER_OR_EQUAL:
return actualValue >= targetValue;
case HAS:
return actualValue > 0;
case LESS:
return actualValue < targetValue;
case LESS_OR_EQUAL:
return actualValue <= targetValue;
}
return false;
}
public static CardCollection getCards(CardCollection source, Predicate<Card> filter) {
CardCollection result = new CardCollection();
for (Card card : source) {
if (filter == null || filter.test(card)) {
result.add(card);
}
}
return result;
}
public static Card getCard(GameContext context, SpellDesc spell) {
Card card = null;
String cardName = (String) spell.get(SpellArg.CARD);
card = CardCatalogue.getCardById(cardName);
if (spell.get(SpellArg.CARD).toString().toUpperCase().equals("PENDING_CARD")) {
card = (Card) context.getPendingCard();
} else if (spell.get(SpellArg.CARD).toString().toUpperCase().equals("EVENT_CARD")) {
card = (Card) context.getEventCard();
}
return card;
}
public static Card[] getCards(GameContext context, SpellDesc spell) {
String[] cardNames = null;
if (spell.contains(SpellArg.CARDS)) {
cardNames = (String[]) spell.get(SpellArg.CARDS);
} else {
cardNames = new String[1];
cardNames[0] = (String) spell.get(SpellArg.CARD);
}
Card[] cards = new Card[cardNames.length];
for (int i = 0; i < cards.length; i++) {
cards[i] = context.getCardById(cardNames[i]);
}
return cards;
}
public static DiscoverAction getDiscover(GameContext context, Player player, SpellDesc desc, CardCollection cards) {
SpellDesc spell = (SpellDesc) desc.get(SpellArg.SPELL);
List<GameAction> discoverActions = new ArrayList<>();
for (Card card : cards) {
SpellDesc spellClone = spell.addArg(SpellArg.CARD, card.getCardId());
DiscoverAction discover = DiscoverAction.createDiscover(spellClone);
discover.setCard(card);
discover.setActionSuffix(card.getName());
discoverActions.add(discover);
}
if (discoverActions.size() == 0) {
return null;
}
if (context.getLogic().attributeExists(Attribute.ALL_RANDOM_YOGG_ONLY_FINAL_DESTINATION)) {
return (DiscoverAction) discoverActions.get(context.getLogic().random(discoverActions.size()));
} else {
return (DiscoverAction) player.getBehaviour().requestAction(context, player, discoverActions);
}
}
public static DiscoverAction getSpellDiscover(GameContext context, Player player, SpellDesc desc, List<SpellDesc> spells) {
List<GameAction> discoverActions = new ArrayList<>();
for (SpellDesc spell : spells) {
DiscoverAction discover = DiscoverAction.createDiscover(spell);
discover.setName(spell.getString(SpellArg.NAME));
discover.setDescription(spell.getString(SpellArg.DESCRIPTION));
discover.setActionSuffix((String) spell.get(SpellArg.NAME));
discoverActions.add(discover);
}
if (context.getLogic().attributeExists(Attribute.ALL_RANDOM_YOGG_ONLY_FINAL_DESTINATION)) {
return (DiscoverAction) discoverActions.get(context.getLogic().random(discoverActions.size()));
} else {
return (DiscoverAction) player.getBehaviour().requestAction(context, player, discoverActions);
}
}
public static Card getRandomCard(CardCollection source, Predicate<Card> filter) {
CardCollection result = getCards(source, filter);
if (result.isEmpty()) {
return null;
}
return result.getRandom();
}
public static HeroClass getRandomHeroClass() {
HeroClass[] values = HeroClass.values();
List<HeroClass> heroClasses = new ArrayList<HeroClass>();
for (HeroClass heroClass : values) {
if (heroClass.isBaseClass()) {
heroClasses.add(heroClass);
}
}
return heroClasses.get(ThreadLocalRandom.current().nextInt(heroClasses.size()));
}
public static HeroClass getRandomHeroClassExcept(HeroClass... heroClassesExcluded) {
HeroClass[] values = HeroClass.values();
List<HeroClass> heroClasses = new ArrayList<HeroClass>();
for (HeroClass heroClass : values) {
if (heroClass.isBaseClass()) {
heroClasses.add(heroClass);
for (HeroClass heroClassExcluded : heroClassesExcluded) {
if (heroClassExcluded == heroClass) {
heroClasses.remove(heroClass);
}
}
}
}
return heroClasses.get(ThreadLocalRandom.current().nextInt(heroClasses.size()));
}
public static <T> T getRandomTarget(List<T> targets) {
int randomIndex = ThreadLocalRandom.current().nextInt(targets.size());
return targets.get(randomIndex);
}
public static List<Actor> getValidRandomTargets(List<Entity> targets) {
List<Actor> validTargets = new ArrayList<Actor>();
for (Entity entity : targets) {
Actor actor = (Actor) entity;
if (!actor.isDestroyed() || actor.getEntityType() == EntityType.HERO) {
validTargets.add(actor);
}
}
return validTargets;
}
public static List<Entity> getValidTargets(GameContext context, Player player, List<Entity> allTargets, EntityFilter filter) {
if (filter == null) {
return allTargets;
}
List<Entity> validTargets = new ArrayList<>();
for (Entity entity : allTargets) {
if (filter.matches(context, player, entity)) {
validTargets.add(entity);
}
}
return validTargets;
}
public static int hasHowManyOfRace(Player player, Race race) {
int count = 0;
for (Summon summon : player.getSummons()) {
if (summon.getRace() == race) {
count++;
}
}
return count;
}
public static boolean highlanderDeck(Player player) {
List<String> cards = new ArrayList<String>();
for (Card card : player.getDeck()) {
if (cards.contains(card.getCardId())) {
return false;
}
cards.add(card.getCardId());
}
return true;
}
public static boolean holdsCardOfType(Player player, CardType cardType) {
for (Card card : player.getHand()) {
if (card.getCardType().isCardType(cardType)) {
return true;
}
}
return false;
}
public static boolean holdsMinionOfRace(Player player, Race race) {
for (Card card : player.getHand()) {
if (card.getAttribute(Attribute.RACE) == race) {
return true;
}
}
return false;
}
public static int howManyMinionsDiedThisTurn(GameContext context) {
int currentTurn = context.getTurn();
int count = 0;
for (Player player : context.getPlayers()) {
for (Entity deadEntity : player.getGraveyard()) {
if (deadEntity.getEntityType() != EntityType.MINION) {
continue;
}
if (deadEntity.getAttributeValue(Attribute.DIED_ON_TURN) == currentTurn) {
count++;
}
}
}
return count;
}
public static int getBoardPosition(GameContext context, Player player, SpellDesc desc, Entity source) {
final int UNDEFINED = -1;
int boardPosition = desc.getInt(SpellArg.BOARD_POSITION_ABSOLUTE, UNDEFINED);
if (boardPosition != UNDEFINED) {
return boardPosition;
}
RelativeToSource relativeBoardPosition = (RelativeToSource) desc.get(SpellArg.BOARD_POSITION_RELATIVE);
if (relativeBoardPosition == null) {
return UNDEFINED;
}
int sourcePosition = context.getBoardPosition((Summon) source);
if (sourcePosition == UNDEFINED) {
return UNDEFINED;
}
switch (relativeBoardPosition) {
case LEFT:
return sourcePosition;
case RIGHT:
return sourcePosition + 1;
default:
return UNDEFINED;
}
}
private SpellUtils() {
}
}