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

View File

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

View File

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

View File

@@ -17,19 +17,11 @@
*/ */
package forge.ai; 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.esotericsoftware.minlog.Log;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import forge.ai.ability.ChangeZoneAi; import forge.ai.ability.ChangeZoneAi;
import forge.ai.ability.ExploreAi; import forge.ai.ability.ExploreAi;
import forge.ai.simulation.SpellAbilityPicker; import forge.ai.simulation.SpellAbilityPicker;
@@ -38,38 +30,16 @@ import forge.card.mana.ManaCost;
import forge.deck.CardPool; import forge.deck.CardPool;
import forge.deck.Deck; import forge.deck.Deck;
import forge.deck.DeckSection; import forge.deck.DeckSection;
import forge.game.CardTraitBase; import forge.game.*;
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.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType; import forge.game.ability.ApiType;
import forge.game.ability.SpellApiBased; import forge.game.ability.SpellApiBased;
import forge.game.card.Card; import forge.game.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.CardPredicates.Accessors; import forge.game.card.CardPredicates.Accessors;
import forge.game.card.CardPredicates.Presets; 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.Combat;
import forge.game.combat.CombatUtil; import forge.game.combat.CombatUtil;
import forge.game.cost.Cost; import forge.game.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.keyword.Keyword; import forge.game.keyword.Keyword;
import forge.game.mana.ManaCostBeingPaid; import forge.game.mana.ManaCostBeingPaid;
import forge.game.phase.PhaseType; import forge.game.phase.PhaseType;
@@ -78,15 +48,7 @@ import forge.game.player.PlayerActionConfirmMode;
import forge.game.replacement.ReplaceMoved; import forge.game.replacement.ReplaceMoved;
import forge.game.replacement.ReplacementEffect; import forge.game.replacement.ReplacementEffect;
import forge.game.replacement.ReplacementType; import forge.game.replacement.ReplacementType;
import forge.game.spellability.AbilitySub; import forge.game.spellability.*;
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.staticability.StaticAbility; import forge.game.staticability.StaticAbility;
import forge.game.trigger.Trigger; import forge.game.trigger.Trigger;
import forge.game.trigger.TriggerType; import forge.game.trigger.TriggerType;
@@ -94,13 +56,16 @@ import forge.game.trigger.WrappedAbility;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.item.PaperCard; import forge.item.PaperCard;
import forge.util.Aggregates; import forge.util.Aggregates;
import forge.util.ComparatorUtil;
import forge.util.Expressions; import forge.util.Expressions;
import forge.util.MyRandom; import forge.util.MyRandom;
import forge.util.ComparatorUtil;
import forge.util.collect.FCollectionView; import forge.util.collect.FCollectionView;
import io.sentry.Sentry; import io.sentry.Sentry;
import io.sentry.event.BreadcrumbBuilder; import io.sentry.event.BreadcrumbBuilder;
import java.util.*;
import java.util.Map.Entry;
/** /**
* <p> * <p>
* AiController class. * AiController class.
@@ -114,7 +79,6 @@ public class AiController {
private final Game game; private final Game game;
private final AiCardMemory memory; private final AiCardMemory memory;
private Combat predictedCombat; private Combat predictedCombat;
private Combat predictedCombatNextTurn;
private boolean cheatShuffle; private boolean cheatShuffle;
private boolean useSimulation; private boolean useSimulation;
private SpellAbilityPicker simPicker; private SpellAbilityPicker simPicker;
@@ -159,15 +123,6 @@ public class AiController {
return predictedCombat; 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) { public AiController(final Player computerPlayer, final Game game0) {
player = computerPlayer; player = computerPlayer;
game = game0; game = game0;
@@ -1045,7 +1000,7 @@ public class AiController {
} }
// move snap-casted spells to front // move snap-casted spells to front
if (source.isInZone(ZoneType.Graveyard)) { if (source.isInZone(ZoneType.Graveyard)) {
if (sa.getMayPlay() != null && source.mayPlay(sa.getMayPlay()) != null) { if (!sa.getMayPlayList().isEmpty()) {
p += 50; p += 50;
} }
} }
@@ -1120,8 +1075,9 @@ public class AiController {
CardCollection discards = CardLists.filter(player.getCardsIn(ZoneType.Hand), CardPredicates.hasCMC(cmc)); CardCollection discards = CardLists.filter(player.getCardsIn(ZoneType.Hand), CardPredicates.hasCMC(cmc));
if (discards.isEmpty()) { if (discards.isEmpty()) {
return null; return null;
} else {
return new CardCollection(ComputerUtilCard.getWorstAI(discards));
} }
return new CardCollection(ComputerUtilCard.getWorstAI(discards));
} }
if (sa.hasParam("AnyNumber")) { if (sa.hasParam("AnyNumber")) {
@@ -1408,8 +1364,6 @@ public class AiController {
// Reset cached predicted combat, as it may be stale. It will be // 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. // re-created if needed and used for any AI logic that needs it.
predictedCombat = null; 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 // Reset priority mana reservation that's meant to work for one spell only
AiCardMemory.clearMemorySet(player, AiCardMemory.MemorySet.HELD_MANA_SOURCES_FOR_NEXT_SPELL); 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() if (ComputerUtil.getDamageFromETB(player, land) < player.getLife() || !player.canLoseLife()
|| player.cantLoseForZeroOrLessLife() ) { || player.cantLoseForZeroOrLessLife() ) {
if (!game.getPhaseHandler().is(PhaseType.MAIN1) || !isSafeToHoldLandDropForMain2(land)) { 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()) { if (!abilities.isEmpty()) {
return abilities; return abilities;
} }

View File

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

View File

@@ -17,19 +17,19 @@
*/ */
package forge.ai; 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.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; 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. * Holds default AI personality profile values in an enum.
* Loads profile from the given text file when setProfile is called. * Loads profile from the given text file when setProfile is called.

View File

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

View File

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

View File

@@ -1,20 +1,5 @@
package forge.ai; 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.Predicate;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
@@ -33,16 +18,7 @@ import forge.game.Game;
import forge.game.GameObject; import forge.game.GameObject;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType; import forge.game.ability.ApiType;
import forge.game.card.Card; import forge.game.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.combat.Combat; import forge.game.combat.Combat;
import forge.game.combat.CombatUtil; import forge.game.combat.CombatUtil;
import forge.game.cost.Cost; import forge.game.cost.Cost;
@@ -64,6 +40,12 @@ import forge.item.PaperCard;
import forge.util.Aggregates; import forge.util.Aggregates;
import forge.util.Expressions; import forge.util.Expressions;
import forge.util.MyRandom; 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 class ComputerUtilCard {
public static Card getMostExpensivePermanentAI(final CardCollectionView list, final SpellAbility spell, final boolean targeted) { public static Card getMostExpensivePermanentAI(final CardCollectionView list, final SpellAbility spell, final boolean targeted) {
@@ -327,17 +309,6 @@ public class ComputerUtilCard {
return biggest; 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> * <p>
* getWorstAI. * getWorstAI.
@@ -982,7 +953,7 @@ public class ComputerUtilCard {
for(byte c : MagicColor.WUBRG) { for(byte c : MagicColor.WUBRG) {
String devotionCode = "Count$Devotion." + MagicColor.toLongString(c); 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()) { if (devotion > curDevotion && !CardLists.filter(hand, CardPredicates.isColor(c)).isEmpty()) {
curDevotion = devotion; curDevotion = devotion;
chosenColor = MagicColor.toLongString(c); 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 this thing has AILogic set to "Curse", it's probably meant as some form of disruption
if (!priority) { if (!priority) {
for (final String value : c.getSVars().values()) { for (final String sVar : c.getSVars().keySet()) {
if (value.contains("AILogic$ Curse")) { if (c.getSVars().get(sVar).contains("AILogic$ Curse")) {
// this is a curse ability, so prioritize its removal // this is a curse ability, so prioritize its removal
priority = true; priority = true;
break; break;
@@ -1214,9 +1185,10 @@ public class ComputerUtilCard {
final float valueNow = Math.max(valueTempo, threat); final float valueNow = Math.max(valueTempo, threat);
if (valueNow < 0.2) { //hard floor to reduce ridiculous odds for instants over time if (valueNow < 0.2) { //hard floor to reduce ridiculous odds for instants over time
return false; 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); 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()) { if (list.isEmpty()) {
return AiPlayDecision.MissingNeededCards; 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.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import forge.game.CardTraitBase;
import forge.game.Game; import forge.game.Game;
import forge.game.GameEntity; import forge.game.GameEntity;
import forge.game.ability.AbilityKey; import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType; import forge.game.ability.ApiType;
import forge.game.card.Card; import forge.game.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.combat.Combat; import forge.game.combat.Combat;
import forge.game.combat.CombatUtil; import forge.game.combat.CombatUtil;
import forge.game.cost.CostPayment; import forge.game.cost.CostPayment;
@@ -796,9 +790,9 @@ public class ComputerUtilCombat {
return false; // The trigger should have triggered already return false; // The trigger should have triggered already
} }
if (trigParams.containsKey("ValidCard")) { if (trigParams.containsKey("ValidCard")) {
if (!trigger.matchesValid(attacker, trigParams.get("ValidCard").split(",")) if (!CardTraitBase.matchesValid(attacker, trigParams.get("ValidCard").split(","), source)
&& !(combat.isAttacking(source) && trigger.matchesValid(source, && !(combat.isAttacking(source) && CardTraitBase.matchesValid(source,
trigParams.get("ValidCard").split(",")) trigParams.get("ValidCard").split(","), source)
&& !trigParams.containsKey("Alone"))) { && !trigParams.containsKey("Alone"))) {
return false; return false;
} }
@@ -806,7 +800,7 @@ public class ComputerUtilCombat {
if (trigParams.containsKey("Attacked")) { if (trigParams.containsKey("Attacked")) {
if (combat.isAttacking(attacker)) { if (combat.isAttacking(attacker)) {
GameEntity attacked = combat.getDefenderByAttacker(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; return false;
} }
} else { } else {
@@ -826,7 +820,7 @@ public class ComputerUtilCombat {
if ((defender == null) && mode == TriggerType.AttackerUnblocked) { if ((defender == null) && mode == TriggerType.AttackerUnblocked) {
willTrigger = true; willTrigger = true;
if (trigParams.containsKey("ValidCard")) { if (trigParams.containsKey("ValidCard")) {
if (!trigger.matchesValid(attacker, trigParams.get("ValidCard").split(","))) { if (!CardTraitBase.matchesValid(attacker, trigParams.get("ValidCard").split(","), source)) {
return false; return false;
} }
} }
@@ -848,7 +842,7 @@ public class ComputerUtilCombat {
return false; return false;
} }
} }
if (!trigger.matchesValid(attacker, validBlocked.split(","))) { if (!CardTraitBase.matchesValid(attacker, validBlocked.split(","), source)) {
return false; return false;
} }
} }
@@ -862,35 +856,35 @@ public class ComputerUtilCombat {
return false; return false;
} }
} }
if (!trigger.matchesValid(defender, validBlocker.split(","))) { if (!CardTraitBase.matchesValid(defender, validBlocker.split(","), source)) {
return false; return false;
} }
} }
} else if (mode == TriggerType.AttackerBlocked || mode == TriggerType.AttackerBlockedByCreature) { } else if (mode == TriggerType.AttackerBlocked || mode == TriggerType.AttackerBlockedByCreature) {
willTrigger = true; willTrigger = true;
if (trigParams.containsKey("ValidBlocker")) { if (trigParams.containsKey("ValidBlocker")) {
if (!trigger.matchesValid(defender, trigParams.get("ValidBlocker").split(","))) { if (!CardTraitBase.matchesValid(defender, trigParams.get("ValidBlocker").split(","), source)) {
return false; return false;
} }
} }
if (trigParams.containsKey("ValidCard")) { if (trigParams.containsKey("ValidCard")) {
if (!trigger.matchesValid(attacker, trigParams.get("ValidCard").split(","))) { if (!CardTraitBase.matchesValid(attacker, trigParams.get("ValidCard").split(","), source)) {
return false; return false;
} }
} }
} else if (mode == TriggerType.DamageDone) { } else if (mode == TriggerType.DamageDone) {
willTrigger = true; willTrigger = true;
if (trigParams.containsKey("ValidSource")) { if (trigParams.containsKey("ValidSource")) {
if (!(trigger.matchesValid(defender, trigParams.get("ValidSource").split(",")) if (!(CardTraitBase.matchesValid(defender, trigParams.get("ValidSource").split(","), source)
&& defender.getNetCombatDamage() > 0 && defender.getNetCombatDamage() > 0
&& (!trigParams.containsKey("ValidTarget") && (!trigParams.containsKey("ValidTarget")
|| trigger.matchesValid(attacker, trigParams.get("ValidTarget").split(","))))) { || CardTraitBase.matchesValid(attacker, trigParams.get("ValidTarget").split(","), source)))) {
return false; return false;
} }
if (!(trigger.matchesValid(attacker, trigParams.get("ValidSource").split(",")) if (!(CardTraitBase.matchesValid(attacker, trigParams.get("ValidSource").split(","), source)
&& attacker.getNetCombatDamage() > 0 && attacker.getNetCombatDamage() > 0
&& (!trigParams.containsKey("ValidTarget") && (!trigParams.containsKey("ValidTarget")
|| trigger.matchesValid(defender, trigParams.get("ValidTarget").split(","))))) { || CardTraitBase.matchesValid(defender, trigParams.get("ValidTarget").split(","), source)))) {
return false; return false;
} }
} }

View File

@@ -1,41 +1,16 @@
package forge.ai; 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.base.Predicate;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import forge.ai.ability.AnimateAi; import forge.ai.ability.AnimateAi;
import forge.card.ColorSet; import forge.card.ColorSet;
import forge.game.Game; import forge.game.Game;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.card.Card; import forge.game.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.Presets; 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.combat.Combat;
import forge.game.cost.Cost; import forge.game.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.keyword.Keyword; import forge.game.keyword.Keyword;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.Spell; import forge.game.spellability.Spell;
@@ -45,6 +20,12 @@ import forge.util.MyRandom;
import forge.util.TextUtil; import forge.util.TextUtil;
import forge.util.collect.FCollectionView; 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 { public class ComputerUtilCost {
@@ -137,9 +118,8 @@ public class ComputerUtilCost {
* the source * the source
* @return true, if successful * @return true, if successful
*/ */
public static boolean checkDiscardCost(final Player ai, final Cost cost, final Card source) {
public static boolean checkDiscardCost(final Player ai, final Cost cost, final Card source, SpellAbility sa) { if (cost == null) {
if (cost == null || source.hasSVar("AISkipDiscardCostCheck") /* FIXME: should not be needed! */ ) {
return true; return true;
} }
@@ -153,7 +133,7 @@ public class ComputerUtilCost {
if (type.equals("CARDNAME") && source.getAbilityText().contains("Bloodrush")) { if (type.equals("CARDNAME") && source.getAbilityText().contains("Bloodrush")) {
continue; 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()) { if (typeList.size() > ai.getMaxHandSize()) {
continue; continue;
} }
@@ -163,9 +143,10 @@ public class ComputerUtilCost {
Card pref = ComputerUtil.getCardPreference(ai, source, "DiscardCost", typeList); Card pref = ComputerUtil.getCardPreference(ai, source, "DiscardCost", typeList);
if (pref == null) { if (pref == null) {
return false; 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 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; int count = 0;
while (count < amount) { while (count < amount) {
@@ -320,7 +301,7 @@ public class ComputerUtilCost {
} }
final CardCollection sacList = new CardCollection(); 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; int count = 0;
while (count < amount) { while (count < amount) {
@@ -641,7 +622,7 @@ public class ComputerUtilCost {
return checkLifeCost(payer, cost, source, 4, sa) return checkLifeCost(payer, cost, source, 4, sa)
&& checkDamageCost(payer, cost, source, 4) && checkDamageCost(payer, cost, source, 4)
&& (isMine || checkSacrificeCost(payer, cost, source, sa)) && (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("Tyrannize") || payer.getCardsIn(ZoneType.Hand).size() > 2)
&& (!source.getName().equals("Perplex") || 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) && (!source.getName().equals("Breaking Point") || payer.getCreaturesInPlay().size() > 1)
@@ -722,7 +703,7 @@ public class ComputerUtilCost {
continue; 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; int count = 0;
while (count < val) { while (count < val) {

View File

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

View File

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

View File

@@ -1,23 +1,11 @@
package forge.ai; 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.Predicate;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.ListMultimap; import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import forge.LobbyPlayer; import forge.LobbyPlayer;
import forge.ai.ability.ProtectAi; import forge.ai.ability.ProtectAi;
import forge.card.CardStateName; import forge.card.CardStateName;
@@ -33,43 +21,19 @@ import forge.game.GameObject;
import forge.game.GameType; import forge.game.GameType;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType; import forge.game.ability.ApiType;
import forge.game.card.Card; import forge.game.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.CardPredicates.Presets; 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.combat.Combat;
import forge.game.cost.Cost; import forge.game.cost.*;
import forge.game.cost.CostAdjustment;
import forge.game.cost.CostExile;
import forge.game.cost.CostPart;
import forge.game.cost.CostPartMana;
import forge.game.keyword.KeywordInterface; import forge.game.keyword.KeywordInterface;
import forge.game.mana.Mana; import forge.game.mana.Mana;
import forge.game.mana.ManaConversionMatrix; import forge.game.mana.ManaConversionMatrix;
import forge.game.mana.ManaCostBeingPaid; import forge.game.mana.ManaCostBeingPaid;
import forge.game.phase.PhaseHandler; import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType; import forge.game.phase.PhaseType;
import forge.game.player.DelayedReveal; import forge.game.player.*;
import forge.game.player.Player;
import forge.game.player.PlayerActionConfirmMode;
import forge.game.player.PlayerController;
import forge.game.player.PlayerView;
import forge.game.replacement.ReplacementEffect; import forge.game.replacement.ReplacementEffect;
import forge.game.spellability.Ability; import forge.game.spellability.*;
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.trigger.WrappedAbility; import forge.game.trigger.WrappedAbility;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.item.PaperCard; import forge.item.PaperCard;
@@ -78,6 +42,13 @@ import forge.util.ITriggerEvent;
import forge.util.MyRandom; import forge.util.MyRandom;
import forge.util.collect.FCollection; import forge.util.collect.FCollection;
import forge.util.collect.FCollectionView; 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 * A prototype for player controller class
@@ -106,7 +77,9 @@ public class PlayerControllerAi extends PlayerController {
if (abilities.size() == 0) { if (abilities.size() == 0) {
return null; return null;
} }
return abilities.get(0); else {
return abilities.get(0);
}
} }
public AiController getAi() { public AiController getAi() {
@@ -543,12 +516,13 @@ public class PlayerControllerAi extends PlayerController {
} }
@Override @Override
public List<String> chooseSomeType(String kindOfType, SpellAbility sa, int min, int max, List<String> validTypes) { public String chooseSomeType(String kindOfType, SpellAbility sa, Collection<String> validTypes, List<String> invalidTypes, boolean isOptional) {
List<String> chosen = ComputerUtil.chooseSomeType(player, kindOfType, sa.getParam("AILogic"), min, max, validTypes); String chosen = ComputerUtil.chooseSomeType(player, kindOfType, sa.getParam("AILogic"), validTypes, invalidTypes);
if (chosen.isEmpty()) { if (StringUtils.isBlank(chosen) && !validTypes.isEmpty()) {
return validTypes.subList(0, min); 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; return chosen;
} }
@@ -1005,11 +979,7 @@ public class PlayerControllerAi extends PlayerController {
} else { } else {
if (sa.isCopied()) { if (sa.isCopied()) {
if (sa.isSpell()) { if (sa.isSpell()) {
if (!sa.getHostCard().isInZone(ZoneType.Stack)) { player.getGame().getStackZone().add(sa.getHostCard());
sa.setHostCard(player.getGame().getAction().moveToStack(sa.getHostCard(), sa));
} else {
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 /* 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")) { } else if (logic.equals("MostProminentInHumanDeck")) {
return ComputerUtilCard.getMostProminentCardName(oppLibrary); return ComputerUtilCard.getMostProminentCardName(oppLibrary);
} else if (logic.equals("MostProminentCreatureInComputerDeck")) { } 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); return ComputerUtilCard.getMostProminentCardName(cards);
} else if (logic.equals("BestCreatureInComputerDeck")) { } else if (logic.equals("BestCreatureInComputerDeck")) {
Card bestCreature = ComputerUtilCard.getBestCreatureAI(aiLibrary); Card bestCreature = ComputerUtilCard.getBestCreatureAI(aiLibrary);
@@ -1197,7 +1167,7 @@ public class PlayerControllerAi extends PlayerController {
} else if (logic.equals("RandomInComputerDeck")) { } else if (logic.equals("RandomInComputerDeck")) {
return Aggregates.random(aiLibrary).getName(); return Aggregates.random(aiLibrary).getName();
} else if (logic.equals("MostProminentSpellInComputerDeck")) { } 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); return ComputerUtilCard.getMostProminentCardName(cards);
} else if (logic.equals("CursedScroll")) { } else if (logic.equals("CursedScroll")) {
return SpecialCardAi.CursedScroll.chooseCard(player, sa); return SpecialCardAi.CursedScroll.chooseCard(player, sa);

View File

@@ -9,13 +9,7 @@ import forge.ai.ability.TokenAi;
import forge.game.Game; import forge.game.Game;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType; import forge.game.ability.ApiType;
import forge.game.card.Card; import forge.game.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.combat.Combat; import forge.game.combat.Combat;
import forge.game.keyword.Keyword; import forge.game.keyword.Keyword;
import forge.game.phase.PhaseHandler; import forge.game.phase.PhaseHandler;

View File

@@ -17,17 +17,10 @@
*/ */
package forge.ai; 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.Predicate;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import forge.ai.ability.AnimateAi; import forge.ai.ability.AnimateAi;
import forge.card.ColorSet; import forge.card.ColorSet;
import forge.card.MagicColor; import forge.card.MagicColor;
@@ -36,14 +29,7 @@ import forge.game.Game;
import forge.game.GameType; import forge.game.GameType;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType; import forge.game.ability.ApiType;
import forge.game.card.Card; import forge.game.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.combat.Combat; import forge.game.combat.Combat;
import forge.game.combat.CombatUtil; import forge.game.combat.CombatUtil;
import forge.game.cost.CostPart; import forge.game.cost.CostPart;
@@ -64,6 +50,11 @@ import forge.util.MyRandom;
import forge.util.TextUtil; import forge.util.TextUtil;
import forge.util.maps.LinkedHashMapToAmount; import forge.util.maps.LinkedHashMapToAmount;
import forge.util.maps.MapToAmount; 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 * Special logic for individual cards
@@ -1000,7 +991,7 @@ public class SpecialCardAi {
return false; return false;
} }
String prominentColor = ComputerUtilCard.getMostProminentColor(ai.getCardsIn(ZoneType.Battlefield)); 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); 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) // 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; 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.Iterables;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import forge.card.CardStateName; import forge.card.CardStateName;
import forge.card.ICardFace; import forge.card.ICardFace;
import forge.card.mana.ManaCost; import forge.card.mana.ManaCost;
@@ -26,6 +21,10 @@ import forge.game.spellability.SpellAbility;
import forge.game.spellability.SpellAbilityCondition; import forge.game.spellability.SpellAbilityCondition;
import forge.util.MyRandom; import forge.util.MyRandom;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/** /**
* Base class for API-specific AI logic * Base class for API-specific AI logic
* <p> * <p>
@@ -127,7 +126,7 @@ public abstract class SpellAbilityAi {
if (!ComputerUtilCost.checkLifeCost(ai, cost, source, 4, sa)) { if (!ComputerUtilCost.checkLifeCost(ai, cost, source, 4, sa)) {
return false; return false;
} }
if (!ComputerUtilCost.checkDiscardCost(ai, cost, source, sa)) { if (!ComputerUtilCost.checkDiscardCost(ai, cost, source)) {
return false; return false;
} }
if (!ComputerUtilCost.checkSacrificeCost(ai, cost, source, sa)) { if (!ComputerUtilCost.checkSacrificeCost(ai, cost, source, sa)) {

View File

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

View File

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

View File

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

View File

@@ -9,11 +9,7 @@ import forge.ai.ComputerUtilCard;
import forge.ai.SpellAbilityAi; import forge.ai.SpellAbilityAi;
import forge.game.Game; import forge.game.Game;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.card.Card; import forge.game.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.token.TokenInfo; import forge.game.card.token.TokenInfo;
import forge.game.phase.PhaseHandler; import forge.game.phase.PhaseHandler;
import forge.game.player.Player; import forge.game.player.Player;
@@ -30,38 +26,40 @@ public class AmassAi extends SpellAbilityAi {
if (!aiArmies.isEmpty()) { if (!aiArmies.isEmpty()) {
return CardLists.count(aiArmies, CardPredicates.canReceiveCounters(CounterEnumType.P1P1)) > 0; return CardLists.count(aiArmies, CardPredicates.canReceiveCounters(CounterEnumType.P1P1)) > 0;
} } else {
final String tokenScript = "b_0_0_zombie_army"; final String tokenScript = "b_0_0_zombie_army";
final int amount = AbilityUtils.calculateAmount(host, sa.getParamOrDefault("Num", "1"), sa); 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) { if (token == null) {
return false; 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 @Override

View File

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

View File

@@ -1,39 +1,17 @@
package forge.ai.ability; 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.Predicate;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import forge.ai.*;
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.game.Game; import forge.game.Game;
import forge.game.GameObject; import forge.game.GameObject;
import forge.game.GlobalRuleChange; import forge.game.GlobalRuleChange;
import forge.game.ability.AbilityFactory; import forge.game.ability.AbilityFactory;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType; import forge.game.ability.ApiType;
import forge.game.card.Card; import forge.game.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.combat.Combat; import forge.game.combat.Combat;
import forge.game.combat.CombatUtil; import forge.game.combat.CombatUtil;
import forge.game.cost.Cost; import forge.game.cost.Cost;
@@ -53,6 +31,8 @@ import forge.game.trigger.TriggerType;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.util.MyRandom; import forge.util.MyRandom;
import java.util.*;
public class AttachAi extends SpellAbilityAi { public class AttachAi extends SpellAbilityAi {
/* (non-Javadoc) /* (non-Javadoc)

View File

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

View File

@@ -1,8 +1,5 @@
package forge.ai.ability; package forge.ai.ability;
import java.util.Collection;
import java.util.Map;
import forge.ai.SpellAbilityAi; import forge.ai.SpellAbilityAi;
import forge.game.GameEntity; import forge.game.GameEntity;
import forge.game.player.Player; import forge.game.player.Player;
@@ -10,6 +7,9 @@ import forge.game.player.PlayerCollection;
import forge.game.player.PlayerPredicates; import forge.game.player.PlayerPredicates;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import java.util.Collection;
import java.util.Map;
public class ChangeCombatantsAi extends SpellAbilityAi { public class ChangeCombatantsAi extends SpellAbilityAi {
/* (non-Javadoc) /* (non-Javadoc)
* @see forge.card.abilityfactory.SpellAiLogic#canPlayAI(forge.game.player.Player, java.util.Map, forge.card.spellability.SpellAbility) * @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; 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.Predicate;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import forge.ai.*;
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.card.MagicColor; import forge.card.MagicColor;
import forge.game.Game; import forge.game.Game;
import forge.game.GameObject; import forge.game.GameObject;
@@ -37,14 +13,8 @@ import forge.game.GlobalRuleChange;
import forge.game.ability.AbilityKey; import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType; import forge.game.ability.ApiType;
import forge.game.card.Card; import forge.game.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.CardPredicates.Presets; 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.Combat;
import forge.game.cost.Cost; import forge.game.cost.Cost;
import forge.game.cost.CostDiscard; import forge.game.cost.CostDiscard;
@@ -59,6 +29,9 @@ import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetRestrictions; import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.util.MyRandom; import forge.util.MyRandom;
import org.apache.commons.lang3.StringUtils;
import java.util.*;
public class ChangeZoneAi extends SpellAbilityAi { public class ChangeZoneAi extends SpellAbilityAi {
/* /*
@@ -74,11 +47,9 @@ public class ChangeZoneAi extends SpellAbilityAi {
@Override @Override
protected boolean checkAiLogic(final Player ai, final SpellAbility sa, final String aiLogic) { protected boolean checkAiLogic(final Player ai, final SpellAbility sa, final String aiLogic) {
Card host = sa.getHostCard(); if (sa.getHostCard() != null && sa.getHostCard().hasSVar("AIPreferenceOverride")) {
if (host != null && host.hasSVar("AIPreferenceOverride")) {
// currently used by SacAndUpgrade logic, might need simplification // currently used by SacAndUpgrade logic, might need simplification
host.removeSVar("AIPreferenceOverride"); sa.getHostCard().removeSVar("AIPreferenceOverride");
} }
if (aiLogic.equals("BeforeCombat")) { if (aiLogic.equals("BeforeCombat")) {
@@ -92,7 +63,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
} else if (aiLogic.equals("PriorityOptionalCost")) { } else if (aiLogic.equals("PriorityOptionalCost")) {
boolean highPriority = false; 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 // 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 // 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) highPriority |= ai.getGame().getPhaseHandler().is(PhaseType.COMBAT_DECLARE_BLOCKERS)
&& ai.getGame().getCombat() != null && ComputerUtilCombat.lifeInDanger(ai, ai.getGame().getCombat()); && ai.getGame().getCombat() != null && ComputerUtilCombat.lifeInDanger(ai, ai.getGame().getCombat());
@@ -127,40 +98,6 @@ public class ChangeZoneAi extends SpellAbilityAi {
return true; return true;
} else if (aiLogic.equals("Pongify")) { } else if (aiLogic.equals("Pongify")) {
return SpecialAiLogic.doPongifyLogic(ai, sa); 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); return super.checkAiLogic(ai, sa, aiLogic);
@@ -197,15 +134,8 @@ public class ChangeZoneAi extends SpellAbilityAi {
return SpecialCardAi.MazesEnd.consider(aiPlayer, sa); return SpecialCardAi.MazesEnd.consider(aiPlayer, sa);
} else if (aiLogic.equals("Pongify")) { } else if (aiLogic.equals("Pongify")) {
return sa.isTargetNumberValid(); // Pre-targeted in checkAiLogic 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)) { if (isHidden(sa)) {
return hiddenOriginCanPlayAI(aiPlayer, sa); return hiddenOriginCanPlayAI(aiPlayer, sa);
} }
@@ -331,7 +261,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
return false; return false;
} }
if (!ComputerUtilCost.checkDiscardCost(ai, abCost, source, sa)) { if (!ComputerUtilCost.checkDiscardCost(ai, abCost, source)) {
for (final CostPart part : abCost.getCostParts()) { for (final CostPart part : abCost.getCostParts()) {
if (part instanceof CostDiscard) { if (part instanceof CostDiscard) {
CostDiscard cd = (CostDiscard) part; CostDiscard cd = (CostDiscard) part;
@@ -427,7 +357,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
if (type != null && p == ai) { if (type != null && p == ai) {
// AI only "knows" about his information // 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>() { list = CardLists.filter(list, new Predicate<Card>() {
@Override @Override
public boolean apply(final Card c) { 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 // TODO: prevent ai seaching its own library when Ob Nixilis, Unshackled is in play
if (origin != null && origin.isKnown()) { 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()) { if (!activateForCost && list.isEmpty()) {
@@ -1177,7 +1107,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
// Only care about combatants during combat // Only care about combatants during combat
if (game.getPhaseHandler().inCombat() && origin.contains(ZoneType.Battlefield)) { 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()) { if (!newList.isEmpty() || !sa.isTrigger()) {
list = newList; list = newList;
} }
@@ -1495,11 +1425,12 @@ public class ChangeZoneAi extends SpellAbilityAi {
if (sa.getTargets().size() == 0 || sa.getTargets().size() < tgt.getMinTargets(sa.getHostCard(), sa)) { if (sa.getTargets().size() == 0 || sa.getTargets().size() < tgt.getMinTargets(sa.getHostCard(), sa)) {
sa.resetTargets(); sa.resetTargets();
return false; return false;
} else {
if (!ComputerUtil.shouldCastLessThanMax(ai, source)) {
return false;
}
break;
} }
if (!ComputerUtil.shouldCastLessThanMax(ai, source)) {
return false;
}
break;
} }
list.remove(choice); list.remove(choice);
@@ -1774,7 +1705,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
Card source = sa.getHostCard(); Card source = sa.getHostCard();
String definedSac = StringUtils.split(source.getSVar("AIPreference"), "$")[1]; 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)); listToSac.sort(Collections.reverseOrder(CardLists.CmcComparatorInv));
CardCollection listToRet = CardLists.filter(ai.getCardsIn(ZoneType.Graveyard), Presets.CREATURES); CardCollection listToRet = CardLists.filter(ai.getCardsIn(ZoneType.Graveyard), Presets.CREATURES);
@@ -1811,7 +1742,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
String definedGoal = sa.getParam("ChangeType"); String definedGoal = sa.getParam("ChangeType");
boolean anyCMC = !definedGoal.contains(".cmc"); 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)); listToSac.sort(!sacWorst ? CardLists.CmcComparatorInv : Collections.reverseOrder(CardLists.CmcComparatorInv));
for (Card sacCandidate : listToSac) { for (Card sacCandidate : listToSac) {
@@ -1825,12 +1756,12 @@ public class ChangeZoneAi extends SpellAbilityAi {
curGoal = definedGoal.replace("X", String.format("%d", goalCMC)); 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) { if (!anyCMC) {
listGoal = CardLists.getValidCards(listGoal, curGoal, source.getController(), source, sa); listGoal = CardLists.getValidCards(listGoal, curGoal, source.getController(), source);
} else { } 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>() { listGoal = CardLists.filter(listGoal, new Predicate<Card>() {
@@ -2000,8 +1931,9 @@ public class ChangeZoneAi extends SpellAbilityAi {
if (choice != null) { if (choice != null) {
sa.getTargets().add(choice); sa.getTargets().add(choice);
return true; return true;
} else {
return false;
} }
return false;
} }
private static CardCollection getSafeTargetsIfUnlessCostPaid(Player ai, SpellAbility sa, Iterable<Card> potentialTgts) { private static CardCollection getSafeTargetsIfUnlessCostPaid(Player ai, SpellAbility sa, Iterable<Card> potentialTgts) {

View File

@@ -1,29 +1,12 @@
package forge.ai.ability; package forge.ai.ability;
import java.util.Collections;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import forge.ai.*;
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.game.Game; import forge.game.Game;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.card.Card; import forge.game.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.cost.Cost;
import forge.game.phase.PhaseType; import forge.game.phase.PhaseType;
import forge.game.player.Player; import forge.game.player.Player;
@@ -34,6 +17,8 @@ import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.util.MyRandom; import forge.util.MyRandom;
import java.util.Collections;
public class ChangeZoneAllAi extends SpellAbilityAi { public class ChangeZoneAllAi extends SpellAbilityAi {
@Override @Override
protected boolean canPlayAI(Player ai, SpellAbility sa) { protected boolean canPlayAI(Player ai, SpellAbility sa) {
@@ -51,7 +36,7 @@ public class ChangeZoneAllAi extends SpellAbilityAi {
return false; 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"); boolean aiLogicAllowsDiscard = sa.hasParam("AILogic") && sa.getParam("AILogic").startsWith("DiscardAll");
if (!aiLogicAllowsDiscard) { if (!aiLogicAllowsDiscard) {
@@ -245,8 +230,25 @@ public class ChangeZoneAllAi extends SpellAbilityAi {
&& !ComputerUtil.isPlayingReanimator(ai); && !ComputerUtil.isPlayingReanimator(ai);
} }
} else if (origin.equals(ZoneType.Exile)) { } else if (origin.equals(ZoneType.Exile)) {
// TODO: nothing to do here at the moment String logic = sa.getParam("AILogic");
return false;
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)) { } else if (origin.equals(ZoneType.Stack)) {
// time stop can do something like this: // time stop can do something like this:
// Origin$ Stack | Destination$ Exile | SubAbility$ DBSkip // Origin$ Stack | Destination$ Exile | SubAbility$ DBSkip

View File

@@ -1,15 +1,7 @@
package forge.ai.ability; package forge.ai.ability;
import java.util.List;
import java.util.Map;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import forge.ai.*;
import forge.ai.AiController;
import forge.ai.AiPlayDecision;
import forge.ai.ComputerUtilAbility;
import forge.ai.PlayerControllerAi;
import forge.ai.SpellAbilityAi;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.effects.CharmEffect; import forge.game.ability.effects.CharmEffect;
import forge.game.card.Card; import forge.game.card.Card;
@@ -20,6 +12,9 @@ import forge.util.Aggregates;
import forge.util.MyRandom; import forge.util.MyRandom;
import forge.util.collect.FCollection; import forge.util.collect.FCollection;
import java.util.List;
import java.util.Map;
public class CharmAi extends SpellAbilityAi { public class CharmAi extends SpellAbilityAi {
@Override @Override
protected boolean checkApiLogic(Player ai, SpellAbility sa) { 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 com.google.common.collect.Lists;
import forge.ai.ComputerUtilAbility; import forge.ai.ComputerUtilAbility;
import forge.ai.ComputerUtilCard; import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilCombat; import forge.ai.ComputerUtilCombat;
import forge.ai.SpellAbilityAi; import forge.ai.SpellAbilityAi;
@@ -20,6 +21,7 @@ import forge.game.card.CardCollectionView;
import forge.game.card.CardLists; import forge.game.card.CardLists;
import forge.game.card.CardPredicates; import forge.game.card.CardPredicates;
import forge.game.card.CardPredicates.Presets; import forge.game.card.CardPredicates.Presets;
import forge.game.card.CounterEnumType;
import forge.game.combat.Combat; import forge.game.combat.Combat;
import forge.game.keyword.Keyword; import forge.game.keyword.Keyword;
import forge.game.phase.PhaseType; import forge.game.phase.PhaseType;
@@ -64,7 +66,7 @@ public class ChooseCardAi extends SpellAbilityAi {
} }
CardCollectionView choices = ai.getGame().getCardsIn(choiceZone); CardCollectionView choices = ai.getGame().getCardsIn(choiceZone);
if (sa.hasParam("Choices")) { 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")) { if (sa.hasParam("TargetControls")) {
choices = CardLists.filterControlledBy(choices, ai.getOpponents()); 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" final String filter = aiLogic.equals("Clone") ? "Permanent.YouDontCtrl,Permanent.nonLegendary"
: "Permanent.YouDontCtrl+notnamedVesuva,Permanent.nonLegendary+notnamedVesuva"; : "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(); return !choices.isEmpty();
} else if (aiLogic.equals("Never")) { } else if (aiLogic.equals("Never")) {
return false; return false;
@@ -96,9 +98,21 @@ public class ChooseCardAi extends SpellAbilityAi {
return ComputerUtilCombat.damageIfUnblocked(c, ai, combat, true) > ref; 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(); return !choices.isEmpty();
} else if (aiLogic.equals("RandomNonLand")) { } 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")) { } else if (aiLogic.equals("Duneblast")) {
CardCollection aiCreatures = ai.getCreaturesInPlay(); CardCollection aiCreatures = ai.getCreaturesInPlay();
CardCollection oppCreatures = ai.getWeakestOpponent().getCreaturesInPlay(); CardCollection oppCreatures = ai.getWeakestOpponent().getCreaturesInPlay();
@@ -172,7 +186,7 @@ public class ChooseCardAi extends SpellAbilityAi {
choice = null; choice = null;
} }
} else if ("RandomNonLand".equals(logic)) { } 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); choice = Aggregates.random(options);
} else if (logic.equals("Untap")) { } else if (logic.equals("Untap")) {
final String filter = "Permanent.YouCtrl,Permanent.tapped"; 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 // Choose the best (hopefully the fattest, whatever) creature so that hopefully it won't die too easily
choice = ComputerUtilCard.getBestAI(creatures); choice = ComputerUtilCard.getBestAI(creatures);
} }
} else if (logic.equals("NextTurnAttacker")) {
choice = ComputerUtilCard.getBestCreatureToAttackNextTurnAI(ai, options);
} else { } else {
choice = ComputerUtilCard.getBestAI(options); choice = ComputerUtilCard.getBestAI(options);
} }

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,17 +1,16 @@
package forge.ai.ability; package forge.ai.ability;
import java.util.List;
import java.util.Map;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import forge.ai.ComputerUtil; import forge.ai.ComputerUtil;
import forge.ai.SpellAbilityAi; import forge.ai.SpellAbilityAi;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import java.util.List;
import java.util.Map;
public class ChoosePlayerAi extends SpellAbilityAi { public class ChoosePlayerAi extends SpellAbilityAi {
@Override @Override
protected boolean canPlayAI(Player ai, SpellAbility sa) { 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.ComputerUtilCard;
import forge.ai.ComputerUtilCombat; import forge.ai.ComputerUtilCombat;
import forge.ai.ComputerUtilCost;
import forge.ai.SpellAbilityAi; import forge.ai.SpellAbilityAi;
import forge.game.Game; import forge.game.Game;
import forge.game.GameObject; import forge.game.GameObject;
@@ -46,7 +47,20 @@ public class ChooseSourceAi extends SpellAbilityAi {
final Card source = sa.getHostCard(); final Card source = sa.getHostCard();
if (abCost != null) { 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; return false;
} }
} }
@@ -91,7 +105,7 @@ public class ChooseSourceAi extends SpellAbilityAi {
} }
CardCollectionView choices = game.getCardsIn(ZoneType.Battlefield); CardCollectionView choices = game.getCardsIn(ZoneType.Battlefield);
if (sa.hasParam("Choices")) { 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(); final Combat combat = game.getCombat();
choices = CardLists.filter(choices, new Predicate<Card>() { choices = CardLists.filter(choices, new Predicate<Card>() {
@@ -141,26 +155,27 @@ public class ChooseSourceAi extends SpellAbilityAi {
Card bestCreature = ComputerUtilCard.getBestCreatureAI(permanentSources); Card bestCreature = ComputerUtilCard.getBestCreatureAI(permanentSources);
if (bestCreature != null) { if (bestCreature != null) {
return bestCreature; return bestCreature;
} } else {
// No optimal creature was found above, so try to broaden the choice. // No optimal creature was found above, so try to broaden the choice.
if (!Iterables.isEmpty(options)) { if (!Iterables.isEmpty(options)) {
List<Card> oppCreatures = CardLists.filter(options, Predicates.and(CardPredicates.Presets.CREATURES, List<Card> oppCreatures = CardLists.filter(options, Predicates.and(CardPredicates.Presets.CREATURES,
Predicates.not(CardPredicates.isOwner(aiChoser)))); Predicates.not(CardPredicates.isOwner(aiChoser))));
List<Card> aiNonCreatures = CardLists.filter(options, Predicates.and(Predicates.not(CardPredicates.Presets.CREATURES), List<Card> aiNonCreatures = CardLists.filter(options, Predicates.and(Predicates.not(CardPredicates.Presets.CREATURES),
CardPredicates.Presets.PERMANENTS, CardPredicates.isOwner(aiChoser))); CardPredicates.Presets.PERMANENTS, CardPredicates.isOwner(aiChoser)));
if (!oppCreatures.isEmpty()) { if (!oppCreatures.isEmpty()) {
return ComputerUtilCard.getBestCreatureAI(oppCreatures); return ComputerUtilCard.getBestCreatureAI(oppCreatures);
} else if (!aiNonCreatures.isEmpty()) { } else if (!aiNonCreatures.isEmpty()) {
return Aggregates.random(aiNonCreatures); return Aggregates.random(aiNonCreatures);
} else { } else {
return Aggregates.random(options); 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 // Should never get here

View File

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

View File

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

View File

@@ -1,8 +1,5 @@
package forge.ai.ability; package forge.ai.ability;
import java.util.List;
import java.util.Map;
import forge.ai.ComputerUtilCard; import forge.ai.ComputerUtilCard;
import forge.ai.SpellAbilityAi; import forge.ai.SpellAbilityAi;
import forge.game.Game; import forge.game.Game;
@@ -17,6 +14,9 @@ import forge.game.player.PlayerActionConfirmMode;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import java.util.List;
import java.util.Map;
public class CloneAi extends SpellAbilityAi { public class CloneAi extends SpellAbilityAi {
@Override @Override
@@ -124,11 +124,11 @@ public class CloneAi extends SpellAbilityAi {
private boolean cloneTgtAI(final SpellAbility sa) { private boolean cloneTgtAI(final SpellAbility sa) {
// Specific logic for cards // Specific logic for cards
if ("CloneAttacker".equals(sa.getParam("AILogic"))) { 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)); sa.getTargets().add(ComputerUtilCard.getBestCreatureAI(valid));
return true; return true;
} else if ("CloneBestCreature".equals(sa.getParam("AILogic"))) { } 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)); sa.getTargets().add(ComputerUtilCard.getBestCreatureAI(valid));
return true; return true;
} }

View File

@@ -140,7 +140,7 @@ public class ControlExchangeAi extends SpellAbilityAi {
return false; return false;
} }
if (aiWorst != bestFirstTgt) { if (aiWorst != null && aiWorst != bestFirstTgt) {
if (bestFirstTgt.isCreature() && aiWorst.isCreature()) { if (bestFirstTgt.isCreature() && aiWorst.isCreature()) {
if ((ComputerUtilCard.evaluateCreature(bestFirstTgt) > ComputerUtilCard.evaluateCreature(aiWorst) + creatureThreshold) || sa.isMandatory()) { if ((ComputerUtilCard.evaluateCreature(bestFirstTgt) > ComputerUtilCard.evaluateCreature(aiWorst) + creatureThreshold) || sa.isMandatory()) {
sa.getTargets().add(aiWorst); 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); List<Card> list = CardLists.getTargetableCards(ai.getCardsIn(ZoneType.Battlefield), sa);
if (list.isEmpty()) { if (list.isEmpty()) {
return false; 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; 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.Predicate;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import forge.ai.*;
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.game.Game; import forge.game.Game;
import forge.game.ability.AbilityKey; import forge.game.ability.AbilityKey;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.card.Card; import forge.game.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.CardPredicates.Presets; import forge.game.card.CardPredicates.Presets;
import forge.game.card.CardUtil;
import forge.game.phase.PhaseHandler; import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType; import forge.game.phase.PhaseType;
import forge.game.player.Player; import forge.game.player.Player;
@@ -32,6 +17,10 @@ import forge.game.player.PlayerCollection;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import java.util.Collection;
import java.util.List;
import java.util.Map;
public class CopyPermanentAi extends SpellAbilityAi { public class CopyPermanentAi extends SpellAbilityAi {
@Override @Override
protected boolean canPlayAI(Player aiPlayer, SpellAbility sa) { protected boolean canPlayAI(Player aiPlayer, SpellAbility sa) {
@@ -184,7 +173,7 @@ public class CopyPermanentAi extends SpellAbilityAi {
} else if (sa.hasParam("Choices")) { } else if (sa.hasParam("Choices")) {
// only check for options, does not select there // only check for options, does not select there
CardCollectionView choices = game.getCardsIn(ZoneType.Battlefield); 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); Collection<Card> betterChoices = getBetterOptions(aiPlayer, sa, choices, !mandatory);
if (betterChoices.isEmpty()) { if (betterChoices.isEmpty()) {
return mandatory; return mandatory;

View File

@@ -1,15 +1,6 @@
package forge.ai.ability; package forge.ai.ability;
import java.util.List; import forge.ai.*;
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.game.Game; import forge.game.Game;
import forge.game.ability.ApiType; import forge.game.ability.ApiType;
import forge.game.player.Player; import forge.game.player.Player;
@@ -19,6 +10,9 @@ import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetRestrictions; import forge.game.spellability.TargetRestrictions;
import forge.util.MyRandom; import forge.util.MyRandom;
import java.util.List;
import java.util.Map;
public class CopySpellAbilityAi extends SpellAbilityAi { public class CopySpellAbilityAi extends SpellAbilityAi {
@Override @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 // Shouldn't even try with triggered or wrapped abilities at this time, will crash
return false; return false;
} else if (top.getApi() == ApiType.CopySpellAbility) { } else if (top.getApi() == ApiType.CopySpellAbility) {

View File

@@ -1,19 +1,6 @@
package forge.ai.ability; package forge.ai.ability;
import java.util.Iterator; import forge.ai.*;
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.game.Game; import forge.game.Game;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType; import forge.game.ability.ApiType;
@@ -29,6 +16,11 @@ import forge.game.spellability.SpellAbilityStackInstance;
import forge.game.spellability.TargetRestrictions; import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.util.MyRandom; 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 { public class CounterAi extends SpellAbilityAi {

View File

@@ -22,12 +22,7 @@ import java.util.List;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import forge.ai.ComputerUtilCard; import forge.ai.ComputerUtilCard;
import forge.game.card.Card; import forge.game.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.keyword.Keyword; import forge.game.keyword.Keyword;
import forge.util.Aggregates; import forge.util.Aggregates;

View File

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

View File

@@ -1,43 +1,19 @@
package forge.ai.ability; 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.Predicate;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import forge.ai.*;
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.card.CardStateName; import forge.card.CardStateName;
import forge.game.Game; import forge.game.Game;
import forge.game.GameEntity; import forge.game.GameEntity;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType; import forge.game.ability.ApiType;
import forge.game.card.Card; import forge.game.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.combat.Combat; import forge.game.combat.Combat;
import forge.game.combat.CombatUtil; import forge.game.combat.CombatUtil;
import forge.game.cost.Cost; import forge.game.cost.*;
import forge.game.cost.CostPart;
import forge.game.cost.CostPutCounter;
import forge.game.cost.CostRemoveCounter;
import forge.game.cost.CostSacrifice;
import forge.game.keyword.Keyword; import forge.game.keyword.Keyword;
import forge.game.phase.PhaseHandler; import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType; import forge.game.phase.PhaseType;
@@ -51,6 +27,10 @@ import forge.game.zone.ZoneType;
import forge.util.Aggregates; import forge.util.Aggregates;
import forge.util.MyRandom; import forge.util.MyRandom;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class CountersPutAi extends SpellAbilityAi { public class CountersPutAi extends SpellAbilityAi {
/* /*

View File

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

View File

@@ -17,27 +17,21 @@
*/ */
package forge.ai.ability; package forge.ai.ability;
import java.util.List;
import java.util.Map;
import forge.ai.ComputerUtil; import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilCard; import forge.ai.ComputerUtilCard;
import forge.ai.SpellAbilityAi; import forge.ai.SpellAbilityAi;
import forge.game.Game; import forge.game.Game;
import forge.game.GlobalRuleChange; import forge.game.GlobalRuleChange;
import forge.game.card.Card; import forge.game.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.keyword.Keyword; import forge.game.keyword.Keyword;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.player.PlayerController.BinaryChoiceType; import forge.game.player.PlayerController.BinaryChoiceType;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetRestrictions; import forge.game.spellability.TargetRestrictions;
import java.util.List;
import java.util.Map;
/** /**
* <p> * <p>
* AbilityFactory_PutOrRemoveCountersAi class. * AbilityFactory_PutOrRemoveCountersAi class.

View File

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

View File

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

View File

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

View File

@@ -1,39 +1,16 @@
package forge.ai.ability; 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.Predicate;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import forge.ai.*;
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.card.mana.ManaCost; import forge.card.mana.ManaCost;
import forge.game.Game; import forge.game.Game;
import forge.game.GameObject; import forge.game.GameObject;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType; import forge.game.ability.ApiType;
import forge.game.card.Card; import forge.game.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.cost.Cost; import forge.game.cost.Cost;
import forge.game.cost.CostPartMana; import forge.game.cost.CostPartMana;
import forge.game.cost.CostRemoveCounter; import forge.game.cost.CostRemoveCounter;
@@ -49,6 +26,12 @@ import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.util.Aggregates; import forge.util.Aggregates;
import forge.util.MyRandom; 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 { public class DamageDealAi extends DamageAiBase {
@Override @Override
@@ -178,7 +161,7 @@ public class DamageDealAi extends DamageAiBase {
} }
} else if ("WildHunt".equals(logic)) { } 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 // 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); dmg = Aggregates.sum(wolves, CardPredicates.Accessors.fnGetNetPower);
} else if ("Triskelion".equals(logic)) { } else if ("Triskelion".equals(logic)) {
final int n = source.getCounters(CounterEnumType.P1P1); final int n = source.getCounters(CounterEnumType.P1P1);
@@ -245,7 +228,7 @@ public class DamageDealAi extends DamageAiBase {
return false; 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; return false;
} }

View File

@@ -1,12 +1,6 @@
package forge.ai.ability; package forge.ai.ability;
import java.util.ArrayList; import forge.ai.*;
import java.util.List;
import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilCombat;
import forge.ai.SpellAbilityAi;
import forge.game.Game; import forge.game.Game;
import forge.game.GameObject; import forge.game.GameObject;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
@@ -25,6 +19,9 @@ import forge.game.spellability.TargetChoices;
import forge.game.spellability.TargetRestrictions; import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import java.util.ArrayList;
import java.util.List;
public class DamagePreventAi extends SpellAbilityAi { public class DamagePreventAi extends SpellAbilityAi {
@Override @Override
@@ -36,7 +33,20 @@ public class DamagePreventAi extends SpellAbilityAi {
final Cost cost = sa.getPayCosts(); 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; return false;
} }

View File

@@ -1,5 +1,7 @@
package forge.ai.ability; package forge.ai.ability;
import forge.ai.ComputerUtilCost;
import forge.ai.SpellAbilityAi; import forge.ai.SpellAbilityAi;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.cost.Cost; import forge.game.cost.Cost;
@@ -20,7 +22,19 @@ public class DamagePreventAllAi extends SpellAbilityAi {
final Cost cost = sa.getPayCosts(); final Cost cost = sa.getPayCosts();
// temporarily disabled until better AI // 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; return false;
} }

View File

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

View File

@@ -1,14 +1,7 @@
package forge.ai.ability; package forge.ai.ability;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import forge.ai.*;
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.card.mana.ManaCost; import forge.card.mana.ManaCost;
import forge.game.ability.ApiType; import forge.game.ability.ApiType;
import forge.game.card.Card; import forge.game.card.Card;

View File

@@ -1,23 +1,10 @@
package forge.ai.ability; package forge.ai.ability;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import forge.ai.*;
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.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType; import forge.game.ability.ApiType;
import forge.game.card.Card; import forge.game.card.*;
import forge.game.card.CardCollection;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CounterEnumType;
import forge.game.cost.Cost; import forge.game.cost.Cost;
import forge.game.cost.CostPart; import forge.game.cost.CostPart;
import forge.game.cost.CostSacrifice; 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.Predicate;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
import forge.ai.*;
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.card.MagicColor; import forge.card.MagicColor;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardCollection; 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.base.Predicate;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import forge.ai.ComputerUtil; import forge.ai.*;
import forge.ai.ComputerUtilAbility;
import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilCost;
import forge.ai.SpecialCardAi;
import forge.ai.SpellAbilityAi;
import forge.game.Game; import forge.game.Game;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.card.Card; import forge.game.card.Card;

View File

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

View File

@@ -1,13 +1,6 @@
package forge.ai.ability; package forge.ai.ability;
import java.util.List; import forge.ai.*;
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.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardCollectionView; import forge.game.card.CardCollectionView;
@@ -22,6 +15,8 @@ import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.util.MyRandom; import forge.util.MyRandom;
import java.util.List;
public class DiscardAi extends SpellAbilityAi { public class DiscardAi extends SpellAbilityAi {
@Override @Override
@@ -32,9 +27,24 @@ public class DiscardAi extends SpellAbilityAi {
final Cost abCost = sa.getPayCosts(); final Cost abCost = sa.getPayCosts();
final String aiLogic = sa.getParamOrDefault("AILogic", ""); final String aiLogic = sa.getParamOrDefault("AILogic", "");
// temporarily disabled until better AI if (abCost != null) {
if (!willPayCosts(ai, sa, abCost, source)) { // AI currently disabled for these costs
return false; 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)) { if ("Chandra, Flamecaller".equals(sourceName)) {

View File

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

View File

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

View File

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

View File

@@ -1,17 +1,8 @@
package forge.ai.ability; package forge.ai.ability;
import forge.ai.AiController; import forge.ai.*;
import forge.ai.AiProps; import forge.game.card.*;
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.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,27 +1,12 @@
package forge.ai.ability; package forge.ai.ability;
import java.util.Arrays;
import java.util.List;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
import forge.ai.*;
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.card.ColorSet; import forge.card.ColorSet;
import forge.card.MagicColor; import forge.card.MagicColor;
import forge.card.mana.ManaCost; import forge.card.mana.ManaCost;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.card.Card; import forge.game.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.cost.CostPart; import forge.game.cost.CostPart;
import forge.game.cost.CostRemoveCounter; import forge.game.cost.CostRemoveCounter;
import forge.game.keyword.Keyword; import forge.game.keyword.Keyword;
@@ -32,6 +17,9 @@ import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.util.Aggregates; import forge.util.Aggregates;
import java.util.Arrays;
import java.util.List;
public class ManaEffectAi extends SpellAbilityAi { public class ManaEffectAi extends SpellAbilityAi {
/* /*

View File

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

View File

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

View File

@@ -1,13 +1,7 @@
package forge.ai.ability; 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.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import forge.ai.ComputerUtil; import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilCost; import forge.ai.ComputerUtilCost;
import forge.ai.SpecialCardAi; import forge.ai.SpecialCardAi;
@@ -25,6 +19,11 @@ import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetRestrictions; import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType; 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 { public class MillAi extends SpellAbilityAi {
@Override @Override

View File

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

View File

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

View File

@@ -1,5 +1,6 @@
package forge.ai.ability; package forge.ai.ability;
import forge.game.card.*;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
@@ -12,11 +13,6 @@ import forge.card.CardType.Supertype;
import forge.card.mana.ManaCost; import forge.card.mana.ManaCost;
import forge.game.Game; import forge.game.Game;
import forge.game.GlobalRuleChange; 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.cost.Cost;
import forge.game.keyword.KeywordInterface; import forge.game.keyword.KeywordInterface;
import forge.game.mana.ManaCostBeingPaid; import forge.game.mana.ManaCostBeingPaid;

View File

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

View File

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

View File

@@ -1,30 +1,16 @@
package forge.ai.ability; 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.base.Predicate;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import forge.ai.AiController; import forge.ai.*;
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.card.CardStateName; import forge.card.CardStateName;
import forge.card.CardTypeView; import forge.card.CardTypeView;
import forge.game.Game; import forge.game.Game;
import forge.game.GameType; import forge.game.GameType;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.card.Card; import forge.game.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.cost.Cost;
import forge.game.keyword.Keyword; import forge.game.keyword.Keyword;
import forge.game.player.Player; import forge.game.player.Player;
@@ -37,6 +23,10 @@ import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.util.MyRandom; import forge.util.MyRandom;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
public class PlayAi extends SpellAbilityAi { public class PlayAi extends SpellAbilityAi {
@Override @Override

View File

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

View File

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

View File

@@ -1,5 +1,7 @@
package forge.ai.ability; package forge.ai.ability;
import forge.ai.ComputerUtilCost;
import forge.ai.SpellAbilityAi; import forge.ai.SpellAbilityAi;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.cost.Cost; import forge.game.cost.Cost;
@@ -19,7 +21,19 @@ public class ProtectAllAi extends SpellAbilityAi {
final Cost cost = sa.getPayCosts(); final Cost cost = sa.getPayCosts();
// temporarily disabled until better AI // 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; return false;
} }

View File

@@ -1,32 +1,14 @@
package forge.ai.ability; 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.Predicate;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import forge.ai.*;
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.game.Game; import forge.game.Game;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType; import forge.game.ability.ApiType;
import forge.game.card.Card; import forge.game.card.*;
import forge.game.card.CardCollection;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CardPredicates.Presets; 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.Cost;
import forge.game.cost.CostTapType; import forge.game.cost.CostTapType;
import forge.game.keyword.Keyword; import forge.game.keyword.Keyword;
@@ -38,6 +20,10 @@ import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetRestrictions; import forge.game.spellability.TargetRestrictions;
import forge.game.staticability.StaticAbility; import forge.game.staticability.StaticAbility;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import org.apache.commons.lang3.StringUtils;
import java.util.Arrays;
import java.util.List;
public class PumpAi extends PumpAiBase { public class PumpAi extends PumpAiBase {

View File

@@ -1,11 +1,8 @@
package forge.ai.ability; package forge.ai.ability;
import java.util.List;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import forge.ai.ComputerUtil; import forge.ai.ComputerUtil;
import forge.ai.ComputerUtilCard; import forge.ai.ComputerUtilCard;
import forge.ai.ComputerUtilCombat; import forge.ai.ComputerUtilCombat;
@@ -13,12 +10,7 @@ import forge.ai.SpellAbilityAi;
import forge.card.MagicColor; import forge.card.MagicColor;
import forge.game.Game; import forge.game.Game;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.card.Card; import forge.game.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.combat.Combat; import forge.game.combat.Combat;
import forge.game.combat.CombatUtil; import forge.game.combat.CombatUtil;
import forge.game.keyword.Keyword; import forge.game.keyword.Keyword;
@@ -29,6 +21,8 @@ import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import java.util.List;
public abstract class PumpAiBase extends SpellAbilityAi { 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) { 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; 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.base.Predicate;
import forge.ai.ComputerUtil; import forge.ai.ComputerUtil;
@@ -26,6 +22,10 @@ import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetRestrictions; import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class PumpAllAi extends PumpAiBase { public class PumpAllAi extends PumpAiBase {
/* (non-Javadoc) /* (non-Javadoc)
@@ -69,8 +69,8 @@ public class PumpAllAi extends PumpAiBase {
} }
final Player opp = ai.getWeakestOpponent(); final Player opp = ai.getWeakestOpponent();
CardCollection comp = CardLists.getValidCards(ai.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, sa); CardCollection human = CardLists.getValidCards(opp.getCardsIn(ZoneType.Battlefield), valid, source.getController(), source);
final TargetRestrictions tgt = sa.getTargetRestrictions(); final TargetRestrictions tgt = sa.getTargetRestrictions();
if (tgt != null && sa.canTarget(opp) && sa.hasParam("IsCurse")) { 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); return (ComputerUtilCard.evaluateCreatureList(comp) + 200) < ComputerUtilCard.evaluateCreatureList(human);
} // end Curse } // 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() } // pumpAllCanPlayAI()
@Override @Override

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -65,7 +65,7 @@ public class RevealAi extends RevealAiBase {
for (SpellAbility s : c.getBasicSpells()) { for (SpellAbility s : c.getBasicSpells()) {
Spell spell = (Spell) s.copy(ai); Spell spell = (Spell) s.copy(ai);
// timing restrictions still apply // timing restrictions still apply
if (!spell.getRestrictions().checkTimingRestrictions(c, spell)) if (!s.getRestrictions().checkTimingRestrictions(c, s))
continue; continue;
// use hard coded reduce cost // 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)); return game.getCombat() != null && (game.getCombat().isAttacking(source) || game.getCombat().isBlocking(source));
} else if (logic.equals("Main2")) { } else if (logic.equals("Main2")) {
return ph.is(PhaseType.MAIN2, aiPlayer); 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())) { if (cost != null && (sa.getPayCosts().hasManaCost() || sa.getPayCosts().hasTapCost())) {

View File

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

View File

@@ -1,16 +1,11 @@
package forge.ai.ability; package forge.ai.ability;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
import forge.ai.ComputerUtilMana; import forge.ai.ComputerUtilMana;
import forge.ai.SpellAbilityAi; import forge.ai.SpellAbilityAi;
import forge.game.ability.ApiType; import forge.game.ability.ApiType;
import forge.game.card.Card; import forge.game.card.*;
import forge.game.card.Card.SplitCMCMode; 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.PhaseHandler;
import forge.game.phase.PhaseType; import forge.game.phase.PhaseType;
import forge.game.player.Player; import forge.game.player.Player;

View File

@@ -1,20 +1,14 @@
package forge.ai.ability; package forge.ai.ability;
import com.google.common.base.Predicate; import com.google.common.base.Predicate;
import forge.ai.ComputerUtilCard; import forge.ai.ComputerUtilCard;
import forge.ai.SpellAbilityAi; import forge.ai.SpellAbilityAi;
import forge.card.CardStateName; import forge.card.CardStateName;
import forge.game.Game; import forge.game.Game;
import forge.game.GlobalRuleChange; import forge.game.GlobalRuleChange;
import forge.game.ability.AbilityUtils; import forge.game.ability.AbilityUtils;
import forge.game.card.Card; import forge.game.card.*;
import forge.game.card.CardCollection;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates.Presets; 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.PhaseHandler;
import forge.game.phase.PhaseType; import forge.game.phase.PhaseType;
import forge.game.player.Player; 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