Compare commits

..

1 Commits

Author SHA1 Message Date
Hans Mackowiak
33633ebd50 StaticAbilityAlternativeCost: split Mayplay stuff 2021-03-09 08:49:57 +01:00
2592 changed files with 17006 additions and 24380 deletions

View File

@@ -17,26 +17,16 @@
*/
package forge.ai;
import java.util.ArrayList;
import java.util.List;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Lists;
import forge.ai.ability.AnimateAi;
import forge.card.CardTypeView;
import forge.game.GameEntity;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.ability.effects.ProtectEffect;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CardUtil;
import forge.game.card.CounterEnumType;
import forge.game.card.*;
import forge.game.combat.Combat;
import forge.game.combat.CombatUtil;
import forge.game.combat.GlobalAttackRestrictions;
@@ -53,6 +43,9 @@ import forge.util.MyRandom;
import forge.util.TextUtil;
import forge.util.collect.FCollectionView;
import java.util.ArrayList;
import java.util.List;
//doesHumanAttackAndWin() uses the global variable AllZone.getComputerPlayer()
/**
@@ -76,7 +69,6 @@ public class AiAttackController {
private Player defendingOpponent;
private int aiAggression = 0; // added by Masher, how aggressive the ai is attack will be depending on circumstances
private final boolean nextTurn;
/**
@@ -86,24 +78,18 @@ public class AiAttackController {
*
*/
public AiAttackController(final Player ai) {
this(ai, false);
} // constructor
public AiAttackController(final Player ai, boolean nextTurn) {
this.ai = ai;
this.defendingOpponent = choosePreferredDefenderPlayer();
this.defendingOpponent = choosePreferredDefenderPlayer();
this.oppList = getOpponentCreatures(this.defendingOpponent);
this.myList = ai.getCreaturesInPlay();
this.attackers = new ArrayList<>();
for (Card c : myList) {
if (nextTurn && CombatUtil.canAttackNextTurn(c, this.defendingOpponent) ||
CombatUtil.canAttack(c, this.defendingOpponent)) {
if (CombatUtil.canAttack(c, this.defendingOpponent)) {
attackers.add(c);
}
}
this.blockers = getPossibleBlockers(oppList, this.attackers);
this.nextTurn = nextTurn;
} // overloaded constructor to evaluate attackers that should attack next turn
} // constructor
public AiAttackController(final Player ai, Card attacker) {
this.ai = ai;
@@ -115,7 +101,6 @@ public class AiAttackController {
attackers.add(attacker);
}
this.blockers = getPossibleBlockers(oppList, this.attackers);
this.nextTurn = false;
} // overloaded constructor to evaluate single specified attacker
public static List<Card> getOpponentCreatures(final Player defender) {
@@ -147,14 +132,6 @@ public class AiAttackController {
this.oppList.remove(blocker);
}
private boolean canAttackWrapper(final Card attacker, final GameEntity defender) {
if (nextTurn) {
return CombatUtil.canAttackNextTurn(attacker, defender);
} else {
return CombatUtil.canAttack(attacker, defender);
}
}
/** Choose opponent for AI to attack here. Expand as necessary. */
private Player choosePreferredDefenderPlayer() {
Player defender = ai.getWeakestOpponent(); //Gets opponent with the least life
@@ -705,8 +682,6 @@ public class AiAttackController {
final boolean bAssault = this.doAssault(ai);
// TODO: detect Lightmine Field by presence of a card with a specific trigger
final boolean lightmineField = ComputerUtilCard.isPresentOnBattlefield(ai.getGame(), "Lightmine Field");
// TODO: detect Season of the Witch by presence of a card with a specific trigger
final boolean seasonOfTheWitch = ComputerUtilCard.isPresentOnBattlefield(ai.getGame(), "Season of the Witch");
// Determine who will be attacked
GameEntity defender = this.chooseDefender(combat, bAssault);
@@ -727,46 +702,39 @@ public class AiAttackController {
// Attackers that don't really have a choice
int numForcedAttackers = 0;
// nextTurn is now only used by effect from Oracle en-Vec, which can skip check must attack,
// because creatures not chosen can't attack.
if (!nextTurn) {
for (final Card attacker : this.attackers) {
if (!CombatUtil.canAttack(attacker, defender)) {
attackersLeft.remove(attacker);
continue;
}
boolean mustAttack = false;
if (attacker.isGoaded()) {
mustAttack = true;
} else if (attacker.getSVar("MustAttack").equals("True")) {
mustAttack = true;
} else if (attacker.hasSVar("EndOfTurnLeavePlay")
&& isEffectiveAttacker(ai, attacker, combat)) {
mustAttack = true;
} else if (seasonOfTheWitch) {
// TODO: if there are other ways to tap this creature (like mana creature), then don't need to attack
mustAttack = true;
} else {
for (KeywordInterface inst : attacker.getKeywords()) {
String s = inst.getOriginal();
if (s.equals("CARDNAME attacks each turn if able.")
|| s.startsWith("CARDNAME attacks specific player each combat if able")
|| s.equals("CARDNAME attacks each combat if able.")) {
mustAttack = true;
break;
}
for (final Card attacker : this.attackers) {
if (!CombatUtil.canAttack(attacker, defender)) {
attackersLeft.remove(attacker);
continue;
}
boolean mustAttack = false;
if (attacker.isGoaded()) {
mustAttack = true;
} else if (attacker.getSVar("MustAttack").equals("True")) {
mustAttack = true;
} else if (attacker.hasSVar("EndOfTurnLeavePlay")
&& isEffectiveAttacker(ai, attacker, combat)) {
mustAttack = true;
} else {
for (KeywordInterface inst : attacker.getKeywords()) {
String s = inst.getOriginal();
if (s.equals("CARDNAME attacks each turn if able.")
|| s.startsWith("CARDNAME attacks specific player each combat if able")
|| s.equals("CARDNAME attacks each combat if able.")) {
mustAttack = true;
break;
}
}
if (mustAttack || attacker.getController().getMustAttackEntity() != null || attacker.getController().getMustAttackEntityThisTurn() != null) {
combat.addAttacker(attacker, defender);
attackersLeft.remove(attacker);
numForcedAttackers++;
}
}
if (attackersLeft.isEmpty()) {
return;
if (mustAttack || attacker.getController().getMustAttackEntity() != null || attacker.getController().getMustAttackEntityThisTurn() != null) {
combat.addAttacker(attacker, defender);
attackersLeft.remove(attacker);
numForcedAttackers++;
}
}
if (attackersLeft.isEmpty()) {
return;
}
// Lightmine Field: make sure the AI doesn't wipe out its own creatures
if (lightmineField) {
@@ -787,7 +755,7 @@ public class AiAttackController {
if (attackMax != -1 && combat.getAttackers().size() >= attackMax)
return;
if (canAttackWrapper(attacker, defender) && this.isEffectiveAttacker(ai, attacker, combat)) {
if (CombatUtil.canAttack(attacker, defender) && this.isEffectiveAttacker(ai, attacker, combat)) {
combat.addAttacker(attacker, defender);
}
}
@@ -828,7 +796,7 @@ public class AiAttackController {
System.out.println("Exalted");
this.aiAggression = 6;
for (Card attacker : this.attackers) {
if (canAttackWrapper(attacker, defender) && this.shouldAttack(ai, attacker, this.blockers, combat)) {
if (CombatUtil.canAttack(attacker, defender) && this.shouldAttack(ai, attacker, this.blockers, combat)) {
combat.addAttacker(attacker, defender);
return;
}
@@ -844,7 +812,7 @@ public class AiAttackController {
// reached max, breakup
if (attackMax != -1 && combat.getAttackers().size() >= attackMax)
break;
if (canAttackWrapper(attacker, defender) && this.shouldAttack(ai, attacker, this.blockers, combat)) {
if (CombatUtil.canAttack(attacker, defender) && this.shouldAttack(ai, attacker, this.blockers, combat)) {
combat.addAttacker(attacker, defender);
}
}
@@ -1085,7 +1053,7 @@ public class AiAttackController {
continue;
}
if (this.shouldAttack(ai, attacker, this.blockers, combat) && canAttackWrapper(attacker, defender)) {
if (this.shouldAttack(ai, attacker, this.blockers, combat) && CombatUtil.canAttack(attacker, defender)) {
combat.addAttacker(attacker, defender);
// check if attackers are enough to finish the attacked planeswalker
if (defender instanceof Card) {

View File

@@ -17,23 +17,12 @@
*/
package forge.ai;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import forge.card.CardStateName;
import forge.game.CardTraitBase;
import forge.game.GameEntity;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CounterEnumType;
import forge.game.card.*;
import forge.game.combat.Combat;
import forge.game.combat.CombatUtil;
import forge.game.keyword.Keyword;
@@ -44,6 +33,8 @@ import forge.game.zone.ZoneType;
import forge.util.MyRandom;
import forge.util.collect.FCollectionView;
import java.util.*;
/**
* <p>
@@ -272,14 +263,14 @@ public class AiBlockController {
if (mode == TriggerType.DamageDone) {
if ((!trigParams.containsKey("ValidSource")
|| trigger.matchesValid(attacker, trigParams.get("ValidSource").split(",")))
|| CardTraitBase.matchesValid(attacker, trigParams.get("ValidSource").split(","), attacker))
&& attacker.getNetCombatDamage() > 0
&& (!trigParams.containsKey("ValidTarget")
|| trigger.matchesValid(combat.getDefenderByAttacker(attacker), trigParams.get("ValidTarget").split(",")))) {
|| CardTraitBase.matchesValid(combat.getDefenderByAttacker(attacker), trigParams.get("ValidTarget").split(","), attacker))) {
value += 50;
}
} else if (mode == TriggerType.AttackerUnblocked) {
if (trigger.matchesValid(attacker, trigParams.get("ValidCard").split(","))) {
if (CardTraitBase.matchesValid(attacker, trigParams.get("ValidCard").split(","), attacker)) {
value += 50;
}
}

View File

@@ -18,13 +18,13 @@
package forge.ai;
import forge.game.card.Card;
import forge.game.player.Player;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import forge.game.card.Card;
import forge.game.player.Player;
/**
* <p>
* AiCardMemory class.

View File

@@ -17,19 +17,11 @@
*/
package forge.ai;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import com.esotericsoftware.minlog.Log;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import forge.ai.ability.ChangeZoneAi;
import forge.ai.ability.ExploreAi;
import forge.ai.simulation.SpellAbilityPicker;
@@ -38,38 +30,16 @@ import forge.card.mana.ManaCost;
import forge.deck.CardPool;
import forge.deck.Deck;
import forge.deck.DeckSection;
import forge.game.CardTraitBase;
import forge.game.CardTraitPredicates;
import forge.game.Direction;
import forge.game.Game;
import forge.game.GameActionUtil;
import forge.game.GameEntity;
import forge.game.GlobalRuleChange;
import forge.game.*;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.ability.SpellApiBased;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardFactoryUtil;
import forge.game.card.CardLists;
import forge.game.card.CardPlayOption;
import forge.game.card.CardPredicates;
import forge.game.card.*;
import forge.game.card.CardPredicates.Accessors;
import forge.game.card.CardPredicates.Presets;
import forge.game.card.CardUtil;
import forge.game.card.CounterEnumType;
import forge.game.combat.Combat;
import forge.game.combat.CombatUtil;
import forge.game.cost.Cost;
import forge.game.cost.CostAdjustment;
import forge.game.cost.CostDiscard;
import forge.game.cost.CostPart;
import forge.game.cost.CostPayEnergy;
import forge.game.cost.CostPayLife;
import forge.game.cost.CostPutCounter;
import forge.game.cost.CostRemoveCounter;
import forge.game.cost.CostSacrifice;
import forge.game.cost.*;
import forge.game.keyword.Keyword;
import forge.game.mana.ManaCostBeingPaid;
import forge.game.phase.PhaseType;
@@ -78,15 +48,7 @@ import forge.game.player.PlayerActionConfirmMode;
import forge.game.replacement.ReplaceMoved;
import forge.game.replacement.ReplacementEffect;
import forge.game.replacement.ReplacementType;
import forge.game.spellability.AbilitySub;
import forge.game.spellability.LandAbility;
import forge.game.spellability.OptionalCost;
import forge.game.spellability.OptionalCostValue;
import forge.game.spellability.Spell;
import forge.game.spellability.SpellAbility;
import forge.game.spellability.SpellAbilityCondition;
import forge.game.spellability.SpellAbilityPredicates;
import forge.game.spellability.SpellPermanent;
import forge.game.spellability.*;
import forge.game.staticability.StaticAbility;
import forge.game.trigger.Trigger;
import forge.game.trigger.TriggerType;
@@ -94,13 +56,16 @@ import forge.game.trigger.WrappedAbility;
import forge.game.zone.ZoneType;
import forge.item.PaperCard;
import forge.util.Aggregates;
import forge.util.ComparatorUtil;
import forge.util.Expressions;
import forge.util.MyRandom;
import forge.util.ComparatorUtil;
import forge.util.collect.FCollectionView;
import io.sentry.Sentry;
import io.sentry.event.BreadcrumbBuilder;
import java.util.*;
import java.util.Map.Entry;
/**
* <p>
* AiController class.
@@ -114,7 +79,6 @@ public class AiController {
private final Game game;
private final AiCardMemory memory;
private Combat predictedCombat;
private Combat predictedCombatNextTurn;
private boolean cheatShuffle;
private boolean useSimulation;
private SpellAbilityPicker simPicker;
@@ -159,15 +123,6 @@ public class AiController {
return predictedCombat;
}
public Combat getPredictedCombatNextTurn() {
if (predictedCombatNextTurn == null) {
AiAttackController aiAtk = new AiAttackController(player, true);
predictedCombatNextTurn = new Combat(player);
aiAtk.declareAttackers(predictedCombatNextTurn);
}
return predictedCombatNextTurn;
}
public AiController(final Player computerPlayer, final Game game0) {
player = computerPlayer;
game = game0;
@@ -1045,7 +1000,7 @@ public class AiController {
}
// move snap-casted spells to front
if (source.isInZone(ZoneType.Graveyard)) {
if (sa.getMayPlay() != null && source.mayPlay(sa.getMayPlay()) != null) {
if (!sa.getMayPlayList().isEmpty()) {
p += 50;
}
}
@@ -1120,8 +1075,9 @@ public class AiController {
CardCollection discards = CardLists.filter(player.getCardsIn(ZoneType.Hand), CardPredicates.hasCMC(cmc));
if (discards.isEmpty()) {
return null;
} else {
return new CardCollection(ComputerUtilCard.getWorstAI(discards));
}
return new CardCollection(ComputerUtilCard.getWorstAI(discards));
}
if (sa.hasParam("AnyNumber")) {
@@ -1408,8 +1364,6 @@ public class AiController {
// Reset cached predicted combat, as it may be stale. It will be
// re-created if needed and used for any AI logic that needs it.
predictedCombat = null;
// Also reset predicted combat for next turn here
predictedCombatNextTurn = null;
// Reset priority mana reservation that's meant to work for one spell only
AiCardMemory.clearMemorySet(player, AiCardMemory.MemorySet.HELD_MANA_SOURCES_FOR_NEXT_SPELL);
@@ -1441,22 +1395,8 @@ public class AiController {
if (ComputerUtil.getDamageFromETB(player, land) < player.getLife() || !player.canLoseLife()
|| player.cantLoseForZeroOrLessLife() ) {
if (!game.getPhaseHandler().is(PhaseType.MAIN1) || !isSafeToHoldLandDropForMain2(land)) {
final List<SpellAbility> abilities = Lists.newArrayList();
final List<SpellAbility> abilities = GameActionUtil.getAlternativeCosts(land.getFirstSpellAbility(), player);
LandAbility la = new LandAbility(land, player, null);
la.setCardState(land.getCurrentState());
if (la.canPlay()) {
abilities.add(la);
}
// add mayPlay option
for (CardPlayOption o : land.mayPlay(player)) {
la = new LandAbility(land, player, o.getAbility());
la.setCardState(land.getCurrentState());
if (la.canPlay()) {
abilities.add(la);
}
}
if (!abilities.isEmpty()) {
return abilities;
}

View File

@@ -1,14 +1,13 @@
package forge.ai;
import static forge.ai.ComputerUtilCard.getBestCreatureAI;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.ObjectUtils;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import forge.card.CardType;
@@ -22,46 +21,18 @@ import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CounterEnumType;
import forge.game.card.CounterType;
import forge.game.cost.CostAddMana;
import forge.game.cost.CostChooseCreatureType;
import forge.game.cost.CostDamage;
import forge.game.cost.CostDecisionMakerBase;
import forge.game.cost.CostDiscard;
import forge.game.cost.CostDraw;
import forge.game.cost.CostExert;
import forge.game.cost.CostExile;
import forge.game.cost.CostExileFromStack;
import forge.game.cost.CostExiledMoveToGrave;
import forge.game.cost.CostFlipCoin;
import forge.game.cost.CostGainControl;
import forge.game.cost.CostGainLife;
import forge.game.cost.CostMill;
import forge.game.cost.CostPartMana;
import forge.game.cost.CostPayEnergy;
import forge.game.cost.CostPayLife;
import forge.game.cost.CostPutCardToLib;
import forge.game.cost.CostPutCounter;
import forge.game.cost.CostRemoveAnyCounter;
import forge.game.cost.CostRemoveCounter;
import forge.game.cost.CostReturn;
import forge.game.cost.CostReveal;
import forge.game.cost.CostSacrifice;
import forge.game.cost.CostTap;
import forge.game.cost.CostTapType;
import forge.game.cost.CostUnattach;
import forge.game.cost.CostUntap;
import forge.game.cost.CostUntapType;
import forge.game.cost.PaymentDecision;
import forge.game.cost.*;
import forge.game.keyword.Keyword;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import forge.game.spellability.SpellAbilityStackInstance;
import forge.game.zone.ZoneType;
import forge.util.Aggregates;
import forge.util.Localizer;
import forge.util.TextUtil;
import forge.util.collect.FCollectionView;
import static forge.ai.ComputerUtilCard.getBestCreatureAI;
public class AiCostDecision extends CostDecisionMakerBase {
private final SpellAbility ability;
private final Card source;
@@ -92,15 +63,9 @@ public class AiCostDecision extends CostDecisionMakerBase {
@Override
public PaymentDecision visit(CostChooseCreatureType cost) {
Integer amount = cost.convertAmount();
Iterable<String> choices = player.getController().chooseSomeType(
Localizer.getInstance().getMessage("lblCreature"), ability, amount, amount, Lists.newArrayList(CardType.getAllCreatureTypes()));
if (choices == null || Iterables.isEmpty(choices)) {
return null;
}
return PaymentDecision.types(choices);
String choice = player.getController().chooseSomeType("Creature", ability, CardType.getAllCreatureTypes(),
Lists.newArrayList());
return PaymentDecision.type(choice);
}
@Override
@@ -123,7 +88,7 @@ public class AiCostDecision extends CostDecisionMakerBase {
}
else if (type.equals("Hand")) {
if (hand.size() > 1 && ability.getActivatingPlayer() != null) {
hand = ability.getActivatingPlayer().getController().orderMoveToZoneList(hand, ZoneType.Graveyard, ability);
hand = ability.getActivatingPlayer().getController().orderMoveToZoneList(hand, ZoneType.Graveyard);
}
return PaymentDecision.card(hand);
}
@@ -139,7 +104,7 @@ public class AiCostDecision extends CostDecisionMakerBase {
if (type.equals("Random")) {
CardCollectionView randomSubset = CardLists.getRandomSubList(new CardCollection(hand), c);
if (randomSubset.size() > 1 && ability.getActivatingPlayer() != null) {
randomSubset = ability.getActivatingPlayer().getController().orderMoveToZoneList(randomSubset, ZoneType.Graveyard, ability);
randomSubset = ability.getActivatingPlayer().getController().orderMoveToZoneList(randomSubset, ZoneType.Graveyard);
}
return PaymentDecision.card(randomSubset);
}
@@ -220,7 +185,7 @@ public class AiCostDecision extends CostDecisionMakerBase {
return null;
}
else {
CardCollectionView chosen = ComputerUtil.chooseExileFrom(player, cost.getFrom(), cost.getType(), source, ability.getTargetCard(), c, ability);
CardCollectionView chosen = ComputerUtil.chooseExileFrom(player, cost.getFrom(), cost.getType(), source, ability.getTargetCard(), c);
return null == chosen ? null : PaymentDecision.card(chosen);
}
}
@@ -427,7 +392,7 @@ public class AiCostDecision extends CostDecisionMakerBase {
chosen = chosen.subList(0, c);
}
else {
chosen = ComputerUtil.choosePutToLibraryFrom(player, cost.getFrom(), cost.getType(), source, ability.getTargetCard(), c, ability);
chosen = ComputerUtil.choosePutToLibraryFrom(player, cost.getFrom(), cost.getType(), source, ability.getTargetCard(), c);
}
return chosen.isEmpty() ? null : PaymentDecision.card(chosen);
}
@@ -499,7 +464,7 @@ public class AiCostDecision extends CostDecisionMakerBase {
type = TextUtil.fastReplace(type, "+withTotalPowerGE", "");
totap = ComputerUtil.chooseTapTypeAccumulatePower(player, type, ability, !cost.canTapSource, Integer.parseInt(totalP), exclude);
} else {
totap = ComputerUtil.chooseTapType(player, type, source, !cost.canTapSource, c, exclude, ability);
totap = ComputerUtil.chooseTapType(player, type, source, !cost.canTapSource, c, exclude);
}
if (totap == null) {
@@ -516,9 +481,6 @@ public class AiCostDecision extends CostDecisionMakerBase {
if (cost.payCostFromSource()) {
return PaymentDecision.card(source);
}
if (cost.getType().equals("OriginalHost")) {
return PaymentDecision.card(ability.getHostCard());
}
if (cost.getAmount().equals("All")) {
// Does the AI want to use Sacrifice All?
return null;
@@ -545,7 +507,7 @@ public class AiCostDecision extends CostDecisionMakerBase {
c = AbilityUtils.calculateAmount(source, cost.getAmount(), ability);
}
CardCollectionView res = ComputerUtil.chooseReturnType(player, cost.getType(), source, ability.getTargetCard(), c, ability);
CardCollectionView res = ComputerUtil.chooseReturnType(player, cost.getType(), source, ability.getTargetCard(), c);
return res.isEmpty() ? null : PaymentDecision.card(res);
}
@@ -607,7 +569,7 @@ public class AiCostDecision extends CostDecisionMakerBase {
public PaymentDecision visit(CostRemoveAnyCounter cost) {
final String amount = cost.getAmount();
final int c = AbilityUtils.calculateAmount(source, amount, ability);
final Card originalHost = ability.getOriginalOrHost();
final Card originalHost = ObjectUtils.defaultIfNull(ability.getOriginalHost(), source);
if (c <= 0) {
return null;
@@ -863,7 +825,7 @@ public class AiCostDecision extends CostDecisionMakerBase {
c = AbilityUtils.calculateAmount(source, amount, ability);
}
CardCollectionView list = ComputerUtil.chooseUntapType(player, cost.getType(), source, cost.canUntapSource, c, ability);
CardCollectionView list = ComputerUtil.chooseUntapType(player, cost.getType(), source, cost.canUntapSource, c);
if (list == null) {
System.out.println("Couldn't find a valid card to untap for: " + source.getName());

View File

@@ -17,19 +17,19 @@
*/
package forge.ai;
import forge.LobbyPlayer;
import forge.util.Aggregates;
import forge.util.FileUtil;
import forge.util.TextUtil;
import org.apache.commons.lang3.ArrayUtils;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.ArrayUtils;
import forge.LobbyPlayer;
import forge.util.Aggregates;
import forge.util.FileUtil;
import forge.util.TextUtil;
/**
* Holds default AI personality profile values in an enum.
* Loads profile from the given text file when setProfile is called.

View File

@@ -17,22 +17,12 @@
*/
package forge.ai;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import forge.ai.ability.ChooseGenericEffectAi;
import forge.ai.ability.ProtectAi;
import forge.ai.ability.TokenAi;
@@ -40,33 +30,16 @@ import forge.card.CardStateName;
import forge.card.CardType;
import forge.card.ColorSet;
import forge.card.MagicColor;
import forge.game.CardTraitPredicates;
import forge.game.Game;
import forge.game.GameActionUtil;
import forge.game.GameObject;
import forge.game.GameType;
import forge.game.*;
import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.ability.effects.CharmEffect;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.*;
import forge.game.card.CardPredicates.Presets;
import forge.game.card.CardState;
import forge.game.card.CardUtil;
import forge.game.card.CounterEnumType;
import forge.game.card.CounterType;
import forge.game.combat.Combat;
import forge.game.combat.CombatUtil;
import forge.game.cost.Cost;
import forge.game.cost.CostDiscard;
import forge.game.cost.CostPart;
import forge.game.cost.CostPayment;
import forge.game.cost.CostPutCounter;
import forge.game.cost.CostSacrifice;
import forge.game.cost.*;
import forge.game.keyword.Keyword;
import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType;
@@ -88,6 +61,9 @@ import forge.util.Aggregates;
import forge.util.MyRandom;
import forge.util.TextUtil;
import forge.util.collect.FCollection;
import org.apache.commons.lang3.StringUtils;
import java.util.*;
/**
@@ -291,14 +267,14 @@ public class ComputerUtil {
newSA.setHostCard(game.getAction().moveToStack(source, sa));
if (newSA.getApi() == ApiType.Charm && !newSA.isWrapper()) {
if (!CharmEffect.makeChoices(newSA)) {
if (!CharmEffect.makeChoices(sa)) {
return false;
}
}
}
final CostPayment pay = new CostPayment(newSA.getPayCosts(), newSA);
pay.payComputerCosts(new AiCostDecision(ai, newSA));
pay.payComputerCosts(new AiCostDecision(ai, sa));
game.getStack().add(newSA);
return true;
@@ -539,7 +515,7 @@ public class ComputerUtil {
public static CardCollection chooseSacrificeType(final Player ai, final String type, final SpellAbility ability, final Card target, final int amount) {
final Card source = ability.getHostCard();
CardCollection typeList = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), type.split(";"), source.getController(), source, ability);
CardCollection typeList = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), type.split(";"), source.getController(), source, null);
typeList = CardLists.filter(typeList, CardPredicates.canBeSacrificedBy(ability));
@@ -570,8 +546,8 @@ public class ComputerUtil {
}
public static CardCollection chooseExileFrom(final Player ai, final ZoneType zone, final String type, final Card activate,
final Card target, final int amount, SpellAbility sa) {
CardCollection typeList = CardLists.getValidCards(ai.getCardsIn(zone), type.split(";"), activate.getController(), activate, sa);
final Card target, final int amount) {
CardCollection typeList = CardLists.getValidCards(ai.getCardsIn(zone), type.split(";"), activate.getController(), activate, null);
if ((target != null) && target.getController() == ai) {
typeList.remove(target); // don't exile the card we're pumping
@@ -591,8 +567,8 @@ public class ComputerUtil {
}
public static CardCollection choosePutToLibraryFrom(final Player ai, final ZoneType zone, final String type, final Card activate,
final Card target, final int amount, SpellAbility sa) {
CardCollection typeList = CardLists.getValidCards(ai.getCardsIn(zone), type.split(";"), activate.getController(), activate, sa);
final Card target, final int amount) {
CardCollection typeList = CardLists.getValidCards(ai.getCardsIn(zone), type.split(";"), activate.getController(), activate, null);
if ((target != null) && target.getController() == ai) {
typeList.remove(target); // don't move the card we're pumping
@@ -615,11 +591,14 @@ public class ComputerUtil {
return list;
}
public static CardCollection chooseTapType(final Player ai, final String type, final Card activate, final boolean tap, final int amount, final CardCollectionView exclude, SpellAbility sa) {
public static CardCollection chooseTapType(final Player ai, final String type, final Card activate, final boolean tap, final int amount) {
return chooseTapType(ai, type, activate, tap, amount, CardCollection.EMPTY);
}
public static CardCollection chooseTapType(final Player ai, final String type, final Card activate, final boolean tap, final int amount, final CardCollectionView exclude) {
CardCollection all = new CardCollection(ai.getCardsIn(ZoneType.Battlefield));
all.removeAll(exclude);
CardCollection typeList =
CardLists.getValidCards(all, type.split(";"), activate.getController(), activate, sa);
CardLists.getValidCards(all, type.split(";"), activate.getController(), activate, null);
// is this needed?
typeList = CardLists.filter(typeList, Presets.UNTAPPED);
@@ -692,9 +671,9 @@ public class ComputerUtil {
return tapList;
}
public static CardCollection chooseUntapType(final Player ai, final String type, final Card activate, final boolean untap, final int amount, SpellAbility sa) {
public static CardCollection chooseUntapType(final Player ai, final String type, final Card activate, final boolean untap, final int amount) {
CardCollection typeList =
CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), type.split(";"), activate.getController(), activate, sa);
CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), type.split(";"), activate.getController(), activate, null);
// is this needed?
typeList = CardLists.filter(typeList, Presets.TAPPED);
@@ -717,9 +696,9 @@ public class ComputerUtil {
return untapList;
}
public static CardCollection chooseReturnType(final Player ai, final String type, final Card activate, final Card target, final int amount, SpellAbility sa) {
public static CardCollection chooseReturnType(final Player ai, final String type, final Card activate, final Card target, final int amount) {
final CardCollection typeList =
CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), type.split(";"), activate.getController(), activate, sa);
CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), type.split(";"), activate.getController(), activate, null);
if ((target != null) && target.getController() == ai) {
// don't bounce the card we're pumping
typeList.remove(target);
@@ -967,7 +946,7 @@ public class ComputerUtil {
}
final TargetRestrictions tgt = sa.getTargetRestrictions();
if (tgt != null) {
if (CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), tgt.getValidTgts(), controller, sa.getHostCard(), sa).contains(card)) {
if (CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), tgt.getValidTgts(), controller, sa.getHostCard(), null).contains(card)) {
prevented += AbilityUtils.calculateAmount(sa.getHostCard(), sa.getParam("Amount"), sa);
}
@@ -1583,8 +1562,9 @@ public class ComputerUtil {
if (threatApi == null) {
return threatened;
}
final TargetRestrictions tgt = topStack.getTargetRestrictions();
if (!topStack.usesTargeting()) {
if (tgt == null) {
if (topStack.hasParam("Defined")) {
objects = AbilityUtils.getDefinedObjects(source, topStack.getParam("Defined"), topStack);
} else if (topStack.hasParam("ValidCards")) {
@@ -1681,7 +1661,7 @@ public class ComputerUtil {
if (saviourApi == ApiType.Pump || saviourApi == ApiType.PumpAll) {
boolean canSave = ComputerUtilCombat.predictDamageTo(c, dmg - toughness, source, false) < ComputerUtilCombat.getDamageToKill(c);
if ((!topStack.usesTargeting() && !grantIndestructible && !canSave)
if ((tgt == null && !grantIndestructible && !canSave)
|| (!grantIndestructible && !grantShroud && !canSave)) {
continue;
}
@@ -1741,7 +1721,7 @@ public class ComputerUtil {
final boolean cantSave = c.getNetToughness() + toughness <= dmg
|| (!c.hasKeyword(Keyword.INDESTRUCTIBLE) && c.getShieldCount() == 0 && !grantIndestructible
&& (dmg >= toughness + ComputerUtilCombat.getDamageToKill(c)));
if (cantSave && (!topStack.usesTargeting() || !grantShroud)) {
if (cantSave && (tgt == null || !grantShroud)) {
continue;
}
}
@@ -1754,7 +1734,7 @@ public class ComputerUtil {
}
if (saviourApi == ApiType.Protection) {
if (!topStack.usesTargeting() || (ProtectAi.toProtectFrom(source, saviour) == null)) {
if (tgt == null || (ProtectAi.toProtectFrom(source, saviour) == null)) {
continue;
}
}
@@ -1791,13 +1771,13 @@ public class ComputerUtil {
if (saviourApi == ApiType.Pump || saviourApi == ApiType.PumpAll
|| saviorWithSubsApi == ApiType.Pump
|| saviorWithSubsApi == ApiType.PumpAll) {
if ((!topStack.usesTargeting() && !grantIndestructible)
if ((tgt == null && !grantIndestructible)
|| (!grantShroud && !grantIndestructible)) {
continue;
}
}
if (saviourApi == ApiType.Protection) {
if (!topStack.usesTargeting() || (ProtectAi.toProtectFrom(source, saviour) == null)) {
if (tgt == null || (ProtectAi.toProtectFrom(source, saviour) == null)) {
continue;
}
}
@@ -1826,11 +1806,11 @@ public class ComputerUtil {
if (o instanceof Card) {
final Card c = (Card) o;
// give Shroud to targeted creatures
if ((saviourApi == ApiType.Pump || saviourApi == ApiType.PumpAll) && (!topStack.usesTargeting() || !grantShroud)) {
if ((saviourApi == ApiType.Pump || saviourApi == ApiType.PumpAll) && (tgt == null || !grantShroud)) {
continue;
}
if (saviourApi == ApiType.Protection) {
if (!topStack.usesTargeting() || (ProtectAi.toProtectFrom(source, saviour) == null)) {
if (tgt == null || (ProtectAi.toProtectFrom(source, saviour) == null)) {
continue;
}
}
@@ -1854,11 +1834,11 @@ public class ComputerUtil {
if (o instanceof Card) {
final Card c = (Card) o;
// give Shroud to targeted creatures
if ((saviourApi == ApiType.Pump || saviourApi == ApiType.PumpAll && !topStack.usesTargeting()) && !grantShroud) {
if ((saviourApi == ApiType.Pump || saviourApi == ApiType.PumpAll && tgt == null) && !grantShroud) {
continue;
}
if (saviourApi == ApiType.Protection) {
if (!topStack.usesTargeting() || (ProtectAi.toProtectFrom(source, saviour) == null)) {
if (tgt == null || (ProtectAi.toProtectFrom(source, saviour) == null)) {
continue;
}
}
@@ -1875,11 +1855,11 @@ public class ComputerUtil {
if (o instanceof Card) {
final Card c = (Card) o;
// give Shroud to targeted creatures
if ((saviourApi == ApiType.Pump || saviourApi == ApiType.PumpAll && !topStack.usesTargeting()) && !grantShroud) {
if ((saviourApi == ApiType.Pump || saviourApi == ApiType.PumpAll && tgt == null) && !grantShroud) {
continue;
}
if (saviourApi == ApiType.Protection) {
if (!topStack.usesTargeting() || (ProtectAi.toProtectFrom(source, saviour) == null)) {
if (tgt == null || (ProtectAi.toProtectFrom(source, saviour) == null)) {
continue;
}
}
@@ -1972,10 +1952,10 @@ public class ComputerUtil {
ComputerUtilCombat.combatantWouldBeDestroyed(ai, source, game.getCombat())) {
return true;
}
} else if (zone.getZoneType() == ZoneType.Exile && sa.getMayPlay() != null) {
} else if (zone.getZoneType() == ZoneType.Exile) {
// play cards in exile that can only be played that turn
if (game.getPhaseHandler().getPhase() == PhaseType.MAIN2) {
if (source.mayPlay(sa.getMayPlay()) != null) {
if (!sa.getMayPlayList().isEmpty()) {
return true;
}
}
@@ -2076,8 +2056,8 @@ public class ComputerUtil {
final CardCollection candidates = new CardCollection();
final CardCollectionView handList = ai.getCardsIn(ZoneType.Hand);
final CardCollection lands = CardLists.getValidCards(handList, "Card.Land", ai, null, null);
final CardCollection nonLands = CardLists.getValidCards(handList, "Card.nonLand", ai, null, null);
final CardCollection lands = CardLists.getValidCards(handList, "Card.Land", ai, null);
final CardCollection nonLands = CardLists.getValidCards(handList, "Card.nonLand", ai, null);
CardLists.sortByCmcDesc(nonLands);
if (lands.size() >= 3 && lands.size() <= 4) {
@@ -2256,16 +2236,17 @@ public class ComputerUtil {
return getCardsToDiscardFromOpponent(aiChooser, p, sa, validCards, min, max);
}
public static List<String> chooseSomeType(Player ai, String kindOfType, String logic, int min, int max, Collection<String> validTypes) {
public static String chooseSomeType(Player ai, String kindOfType, String logic, Collection<String> validTypes, List<String> invalidTypes) {
if (invalidTypes == null) {
invalidTypes = ImmutableList.of();
}
if (validTypes == null) {
validTypes = ImmutableList.of();
}
final Game game = ai.getGame();
List<String> chosenList = Lists.newArrayList();
String chosen = "";
if (kindOfType.equals("Card")) {
String chosen = "";
// TODO
// computer will need to choose a type
// based on whether it needs a creature or land,
@@ -2273,25 +2254,24 @@ public class ComputerUtil {
// then, reveal chosenType to Human
if (game.getPhaseHandler().is(PhaseType.UNTAP) && logic == null) { // Storage Matrix
double amount = 0;
for (String type : validTypes) {
CardCollection list = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.isType(type), Presets.TAPPED);
double i = type.equals("Creature") ? list.size() * 1.5 : list.size();
if (i > amount) {
amount = i;
chosen = type;
for (String type : CardType.getAllCardTypes()) {
if (!invalidTypes.contains(type)) {
CardCollection list = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.isType(type), Presets.TAPPED);
double i = type.equals("Creature") ? list.size() * 1.5 : list.size();
if (i > amount) {
amount = i;
chosen = type;
}
}
}
} else if (logic == "MostProminentInComputerDeck") {
chosen = ComputerUtilCard.getMostProminentType(ai.getAllCards(), validTypes);
}
if (StringUtils.isEmpty(chosen)) {
chosen = validTypes.isEmpty() ? "Creature" : Aggregates.random(validTypes);
}
chosenList.add(chosen);
} else if (kindOfType.equals("Creature")) {
String chosen = "";
if (logic != null) {
List <String> valid = Lists.newArrayList(validTypes);
List <String> valid = Lists.newArrayList(CardType.getAllCreatureTypes());
valid.removeAll(invalidTypes);
if (logic.equals("MostProminentOnBattlefield")) {
chosen = ComputerUtilCard.getMostProminentType(game.getCardsIn(ZoneType.Battlefield), valid);
@@ -2302,7 +2282,7 @@ public class ComputerUtil {
else if (logic.equals("MostProminentOppControls")) {
CardCollection list = CardLists.filterControlledBy(game.getCardsIn(ZoneType.Battlefield), ai.getOpponents());
chosen = ComputerUtilCard.getMostProminentType(list, valid);
if (!CardType.isACreatureType(chosen) || !validTypes.contains(chosen)) {
if (!CardType.isACreatureType(chosen) || invalidTypes.contains(chosen)) {
list = CardLists.filterControlledBy(game.getCardsInGame(), ai.getOpponents());
chosen = ComputerUtilCard.getMostProminentType(list, valid);
}
@@ -2314,17 +2294,16 @@ public class ComputerUtil {
chosen = ComputerUtilCard.getMostProminentType(ai.getCardsIn(ZoneType.Graveyard), valid);
}
}
if (!CardType.isACreatureType(chosen) || !validTypes.contains(chosen)) {
chosen = Iterables.getFirst(validTypes, null);
if (!CardType.isACreatureType(chosen) || invalidTypes.contains(chosen)) {
chosen = "Sliver";
}
chosenList.add(chosen);
} else if (kindOfType.equals("Basic Land")) {
String chosen = "";
if (logic != null) {
if (logic.equals("MostProminentOppControls")) {
CardCollection list = CardLists.filterControlledBy(game.getCardsIn(ZoneType.Battlefield), ai.getOpponents());
List<String> valid = Lists.newArrayList(validTypes);
List<String> valid = Lists.newArrayList(CardType.getBasicTypes());
valid.removeAll(invalidTypes);
chosen = ComputerUtilCard.getMostProminentType(list, valid);
} else if (logic.equals("MostNeededType")) {
@@ -2347,9 +2326,9 @@ public class ComputerUtil {
}
}
else if (logic.equals("ChosenLandwalk")) {
for (Card c : ai.getWeakestOpponent().getLandsInPlay()) {
for (Card c : ComputerUtil.getOpponentFor(ai).getLandsInPlay()) {
for (String t : c.getType()) {
if (validTypes.contains(t) && CardType.isABasicLandType(t)) {
if (!invalidTypes.contains(t) && CardType.isABasicLandType(t)) {
chosen = t;
break;
}
@@ -2358,28 +2337,16 @@ public class ComputerUtil {
}
}
if (!CardType.isABasicLandType(chosen) || !validTypes.contains(chosen)) {
chosen = Iterables.getFirst(validTypes, null);
}
chosenList.add(chosen);
// the only one with choosing two types is Illusionary Terrain
// and it needs other AI logic
while (chosenList.size() < min) {
validTypes.remove(chosen);
chosen = Iterables.getFirst(validTypes, null);
if (chosen == null) {
return Lists.newArrayList();
}
chosenList.add(chosen);
if (!CardType.isABasicLandType(chosen) || invalidTypes.contains(chosen)) {
chosen = "Island";
}
}
else if (kindOfType.equals("Land")) {
String chosen = "";
if (logic != null) {
if (logic.equals("ChosenLandwalk")) {
for (Card c : ai.getWeakestOpponent().getLandsInPlay()) {
for (Card c : ComputerUtil.getOpponentFor(ai).getLandsInPlay()) {
for (String t : c.getType().getLandTypes()) {
if (validTypes.contains(t)) {
if (!invalidTypes.contains(t)) {
chosen = t;
break;
}
@@ -2388,11 +2355,10 @@ public class ComputerUtil {
}
}
if (StringUtils.isEmpty(chosen)) {
chosen = Iterables.getFirst(validTypes, null);
chosen = "Island";
}
chosenList.add(chosen);
}
return chosenList;
return chosen;
}
public static Object vote(Player ai, List<Object> options, SpellAbility sa, Multimap<Object, Player> votes, Player forPlayer) {
@@ -2943,8 +2909,9 @@ public class ComputerUtil {
}
if (targetSpellCard == null) {
return false;
} else {
sa.getTargets().add(targetSpellCard);
}
sa.getTargets().add(targetSpellCard);
return true;
}
@@ -3029,7 +2996,7 @@ public class ComputerUtil {
}
});
} else {
list = CardLists.getValidCards(srcList, sa.getParam("AITgts"), sa.getActivatingPlayer(), source, sa);
list = CardLists.getValidCards(srcList, sa.getParam("AITgts"), sa.getActivatingPlayer(), source);
}
if (!list.isEmpty() || sa.hasParam("AITgtsStrict") || alwaysStrict) {

View File

@@ -1,11 +1,9 @@
package forge.ai;
import java.util.Iterator;
import java.util.List;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import forge.card.CardStateName;
import forge.game.Game;
import forge.game.GameActionUtil;
@@ -16,11 +14,15 @@ import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates.Presets;
import forge.game.player.Player;
import forge.game.spellability.LandAbility;
import forge.game.spellability.OptionalCostValue;
import forge.game.spellability.SpellAbility;
import forge.game.spellability.SpellAbilityStackInstance;
import forge.game.zone.ZoneType;
import java.util.Iterator;
import java.util.List;
public class ComputerUtilAbility {
public static CardCollection getAvailableLandsToPlay(final Game game, final Player player) {
if (!game.getStack().isEmpty() || !game.getPhaseHandler().getPhase().isMain()) {
@@ -54,7 +56,8 @@ public class ComputerUtilAbility {
if (!(crd.isLand() || (crd.isFaceDown() && crd.getState(CardStateName.Original).getType().isLand()))) {
continue;
}
if (!crd.mayPlay(player).isEmpty()) {
if (Iterables.any(crd.getAllPossibleAbilities(player, true), Predicates.instanceOf(LandAbility.class))) {
landList.add(crd);
}
}
@@ -117,7 +120,7 @@ public class ComputerUtilAbility {
newAbilities.add(sa);
newAbilities.addAll(otherAltSa);
}
final List<SpellAbility> result = Lists.newArrayList();
for (SpellAbility sa : newAbilities) {
sa.setActivatingPlayer(player);
@@ -171,8 +174,12 @@ public class ComputerUtilAbility {
return sa;
}
public static Card getAbilitySource(SpellAbility sa) {
return sa.getOriginalHost() != null ? sa.getOriginalHost() : sa.getHostCard();
}
public static String getAbilitySourceName(SpellAbility sa) {
final Card c = sa.getOriginalOrHost();
final Card c = getAbilitySource(sa);
return c != null ? c.getName() : "";
}

View File

@@ -1,20 +1,5 @@
package forge.ai;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.MutablePair;
import org.apache.commons.lang3.tuple.Pair;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
@@ -33,16 +18,7 @@ import forge.game.Game;
import forge.game.GameObject;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardFactory;
import forge.game.card.CardFactoryUtil;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CardUtil;
import forge.game.card.CounterEnumType;
import forge.game.card.CounterType;
import forge.game.card.*;
import forge.game.combat.Combat;
import forge.game.combat.CombatUtil;
import forge.game.cost.Cost;
@@ -64,6 +40,12 @@ import forge.item.PaperCard;
import forge.util.Aggregates;
import forge.util.Expressions;
import forge.util.MyRandom;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.MutablePair;
import org.apache.commons.lang3.tuple.Pair;
import java.util.*;
import java.util.Map.Entry;
public class ComputerUtilCard {
public static Card getMostExpensivePermanentAI(final CardCollectionView list, final SpellAbility spell, final boolean targeted) {
@@ -327,17 +309,6 @@ public class ComputerUtilCard {
return biggest;
}
// For ability of Oracle en-Vec, return the first card that are going to attack next turn
public static Card getBestCreatureToAttackNextTurnAI(final Player aiPlayer, final Iterable<Card> list) {
AiController aic = ((PlayerControllerAi)aiPlayer.getController()).getAi();
for(final Card card : list) {
if (aic.getPredictedCombatNextTurn().isAttacking(card)) {
return card;
}
}
return null;
}
/**
* <p>
* getWorstAI.
@@ -982,7 +953,7 @@ public class ComputerUtilCard {
for(byte c : MagicColor.WUBRG) {
String devotionCode = "Count$Devotion." + MagicColor.toLongString(c);
int devotion = AbilityUtils.calculateAmount(sa.getHostCard(), devotionCode, sa);
int devotion = CardFactoryUtil.xCount(sa.getHostCard(), devotionCode);
if (devotion > curDevotion && !CardLists.filter(hand, CardPredicates.isColor(c)).isEmpty()) {
curDevotion = devotion;
chosenColor = MagicColor.toLongString(c);
@@ -1171,8 +1142,8 @@ public class ComputerUtilCard {
}
// if this thing has AILogic set to "Curse", it's probably meant as some form of disruption
if (!priority) {
for (final String value : c.getSVars().values()) {
if (value.contains("AILogic$ Curse")) {
for (final String sVar : c.getSVars().keySet()) {
if (c.getSVars().get(sVar).contains("AILogic$ Curse")) {
// this is a curse ability, so prioritize its removal
priority = true;
break;
@@ -1214,9 +1185,10 @@ public class ComputerUtilCard {
final float valueNow = Math.max(valueTempo, threat);
if (valueNow < 0.2) { //hard floor to reduce ridiculous odds for instants over time
return false;
} else {
final float chance = MyRandom.getRandom().nextFloat();
return chance < valueNow;
}
final float chance = MyRandom.getRandom().nextFloat();
return chance < valueNow;
}
/**
@@ -1912,7 +1884,7 @@ public class ComputerUtilCard {
CardCollectionView list = game.getCardsIn(ZoneType.Battlefield);
list = CardLists.getValidCards(list, needsToPlay.split(","), card.getController(), card, sa);
list = CardLists.getValidCards(list, needsToPlay.split(","), card.getController(), card, null);
if (list.isEmpty()) {
return AiPlayDecision.MissingNeededCards;
}

View File

@@ -25,19 +25,13 @@ import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import forge.game.CardTraitBase;
import forge.game.Game;
import forge.game.GameEntity;
import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardFactoryUtil;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CardUtil;
import forge.game.card.CounterEnumType;
import forge.game.card.*;
import forge.game.combat.Combat;
import forge.game.combat.CombatUtil;
import forge.game.cost.CostPayment;
@@ -796,9 +790,9 @@ public class ComputerUtilCombat {
return false; // The trigger should have triggered already
}
if (trigParams.containsKey("ValidCard")) {
if (!trigger.matchesValid(attacker, trigParams.get("ValidCard").split(","))
&& !(combat.isAttacking(source) && trigger.matchesValid(source,
trigParams.get("ValidCard").split(","))
if (!CardTraitBase.matchesValid(attacker, trigParams.get("ValidCard").split(","), source)
&& !(combat.isAttacking(source) && CardTraitBase.matchesValid(source,
trigParams.get("ValidCard").split(","), source)
&& !trigParams.containsKey("Alone"))) {
return false;
}
@@ -806,7 +800,7 @@ public class ComputerUtilCombat {
if (trigParams.containsKey("Attacked")) {
if (combat.isAttacking(attacker)) {
GameEntity attacked = combat.getDefenderByAttacker(attacker);
if (!trigger.matchesValid(attacked, trigParams.get("Attacked").split(","))) {
if (!CardTraitBase.matchesValid(attacked, trigParams.get("Attacked").split(","), source)) {
return false;
}
} else {
@@ -826,7 +820,7 @@ public class ComputerUtilCombat {
if ((defender == null) && mode == TriggerType.AttackerUnblocked) {
willTrigger = true;
if (trigParams.containsKey("ValidCard")) {
if (!trigger.matchesValid(attacker, trigParams.get("ValidCard").split(","))) {
if (!CardTraitBase.matchesValid(attacker, trigParams.get("ValidCard").split(","), source)) {
return false;
}
}
@@ -848,7 +842,7 @@ public class ComputerUtilCombat {
return false;
}
}
if (!trigger.matchesValid(attacker, validBlocked.split(","))) {
if (!CardTraitBase.matchesValid(attacker, validBlocked.split(","), source)) {
return false;
}
}
@@ -862,35 +856,35 @@ public class ComputerUtilCombat {
return false;
}
}
if (!trigger.matchesValid(defender, validBlocker.split(","))) {
if (!CardTraitBase.matchesValid(defender, validBlocker.split(","), source)) {
return false;
}
}
} else if (mode == TriggerType.AttackerBlocked || mode == TriggerType.AttackerBlockedByCreature) {
willTrigger = true;
if (trigParams.containsKey("ValidBlocker")) {
if (!trigger.matchesValid(defender, trigParams.get("ValidBlocker").split(","))) {
if (!CardTraitBase.matchesValid(defender, trigParams.get("ValidBlocker").split(","), source)) {
return false;
}
}
if (trigParams.containsKey("ValidCard")) {
if (!trigger.matchesValid(attacker, trigParams.get("ValidCard").split(","))) {
if (!CardTraitBase.matchesValid(attacker, trigParams.get("ValidCard").split(","), source)) {
return false;
}
}
} else if (mode == TriggerType.DamageDone) {
willTrigger = true;
if (trigParams.containsKey("ValidSource")) {
if (!(trigger.matchesValid(defender, trigParams.get("ValidSource").split(","))
if (!(CardTraitBase.matchesValid(defender, trigParams.get("ValidSource").split(","), source)
&& defender.getNetCombatDamage() > 0
&& (!trigParams.containsKey("ValidTarget")
|| trigger.matchesValid(attacker, trigParams.get("ValidTarget").split(","))))) {
|| CardTraitBase.matchesValid(attacker, trigParams.get("ValidTarget").split(","), source)))) {
return false;
}
if (!(trigger.matchesValid(attacker, trigParams.get("ValidSource").split(","))
if (!(CardTraitBase.matchesValid(attacker, trigParams.get("ValidSource").split(","), source)
&& attacker.getNetCombatDamage() > 0
&& (!trigParams.containsKey("ValidTarget")
|| trigger.matchesValid(defender, trigParams.get("ValidTarget").split(","))))) {
|| CardTraitBase.matchesValid(defender, trigParams.get("ValidTarget").split(","), source)))) {
return false;
}
}

View File

@@ -1,41 +1,16 @@
package forge.ai;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import forge.ai.ability.AnimateAi;
import forge.card.ColorSet;
import forge.game.Game;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardFactoryUtil;
import forge.game.card.CardLists;
import forge.game.card.*;
import forge.game.card.CardPredicates.Presets;
import forge.game.card.CardUtil;
import forge.game.card.CounterEnumType;
import forge.game.card.CounterType;
import forge.game.combat.Combat;
import forge.game.cost.Cost;
import forge.game.cost.CostDamage;
import forge.game.cost.CostDiscard;
import forge.game.cost.CostPart;
import forge.game.cost.CostPayLife;
import forge.game.cost.CostPayment;
import forge.game.cost.CostPutCounter;
import forge.game.cost.CostRemoveAnyCounter;
import forge.game.cost.CostRemoveCounter;
import forge.game.cost.CostSacrifice;
import forge.game.cost.CostTapType;
import forge.game.cost.PaymentDecision;
import forge.game.cost.*;
import forge.game.keyword.Keyword;
import forge.game.player.Player;
import forge.game.spellability.Spell;
@@ -45,6 +20,12 @@ import forge.util.MyRandom;
import forge.util.TextUtil;
import forge.util.collect.FCollectionView;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import java.util.List;
import java.util.Set;
public class ComputerUtilCost {
@@ -137,9 +118,8 @@ public class ComputerUtilCost {
* the source
* @return true, if successful
*/
public static boolean checkDiscardCost(final Player ai, final Cost cost, final Card source, SpellAbility sa) {
if (cost == null || source.hasSVar("AISkipDiscardCostCheck") /* FIXME: should not be needed! */ ) {
public static boolean checkDiscardCost(final Player ai, final Cost cost, final Card source) {
if (cost == null) {
return true;
}
@@ -153,7 +133,7 @@ public class ComputerUtilCost {
if (type.equals("CARDNAME") && source.getAbilityText().contains("Bloodrush")) {
continue;
}
final CardCollection typeList = CardLists.getValidCards(hand, type.split(","), source.getController(), source, sa);
final CardCollection typeList = CardLists.getValidCards(hand, type.split(","), source.getController(), source, null);
if (typeList.size() > ai.getMaxHandSize()) {
continue;
}
@@ -163,9 +143,10 @@ public class ComputerUtilCost {
Card pref = ComputerUtil.getCardPreference(ai, source, "DiscardCost", typeList);
if (pref == null) {
return false;
} else {
typeList.remove(pref);
hand.remove(pref);
}
typeList.remove(pref);
hand.remove(pref);
}
}
}
@@ -270,7 +251,7 @@ public class ComputerUtilCost {
}
final CardCollection sacList = new CardCollection();
final CardCollection typeList = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), type.split(";"), source.getController(), source, sourceAbility);
final CardCollection typeList = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), type.split(";"), source.getController(), source, null);
int count = 0;
while (count < amount) {
@@ -320,7 +301,7 @@ public class ComputerUtilCost {
}
final CardCollection sacList = new CardCollection();
final CardCollection typeList = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), type.split(";"), source.getController(), source, sourceAbility);
final CardCollection typeList = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), type.split(";"), source.getController(), source, null);
int count = 0;
while (count < amount) {
@@ -641,7 +622,7 @@ public class ComputerUtilCost {
return checkLifeCost(payer, cost, source, 4, sa)
&& checkDamageCost(payer, cost, source, 4)
&& (isMine || checkSacrificeCost(payer, cost, source, sa))
&& (isMine || checkDiscardCost(payer, cost, source, sa))
&& (isMine || checkDiscardCost(payer, cost, source))
&& (!source.getName().equals("Tyrannize") || payer.getCardsIn(ZoneType.Hand).size() > 2)
&& (!source.getName().equals("Perplex") || payer.getCardsIn(ZoneType.Hand).size() < 2)
&& (!source.getName().equals("Breaking Point") || payer.getCreaturesInPlay().size() > 1)
@@ -722,7 +703,7 @@ public class ComputerUtilCost {
continue;
}
final CardCollection typeList = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), part.getType().split(";"), source.getController(), source, sa);
final CardCollection typeList = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), part.getType().split(";"), source.getController(), source, null);
int count = 0;
while (count < val) {

View File

@@ -1,26 +1,8 @@
package forge.ai;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.*;
import forge.ai.ability.AnimateAi;
import forge.card.ColorSet;
import forge.card.MagicColor;
@@ -31,23 +13,11 @@ import forge.card.mana.ManaCostShard;
import forge.game.CardTraitPredicates;
import forge.game.Game;
import forge.game.GameActionUtil;
import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CardUtil;
import forge.game.card.CounterEnumType;
import forge.game.ability.*;
import forge.game.card.*;
import forge.game.combat.Combat;
import forge.game.combat.CombatUtil;
import forge.game.cost.Cost;
import forge.game.cost.CostAdjustment;
import forge.game.cost.CostPartMana;
import forge.game.cost.CostPayEnergy;
import forge.game.cost.CostPayment;
import forge.game.cost.*;
import forge.game.keyword.Keyword;
import forge.game.mana.Mana;
import forge.game.mana.ManaCostBeingPaid;
@@ -61,12 +31,15 @@ import forge.game.replacement.ReplacementType;
import forge.game.spellability.AbilityManaPart;
import forge.game.spellability.AbilitySub;
import forge.game.spellability.SpellAbility;
import forge.game.staticability.StaticAbility;
import forge.game.trigger.Trigger;
import forge.game.trigger.TriggerType;
import forge.game.zone.ZoneType;
import forge.util.MyRandom;
import forge.util.TextUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import java.util.*;
public class ComputerUtilMana {
private final static boolean DEBUG_MANA_PAYMENT = false;
@@ -319,8 +292,8 @@ public class ComputerUtilMana {
// Exception: when paying generic mana with Cavern of Souls, prefer the colored mana producing ability
// to attempt to make the spell uncounterable when possible.
if (ComputerUtilAbility.getAbilitySourceName(ma).equals("Cavern of Souls") && ma.hasChosenType()
&& sa.getHostCard().getType().getCreatureTypes().contains(ma.getChosenType(0))) {
if (ComputerUtilAbility.getAbilitySourceName(ma).equals("Cavern of Souls")
&& sa.getHostCard().getType().getCreatureTypes().contains(ma.getHostCard().getChosenType())) {
if (toPay == ManaCostShard.COLORLESS && cost.getUnpaidShards().contains(ManaCostShard.GENERIC)) {
// Deprioritize Cavern of Souls, try to pay generic mana with it instead to use the NoCounter ability
continue;
@@ -414,6 +387,7 @@ public class ComputerUtilMana {
// then apply this one
if (!replaceType.isEmpty()) {
for (SpellAbility saMana : replaceAmount) {
Card card = saMana.getHostCard();
if (saMana.hasParam("ReplaceType")) {
// replace color and colorless
String color = saMana.getParam("ReplaceType");
@@ -435,8 +409,8 @@ public class ComputerUtilMana {
// replace color
String color = saMana.getParam("ReplaceColor");
if ("Chosen".equals(color)) {
if (saMana.hasChosenColor()) {
color = MagicColor.toShortString(saMana.getChosenColor());
if (card.hasChosenColor()) {
color = MagicColor.toShortString(card.getChosenColor());
}
}
if (saMana.hasParam("ReplaceOnly")) {
@@ -488,7 +462,7 @@ public class ComputerUtilMana {
int pAmount = AbilityUtils.calculateAmount(trSA.getHostCard(), trSA.getParamOrDefault("Amount", "1"), trSA);
String produced = trSA.getParam("Produced");
if (produced.equals("Chosen")) {
produced = MagicColor.toShortString(trSA.getHostCard().getChosenColor(trSA));
produced = MagicColor.toShortString(trSA.getHostCard().getChosenColor());
}
manaProduced += " " + StringUtils.repeat(produced, pAmount);
} else if (ApiType.ManaReflected.equals(trSA.getApi())) {
@@ -629,13 +603,10 @@ public class ComputerUtilMana {
int testEnergyPool = ai.getCounters(CounterEnumType.ENERGY);
boolean ignoreColor = false, ignoreType = false;
StaticAbility mayPlay = sa.getMayPlay();
if (mayPlay != null) {
if (mayPlay.hasParam("MayPlayIgnoreColor")) {
ignoreColor = true;
} else if (mayPlay.hasParam("MayPlayIgnoreType")) {
ignoreType = true;
}
if (sa.isIgnoreManaCostType()) {
ignoreType = true;
} else if (sa.isIgnoreManaCostColor()) {
ignoreColor = true;
}
List<SpellAbility> paymentList = Lists.newArrayList();

View File

@@ -1,25 +1,9 @@
package forge.ai;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import forge.StaticData;
import forge.card.CardStateName;
import forge.card.MagicColor;
@@ -29,12 +13,7 @@ import forge.game.GameObject;
import forge.game.ability.AbilityFactory;
import forge.game.ability.AbilityKey;
import forge.game.ability.effects.DetachedCardEffect;
import forge.game.card.Card;
import forge.game.card.CardCloneStates;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardFactory;
import forge.game.card.CounterType;
import forge.game.card.*;
import forge.game.card.token.TokenInfo;
import forge.game.combat.Combat;
import forge.game.combat.CombatUtil;
@@ -53,6 +32,13 @@ import forge.item.IPaperCard;
import forge.item.PaperCard;
import forge.util.TextUtil;
import forge.util.collect.FCollectionView;
import org.apache.commons.lang3.StringUtils;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.*;
import java.util.Map.Entry;
public abstract class GameState {
private static final Map<ZoneType, String> ZONES = new HashMap<>();
@@ -89,7 +75,8 @@ public abstract class GameState {
private final Map<Card, Integer> markedDamage = new HashMap<>();
private final Map<Card, List<String>> cardToChosenClrs = new HashMap<>();
private final Map<Card, CardCollection> cardToChosenCards = new HashMap<>();
private final Map<Card, List<String>> cardToChosenTypes = new HashMap<>();
private final Map<Card, String> cardToChosenType = new HashMap<>();
private final Map<Card, String> cardToChosenType2 = new HashMap<>();
private final Map<Card, List<String>> cardToRememberedId = new HashMap<>();
private final Map<Card, List<String>> cardToImprintedId = new HashMap<>();
private final Map<Card, List<String>> cardToMergedCards = new HashMap<>();
@@ -340,16 +327,15 @@ public abstract class GameState {
newText.append("|Damage:").append(c.getDamage());
}
SpellAbility first = c.getFirstSpellAbility();
if (first != null) {
if (first.hasChosenColor()) {
newText.append("|ChosenColor:").append(TextUtil.join(first.getChosenColors(), ","));
}
if (first.hasChosenType()) {
newText.append("|ChosenType:").append(TextUtil.join(first.getChosenType(), ","));
}
if (!c.getChosenColor().isEmpty()) {
newText.append("|ChosenColor:").append(TextUtil.join(c.getChosenColors(), ","));
}
if (!c.getChosenType().isEmpty()) {
newText.append("|ChosenType:").append(c.getChosenType());
}
if (!c.getChosenType2().isEmpty()) {
newText.append("|ChosenType2:").append(c.getChosenType2());
}
if (!c.getNamedCard().isEmpty()) {
newText.append("|NamedCard:").append(c.getNamedCard());
}
@@ -638,7 +624,8 @@ public abstract class GameState {
markedDamage.clear();
cardToChosenClrs.clear();
cardToChosenCards.clear();
cardToChosenTypes.clear();
cardToChosenType.clear();
cardToChosenType2.clear();
cardToMergedCards.clear();
cardToScript.clear();
cardAttackMap.clear();
@@ -733,7 +720,7 @@ public abstract class GameState {
if (persistent) {
produced.put("PersistentMana", "True");
}
final AbilityManaPart abMana = new AbilityManaPart(dummy, null, produced);
final AbilityManaPart abMana = new AbilityManaPart(dummy, produced);
game.getAction().invoke(new Runnable() {
@Override
public void run() {
@@ -828,7 +815,6 @@ public abstract class GameState {
Card exiledWith = idToCard.get(Integer.parseInt(id));
c.setExiledWith(exiledWith);
c.setExiledBy(exiledWith.getController());
exiledWith.addExiledWith(c);
}
}
@@ -1087,13 +1073,19 @@ public abstract class GameState {
Card c = entry.getKey();
List<String> colors = entry.getValue();
c.setChosenColors(colors, c.getFirstSpellAbility());
c.setChosenColors(colors);
}
// Chosen type
for (Entry<Card, List<String>> entry : cardToChosenTypes.entrySet()) {
for (Entry<Card, String> entry : cardToChosenType.entrySet()) {
Card c = entry.getKey();
c.setChosenType(entry.getValue(), c.getFirstSpellAbility());
c.setChosenType(entry.getValue());
}
// Chosen type 2
for (Entry<Card, String> entry : cardToChosenType2.entrySet()) {
Card c = entry.getKey();
c.setChosenType2(entry.getValue());
}
// Named card
@@ -1379,7 +1371,9 @@ public abstract class GameState {
} else if (info.startsWith("ChosenColor:")) {
cardToChosenClrs.put(c, Arrays.asList(info.substring(info.indexOf(':') + 1).split(",")));
} else if (info.startsWith("ChosenType:")) {
cardToChosenTypes.put(c, Arrays.asList(info.substring(info.indexOf(':') + 1).split(",")));
cardToChosenType.put(c, info.substring(info.indexOf(':') + 1));
} else if (info.startsWith("ChosenType2:")) {
cardToChosenType2.put(c, info.substring(info.indexOf(':') + 1));
} else if (info.startsWith("ChosenCards:")) {
CardCollection chosen = new CardCollection();
String[] idlist = info.substring(info.indexOf(':') + 1).split(",");

View File

@@ -1,23 +1,11 @@
package forge.ai;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import forge.LobbyPlayer;
import forge.ai.ability.ProtectAi;
import forge.card.CardStateName;
@@ -33,43 +21,19 @@ import forge.game.GameObject;
import forge.game.GameType;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.*;
import forge.game.card.CardPredicates.Presets;
import forge.game.card.CardUtil;
import forge.game.card.CardView;
import forge.game.card.CounterType;
import forge.game.combat.Combat;
import forge.game.cost.Cost;
import forge.game.cost.CostAdjustment;
import forge.game.cost.CostExile;
import forge.game.cost.CostPart;
import forge.game.cost.CostPartMana;
import forge.game.cost.*;
import forge.game.keyword.KeywordInterface;
import forge.game.mana.Mana;
import forge.game.mana.ManaConversionMatrix;
import forge.game.mana.ManaCostBeingPaid;
import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType;
import forge.game.player.DelayedReveal;
import forge.game.player.Player;
import forge.game.player.PlayerActionConfirmMode;
import forge.game.player.PlayerController;
import forge.game.player.PlayerView;
import forge.game.player.*;
import forge.game.replacement.ReplacementEffect;
import forge.game.spellability.Ability;
import forge.game.spellability.AbilityStatic;
import forge.game.spellability.AbilitySub;
import forge.game.spellability.LandAbility;
import forge.game.spellability.OptionalCost;
import forge.game.spellability.OptionalCostValue;
import forge.game.spellability.Spell;
import forge.game.spellability.SpellAbility;
import forge.game.spellability.SpellAbilityStackInstance;
import forge.game.spellability.TargetChoices;
import forge.game.spellability.*;
import forge.game.trigger.WrappedAbility;
import forge.game.zone.ZoneType;
import forge.item.PaperCard;
@@ -78,6 +42,13 @@ import forge.util.ITriggerEvent;
import forge.util.MyRandom;
import forge.util.collect.FCollection;
import forge.util.collect.FCollectionView;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import java.security.InvalidParameterException;
import java.util.*;
/**
* A prototype for player controller class
@@ -106,7 +77,9 @@ public class PlayerControllerAi extends PlayerController {
if (abilities.size() == 0) {
return null;
}
return abilities.get(0);
else {
return abilities.get(0);
}
}
public AiController getAi() {
@@ -543,12 +516,13 @@ public class PlayerControllerAi extends PlayerController {
}
@Override
public List<String> chooseSomeType(String kindOfType, SpellAbility sa, int min, int max, List<String> validTypes) {
List<String> chosen = ComputerUtil.chooseSomeType(player, kindOfType, sa.getParam("AILogic"), min, max, validTypes);
if (chosen.isEmpty()) {
return validTypes.subList(0, min);
public String chooseSomeType(String kindOfType, SpellAbility sa, Collection<String> validTypes, List<String> invalidTypes, boolean isOptional) {
String chosen = ComputerUtil.chooseSomeType(player, kindOfType, sa.getParam("AILogic"), validTypes, invalidTypes);
if (StringUtils.isBlank(chosen) && !validTypes.isEmpty()) {
chosen = validTypes.iterator().next();
System.err.println("AI has no idea how to choose " + kindOfType +", defaulting to arbitrary element: chosen");
}
getGame().getAction().notifyOfValue(sa, player, chosen.toString(), player);
getGame().getAction().notifyOfValue(sa, player, chosen, player);
return chosen;
}
@@ -1005,11 +979,7 @@ public class PlayerControllerAi extends PlayerController {
} else {
if (sa.isCopied()) {
if (sa.isSpell()) {
if (!sa.getHostCard().isInZone(ZoneType.Stack)) {
sa.setHostCard(player.getGame().getAction().moveToStack(sa.getHostCard(), sa));
} else {
player.getGame().getStackZone().add(sa.getHostCard());
}
player.getGame().getStackZone().add(sa.getHostCard());
}
/* FIXME: the new implementation (below) requires implementing setupNewTargets in the AI controller, among other possible changes, otherwise breaks AI
@@ -1189,7 +1159,7 @@ public class PlayerControllerAi extends PlayerController {
} else if (logic.equals("MostProminentInHumanDeck")) {
return ComputerUtilCard.getMostProminentCardName(oppLibrary);
} else if (logic.equals("MostProminentCreatureInComputerDeck")) {
CardCollectionView cards = CardLists.getValidCards(aiLibrary, "Creature", player, sa.getHostCard(), sa);
CardCollectionView cards = CardLists.getValidCards(aiLibrary, "Creature", player, sa.getHostCard());
return ComputerUtilCard.getMostProminentCardName(cards);
} else if (logic.equals("BestCreatureInComputerDeck")) {
Card bestCreature = ComputerUtilCard.getBestCreatureAI(aiLibrary);
@@ -1197,7 +1167,7 @@ public class PlayerControllerAi extends PlayerController {
} else if (logic.equals("RandomInComputerDeck")) {
return Aggregates.random(aiLibrary).getName();
} else if (logic.equals("MostProminentSpellInComputerDeck")) {
CardCollectionView cards = CardLists.getValidCards(aiLibrary, "Card.Instant,Card.Sorcery", player, sa.getHostCard(), sa);
CardCollectionView cards = CardLists.getValidCards(aiLibrary, "Card.Instant,Card.Sorcery", player, sa.getHostCard());
return ComputerUtilCard.getMostProminentCardName(cards);
} else if (logic.equals("CursedScroll")) {
return SpecialCardAi.CursedScroll.chooseCard(player, sa);

View File

@@ -9,13 +9,7 @@ import forge.ai.ability.TokenAi;
import forge.game.Game;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CardUtil;
import forge.game.card.CounterEnumType;
import forge.game.card.CounterType;
import forge.game.card.*;
import forge.game.combat.Combat;
import forge.game.keyword.Keyword;
import forge.game.phase.PhaseHandler;

View File

@@ -17,17 +17,10 @@
*/
package forge.ai;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.apache.commons.lang3.tuple.Pair;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import forge.ai.ability.AnimateAi;
import forge.card.ColorSet;
import forge.card.MagicColor;
@@ -36,14 +29,7 @@ import forge.game.Game;
import forge.game.GameType;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardFactoryUtil;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CardUtil;
import forge.game.card.CounterEnumType;
import forge.game.card.*;
import forge.game.combat.Combat;
import forge.game.combat.CombatUtil;
import forge.game.cost.CostPart;
@@ -64,6 +50,11 @@ import forge.util.MyRandom;
import forge.util.TextUtil;
import forge.util.maps.LinkedHashMapToAmount;
import forge.util.maps.MapToAmount;
import org.apache.commons.lang3.tuple.Pair;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* Special logic for individual cards
@@ -1000,7 +991,7 @@ public class SpecialCardAi {
return false;
}
String prominentColor = ComputerUtilCard.getMostProminentColor(ai.getCardsIn(ZoneType.Battlefield));
int devotion = AbilityUtils.calculateAmount(sa.getHostCard(), "Count$Devotion." + prominentColor, sa);
int devotion = CardFactoryUtil.xCount(sa.getHostCard(), "Count$Devotion." + prominentColor);
int activationCost = sa.getPayCosts().getTotalMana().getCMC() + (sa.getPayCosts().hasTapCost() ? 1 : 0);
// do not use this SA if devotion to most prominent color is less than its own activation cost + 1 (to actually get advantage)

View File

@@ -1,12 +1,7 @@
package forge.ai;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import forge.card.CardStateName;
import forge.card.ICardFace;
import forge.card.mana.ManaCost;
@@ -26,6 +21,10 @@ import forge.game.spellability.SpellAbility;
import forge.game.spellability.SpellAbilityCondition;
import forge.util.MyRandom;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* Base class for API-specific AI logic
* <p>
@@ -127,7 +126,7 @@ public abstract class SpellAbilityAi {
if (!ComputerUtilCost.checkLifeCost(ai, cost, source, 4, sa)) {
return false;
}
if (!ComputerUtilCost.checkDiscardCost(ai, cost, source, sa)) {
if (!ComputerUtilCost.checkDiscardCost(ai, cost, source)) {
return false;
}
if (!ComputerUtilCost.checkSacrificeCost(ai, cost, source, sa)) {

View File

@@ -1,14 +1,13 @@
package forge.ai;
import java.util.Map;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import forge.ai.ability.*;
import forge.game.ability.ApiType;
import forge.util.ReflectionUtil;
import java.util.Map;
public enum SpellApiToAi {
Converter;
@@ -153,10 +152,9 @@ public enum SpellApiToAi {
.put(ApiType.SetLife, LifeSetAi.class)
.put(ApiType.SetState, SetStateAi.class)
.put(ApiType.Shuffle, ShuffleAi.class)
.put(ApiType.SkipPhase, SkipPhaseAi.class)
.put(ApiType.SkipTurn, SkipTurnAi.class)
.put(ApiType.StoreMap, StoreMapAi.class)
.put(ApiType.StoreSVar, StoreSVarAi.class)
.put(ApiType.Subgame, AlwaysPlayAi.class)
.put(ApiType.Surveil, SurveilAi.class)
.put(ApiType.Tap, TapAi.class)
.put(ApiType.TapAll, TapAllAi.class)

View File

@@ -1,8 +1,5 @@
package forge.ai.ability;
import java.util.List;
import java.util.Map;
import forge.ai.SpellAbilityAi;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
@@ -13,6 +10,9 @@ import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType;
import forge.util.MyRandom;
import java.util.List;
import java.util.Map;
public class ActivateAbilityAi extends SpellAbilityAi {
@Override

View File

@@ -17,15 +17,15 @@
*/
package forge.ai.ability;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import forge.ai.SpellAbilityAi;
import forge.game.ability.AbilityUtils;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
/**
* <p>
* AbilityFactory_Turns class.

View File

@@ -9,11 +9,7 @@ import forge.ai.ComputerUtilCard;
import forge.ai.SpellAbilityAi;
import forge.game.Game;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CounterEnumType;
import forge.game.card.*;
import forge.game.card.token.TokenInfo;
import forge.game.phase.PhaseHandler;
import forge.game.player.Player;
@@ -30,38 +26,40 @@ public class AmassAi extends SpellAbilityAi {
if (!aiArmies.isEmpty()) {
return CardLists.count(aiArmies, CardPredicates.canReceiveCounters(CounterEnumType.P1P1)) > 0;
}
final String tokenScript = "b_0_0_zombie_army";
final int amount = AbilityUtils.calculateAmount(host, sa.getParamOrDefault("Num", "1"), sa);
} else {
final String tokenScript = "b_0_0_zombie_army";
final int amount = AbilityUtils.calculateAmount(host, sa.getParamOrDefault("Num", "1"), sa);
Card token = TokenInfo.getProtoType(tokenScript, sa, false);
Card token = TokenInfo.getProtoType(tokenScript, sa, false);
if (token == null) {
return false;
if (token == null) {
return false;
}
token.setController(ai, 0);
token.setLastKnownZone(ai.getZone(ZoneType.Battlefield));
boolean result = true;
// need to check what the cards would be on the battlefield
// do not attach yet, that would cause Events
CardCollection preList = new CardCollection(token);
game.getAction().checkStaticAbilities(false, Sets.newHashSet(token), preList);
if (token.canReceiveCounters(CounterEnumType.P1P1)) {
token.setCounters(CounterEnumType.P1P1, amount);
}
if (token.isCreature() && token.getNetToughness() < 1) {
result = false;
}
//reset static abilities
game.getAction().checkStaticAbilities(false);
return result;
}
token.setController(ai, 0);
token.setLastKnownZone(ai.getZone(ZoneType.Battlefield));
boolean result = true;
// need to check what the cards would be on the battlefield
// do not attach yet, that would cause Events
CardCollection preList = new CardCollection(token);
game.getAction().checkStaticAbilities(false, Sets.newHashSet(token), preList);
if (token.canReceiveCounters(CounterEnumType.P1P1)) {
token.setCounters(CounterEnumType.P1P1, amount);
}
if (token.isCreature() && token.getNetToughness() < 1) {
result = false;
}
//reset static abilities
game.getAction().checkStaticAbilities(false);
return result;
}
@Override

View File

@@ -1,31 +1,14 @@
package forge.ai.ability;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import forge.ai.AiCardMemory;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilCost;
import forge.ai.ComputerUtilMana;
import forge.ai.SpellAbilityAi;
import forge.ai.*;
import forge.card.CardType;
import forge.game.Game;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.ability.effects.AnimateEffectBase;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CardTraitChanges;
import forge.game.card.CardUtil;
import forge.game.card.*;
import forge.game.cost.CostPutCounter;
import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType;
@@ -36,6 +19,12 @@ import forge.game.staticability.StaticAbilityContinuous;
import forge.game.staticability.StaticAbilityLayer;
import forge.game.zone.ZoneType;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import forge.game.ability.effects.AnimateEffectBase;
/**
* <p>
* AbilityFactoryAnimate class.
@@ -369,6 +358,7 @@ public class AnimateAi extends SpellAbilityAi {
// duplicating AnimateEffect.resolve
final Card source = sa.getHostCard();
final Game game = sa.getActivatingPlayer().getGame();
final Map<String, String> svars = source.getSVars();
final long timestamp = game.getNextTimestamp();
card.setSickness(hasOriginalCardSickness);
@@ -401,7 +391,7 @@ public class AnimateAi extends SpellAbilityAi {
// allow ChosenType - overrides anything else specified
if (types.hasSubtype("ChosenType")) {
types.clear();
types.addAll(sa.getChosenType());
types.add(source.getChosenType());
}
final List<String> keywords = Lists.newArrayList();
@@ -421,8 +411,8 @@ public class AnimateAi extends SpellAbilityAi {
// allow SVar substitution for keywords
for (int i = 0; i < keywords.size(); i++) {
final String k = keywords.get(i);
if (source.hasSVar(k)) {
keywords.add(source.getSVar(k));
if (svars.containsKey(k)) {
keywords.add(svars.get(k));
keywords.remove(k);
}
}
@@ -432,7 +422,7 @@ public class AnimateAi extends SpellAbilityAi {
if (sa.hasParam("Colors")) {
final String colors = sa.getParam("Colors");
if (colors.equals("ChosenColor")) {
tmpDesc = CardUtil.getShortColorsString(sa.getChosenColors());
tmpDesc = CardUtil.getShortColorsString(source.getChosenColors());
} else {
tmpDesc = CardUtil.getShortColorsString(Lists.newArrayList(Arrays.asList(colors.split(","))));
}

View File

@@ -1,39 +1,17 @@
package forge.ai.ability;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import forge.ai.AiCardMemory;
import forge.ai.AiController;
import forge.ai.AiProps;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilAbility;
import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilCombat;
import forge.ai.ComputerUtilCost;
import forge.ai.PlayerControllerAi;
import forge.ai.SpecialCardAi;
import forge.ai.SpellAbilityAi;
import forge.ai.*;
import forge.game.Game;
import forge.game.GameObject;
import forge.game.GlobalRuleChange;
import forge.game.ability.AbilityFactory;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CardUtil;
import forge.game.card.*;
import forge.game.combat.Combat;
import forge.game.combat.CombatUtil;
import forge.game.cost.Cost;
@@ -53,6 +31,8 @@ import forge.game.trigger.TriggerType;
import forge.game.zone.ZoneType;
import forge.util.MyRandom;
import java.util.*;
public class AttachAi extends SpellAbilityAi {
/* (non-Javadoc)

View File

@@ -1,13 +1,13 @@
package forge.ai.ability;
import java.util.List;
import java.util.Map;
import forge.ai.SpellAbilityAi;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import java.util.List;
import java.util.Map;
public class CanPlayAsDrawbackAi extends SpellAbilityAi {
/* (non-Javadoc)

View File

@@ -1,8 +1,5 @@
package forge.ai.ability;
import java.util.Collection;
import java.util.Map;
import forge.ai.SpellAbilityAi;
import forge.game.GameEntity;
import forge.game.player.Player;
@@ -10,6 +7,9 @@ import forge.game.player.PlayerCollection;
import forge.game.player.PlayerPredicates;
import forge.game.spellability.SpellAbility;
import java.util.Collection;
import java.util.Map;
public class ChangeCombatantsAi extends SpellAbilityAi {
/* (non-Javadoc)
* @see forge.card.abilityfactory.SpellAiLogic#canPlayAI(forge.game.player.Player, java.util.Map, forge.card.spellability.SpellAbility)

View File

@@ -1,35 +1,11 @@
package forge.ai.ability;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import forge.ai.AiBlockController;
import forge.ai.AiCardMemory;
import forge.ai.AiController;
import forge.ai.AiProps;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilAbility;
import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilCombat;
import forge.ai.ComputerUtilCost;
import forge.ai.ComputerUtilMana;
import forge.ai.PlayerControllerAi;
import forge.ai.SpecialAiLogic;
import forge.ai.SpecialCardAi;
import forge.ai.SpellAbilityAi;
import forge.ai.SpellApiToAi;
import forge.ai.*;
import forge.card.MagicColor;
import forge.game.Game;
import forge.game.GameObject;
@@ -37,14 +13,8 @@ import forge.game.GlobalRuleChange;
import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.*;
import forge.game.card.CardPredicates.Presets;
import forge.game.card.CardUtil;
import forge.game.card.CounterEnumType;
import forge.game.combat.Combat;
import forge.game.cost.Cost;
import forge.game.cost.CostDiscard;
@@ -59,6 +29,9 @@ import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType;
import forge.util.MyRandom;
import org.apache.commons.lang3.StringUtils;
import java.util.*;
public class ChangeZoneAi extends SpellAbilityAi {
/*
@@ -74,11 +47,9 @@ public class ChangeZoneAi extends SpellAbilityAi {
@Override
protected boolean checkAiLogic(final Player ai, final SpellAbility sa, final String aiLogic) {
Card host = sa.getHostCard();
if (host != null && host.hasSVar("AIPreferenceOverride")) {
if (sa.getHostCard() != null && sa.getHostCard().hasSVar("AIPreferenceOverride")) {
// currently used by SacAndUpgrade logic, might need simplification
host.removeSVar("AIPreferenceOverride");
sa.getHostCard().removeSVar("AIPreferenceOverride");
}
if (aiLogic.equals("BeforeCombat")) {
@@ -92,7 +63,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
} else if (aiLogic.equals("PriorityOptionalCost")) {
boolean highPriority = false;
// if we have more than one of these in hand, might not be worth waiting for optional cost payment on the additional copy
highPriority |= CardLists.filter(ai.getCardsIn(ZoneType.Hand), CardPredicates.nameEquals(host.getName())).size() > 1;
highPriority |= CardLists.filter(ai.getCardsIn(ZoneType.Hand), CardPredicates.nameEquals(sa.getHostCard().getName())).size() > 1;
// if we are in danger in combat, no need to wait to pay the optional cost
highPriority |= ai.getGame().getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS)
&& ai.getGame().getCombat() != null && ComputerUtilCombat.lifeInDanger(ai, ai.getGame().getCombat());
@@ -127,40 +98,6 @@ public class ChangeZoneAi extends SpellAbilityAi {
return true;
} else if (aiLogic.equals("Pongify")) {
return SpecialAiLogic.doPongifyLogic(ai, sa);
} else if (aiLogic.equals("Ashiok")) {
final int loyalty = host.getCurrentLoyalty() - 1;
CardCollectionView choices = new CardCollection();
for (int i = loyalty; i >= 0; i--) {
sa.setXManaCostPaid(i);
choices = ai.getGame().getCardsIn(ZoneType.listValueOf(sa.getParam("Origin")));
choices = CardLists.getValidCards(choices, sa.getParam("ChangeType"), host.getController(), host, sa);
if (!choices.isEmpty()) {
return true;
}
}
return false;
} else if (aiLogic.equals("BestCard")) {
CardCollectionView choices = ai.getGame().getCardsIn(ZoneType.listValueOf(sa.getParam("Origin")));
choices = CardLists.getValidCards(choices, sa.getParam("ChangeType"), host.getController(), host, sa);
if (!choices.isEmpty()) {
return true;
}
} else if (aiLogic.startsWith("DiscardAllAndRetExiled")) {
int numExiledWithSrc = CardLists.filter(ai.getCardsIn(ZoneType.Exile), CardPredicates.isExiledWith(host)).size();
int curHandSize = ai.getCardsIn(ZoneType.Hand).size();
// minimum card advantage unless the hand will be fully reloaded
int minAdv = aiLogic.contains(".minAdv") ? Integer.parseInt(aiLogic.substring(aiLogic.indexOf(".minAdv") + 7)) : 0;
if (numExiledWithSrc > curHandSize) {
if (ComputerUtil.predictThreatenedObjects(ai, sa, true).contains(host)) {
// Try to gain some card advantage if the card will die anyway
// TODO: ideally, should evaluate the hand value and not discard good hands to it
return true;
}
}
return (curHandSize + minAdv - 1 < numExiledWithSrc) || (numExiledWithSrc >= ai.getMaxHandSize());
}
return super.checkAiLogic(ai, sa, aiLogic);
@@ -197,15 +134,8 @@ public class ChangeZoneAi extends SpellAbilityAi {
return SpecialCardAi.MazesEnd.consider(aiPlayer, sa);
} else if (aiLogic.equals("Pongify")) {
return sa.isTargetNumberValid(); // Pre-targeted in checkAiLogic
} else if (aiLogic.equals("Ashiok")) {
return true; // If checkAiLogic returns true, then we should be good to go
} else if (aiLogic.equals("BestCard")) {
return true; // If checkAiLogic returns true, then we should be good to go
} else if (aiLogic.startsWith("DiscardAllAndRetExiled")) {
return true; // If checkAiLogic returns true, then we should be good to go
}
}
if (isHidden(sa)) {
return hiddenOriginCanPlayAI(aiPlayer, sa);
}
@@ -331,7 +261,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
return false;
}
if (!ComputerUtilCost.checkDiscardCost(ai, abCost, source, sa)) {
if (!ComputerUtilCost.checkDiscardCost(ai, abCost, source)) {
for (final CostPart part : abCost.getCostParts()) {
if (part instanceof CostDiscard) {
CostDiscard cd = (CostDiscard) part;
@@ -427,7 +357,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
if (type != null && p == ai) {
// AI only "knows" about his information
list = CardLists.getValidCards(list, type, source.getController(), source, sa);
list = CardLists.getValidCards(list, type, source.getController(), source);
list = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
@@ -440,7 +370,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
}
// TODO: prevent ai seaching its own library when Ob Nixilis, Unshackled is in play
if (origin != null && origin.isKnown()) {
list = CardLists.getValidCards(list, type, source.getController(), source, sa);
list = CardLists.getValidCards(list, type, source.getController(), source);
}
if (!activateForCost && list.isEmpty()) {
@@ -1177,7 +1107,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
// Only care about combatants during combat
if (game.getPhaseHandler().inCombat() && origin.contains(ZoneType.Battlefield)) {
CardCollection newList = CardLists.getValidCards(list, "Card.attacking,Card.blocking", null, null, null);
CardCollection newList = CardLists.getValidCards(list, "Card.attacking,Card.blocking", null, null);
if (!newList.isEmpty() || !sa.isTrigger()) {
list = newList;
}
@@ -1495,11 +1425,12 @@ public class ChangeZoneAi extends SpellAbilityAi {
if (sa.getTargets().size() == 0 || sa.getTargets().size() < tgt.getMinTargets(sa.getHostCard(), sa)) {
sa.resetTargets();
return false;
}
if (!ComputerUtil.shouldCastLessThanMax(ai, source)) {
return false;
} else {
if (!ComputerUtil.shouldCastLessThanMax(ai, source)) {
return false;
}
break;
}
break;
}
list.remove(choice);
@@ -1774,7 +1705,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
Card source = sa.getHostCard();
String definedSac = StringUtils.split(source.getSVar("AIPreference"), "$")[1];
CardCollection listToSac = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), definedSac, ai, source, sa);
CardCollection listToSac = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.restriction(definedSac.split(","), ai, source, sa));
listToSac.sort(Collections.reverseOrder(CardLists.CmcComparatorInv));
CardCollection listToRet = CardLists.filter(ai.getCardsIn(ZoneType.Graveyard), Presets.CREATURES);
@@ -1811,7 +1742,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
String definedGoal = sa.getParam("ChangeType");
boolean anyCMC = !definedGoal.contains(".cmc");
CardCollection listToSac = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), definedSac, ai, source, sa);
CardCollection listToSac = CardLists.filter(ai.getCardsIn(ZoneType.Battlefield), CardPredicates.restriction(definedSac.split(","), ai, source, sa));
listToSac.sort(!sacWorst ? CardLists.CmcComparatorInv : Collections.reverseOrder(CardLists.CmcComparatorInv));
for (Card sacCandidate : listToSac) {
@@ -1825,12 +1756,12 @@ public class ChangeZoneAi extends SpellAbilityAi {
curGoal = definedGoal.replace("X", String.format("%d", goalCMC));
}
CardCollection listGoal = CardLists.getValidCards(ai.getCardsIn(ZoneType.Library), curGoal, ai, source, sa);
CardCollection listGoal = CardLists.filter(ai.getCardsIn(ZoneType.Library), CardPredicates.restriction(curGoal.split(","), ai, source, sa));
if (!anyCMC) {
listGoal = CardLists.getValidCards(listGoal, curGoal, source.getController(), source, sa);
listGoal = CardLists.getValidCards(listGoal, curGoal, source.getController(), source);
} else {
listGoal = CardLists.getValidCards(listGoal, curGoal + (curGoal.contains(".") ? "+" : ".") + "cmcGE" + goalCMC, source.getController(), source, sa);
listGoal = CardLists.getValidCards(listGoal, curGoal + (curGoal.contains(".") ? "+" : ".") + "cmcGE" + goalCMC, source.getController(), source);
}
listGoal = CardLists.filter(listGoal, new Predicate<Card>() {
@@ -2000,8 +1931,9 @@ public class ChangeZoneAi extends SpellAbilityAi {
if (choice != null) {
sa.getTargets().add(choice);
return true;
} else {
return false;
}
return false;
}
private static CardCollection getSafeTargetsIfUnlessCostPaid(Player ai, SpellAbility sa, Iterable<Card> potentialTgts) {

View File

@@ -1,29 +1,12 @@
package forge.ai.ability;
import java.util.Collections;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import forge.ai.AiController;
import forge.ai.AiPlayerPredicates;
import forge.ai.AiProps;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilAbility;
import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilCombat;
import forge.ai.ComputerUtilCost;
import forge.ai.PlayerControllerAi;
import forge.ai.SpecialCardAi;
import forge.ai.SpellAbilityAi;
import forge.ai.*;
import forge.game.Game;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.*;
import forge.game.cost.Cost;
import forge.game.phase.PhaseType;
import forge.game.player.Player;
@@ -34,6 +17,8 @@ import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import forge.util.MyRandom;
import java.util.Collections;
public class ChangeZoneAllAi extends SpellAbilityAi {
@Override
protected boolean canPlayAI(Player ai, SpellAbility sa) {
@@ -51,7 +36,7 @@ public class ChangeZoneAllAi extends SpellAbilityAi {
return false;
}
if (!ComputerUtilCost.checkDiscardCost(ai, abCost, source, sa)) {
if (!ComputerUtilCost.checkDiscardCost(ai, abCost, source)) {
boolean aiLogicAllowsDiscard = sa.hasParam("AILogic") && sa.getParam("AILogic").startsWith("DiscardAll");
if (!aiLogicAllowsDiscard) {
@@ -245,8 +230,25 @@ public class ChangeZoneAllAi extends SpellAbilityAi {
&& !ComputerUtil.isPlayingReanimator(ai);
}
} else if (origin.equals(ZoneType.Exile)) {
// TODO: nothing to do here at the moment
return false;
String logic = sa.getParam("AILogic");
if (logic != null && logic.startsWith("DiscardAllAndRetExiled")) {
int numExiledWithSrc = CardLists.filter(ai.getCardsIn(ZoneType.Exile), CardPredicates.isExiledWith(source)).size();
int curHandSize = ai.getCardsIn(ZoneType.Hand).size();
// minimum card advantage unless the hand will be fully reloaded
int minAdv = logic.contains(".minAdv") ? Integer.parseInt(logic.substring(logic.indexOf(".minAdv") + 7)) : 0;
if (numExiledWithSrc > curHandSize) {
if (ComputerUtil.predictThreatenedObjects(ai, sa, true).contains(source)) {
// Try to gain some card advantage if the card will die anyway
// TODO: ideally, should evaluate the hand value and not discard good hands to it
return true;
}
}
return (curHandSize + minAdv - 1 < numExiledWithSrc) || (numExiledWithSrc >= ai.getMaxHandSize());
}
} else if (origin.equals(ZoneType.Stack)) {
// time stop can do something like this:
// Origin$ Stack | Destination$ Exile | SubAbility$ DBSkip

View File

@@ -1,15 +1,7 @@
package forge.ai.ability;
import java.util.List;
import java.util.Map;
import com.google.common.collect.Lists;
import forge.ai.AiController;
import forge.ai.AiPlayDecision;
import forge.ai.ComputerUtilAbility;
import forge.ai.PlayerControllerAi;
import forge.ai.SpellAbilityAi;
import forge.ai.*;
import forge.game.ability.AbilityUtils;
import forge.game.ability.effects.CharmEffect;
import forge.game.card.Card;
@@ -20,6 +12,9 @@ import forge.util.Aggregates;
import forge.util.MyRandom;
import forge.util.collect.FCollection;
import java.util.List;
import java.util.Map;
public class CharmAi extends SpellAbilityAi {
@Override
protected boolean checkApiLogic(Player ai, SpellAbility sa) {

View File

@@ -10,6 +10,7 @@ import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import forge.ai.ComputerUtilAbility;
import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilCombat;
import forge.ai.SpellAbilityAi;
@@ -20,6 +21,7 @@ import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CardPredicates.Presets;
import forge.game.card.CounterEnumType;
import forge.game.combat.Combat;
import forge.game.keyword.Keyword;
import forge.game.phase.PhaseType;
@@ -64,7 +66,7 @@ public class ChooseCardAi extends SpellAbilityAi {
}
CardCollectionView choices = ai.getGame().getCardsIn(choiceZone);
if (sa.hasParam("Choices")) {
choices = CardLists.getValidCards(choices, sa.getParam("Choices"), host.getController(), host, sa);
choices = CardLists.getValidCards(choices, sa.getParam("Choices"), host.getController(), host);
}
if (sa.hasParam("TargetControls")) {
choices = CardLists.filterControlledBy(choices, ai.getOpponents());
@@ -77,7 +79,7 @@ public class ChooseCardAi extends SpellAbilityAi {
final String filter = aiLogic.equals("Clone") ? "Permanent.YouDontCtrl,Permanent.nonLegendary"
: "Permanent.YouDontCtrl+notnamedVesuva,Permanent.nonLegendary+notnamedVesuva";
choices = CardLists.getValidCards(choices, filter, host.getController(), host, sa);
choices = CardLists.getValidCards(choices, filter, host.getController(), host);
return !choices.isEmpty();
} else if (aiLogic.equals("Never")) {
return false;
@@ -96,9 +98,21 @@ public class ChooseCardAi extends SpellAbilityAi {
return ComputerUtilCombat.damageIfUnblocked(c, ai, combat, true) > ref;
}
});
return !choices.isEmpty();
} else if (aiLogic.equals("Ashiok")) {
final int loyalty = host.getCounters(CounterEnumType.LOYALTY) - 1;
for (int i = loyalty; i >= 0; i--) {
sa.setXManaCostPaid(i);
choices = ai.getGame().getCardsIn(choiceZone);
choices = CardLists.getValidCards(choices, sa.getParam("Choices"), host.getController(), host, sa);
if (!choices.isEmpty()) {
return true;
}
}
return !choices.isEmpty();
} else if (aiLogic.equals("RandomNonLand")) {
return !CardLists.getValidCards(choices, "Card.nonLand", host.getController(), host, sa).isEmpty();
return !CardLists.getValidCards(choices, "Card.nonLand", host.getController(), host).isEmpty();
} else if (aiLogic.equals("Duneblast")) {
CardCollection aiCreatures = ai.getCreaturesInPlay();
CardCollection oppCreatures = ai.getWeakestOpponent().getCreaturesInPlay();
@@ -172,7 +186,7 @@ public class ChooseCardAi extends SpellAbilityAi {
choice = null;
}
} else if ("RandomNonLand".equals(logic)) {
options = CardLists.getValidCards(options, "Card.nonLand", host.getController(), host, sa);
options = CardLists.getValidCards(options, "Card.nonLand", host.getController(), host);
choice = Aggregates.random(options);
} else if (logic.equals("Untap")) {
final String filter = "Permanent.YouCtrl,Permanent.tapped";
@@ -275,8 +289,6 @@ public class ChooseCardAi extends SpellAbilityAi {
// Choose the best (hopefully the fattest, whatever) creature so that hopefully it won't die too easily
choice = ComputerUtilCard.getBestAI(creatures);
}
} else if (logic.equals("NextTurnAttacker")) {
choice = ComputerUtilCard.getBestCreatureToAttackNextTurnAI(ai, options);
} else {
choice = ComputerUtilCard.getBestAI(options);
}

View File

@@ -7,10 +7,7 @@ import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import forge.StaticData;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilCard;
import forge.ai.SpecialCardAi;
import forge.ai.SpellAbilityAi;
import forge.ai.*;
import forge.card.CardDb;
import forge.card.CardRules;
import forge.card.CardSplitType;

View File

@@ -8,9 +8,7 @@ import forge.ai.SpecialCardAi;
import forge.ai.SpellAbilityAi;
import forge.card.MagicColor;
import forge.game.Game;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.*;
import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType;
import forge.game.player.Player;

View File

@@ -1,16 +1,15 @@
package forge.ai.ability;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import com.google.common.collect.Lists;
import forge.ai.SpellAbilityAi;
import forge.game.card.Card;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class ChooseCompanionAi extends SpellAbilityAi {
/* (non-Javadoc)

View File

@@ -1,29 +1,14 @@
package forge.ai.ability;
import java.util.List;
import java.util.Map;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import forge.ai.ComputerUtilAbility;
import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilCost;
import forge.ai.SpecialCardAi;
import forge.ai.SpellAbilityAi;
import forge.ai.SpellApiToAi;
import forge.ai.*;
import forge.card.MagicColor;
import forge.game.Game;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.*;
import forge.game.card.CardPredicates.Presets;
import forge.game.card.CardUtil;
import forge.game.card.CounterEnumType;
import forge.game.combat.Combat;
import forge.game.combat.CombatUtil;
import forge.game.cost.Cost;
@@ -32,11 +17,13 @@ import forge.game.phase.PhaseType;
import forge.game.player.Player;
import forge.game.spellability.AbilitySub;
import forge.game.spellability.SpellAbility;
import forge.game.staticability.StaticAbilityCantBeCast;
import forge.game.zone.ZoneType;
import forge.util.Aggregates;
import forge.util.collect.FCollection;
import java.util.List;
import java.util.Map;
public class ChooseGenericEffectAi extends SpellAbilityAi {
@@ -172,10 +159,10 @@ public class ChooseGenericEffectAi extends SpellAbilityAi {
}
}
// FatespinnerSkipDraw,FatespinnerSkipMain,FatespinnerSkipCombat
if (game.getReplacementHandler().wouldPhaseBeSkipped(player, "Draw")) {
if (player.hasKeyword("Skip your draw step.")) {
return skipDraw;
}
if (game.getReplacementHandler().wouldPhaseBeSkipped(player, "BeginCombat")) {
if (player.hasKeyword("Skip your next combat phase.")) {
return skipCombat;
}
@@ -230,10 +217,11 @@ public class ChooseGenericEffectAi extends SpellAbilityAi {
return allow;
}
SpellAbility firstSpell = imprinted.getFirstSpellAbility();
// check if something would prevent it from casting
if (firstSpell == null || StaticAbilityCantBeCast.cantBeCastAbility(firstSpell, imprinted, owner)) {
return allow;
//if Iona does prevent from casting, allow it to draw
for (final Card io : player.getCardsIn(ZoneType.Battlefield, "Iona, Shield of Emeria")) {
if (CardUtil.getColors(imprinted).hasAnyColor(MagicColor.fromName(io.getChosenColor()))) {
return allow;
}
}
if (dmg == 0) {

View File

@@ -1,17 +1,16 @@
package forge.ai.ability;
import java.util.List;
import java.util.Map;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import forge.ai.ComputerUtil;
import forge.ai.SpellAbilityAi;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import java.util.List;
import java.util.Map;
public class ChoosePlayerAi extends SpellAbilityAi {
@Override
protected boolean canPlayAI(Player ai, SpellAbility sa) {

View File

@@ -10,6 +10,7 @@ import com.google.common.collect.Lists;
import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilCombat;
import forge.ai.ComputerUtilCost;
import forge.ai.SpellAbilityAi;
import forge.game.Game;
import forge.game.GameObject;
@@ -46,7 +47,20 @@ public class ChooseSourceAi extends SpellAbilityAi {
final Card source = sa.getHostCard();
if (abCost != null) {
if (!willPayCosts(ai, sa, abCost, source)) {
// AI currently disabled for these costs
if (!ComputerUtilCost.checkLifeCost(ai, abCost, source, 4, sa)) {
return false;
}
if (!ComputerUtilCost.checkDiscardCost(ai, abCost, source)) {
return false;
}
if (!ComputerUtilCost.checkSacrificeCost(ai, abCost, source, sa)) {
return false;
}
if (!ComputerUtilCost.checkRemoveCounterCost(abCost, source, sa)) {
return false;
}
}
@@ -91,7 +105,7 @@ public class ChooseSourceAi extends SpellAbilityAi {
}
CardCollectionView choices = game.getCardsIn(ZoneType.Battlefield);
if (sa.hasParam("Choices")) {
choices = CardLists.getValidCards(choices, sa.getParam("Choices"), host.getController(), host, sa);
choices = CardLists.getValidCards(choices, sa.getParam("Choices"), host.getController(), host);
}
final Combat combat = game.getCombat();
choices = CardLists.filter(choices, new Predicate<Card>() {
@@ -141,26 +155,27 @@ public class ChooseSourceAi extends SpellAbilityAi {
Card bestCreature = ComputerUtilCard.getBestCreatureAI(permanentSources);
if (bestCreature != null) {
return bestCreature;
}
// No optimal creature was found above, so try to broaden the choice.
if (!Iterables.isEmpty(options)) {
List<Card> oppCreatures = CardLists.filter(options, Predicates.and(CardPredicates.Presets.CREATURES,
Predicates.not(CardPredicates.isOwner(aiChoser))));
List<Card> aiNonCreatures = CardLists.filter(options, Predicates.and(Predicates.not(CardPredicates.Presets.CREATURES),
CardPredicates.Presets.PERMANENTS, CardPredicates.isOwner(aiChoser)));
} else {
// No optimal creature was found above, so try to broaden the choice.
if (!Iterables.isEmpty(options)) {
List<Card> oppCreatures = CardLists.filter(options, Predicates.and(CardPredicates.Presets.CREATURES,
Predicates.not(CardPredicates.isOwner(aiChoser))));
List<Card> aiNonCreatures = CardLists.filter(options, Predicates.and(Predicates.not(CardPredicates.Presets.CREATURES),
CardPredicates.Presets.PERMANENTS, CardPredicates.isOwner(aiChoser)));
if (!oppCreatures.isEmpty()) {
return ComputerUtilCard.getBestCreatureAI(oppCreatures);
} else if (!aiNonCreatures.isEmpty()) {
return Aggregates.random(aiNonCreatures);
} else {
return Aggregates.random(options);
if (!oppCreatures.isEmpty()) {
return ComputerUtilCard.getBestCreatureAI(oppCreatures);
} else if (!aiNonCreatures.isEmpty()) {
return Aggregates.random(aiNonCreatures);
} else {
return Aggregates.random(options);
}
} else if (!game.getStack().isEmpty()) {
// No permanent for the AI to choose. Should normally not happen unless using dev mode or something,
// but when it does happen, choose the top card on stack if possible (generally it'll be the SA
// source) in order to choose at least something, or the game will hang.
return game.getStack().peekAbility().getHostCard();
}
} else if (!game.getStack().isEmpty()) {
// No permanent for the AI to choose. Should normally not happen unless using dev mode or something,
// but when it does happen, choose the top card on stack if possible (generally it'll be the SA
// source) in order to choose at least something, or the game will hang.
return game.getStack().peekAbility().getHostCard();
}
// Should never get here

View File

@@ -1,23 +1,11 @@
package forge.ai.ability;
import java.util.HashSet;
import java.util.Set;
import com.google.common.base.Predicates;
import forge.ai.AiCardMemory;
import forge.ai.ComputerUtilAbility;
import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilMana;
import forge.ai.SpellAbilityAi;
import forge.ai.*;
import forge.card.CardType;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.*;
import forge.game.keyword.Keyword;
import forge.game.phase.PhaseType;
import forge.game.player.Player;
@@ -25,6 +13,9 @@ import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import forge.util.Aggregates;
import java.util.HashSet;
import java.util.Set;
public class ChooseTypeAi extends SpellAbilityAi {
@Override
protected boolean canPlayAI(Player aiPlayer, SpellAbility sa) {

View File

@@ -4,8 +4,8 @@ package forge.ai.ability;
import java.util.Map;
import com.google.common.collect.Iterables;
import forge.ai.ComputerUtilCard;
import forge.ai.SpellAbilityAi;
import forge.game.card.Card;
import forge.game.card.CardCollectionView;

View File

@@ -1,8 +1,5 @@
package forge.ai.ability;
import java.util.List;
import java.util.Map;
import forge.ai.ComputerUtilCard;
import forge.ai.SpellAbilityAi;
import forge.game.Game;
@@ -17,6 +14,9 @@ import forge.game.player.PlayerActionConfirmMode;
import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import java.util.List;
import java.util.Map;
public class CloneAi extends SpellAbilityAi {
@Override
@@ -124,11 +124,11 @@ public class CloneAi extends SpellAbilityAi {
private boolean cloneTgtAI(final SpellAbility sa) {
// Specific logic for cards
if ("CloneAttacker".equals(sa.getParam("AILogic"))) {
CardCollection valid = CardLists.getValidCards(sa.getHostCard().getController().getCardsIn(ZoneType.Battlefield), sa.getParam("ValidTgts"), sa.getHostCard().getController(), sa.getHostCard(), sa);
CardCollection valid = CardLists.getValidCards(sa.getHostCard().getController().getCardsIn(ZoneType.Battlefield), sa.getParam("ValidTgts"), sa.getHostCard().getController(), sa.getHostCard());
sa.getTargets().add(ComputerUtilCard.getBestCreatureAI(valid));
return true;
} else if ("CloneBestCreature".equals(sa.getParam("AILogic"))) {
CardCollection valid = CardLists.getValidCards(sa.getHostCard().getController().getGame().getCardsIn(ZoneType.Battlefield), sa.getParam("ValidTgts"), sa.getHostCard().getController(), sa.getHostCard(), sa);
CardCollection valid = CardLists.getValidCards(sa.getHostCard().getController().getGame().getCardsIn(ZoneType.Battlefield), sa.getParam("ValidTgts"), sa.getHostCard().getController(), sa.getHostCard());
sa.getTargets().add(ComputerUtilCard.getBestCreatureAI(valid));
return true;
}

View File

@@ -140,7 +140,7 @@ public class ControlExchangeAi extends SpellAbilityAi {
return false;
}
if (aiWorst != bestFirstTgt) {
if (aiWorst != null && aiWorst != bestFirstTgt) {
if (bestFirstTgt.isCreature() && aiWorst.isCreature()) {
if ((ComputerUtilCard.evaluateCreature(bestFirstTgt) > ComputerUtilCard.evaluateCreature(aiWorst) + creatureThreshold) || sa.isMandatory()) {
sa.getTargets().add(aiWorst);

View File

@@ -268,8 +268,9 @@ public class ControlGainAi extends SpellAbilityAi {
List<Card> list = CardLists.getTargetableCards(ai.getCardsIn(ZoneType.Battlefield), sa);
if (list.isEmpty()) {
return false;
} else {
sa.getTargets().add(ComputerUtilCard.getWorstAI(list));
}
sa.getTargets().add(ComputerUtilCard.getWorstAI(list));
}
}

View File

@@ -1,29 +1,14 @@
package forge.ai.ability;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import forge.ai.AiPlayDecision;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilAbility;
import forge.ai.ComputerUtilCard;
import forge.ai.SpecialCardAi;
import forge.ai.SpellAbilityAi;
import forge.ai.*;
import forge.game.Game;
import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.*;
import forge.game.card.CardPredicates.Presets;
import forge.game.card.CardUtil;
import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType;
import forge.game.player.Player;
@@ -32,6 +17,10 @@ import forge.game.player.PlayerCollection;
import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import java.util.Collection;
import java.util.List;
import java.util.Map;
public class CopyPermanentAi extends SpellAbilityAi {
@Override
protected boolean canPlayAI(Player aiPlayer, SpellAbility sa) {
@@ -184,7 +173,7 @@ public class CopyPermanentAi extends SpellAbilityAi {
} else if (sa.hasParam("Choices")) {
// only check for options, does not select there
CardCollectionView choices = game.getCardsIn(ZoneType.Battlefield);
choices = CardLists.getValidCards(choices, sa.getParam("Choices"), activator, host, sa);
choices = CardLists.getValidCards(choices, sa.getParam("Choices"), activator, host);
Collection<Card> betterChoices = getBetterOptions(aiPlayer, sa, choices, !mandatory);
if (betterChoices.isEmpty()) {
return mandatory;

View File

@@ -1,15 +1,6 @@
package forge.ai.ability;
import java.util.List;
import java.util.Map;
import forge.ai.AiCardMemory;
import forge.ai.AiPlayDecision;
import forge.ai.AiProps;
import forge.ai.ComputerUtilCard;
import forge.ai.PlayerControllerAi;
import forge.ai.SpecialCardAi;
import forge.ai.SpellAbilityAi;
import forge.ai.*;
import forge.game.Game;
import forge.game.ability.ApiType;
import forge.game.player.Player;
@@ -19,6 +10,9 @@ import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetRestrictions;
import forge.util.MyRandom;
import java.util.List;
import java.util.Map;
public class CopySpellAbilityAi extends SpellAbilityAi {
@Override
@@ -68,7 +62,7 @@ public class CopySpellAbilityAi extends SpellAbilityAi {
}
}
if (top.isWrapper() || top.isActivatedAbility()) {
if (top.isWrapper() || !(top instanceof SpellAbility || top.isActivatedAbility())) {
// Shouldn't even try with triggered or wrapped abilities at this time, will crash
return false;
} else if (top.getApi() == ApiType.CopySpellAbility) {

View File

@@ -1,19 +1,6 @@
package forge.ai.ability;
import java.util.Iterator;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import forge.ai.AiController;
import forge.ai.AiProps;
import forge.ai.ComputerUtilAbility;
import forge.ai.ComputerUtilCost;
import forge.ai.ComputerUtilMana;
import forge.ai.PlayerControllerAi;
import forge.ai.SpecialCardAi;
import forge.ai.SpellAbilityAi;
import forge.ai.*;
import forge.game.Game;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
@@ -29,6 +16,11 @@ import forge.game.spellability.SpellAbilityStackInstance;
import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType;
import forge.util.MyRandom;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import java.util.Iterator;
public class CounterAi extends SpellAbilityAi {

View File

@@ -22,12 +22,7 @@ import java.util.List;
import com.google.common.base.Predicate;
import forge.ai.ComputerUtilCard;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.CounterEnumType;
import forge.game.card.CounterType;
import forge.game.card.*;
import forge.game.keyword.Keyword;
import forge.util.Aggregates;

View File

@@ -1,22 +1,13 @@
package forge.ai.ability;
import java.util.List;
import java.util.Map;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilCard;
import forge.ai.SpellAbilityAi;
import forge.game.Game;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CardUtil;
import forge.game.card.CounterEnumType;
import forge.game.card.CounterType;
import forge.game.card.*;
import forge.game.keyword.Keyword;
import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType;
@@ -26,6 +17,9 @@ import forge.game.zone.ZoneType;
import forge.util.MyRandom;
import forge.util.collect.FCollection;
import java.util.List;
import java.util.Map;
public class CountersMoveAi extends SpellAbilityAi {
@Override
protected boolean checkApiLogic(final Player ai, final SpellAbility sa) {

View File

@@ -1,43 +1,19 @@
package forge.ai.ability;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import forge.ai.AiCardMemory;
import forge.ai.AiProps;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilAbility;
import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilCombat;
import forge.ai.ComputerUtilCost;
import forge.ai.PlayerControllerAi;
import forge.ai.SpecialAiLogic;
import forge.ai.SpecialCardAi;
import forge.ai.SpellAbilityAi;
import forge.ai.*;
import forge.card.CardStateName;
import forge.game.Game;
import forge.game.GameEntity;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CounterEnumType;
import forge.game.card.CounterType;
import forge.game.card.*;
import forge.game.combat.Combat;
import forge.game.combat.CombatUtil;
import forge.game.cost.Cost;
import forge.game.cost.CostPart;
import forge.game.cost.CostPutCounter;
import forge.game.cost.CostRemoveCounter;
import forge.game.cost.CostSacrifice;
import forge.game.cost.*;
import forge.game.keyword.Keyword;
import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType;
@@ -51,6 +27,10 @@ import forge.game.zone.ZoneType;
import forge.util.Aggregates;
import forge.util.MyRandom;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class CountersPutAi extends SpellAbilityAi {
/*

View File

@@ -1,10 +1,7 @@
package forge.ai.ability;
import java.util.List;
import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
import forge.ai.ComputerUtilCost;
import forge.ai.SpellAbilityAi;
import forge.game.ability.AbilityUtils;
@@ -21,6 +18,8 @@ import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType;
import forge.util.MyRandom;
import java.util.List;
public class CountersPutAllAi extends SpellAbilityAi {
@Override
protected boolean canPlayAI(Player ai, SpellAbility sa) {
@@ -39,11 +38,11 @@ public class CountersPutAllAi extends SpellAbilityAi {
final TargetRestrictions tgt = sa.getTargetRestrictions();
if ("OwnCreatsAndOtherPWs".equals(sa.getParam("AILogic"))) {
hList = CardLists.getValidCards(ai.getWeakestOpponent().getCardsIn(ZoneType.Battlefield), "Creature.YouCtrl,Planeswalker.YouCtrl+Other", source.getController(), source, sa);
cList = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), "Creature.YouCtrl,Planeswalker.YouCtrl+Other", source.getController(), source, sa);
hList = CardLists.getValidCards(ai.getWeakestOpponent().getCardsIn(ZoneType.Battlefield), "Creature.YouCtrl,Planeswalker.YouCtrl+Other", source.getController(), source);
cList = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), "Creature.YouCtrl,Planeswalker.YouCtrl+Other", source.getController(), source);
} else {
hList = CardLists.getValidCards(ai.getWeakestOpponent().getCardsIn(ZoneType.Battlefield), valid, source.getController(), source, sa);
cList = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), valid, source.getController(), source, sa);
hList = CardLists.getValidCards(ai.getWeakestOpponent().getCardsIn(ZoneType.Battlefield), valid, source.getController(), source);
cList = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), valid, source.getController(), source);
}
if (abCost != null) {
@@ -52,7 +51,7 @@ public class CountersPutAllAi extends SpellAbilityAi {
return false;
}
if (!ComputerUtilCost.checkDiscardCost(ai, abCost, source, sa)) {
if (!ComputerUtilCost.checkDiscardCost(ai, abCost, source)) {
return false;
}

View File

@@ -17,27 +17,21 @@
*/
package forge.ai.ability;
import java.util.List;
import java.util.Map;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilCard;
import forge.ai.SpellAbilityAi;
import forge.game.Game;
import forge.game.GlobalRuleChange;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CounterEnumType;
import forge.game.card.CounterType;
import forge.game.card.*;
import forge.game.keyword.Keyword;
import forge.game.player.Player;
import forge.game.player.PlayerController.BinaryChoiceType;
import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetRestrictions;
import java.util.List;
import java.util.Map;
/**
* <p>
* AbilityFactory_PutOrRemoveCountersAi class.

View File

@@ -1,10 +1,6 @@
package forge.ai.ability;
import java.util.List;
import java.util.Map;
import com.google.common.base.Predicates;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilCost;
@@ -13,13 +9,7 @@ import forge.game.Game;
import forge.game.GameEntity;
import forge.game.GlobalRuleChange;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CounterEnumType;
import forge.game.card.CounterType;
import forge.game.card.*;
import forge.game.keyword.Keyword;
import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType;
@@ -28,6 +18,9 @@ import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType;
import java.util.List;
import java.util.Map;
public class CountersRemoveAi extends SpellAbilityAi {
@Override

View File

@@ -1,7 +1,6 @@
package forge.ai.ability;
import com.google.common.collect.Iterables;
import forge.ai.ComputerUtilCombat;
import forge.ai.SpellAbilityAi;
import forge.game.Game;

View File

@@ -1,12 +1,7 @@
package forge.ai.ability;
import com.google.common.base.Predicate;
import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilCombat;
import forge.ai.ComputerUtilCost;
import forge.ai.ComputerUtilMana;
import forge.ai.SpellAbilityAi;
import forge.ai.*;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
import forge.game.card.CardCollection;

View File

@@ -1,39 +1,16 @@
package forge.ai.ability;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import forge.ai.AiController;
import forge.ai.AiProps;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilAbility;
import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilCombat;
import forge.ai.ComputerUtilCost;
import forge.ai.ComputerUtilMana;
import forge.ai.PlayerControllerAi;
import forge.ai.SpecialCardAi;
import forge.ai.SpellAbilityAi;
import forge.ai.*;
import forge.card.mana.ManaCost;
import forge.game.Game;
import forge.game.GameObject;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardFactoryUtil;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CounterEnumType;
import forge.game.card.*;
import forge.game.cost.Cost;
import forge.game.cost.CostPartMana;
import forge.game.cost.CostRemoveCounter;
@@ -49,6 +26,12 @@ import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType;
import forge.util.Aggregates;
import forge.util.MyRandom;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
public class DamageDealAi extends DamageAiBase {
@Override
@@ -178,7 +161,7 @@ public class DamageDealAi extends DamageAiBase {
}
} else if ("WildHunt".equals(logic)) {
// This dummy ability will just deal 0 damage, but holds the logic for the AI for Master of Wild Hunt
List<Card> wolves = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), "Creature.Wolf+untapped+YouCtrl+Other", ai, source, sa);
List<Card> wolves = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), "Creature.Wolf+untapped+YouCtrl+Other", ai, source);
dmg = Aggregates.sum(wolves, CardPredicates.Accessors.fnGetNetPower);
} else if ("Triskelion".equals(logic)) {
final int n = source.getCounters(CounterEnumType.P1P1);
@@ -245,7 +228,7 @@ public class DamageDealAi extends DamageAiBase {
return false;
}
if ("DiscardLands".equals(sa.getParam("AILogic")) && !ComputerUtilCost.checkDiscardCost(ai, abCost, source, sa)) {
if ("DiscardLands".equals(sa.getParam("AILogic")) && !ComputerUtilCost.checkDiscardCost(ai, abCost, source)) {
return false;
}

View File

@@ -1,12 +1,6 @@
package forge.ai.ability;
import java.util.ArrayList;
import java.util.List;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilCombat;
import forge.ai.SpellAbilityAi;
import forge.ai.*;
import forge.game.Game;
import forge.game.GameObject;
import forge.game.ability.AbilityUtils;
@@ -25,6 +19,9 @@ import forge.game.spellability.TargetChoices;
import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType;
import java.util.ArrayList;
import java.util.List;
public class DamagePreventAi extends SpellAbilityAi {
@Override
@@ -36,7 +33,20 @@ public class DamagePreventAi extends SpellAbilityAi {
final Cost cost = sa.getPayCosts();
if (!willPayCosts(ai, sa, cost, hostCard)) {
// temporarily disabled until better AI
if (!ComputerUtilCost.checkLifeCost(ai, cost, hostCard, 4, sa)) {
return false;
}
if (!ComputerUtilCost.checkDiscardCost(ai, cost, hostCard)) {
return false;
}
if (!ComputerUtilCost.checkSacrificeCost(ai, cost, hostCard, sa)) {
return false;
}
if (!ComputerUtilCost.checkRemoveCounterCost(cost, hostCard, sa)) {
return false;
}

View File

@@ -1,5 +1,7 @@
package forge.ai.ability;
import forge.ai.ComputerUtilCost;
import forge.ai.SpellAbilityAi;
import forge.game.card.Card;
import forge.game.cost.Cost;
@@ -20,7 +22,19 @@ public class DamagePreventAllAi extends SpellAbilityAi {
final Cost cost = sa.getPayCosts();
// temporarily disabled until better AI
if (!willPayCosts(ai, sa, cost, hostCard)) {
if (!ComputerUtilCost.checkLifeCost(ai, cost, hostCard, 4, sa)) {
return false;
}
if (!ComputerUtilCost.checkDiscardCost(ai, cost, hostCard)) {
return false;
}
if (!ComputerUtilCost.checkSacrificeCost(ai, cost, hostCard, sa)) {
return false;
}
if (!ComputerUtilCost.checkRemoveCounterCost(cost, hostCard, sa)) {
return false;
}

View File

@@ -1,9 +1,5 @@
package forge.ai.ability;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
@@ -25,6 +21,10 @@ import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class DebuffAi extends SpellAbilityAi {
// *************************************************************************
// ***************************** Debuff ************************************

View File

@@ -1,14 +1,7 @@
package forge.ai.ability;
import com.google.common.base.Predicate;
import forge.ai.AiController;
import forge.ai.AiPlayDecision;
import forge.ai.ComputerUtilAbility;
import forge.ai.ComputerUtilMana;
import forge.ai.PlayerControllerAi;
import forge.ai.SpellAbilityAi;
import forge.ai.SpellApiToAi;
import forge.ai.*;
import forge.card.mana.ManaCost;
import forge.game.ability.ApiType;
import forge.game.card.Card;

View File

@@ -1,23 +1,10 @@
package forge.ai.ability;
import com.google.common.base.Predicate;
import forge.ai.AiController;
import forge.ai.AiProps;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilCost;
import forge.ai.PlayerControllerAi;
import forge.ai.SpecialAiLogic;
import forge.ai.SpecialCardAi;
import forge.ai.SpellAbilityAi;
import forge.ai.*;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CounterEnumType;
import forge.game.card.*;
import forge.game.cost.Cost;
import forge.game.cost.CostPart;
import forge.game.cost.CostSacrifice;

View File

@@ -2,13 +2,7 @@ package forge.ai.ability;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import forge.ai.AiBlockController;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilCombat;
import forge.ai.ComputerUtilCost;
import forge.ai.SpellAbilityAi;
import forge.ai.*;
import forge.card.MagicColor;
import forge.game.card.Card;
import forge.game.card.CardCollection;

View File

@@ -5,12 +5,7 @@ import java.util.Map;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilAbility;
import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilCost;
import forge.ai.SpecialCardAi;
import forge.ai.SpellAbilityAi;
import forge.ai.*;
import forge.game.Game;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card;

View File

@@ -1,7 +1,5 @@
package forge.ai.ability;
import java.util.List;
import forge.ai.ComputerUtilCost;
import forge.ai.SpellAbilityAi;
import forge.game.card.Card;
@@ -14,6 +12,8 @@ import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import forge.util.MyRandom;
import java.util.List;
public class DigUntilAi extends SpellAbilityAi {
@Override

View File

@@ -1,13 +1,6 @@
package forge.ai.ability;
import java.util.List;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilAbility;
import forge.ai.ComputerUtilCost;
import forge.ai.ComputerUtilMana;
import forge.ai.SpecialCardAi;
import forge.ai.SpellAbilityAi;
import forge.ai.*;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
import forge.game.card.CardCollectionView;
@@ -22,6 +15,8 @@ import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType;
import forge.util.MyRandom;
import java.util.List;
public class DiscardAi extends SpellAbilityAi {
@Override
@@ -32,11 +27,26 @@ public class DiscardAi extends SpellAbilityAi {
final Cost abCost = sa.getPayCosts();
final String aiLogic = sa.getParamOrDefault("AILogic", "");
// temporarily disabled until better AI
if (!willPayCosts(ai, sa, abCost, source)) {
return false;
}
if (abCost != null) {
// AI currently disabled for these costs
if (!ComputerUtilCost.checkSacrificeCost(ai, abCost, source, sa)) {
return false;
}
if (!ComputerUtilCost.checkLifeCost(ai, abCost, source, 4, sa)) {
return false;
}
if (!ComputerUtilCost.checkDiscardCost(ai, abCost, source)) {
return false;
}
if (!ComputerUtilCost.checkRemoveCounterCost(abCost, source, sa)) {
return false;
}
}
if ("Chandra, Flamecaller".equals(sourceName)) {
final int hand = ai.getCardsIn(ZoneType.Hand).size();
return MyRandom.getRandom().nextFloat() < (1.0 / (1 + hand));

View File

@@ -1,7 +1,5 @@
package forge.ai.ability;
import java.util.List;
import forge.ai.SpellAbilityAi;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
@@ -10,6 +8,8 @@ import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetRestrictions;
import forge.util.MyRandom;
import java.util.List;
public class DrainManaAi extends SpellAbilityAi {
@Override

View File

@@ -18,26 +18,14 @@
*/
package forge.ai.ability;
import forge.ai.AiCostDecision;
import forge.ai.AiProps;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilAbility;
import forge.ai.ComputerUtilCost;
import forge.ai.ComputerUtilMana;
import forge.ai.PlayerControllerAi;
import forge.ai.SpecialCardAi;
import forge.ai.SpellAbilityAi;
import forge.ai.*;
import forge.game.Game;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.card.Card;
import forge.game.card.CounterEnumType;
import forge.game.card.CounterType;
import forge.game.cost.Cost;
import forge.game.cost.CostDiscard;
import forge.game.cost.CostPart;
import forge.game.cost.CostPayLife;
import forge.game.cost.PaymentDecision;
import forge.game.cost.*;
import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType;
import forge.game.player.Player;
@@ -102,7 +90,7 @@ public class DrawAi extends SpellAbilityAi {
return false;
}
if (!ComputerUtilCost.checkDiscardCost(ai, cost, source,sa)) {
if (!ComputerUtilCost.checkDiscardCost(ai, cost, source)) {
AiCostDecision aiDecisions = new AiCostDecision(ai, sa);
for (final CostPart part : cost.getCostParts()) {
if (part instanceof CostDiscard) {
@@ -265,8 +253,8 @@ public class DrawAi extends SpellAbilityAi {
if (sa.getPayCosts().hasSpecificCostType(CostPayLife.class)) {
// [Necrologia, Pay X Life : Draw X Cards]
// Don't draw more than what's "safe" and don't risk a near death experience
boolean aggroAI = (((PlayerControllerAi) ai.getController()).getAi()).getBooleanProperty(AiProps.PLAY_AGGRO);
while ((ComputerUtil.aiLifeInDanger(ai, aggroAI, numCards) && (numCards > 0))) {
// Maybe would be better to check for "serious danger" and take more risk?
while ((ComputerUtil.aiLifeInDanger(ai, false, numCards) && (numCards > 0))) {
numCards--;
}
}

View File

@@ -1,28 +1,12 @@
package forge.ai.ability;
import java.util.List;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import forge.ai.AiCardMemory;
import forge.ai.AiController;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilCombat;
import forge.ai.ComputerUtilMana;
import forge.ai.PlayerControllerAi;
import forge.ai.SpecialCardAi;
import forge.ai.SpellAbilityAi;
import forge.ai.SpellApiToAi;
import forge.ai.*;
import forge.game.Game;
import forge.game.ability.ApiType;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.*;
import forge.game.combat.Combat;
import forge.game.combat.CombatUtil;
import forge.game.phase.PhaseHandler;
@@ -34,6 +18,8 @@ import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType;
import forge.util.MyRandom;
import java.util.List;
public class EffectAi extends SpellAbilityAi {
@Override
protected boolean canPlayAI(final Player ai,final SpellAbility sa) {

View File

@@ -1,17 +1,8 @@
package forge.ai.ability;
import forge.ai.AiController;
import forge.ai.AiProps;
import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilMana;
import forge.ai.PlayerControllerAi;
import forge.ai.SpellAbilityAi;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.ai.*;
import forge.game.card.*;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;

View File

@@ -1,13 +1,6 @@
package forge.ai.ability;
import java.util.List;
import java.util.Map;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilAbility;
import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilCombat;
import forge.ai.SpellAbilityAi;
import forge.ai.*;
import forge.game.ability.AbilityFactory;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
@@ -23,6 +16,9 @@ import forge.game.trigger.Trigger;
import forge.game.trigger.TriggerType;
import forge.util.MyRandom;
import java.util.List;
import java.util.Map;
public class FightAi extends SpellAbilityAi {
@Override
protected boolean checkAiLogic(final Player ai, final SpellAbility sa, final String aiLogic) {

View File

@@ -1,13 +1,7 @@
package forge.ai.ability;
import java.util.List;
import forge.ai.AiCardMemory;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilCombat;
import forge.ai.PlayerControllerAi;
import forge.ai.SpellAbilityAi;
import forge.ai.*;
import forge.game.Game;
import forge.game.GameObject;
import forge.game.card.Card;
@@ -18,6 +12,8 @@ import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import forge.util.Aggregates;
import java.util.List;
public class FogAi extends SpellAbilityAi {
/* (non-Javadoc)

View File

@@ -1,11 +1,6 @@
package forge.ai.ability;
import forge.ai.AiController;
import forge.ai.AiPlayDecision;
import forge.ai.ComputerUtilCost;
import forge.ai.PlayerControllerAi;
import forge.ai.SpellAbilityAi;
import forge.ai.SpellApiToAi;
import forge.ai.*;
import forge.game.player.Player;
import forge.game.spellability.AbilitySub;
import forge.game.spellability.SpellAbility;

View File

@@ -3,7 +3,6 @@ package forge.ai.ability;
import java.util.Map;
import com.google.common.collect.Iterables;
import forge.ai.SpellAbilityAi;
import forge.game.card.Card;
import forge.game.card.CounterEnumType;

View File

@@ -1,11 +1,6 @@
package forge.ai.ability;
import forge.ai.AiProps;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilAbility;
import forge.ai.ComputerUtilCombat;
import forge.ai.PlayerControllerAi;
import forge.ai.SpellAbilityAi;
import forge.ai.*;
import forge.game.Game;
import forge.game.card.Card;
import forge.game.keyword.Keyword;

View File

@@ -1,12 +1,7 @@
package forge.ai.ability;
import com.google.common.collect.Iterables;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilAbility;
import forge.ai.ComputerUtilCombat;
import forge.ai.ComputerUtilCost;
import forge.ai.SpellAbilityAi;
import forge.ai.*;
import forge.game.Game;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
@@ -43,14 +38,14 @@ public class LifeGainAi extends SpellAbilityAi {
if (!lifeCritical) {
// return super.willPayCosts(ai, sa, cost, source);
if (!ComputerUtilCost.checkSacrificeCost(ai, cost, source, sa, false)) {
if (!ComputerUtilCost.checkSacrificeCost(ai, cost, source, sa,false)) {
return false;
}
if (!ComputerUtilCost.checkLifeCost(ai, cost, source, 4, sa)) {
return false;
}
if (!ComputerUtilCost.checkDiscardCost(ai, cost, source, sa)) {
if (!ComputerUtilCost.checkDiscardCost(ai, cost, source)) {
return false;
}

View File

@@ -1,27 +1,12 @@
package forge.ai.ability;
import java.util.Arrays;
import java.util.List;
import com.google.common.base.Predicates;
import forge.ai.AiPlayDecision;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilAbility;
import forge.ai.ComputerUtilCost;
import forge.ai.ComputerUtilMana;
import forge.ai.PlayerControllerAi;
import forge.ai.SpellAbilityAi;
import forge.ai.*;
import forge.card.ColorSet;
import forge.card.MagicColor;
import forge.card.mana.ManaCost;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CounterEnumType;
import forge.game.card.CounterType;
import forge.game.card.*;
import forge.game.cost.CostPart;
import forge.game.cost.CostRemoveCounter;
import forge.game.keyword.Keyword;
@@ -32,6 +17,9 @@ import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import forge.util.Aggregates;
import java.util.Arrays;
import java.util.List;
public class ManaEffectAi extends SpellAbilityAi {
/*

View File

@@ -1,11 +1,7 @@
package forge.ai.ability;
import java.util.List;
import java.util.Map;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilCost;
@@ -28,6 +24,9 @@ import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import forge.util.MyRandom;
import java.util.List;
import java.util.Map;
/**
* Created by friarsol on 1/23/15.
*/
@@ -142,7 +141,7 @@ public class ManifestAi extends SpellAbilityAi {
}
CardCollection choices = new CardCollection(game.getCardsIn(choiceZone));
if (sa.hasParam("Choices")) {
choices = CardLists.getValidCards(choices, sa.getParam("Choices"), ai, host, sa);
choices = CardLists.getValidCards(choices, sa.getParam("Choices"), ai, host);
}
if (choices.isEmpty()) {
return false;

View File

@@ -1,7 +1,6 @@
package forge.ai.ability;
import com.google.common.base.Predicates;
import forge.ai.SpellAbilityAi;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;

View File

@@ -1,13 +1,7 @@
package forge.ai.ability;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilCost;
import forge.ai.SpecialCardAi;
@@ -25,6 +19,11 @@ import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
public class MillAi extends SpellAbilityAi {
@Override

View File

@@ -1,16 +1,9 @@
package forge.ai.ability;
import java.util.List;
import java.util.Map;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import forge.ai.AiCardMemory;
import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilCombat;
import forge.ai.SpellAbilityAi;
import forge.ai.*;
import forge.game.Game;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
@@ -24,6 +17,9 @@ import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import java.util.List;
import java.util.Map;
public class MustBlockAi extends SpellAbilityAi {
@Override

View File

@@ -1,10 +1,7 @@
package forge.ai.ability;
import java.util.Map;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import forge.ai.ComputerUtilCard;
import forge.ai.SpellAbilityAi;
import forge.game.card.Card;
@@ -16,6 +13,8 @@ import forge.game.player.Player;
import forge.game.player.PlayerActionConfirmMode;
import forge.game.spellability.SpellAbility;
import java.util.Map;
public class MutateAi extends SpellAbilityAi {
@Override
protected boolean canPlayAI(Player aiPlayer, SpellAbility sa) {

View File

@@ -1,5 +1,6 @@
package forge.ai.ability;
import forge.game.card.*;
import org.apache.commons.lang3.StringUtils;
import com.google.common.base.Predicates;
@@ -12,11 +13,6 @@ import forge.card.CardType.Supertype;
import forge.card.mana.ManaCost;
import forge.game.Game;
import forge.game.GlobalRuleChange;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.cost.Cost;
import forge.game.keyword.KeywordInterface;
import forge.game.mana.ManaCostBeingPaid;

View File

@@ -1,14 +1,7 @@
package forge.ai.ability;
import com.google.common.base.Predicate;
import forge.ai.AiController;
import forge.ai.AiProps;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilCombat;
import forge.ai.ComputerUtilCost;
import forge.ai.PlayerControllerAi;
import forge.ai.*;
import forge.card.mana.ManaCost;
import forge.game.Game;
import forge.game.ability.ApiType;
@@ -66,7 +59,7 @@ public class PermanentCreatureAi extends PermanentAi {
if (sa.isDash()) {
//only checks that the dashed creature will attack
if (ph.isPlayerTurn(ai) && ph.getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS)) {
if (game.getReplacementHandler().wouldPhaseBeSkipped(ai, "BeginCombat"))
if (ai.hasKeyword("Skip your next combat phase."))
return false;
if (ComputerUtilCost.canPayCost(sa.getHostCard().getSpellPermanent(), ai)) {
//do not dash if creature can be played normally
@@ -84,7 +77,7 @@ public class PermanentCreatureAi extends PermanentAi {
// after attacking
if (card.hasSVar("EndOfTurnLeavePlay")
&& (!ph.isPlayerTurn(ai) || ph.getPhase().isAfter(PhaseType.COMBAT_DECLARE_ATTACKERS)
|| game.getReplacementHandler().wouldPhaseBeSkipped(ai, "BeginCombat"))) {
|| ai.hasKeyword("Skip your next combat phase."))) {
// AiPlayDecision.AnotherTime
return false;
}

View File

@@ -1,9 +1,6 @@
package forge.ai.ability;
import java.util.List;
import com.google.common.base.Predicates;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilCard;
import forge.ai.SpellAbilityAi;
@@ -19,6 +16,8 @@ import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType;
import forge.util.MyRandom;
import java.util.List;
public class PhasesAi extends SpellAbilityAi {
@Override
protected boolean canPlayAI(Player aiPlayer, SpellAbility sa) {

View File

@@ -1,30 +1,16 @@
package forge.ai.ability;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import forge.ai.AiController;
import forge.ai.AiPlayDecision;
import forge.ai.AiProps;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilCard;
import forge.ai.PlayerControllerAi;
import forge.ai.SpellAbilityAi;
import forge.ai.*;
import forge.card.CardStateName;
import forge.card.CardTypeView;
import forge.game.Game;
import forge.game.GameType;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.*;
import forge.game.cost.Cost;
import forge.game.keyword.Keyword;
import forge.game.player.Player;
@@ -37,6 +23,10 @@ import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType;
import forge.util.MyRandom;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
public class PlayAi extends SpellAbilityAi {
@Override

View File

@@ -1,8 +1,5 @@
package forge.ai.ability;
import java.util.Collections;
import java.util.List;
import com.google.common.base.Predicate;
import forge.ai.ComputerUtilCard;
@@ -17,6 +14,9 @@ import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType;
import forge.util.MyRandom;
import java.util.Collections;
import java.util.List;
public class PowerExchangeAi extends SpellAbilityAi {
/* (non-Javadoc)

View File

@@ -5,12 +5,7 @@ import java.util.List;
import com.google.common.base.Predicate;
import forge.ai.AiAttackController;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilCombat;
import forge.ai.ComputerUtilCost;
import forge.ai.SpellAbilityAi;
import forge.ai.*;
import forge.card.MagicColor;
import forge.game.Game;
import forge.game.GameObject;

View File

@@ -1,5 +1,7 @@
package forge.ai.ability;
import forge.ai.ComputerUtilCost;
import forge.ai.SpellAbilityAi;
import forge.game.card.Card;
import forge.game.cost.Cost;
@@ -19,7 +21,19 @@ public class ProtectAllAi extends SpellAbilityAi {
final Cost cost = sa.getPayCosts();
// temporarily disabled until better AI
if (!willPayCosts(ai, sa, cost, hostCard)) {
if (!ComputerUtilCost.checkLifeCost(ai, cost, hostCard, 4, sa)) {
return false;
}
if (!ComputerUtilCost.checkDiscardCost(ai, cost, hostCard)) {
return false;
}
if (!ComputerUtilCost.checkSacrificeCost(ai, cost, hostCard, sa)) {
return false;
}
if (!ComputerUtilCost.checkRemoveCounterCost(cost, hostCard, sa)) {
return false;
}

View File

@@ -1,32 +1,14 @@
package forge.ai.ability;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Lists;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilAbility;
import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilCost;
import forge.ai.SpecialAiLogic;
import forge.ai.SpecialCardAi;
import forge.ai.SpellAbilityAi;
import forge.ai.*;
import forge.game.Game;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.*;
import forge.game.card.CardPredicates.Presets;
import forge.game.card.CardUtil;
import forge.game.card.CounterEnumType;
import forge.game.card.CounterType;
import forge.game.cost.Cost;
import forge.game.cost.CostTapType;
import forge.game.keyword.Keyword;
@@ -38,6 +20,10 @@ import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetRestrictions;
import forge.game.staticability.StaticAbility;
import forge.game.zone.ZoneType;
import org.apache.commons.lang3.StringUtils;
import java.util.Arrays;
import java.util.List;
public class PumpAi extends PumpAiBase {

View File

@@ -1,11 +1,8 @@
package forge.ai.ability;
import java.util.List;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilCombat;
@@ -13,12 +10,7 @@ import forge.ai.SpellAbilityAi;
import forge.card.MagicColor;
import forge.game.Game;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CardUtil;
import forge.game.card.*;
import forge.game.combat.Combat;
import forge.game.combat.CombatUtil;
import forge.game.keyword.Keyword;
@@ -29,6 +21,8 @@ import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import java.util.List;
public abstract class PumpAiBase extends SpellAbilityAi {
public boolean containsUsefulKeyword(final Player ai, final List<String> keywords, final Card card, final SpellAbility sa, final int attack) {

View File

@@ -1,9 +1,5 @@
package forge.ai.ability;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.google.common.base.Predicate;
import forge.ai.ComputerUtil;
@@ -26,6 +22,10 @@ import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class PumpAllAi extends PumpAiBase {
/* (non-Javadoc)
@@ -69,8 +69,8 @@ public class PumpAllAi extends PumpAiBase {
}
final Player opp = ai.getWeakestOpponent();
CardCollection comp = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), valid, source.getController(), source, sa);
CardCollection human = CardLists.getValidCards(opp.getCardsIn(ZoneType.Battlefield), valid, source.getController(), source, sa);
CardCollection comp = CardLists.getValidCards(ai.getCardsIn(ZoneType.Battlefield), valid, source.getController(), source);
CardCollection human = CardLists.getValidCards(opp.getCardsIn(ZoneType.Battlefield), valid, source.getController(), source);
final TargetRestrictions tgt = sa.getTargetRestrictions();
if (tgt != null && sa.canTarget(opp) && sa.hasParam("IsCurse")) {
@@ -144,7 +144,7 @@ public class PumpAllAi extends PumpAiBase {
return (ComputerUtilCard.evaluateCreatureList(comp) + 200) < ComputerUtilCard.evaluateCreatureList(human);
} // end Curse
return !CardLists.getValidCards(getPumpCreatures(ai, sa, defense, power, keywords, false), valid, source.getController(), source, sa).isEmpty();
return !CardLists.getValidCards(getPumpCreatures(ai, sa, defense, power, keywords, false), valid, source.getController(), source).isEmpty();
} // pumpAllCanPlayAI()
@Override

View File

@@ -1,12 +1,7 @@
package forge.ai.ability;
import forge.ai.AiCardMemory;
import forge.ai.AiController;
import forge.ai.AiProps;
import forge.ai.ComputerUtilMana;
import forge.ai.PlayerControllerAi;
import forge.ai.SpellAbilityAi;
import forge.ai.*;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
import forge.game.card.CardLists;

View File

@@ -17,13 +17,7 @@
*/
package forge.ai.ability;
import java.util.ArrayList;
import java.util.List;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilCombat;
import forge.ai.SpellAbilityAi;
import forge.ai.*;
import forge.game.Game;
import forge.game.GameObject;
import forge.game.ability.AbilityUtils;
@@ -39,6 +33,9 @@ import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType;
import java.util.ArrayList;
import java.util.List;
/**
* <p>
* AbilityFactory_Regenerate class.

View File

@@ -1,7 +1,5 @@
package forge.ai.ability;
import java.util.List;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilCombat;
import forge.ai.SpellAbilityAi;
@@ -17,6 +15,8 @@ import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import java.util.List;
public class RegenerateAllAi extends SpellAbilityAi {
@Override

View File

@@ -1,10 +1,7 @@
package forge.ai.ability;
import forge.ai.AiController;
import forge.ai.ComputerUtilCost;
import forge.ai.PlayerControllerAi;
import forge.ai.SpellAbilityAi;
import forge.ai.*;
import forge.game.phase.PhaseType;
import forge.game.player.Player;
import forge.game.player.PlayerActionConfirmMode;

View File

@@ -1,10 +1,6 @@
package forge.ai.ability;
import java.util.List;
import java.util.Map;
import com.google.common.base.Predicate;
import forge.ai.ComputerUtilCard;
import forge.ai.SpecialCardAi;
import forge.ai.SpellAbilityAi;
@@ -21,6 +17,9 @@ import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import forge.util.TextUtil;
import java.util.List;
import java.util.Map;
public class RepeatEachAi extends SpellAbilityAi {

View File

@@ -1,14 +1,6 @@
package forge.ai.ability;
import com.google.common.collect.Iterables;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilCard;
import forge.ai.SpellAbilityAi;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates.Presets;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
@@ -24,18 +16,13 @@ public class RestartGameAi extends SpellAbilityAi {
*/
@Override
protected boolean canPlayAI(Player ai, SpellAbility sa) {
if (ComputerUtil.aiLifeInDanger(ai, true, 0)) {
return true;
}
// The only card that uses this is Karn Liberated
// check if enough good permanents will be available to be returned, so AI can "autowin"
CardCollection exiled = new CardCollection(Iterables.filter(sa.getHostCard().getRemembered(), Card.class));
exiled = CardLists.filter(exiled, Presets.PERMANENTS);
if (ComputerUtilCard.evaluatePermanentList(exiled) > 20) {
return true;
}
// TODO Add Logic, check if AI is losing game state, or life
return false;
// TODO Add Logic, check if any good cards will be available to be returned
return true;
}
@Override

View File

@@ -65,7 +65,7 @@ public class RevealAi extends RevealAiBase {
for (SpellAbility s : c.getBasicSpells()) {
Spell spell = (Spell) s.copy(ai);
// timing restrictions still apply
if (!spell.getRestrictions().checkTimingRestrictions(c, spell))
if (!s.getRestrictions().checkTimingRestrictions(c, s))
continue;
// use hard coded reduce cost

View File

@@ -26,8 +26,6 @@ public class RollDiceAi extends SpellAbilityAi {
return game.getCombat() != null && (game.getCombat().isAttacking(source) || game.getCombat().isBlocking(source));
} else if (logic.equals("Main2")) {
return ph.is(PhaseType.MAIN2, aiPlayer);
} else if (logic.equals("AtOppEOT")) {
return ph.getNextTurn() == aiPlayer && ph.is(PhaseType.END_OF_TURN);
}
if (cost != null && (sa.getPayCosts().hasManaCost() || sa.getPayCosts().hasTapCost())) {

View File

@@ -1,7 +1,5 @@
package forge.ai.ability;
import java.util.List;
import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilCost;
import forge.ai.ComputerUtilMana;
@@ -19,6 +17,8 @@ import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType;
import java.util.List;
public class SacrificeAi extends SpellAbilityAi {
// **************************************************************
// *************************** Sacrifice ***********************

View File

@@ -1,16 +1,11 @@
package forge.ai.ability;
import com.google.common.base.Predicates;
import forge.ai.ComputerUtilMana;
import forge.ai.SpellAbilityAi;
import forge.game.ability.ApiType;
import forge.game.card.Card;
import forge.game.card.*;
import forge.game.card.Card.SplitCMCMode;
import forge.game.card.CardCollection;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CounterEnumType;
import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType;
import forge.game.player.Player;

View File

@@ -1,20 +1,14 @@
package forge.ai.ability;
import com.google.common.base.Predicate;
import forge.ai.ComputerUtilCard;
import forge.ai.SpellAbilityAi;
import forge.card.CardStateName;
import forge.game.Game;
import forge.game.GlobalRuleChange;
import forge.game.ability.AbilityUtils;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardLists;
import forge.game.card.*;
import forge.game.card.CardPredicates.Presets;
import forge.game.card.CardState;
import forge.game.card.CardUtil;
import forge.game.card.CounterEnumType;
import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType;
import forge.game.player.Player;

View File

@@ -1,23 +0,0 @@
package forge.ai.ability;
import forge.ai.SpellAbilityAi;
import forge.game.player.Player;
import forge.game.player.PlayerActionConfirmMode;
import forge.game.spellability.SpellAbility;
public class SkipPhaseAi extends SpellAbilityAi {
@Override
protected boolean canPlayAI(Player aiPlayer, SpellAbility sa) {
return true;
}
@Override
protected boolean doTriggerAINoCost(Player aiPlayer, SpellAbility sa, boolean mandatory) {
return mandatory || canPlayAI(aiPlayer, sa);
}
@Override
public boolean confirmAction(Player player, SpellAbility sa, PlayerActionConfirmMode mode, String message) {
return true;
}
}

View File

@@ -0,0 +1,21 @@
package forge.ai.ability;
import forge.ai.SpellAbilityAi;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
public class StoreMapAi extends SpellAbilityAi {
@Override
protected boolean canPlayAI(Player ai, SpellAbility sa) {
return true;
}
@Override
protected boolean doTriggerAINoCost(Player aiPlayer, SpellAbility sa, boolean mandatory) {
return true;
}
}

Some files were not shown because too many files have changed in this diff Show More