mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-15 18:28:00 +00:00
predictThreatenedObjects moved from AbilityFactory to ComputerUtil (for now, will find a more specific place later)
GameActionUtil.payCostDuringAbilityResolve method now demands player parameter (though it is always human player)
This commit is contained in:
@@ -555,7 +555,7 @@ public class GameAction {
|
|||||||
public void resolve() {
|
public void resolve() {
|
||||||
Player p = recoverable.getController();
|
Player p = recoverable.getController();
|
||||||
if (p.isHuman()) {
|
if (p.isHuman()) {
|
||||||
GameActionUtil.payCostDuringAbilityResolve(abRecover, abRecover.getPayCosts(),
|
GameActionUtil.payCostDuringAbilityResolve(p, abRecover, abRecover.getPayCosts(),
|
||||||
paidCommand, unpaidCommand, null, game);
|
paidCommand, unpaidCommand, null, game);
|
||||||
} else { // computer
|
} else { // computer
|
||||||
if (ComputerUtilCost.canPayCost(abRecover, p)) {
|
if (ComputerUtilCost.canPayCost(abRecover, p)) {
|
||||||
|
|||||||
@@ -423,11 +423,10 @@ public final class GameActionUtil {
|
|||||||
* a {@link forge.Command} object.
|
* a {@link forge.Command} object.
|
||||||
* @param sourceAbility TODO
|
* @param sourceAbility TODO
|
||||||
*/
|
*/
|
||||||
public static void payCostDuringAbilityResolve(final SpellAbility ability, final Cost cost, final Command paid,
|
public static void payCostDuringAbilityResolve(final Player p, final SpellAbility ability, final Cost cost, final Command paid,
|
||||||
final Command unpaid, SpellAbility sourceAbility, final GameState game) {
|
final Command unpaid, SpellAbility sourceAbility, final GameState game) {
|
||||||
final Card source = ability.getSourceCard();
|
final Card source = ability.getSourceCard();
|
||||||
final List<CostPart> parts = cost.getCostParts();
|
final List<CostPart> parts = cost.getCostParts();
|
||||||
Player p = Singletons.getControl().getPlayer();
|
|
||||||
ArrayList<CostPart> remainingParts = new ArrayList<CostPart>(cost.getCostParts());
|
ArrayList<CostPart> remainingParts = new ArrayList<CostPart>(cost.getCostParts());
|
||||||
CostPart costPart = null;
|
CostPart costPart = null;
|
||||||
if (!parts.isEmpty()) {
|
if (!parts.isEmpty()) {
|
||||||
|
|||||||
@@ -1237,196 +1237,6 @@ public class AbilityFactory {
|
|||||||
return objects;
|
return objects;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* predictThreatenedObjects.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param saviourAf
|
|
||||||
* a AbilityFactory object
|
|
||||||
* @return a {@link java.util.ArrayList} object.
|
|
||||||
* @since 1.0.15
|
|
||||||
*/
|
|
||||||
public static ArrayList<Object> predictThreatenedObjects(final Player aiPlayer, final SpellAbility sa) {
|
|
||||||
final ArrayList<Object> objects = new ArrayList<Object>();
|
|
||||||
if (Singletons.getModel().getGame().getStack().isEmpty()) {
|
|
||||||
return objects;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check stack for something that will kill this
|
|
||||||
final SpellAbility topStack = Singletons.getModel().getGame().getStack().peekAbility();
|
|
||||||
objects.addAll(AbilityFactory.predictThreatenedObjects(aiPlayer, sa, topStack));
|
|
||||||
|
|
||||||
return objects;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* predictThreatenedObjects.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param saviourAf
|
|
||||||
* a AbilityFactory object
|
|
||||||
* @param topStack
|
|
||||||
* a {@link forge.card.spellability.SpellAbility} object.
|
|
||||||
* @return a {@link java.util.ArrayList} object.
|
|
||||||
* @since 1.0.15
|
|
||||||
*/
|
|
||||||
public static ArrayList<Object> predictThreatenedObjects(final Player aiPlayer, final SpellAbility saviour,
|
|
||||||
final SpellAbility topStack) {
|
|
||||||
ArrayList<Object> objects = new ArrayList<Object>();
|
|
||||||
final ArrayList<Object> threatened = new ArrayList<Object>();
|
|
||||||
ApiType saviourApi = saviour.getApi();
|
|
||||||
|
|
||||||
if (topStack == null) {
|
|
||||||
return objects;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Card source = topStack.getSourceCard();
|
|
||||||
final ApiType threatApi = topStack.getApi();
|
|
||||||
|
|
||||||
// Can only Predict things from AFs
|
|
||||||
if (threatApi != null) {
|
|
||||||
final Target tgt = topStack.getTarget();
|
|
||||||
|
|
||||||
if (tgt == null) {
|
|
||||||
if (topStack.hasParam("Defined")) {
|
|
||||||
objects = AbilityFactory.getDefinedObjects(source, topStack.getParam("Defined"), topStack);
|
|
||||||
} else if (topStack.hasParam("ValidCards")) {
|
|
||||||
List<Card> battleField = aiPlayer.getCardsIn(ZoneType.Battlefield);
|
|
||||||
List<Card> cards = CardLists.getValidCards(battleField, topStack.getParam("ValidCards").split(","), source.getController(), source);
|
|
||||||
for (Card card : cards) {
|
|
||||||
objects.add(card);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
objects = tgt.getTargets();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine if Defined Objects are "threatened" will be destroyed
|
|
||||||
// due to this SA
|
|
||||||
|
|
||||||
// Lethal Damage => prevent damage/regeneration/bounce/shroud
|
|
||||||
if (threatApi == ApiType.DealDamage || threatApi == ApiType.DamageAll) {
|
|
||||||
// If PredictDamage is >= Lethal Damage
|
|
||||||
final int dmg = AbilityFactory.calculateAmount(topStack.getSourceCard(),
|
|
||||||
topStack.getParam("NumDmg"), topStack);
|
|
||||||
for (final Object o : objects) {
|
|
||||||
if (o instanceof Card) {
|
|
||||||
final Card c = (Card) o;
|
|
||||||
|
|
||||||
// indestructible
|
|
||||||
if (c.hasKeyword("Indestructible")) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// already regenerated
|
|
||||||
if (c.getShield() > 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// don't use it on creatures that can't be regenerated
|
|
||||||
if ((saviourApi == ApiType.Regenerate || saviourApi == ApiType.RegenerateAll) && !c.canBeShielded()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// give Shroud to targeted creatures
|
|
||||||
if (saviourApi == ApiType.Pump && tgt == null && saviour.hasParam("KW")
|
|
||||||
&& (saviour.getParam("KW").endsWith("Shroud")
|
|
||||||
|| saviour.getParam("KW").endsWith("Hexproof"))) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// don't bounce or blink a permanent that the human
|
|
||||||
// player owns or is a token
|
|
||||||
if (saviourApi == ApiType.ChangeZone && (c.getOwner().isHuman() || c.isToken())) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c.predictDamage(dmg, source, false) >= c.getKillDamage()) {
|
|
||||||
threatened.add(c);
|
|
||||||
}
|
|
||||||
} else if (o instanceof Player) {
|
|
||||||
final Player p = (Player) o;
|
|
||||||
|
|
||||||
if (source.hasKeyword("Infect")) {
|
|
||||||
if (p.predictDamage(dmg, source, false) >= p.getPoisonCounters()) {
|
|
||||||
threatened.add(p);
|
|
||||||
}
|
|
||||||
} else if (p.predictDamage(dmg, source, false) >= p.getLife()) {
|
|
||||||
threatened.add(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Destroy => regeneration/bounce/shroud
|
|
||||||
else if ((threatApi == ApiType.Destroy || threatApi == ApiType.DestroyAll)
|
|
||||||
&& (((saviourApi == ApiType.Regenerate || saviourApi == ApiType.RegenerateAll)
|
|
||||||
&& !topStack.hasParam("NoRegen")) || saviourApi == ApiType.ChangeZone || saviourApi == ApiType.Pump)) {
|
|
||||||
for (final Object o : objects) {
|
|
||||||
if (o instanceof Card) {
|
|
||||||
final Card c = (Card) o;
|
|
||||||
// indestructible
|
|
||||||
if (c.hasKeyword("Indestructible")) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// already regenerated
|
|
||||||
if (c.getShield() > 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// give Shroud to targeted creatures
|
|
||||||
if (saviourApi == ApiType.Pump && tgt == null && saviour.hasParam("KW")
|
|
||||||
&& (saviour.getParam("KW").endsWith("Shroud")
|
|
||||||
|| saviour.getParam("KW").endsWith("Hexproof"))) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// don't bounce or blink a permanent that the human
|
|
||||||
// player owns or is a token
|
|
||||||
if (saviourApi == ApiType.ChangeZone && (c.getOwner().isHuman() || c.isToken())) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// don't use it on creatures that can't be regenerated
|
|
||||||
if (saviourApi == ApiType.Regenerate && !c.canBeShielded()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
threatened.add(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Exiling => bounce/shroud
|
|
||||||
else if ((threatApi == ApiType.ChangeZone || threatApi == ApiType.ChangeZoneAll)
|
|
||||||
&& (saviourApi == ApiType.ChangeZone || saviourApi == ApiType.Pump)
|
|
||||||
&& topStack.hasParam("Destination")
|
|
||||||
&& topStack.getParam("Destination").equals("Exile")) {
|
|
||||||
for (final Object o : objects) {
|
|
||||||
if (o instanceof Card) {
|
|
||||||
final Card c = (Card) o;
|
|
||||||
// give Shroud to targeted creatures
|
|
||||||
if (saviourApi == ApiType.Pump && tgt == null && saviour.hasParam("KW")
|
|
||||||
&& (saviour.getParam("KW").endsWith("Shroud") || saviour.getParam("KW").endsWith("Hexproof"))) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// don't bounce or blink a permanent that the human
|
|
||||||
// player owns or is a token
|
|
||||||
if (saviourApi == ApiType.ChangeZone && (c.getOwner().isHuman() || c.isToken())) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
threatened.add(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
threatened.addAll(AbilityFactory.predictThreatenedObjects(aiPlayer, saviour, topStack.getSubAbility()));
|
|
||||||
return threatened;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* handleRemembering.
|
* handleRemembering.
|
||||||
@@ -1667,7 +1477,7 @@ public class AbilityFactory {
|
|||||||
if (paid) {
|
if (paid) {
|
||||||
unpaidCommand = paidCommand;
|
unpaidCommand = paidCommand;
|
||||||
}
|
}
|
||||||
GameActionUtil.payCostDuringAbilityResolve(ability, cost, paidCommand, unpaidCommand, sa, game);
|
GameActionUtil.payCostDuringAbilityResolve(payer, ability, cost, paidCommand, unpaidCommand, sa, game);
|
||||||
waitForInput = true; // wait for the human input
|
waitForInput = true; // wait for the human input
|
||||||
break; // multiple human players are not supported
|
break; // multiple human players are not supported
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -600,7 +600,7 @@ public class ChangeZoneAi extends SpellAiLogic {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
final ArrayList<Object> objects = AbilityFactory.predictThreatenedObjects(ai, sa);
|
final ArrayList<Object> objects = ComputerUtil.predictThreatenedObjects(ai, sa);
|
||||||
boolean contains = false;
|
boolean contains = false;
|
||||||
for (final Card c : retrieval) {
|
for (final Card c : retrieval) {
|
||||||
if (objects.contains(c)) {
|
if (objects.contains(c)) {
|
||||||
@@ -720,7 +720,7 @@ public class ChangeZoneAi extends SpellAiLogic {
|
|||||||
// check stack for something on the stack that will kill
|
// check stack for something on the stack that will kill
|
||||||
// anything i control
|
// anything i control
|
||||||
if (Singletons.getModel().getGame().getStack().size() > 0) {
|
if (Singletons.getModel().getGame().getStack().size() > 0) {
|
||||||
final ArrayList<Object> objects = AbilityFactory.predictThreatenedObjects(ai, sa);
|
final ArrayList<Object> objects = ComputerUtil.predictThreatenedObjects(ai, sa);
|
||||||
|
|
||||||
final List<Card> threatenedTargets = new ArrayList<Card>();
|
final List<Card> threatenedTargets = new ArrayList<Card>();
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import forge.card.cardfactory.CardFactoryUtil;
|
|||||||
import forge.card.cost.Cost;
|
import forge.card.cost.Cost;
|
||||||
import forge.card.spellability.SpellAbility;
|
import forge.card.spellability.SpellAbility;
|
||||||
import forge.card.spellability.Target;
|
import forge.card.spellability.Target;
|
||||||
|
import forge.game.ai.ComputerUtil;
|
||||||
import forge.game.ai.ComputerUtilCombat;
|
import forge.game.ai.ComputerUtilCombat;
|
||||||
import forge.game.ai.ComputerUtilCost;
|
import forge.game.ai.ComputerUtilCost;
|
||||||
import forge.game.phase.PhaseHandler;
|
import forge.game.phase.PhaseHandler;
|
||||||
@@ -56,7 +57,7 @@ public class DamagePreventAi extends SpellAiLogic {
|
|||||||
|
|
||||||
// react to threats on the stack
|
// react to threats on the stack
|
||||||
if (Singletons.getModel().getGame().getStack().size() > 0) {
|
if (Singletons.getModel().getGame().getStack().size() > 0) {
|
||||||
final ArrayList<Object> threatenedObjects = AbilityFactory.predictThreatenedObjects(sa.getActivatingPlayer(), sa);
|
final ArrayList<Object> threatenedObjects = ComputerUtil.predictThreatenedObjects(sa.getActivatingPlayer(), sa);
|
||||||
for (final Object o : objects) {
|
for (final Object o : objects) {
|
||||||
if (threatenedObjects.contains(o)) {
|
if (threatenedObjects.contains(o)) {
|
||||||
chance = true;
|
chance = true;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import forge.card.abilityfactory.SpellAiLogic;
|
|||||||
import forge.card.cardfactory.CardFactoryUtil;
|
import forge.card.cardfactory.CardFactoryUtil;
|
||||||
import forge.card.spellability.SpellAbility;
|
import forge.card.spellability.SpellAbility;
|
||||||
import forge.game.GameState;
|
import forge.game.GameState;
|
||||||
|
import forge.game.ai.ComputerUtil;
|
||||||
import forge.game.ai.ComputerUtilCombat;
|
import forge.game.ai.ComputerUtilCombat;
|
||||||
import forge.game.phase.Combat;
|
import forge.game.phase.Combat;
|
||||||
import forge.game.phase.CombatUtil;
|
import forge.game.phase.CombatUtil;
|
||||||
@@ -336,7 +337,7 @@ public abstract class PumpAiBase extends SpellAiLogic {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (keyword.equals("Shroud") || keyword.equals("Hexproof")) {
|
} else if (keyword.equals("Shroud") || keyword.equals("Hexproof")) {
|
||||||
if (!AbilityFactory.predictThreatenedObjects(sa.getActivatingPlayer(), sa).contains(card)) {
|
if (!ComputerUtil.predictThreatenedObjects(sa.getActivatingPlayer(), sa).contains(card)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (keyword.equals("Islandwalk")) {
|
} else if (keyword.equals("Islandwalk")) {
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import forge.card.cardfactory.CardFactoryUtil;
|
|||||||
import forge.card.cost.Cost;
|
import forge.card.cost.Cost;
|
||||||
import forge.card.spellability.SpellAbility;
|
import forge.card.spellability.SpellAbility;
|
||||||
import forge.card.spellability.Target;
|
import forge.card.spellability.Target;
|
||||||
|
import forge.game.ai.ComputerUtil;
|
||||||
import forge.game.ai.ComputerUtilCombat;
|
import forge.game.ai.ComputerUtilCombat;
|
||||||
import forge.game.ai.ComputerUtilCost;
|
import forge.game.ai.ComputerUtilCost;
|
||||||
import forge.game.phase.PhaseType;
|
import forge.game.phase.PhaseType;
|
||||||
@@ -83,7 +84,7 @@ public class RegenerateAi extends SpellAiLogic {
|
|||||||
final List<Card> list = AbilityFactory.getDefinedCards(hostCard, sa.getParam("Defined"), sa);
|
final List<Card> list = AbilityFactory.getDefinedCards(hostCard, sa.getParam("Defined"), sa);
|
||||||
|
|
||||||
if (Singletons.getModel().getGame().getStack().size() > 0) {
|
if (Singletons.getModel().getGame().getStack().size() > 0) {
|
||||||
final List<Object> objects = AbilityFactory.predictThreatenedObjects(sa.getActivatingPlayer(), sa);
|
final List<Object> objects = ComputerUtil.predictThreatenedObjects(sa.getActivatingPlayer(), sa);
|
||||||
|
|
||||||
for (final Card c : list) {
|
for (final Card c : list) {
|
||||||
if (objects.contains(c)) {
|
if (objects.contains(c)) {
|
||||||
@@ -119,7 +120,7 @@ public class RegenerateAi extends SpellAiLogic {
|
|||||||
if (Singletons.getModel().getGame().getStack().size() > 0) {
|
if (Singletons.getModel().getGame().getStack().size() > 0) {
|
||||||
// check stack for something on the stack will kill anything i
|
// check stack for something on the stack will kill anything i
|
||||||
// control
|
// control
|
||||||
final ArrayList<Object> objects = AbilityFactory.predictThreatenedObjects(sa.getActivatingPlayer(), sa);
|
final ArrayList<Object> objects = ComputerUtil.predictThreatenedObjects(sa.getActivatingPlayer(), sa);
|
||||||
|
|
||||||
final List<Card> threatenedTargets = new ArrayList<Card>();
|
final List<Card> threatenedTargets = new ArrayList<Card>();
|
||||||
|
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ import forge.Card;
|
|||||||
import forge.CardLists;
|
import forge.CardLists;
|
||||||
import forge.CardPredicates;
|
import forge.CardPredicates;
|
||||||
import forge.Singletons;
|
import forge.Singletons;
|
||||||
import forge.card.abilityfactory.AbilityFactory;
|
|
||||||
import forge.card.abilityfactory.SpellAiLogic;
|
import forge.card.abilityfactory.SpellAiLogic;
|
||||||
import forge.card.cost.Cost;
|
import forge.card.cost.Cost;
|
||||||
import forge.card.spellability.SpellAbility;
|
import forge.card.spellability.SpellAbility;
|
||||||
|
import forge.game.ai.ComputerUtil;
|
||||||
import forge.game.ai.ComputerUtilCombat;
|
import forge.game.ai.ComputerUtilCombat;
|
||||||
import forge.game.ai.ComputerUtilCost;
|
import forge.game.ai.ComputerUtilCost;
|
||||||
import forge.game.phase.PhaseType;
|
import forge.game.phase.PhaseType;
|
||||||
@@ -56,7 +56,7 @@ public class RegenerateAllAi extends SpellAiLogic {
|
|||||||
|
|
||||||
int numSaved = 0;
|
int numSaved = 0;
|
||||||
if (Singletons.getModel().getGame().getStack().size() > 0) {
|
if (Singletons.getModel().getGame().getStack().size() > 0) {
|
||||||
final ArrayList<Object> objects = AbilityFactory.predictThreatenedObjects(sa.getActivatingPlayer(), sa);
|
final ArrayList<Object> objects = ComputerUtil.predictThreatenedObjects(sa.getActivatingPlayer(), sa);
|
||||||
|
|
||||||
for (final Card c : list) {
|
for (final Card c : list) {
|
||||||
if (objects.contains(c) && c.getShield() == 0) {
|
if (objects.contains(c) && c.getShield() == 0) {
|
||||||
|
|||||||
@@ -1047,4 +1047,194 @@ public class ComputerUtil {
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
} // hasACardGivingHaste
|
} // hasACardGivingHaste
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* predictThreatenedObjects.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param saviourAf
|
||||||
|
* a AbilityFactory object
|
||||||
|
* @return a {@link java.util.ArrayList} object.
|
||||||
|
* @since 1.0.15
|
||||||
|
*/
|
||||||
|
public static ArrayList<Object> predictThreatenedObjects(final Player aiPlayer, final SpellAbility sa) {
|
||||||
|
final ArrayList<Object> objects = new ArrayList<Object>();
|
||||||
|
if (Singletons.getModel().getGame().getStack().isEmpty()) {
|
||||||
|
return objects;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check stack for something that will kill this
|
||||||
|
final SpellAbility topStack = Singletons.getModel().getGame().getStack().peekAbility();
|
||||||
|
objects.addAll(ComputerUtil.predictThreatenedObjects(aiPlayer, sa, topStack));
|
||||||
|
|
||||||
|
return objects;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* predictThreatenedObjects.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param saviourAf
|
||||||
|
* a AbilityFactory object
|
||||||
|
* @param topStack
|
||||||
|
* a {@link forge.card.spellability.SpellAbility} object.
|
||||||
|
* @return a {@link java.util.ArrayList} object.
|
||||||
|
* @since 1.0.15
|
||||||
|
*/
|
||||||
|
public static ArrayList<Object> predictThreatenedObjects(final Player aiPlayer, final SpellAbility saviour,
|
||||||
|
final SpellAbility topStack) {
|
||||||
|
ArrayList<Object> objects = new ArrayList<Object>();
|
||||||
|
final ArrayList<Object> threatened = new ArrayList<Object>();
|
||||||
|
ApiType saviourApi = saviour.getApi();
|
||||||
|
|
||||||
|
if (topStack == null) {
|
||||||
|
return objects;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Card source = topStack.getSourceCard();
|
||||||
|
final ApiType threatApi = topStack.getApi();
|
||||||
|
|
||||||
|
// Can only Predict things from AFs
|
||||||
|
if (threatApi != null) {
|
||||||
|
final Target tgt = topStack.getTarget();
|
||||||
|
|
||||||
|
if (tgt == null) {
|
||||||
|
if (topStack.hasParam("Defined")) {
|
||||||
|
objects = AbilityFactory.getDefinedObjects(source, topStack.getParam("Defined"), topStack);
|
||||||
|
} else if (topStack.hasParam("ValidCards")) {
|
||||||
|
List<Card> battleField = aiPlayer.getCardsIn(ZoneType.Battlefield);
|
||||||
|
List<Card> cards = CardLists.getValidCards(battleField, topStack.getParam("ValidCards").split(","), source.getController(), source);
|
||||||
|
for (Card card : cards) {
|
||||||
|
objects.add(card);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
objects = tgt.getTargets();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine if Defined Objects are "threatened" will be destroyed
|
||||||
|
// due to this SA
|
||||||
|
|
||||||
|
// Lethal Damage => prevent damage/regeneration/bounce/shroud
|
||||||
|
if (threatApi == ApiType.DealDamage || threatApi == ApiType.DamageAll) {
|
||||||
|
// If PredictDamage is >= Lethal Damage
|
||||||
|
final int dmg = AbilityFactory.calculateAmount(topStack.getSourceCard(),
|
||||||
|
topStack.getParam("NumDmg"), topStack);
|
||||||
|
for (final Object o : objects) {
|
||||||
|
if (o instanceof Card) {
|
||||||
|
final Card c = (Card) o;
|
||||||
|
|
||||||
|
// indestructible
|
||||||
|
if (c.hasKeyword("Indestructible")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// already regenerated
|
||||||
|
if (c.getShield() > 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't use it on creatures that can't be regenerated
|
||||||
|
if ((saviourApi == ApiType.Regenerate || saviourApi == ApiType.RegenerateAll) && !c.canBeShielded()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// give Shroud to targeted creatures
|
||||||
|
if (saviourApi == ApiType.Pump && tgt == null && saviour.hasParam("KW")
|
||||||
|
&& (saviour.getParam("KW").endsWith("Shroud")
|
||||||
|
|| saviour.getParam("KW").endsWith("Hexproof"))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't bounce or blink a permanent that the human
|
||||||
|
// player owns or is a token
|
||||||
|
if (saviourApi == ApiType.ChangeZone && (c.getOwner().isHuman() || c.isToken())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c.predictDamage(dmg, source, false) >= c.getKillDamage()) {
|
||||||
|
threatened.add(c);
|
||||||
|
}
|
||||||
|
} else if (o instanceof Player) {
|
||||||
|
final Player p = (Player) o;
|
||||||
|
|
||||||
|
if (source.hasKeyword("Infect")) {
|
||||||
|
if (p.predictDamage(dmg, source, false) >= p.getPoisonCounters()) {
|
||||||
|
threatened.add(p);
|
||||||
|
}
|
||||||
|
} else if (p.predictDamage(dmg, source, false) >= p.getLife()) {
|
||||||
|
threatened.add(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Destroy => regeneration/bounce/shroud
|
||||||
|
else if ((threatApi == ApiType.Destroy || threatApi == ApiType.DestroyAll)
|
||||||
|
&& (((saviourApi == ApiType.Regenerate || saviourApi == ApiType.RegenerateAll)
|
||||||
|
&& !topStack.hasParam("NoRegen")) || saviourApi == ApiType.ChangeZone || saviourApi == ApiType.Pump)) {
|
||||||
|
for (final Object o : objects) {
|
||||||
|
if (o instanceof Card) {
|
||||||
|
final Card c = (Card) o;
|
||||||
|
// indestructible
|
||||||
|
if (c.hasKeyword("Indestructible")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// already regenerated
|
||||||
|
if (c.getShield() > 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// give Shroud to targeted creatures
|
||||||
|
if (saviourApi == ApiType.Pump && tgt == null && saviour.hasParam("KW")
|
||||||
|
&& (saviour.getParam("KW").endsWith("Shroud")
|
||||||
|
|| saviour.getParam("KW").endsWith("Hexproof"))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't bounce or blink a permanent that the human
|
||||||
|
// player owns or is a token
|
||||||
|
if (saviourApi == ApiType.ChangeZone && (c.getOwner().isHuman() || c.isToken())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't use it on creatures that can't be regenerated
|
||||||
|
if (saviourApi == ApiType.Regenerate && !c.canBeShielded()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
threatened.add(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Exiling => bounce/shroud
|
||||||
|
else if ((threatApi == ApiType.ChangeZone || threatApi == ApiType.ChangeZoneAll)
|
||||||
|
&& (saviourApi == ApiType.ChangeZone || saviourApi == ApiType.Pump)
|
||||||
|
&& topStack.hasParam("Destination")
|
||||||
|
&& topStack.getParam("Destination").equals("Exile")) {
|
||||||
|
for (final Object o : objects) {
|
||||||
|
if (o instanceof Card) {
|
||||||
|
final Card c = (Card) o;
|
||||||
|
// give Shroud to targeted creatures
|
||||||
|
if (saviourApi == ApiType.Pump && tgt == null && saviour.hasParam("KW")
|
||||||
|
&& (saviour.getParam("KW").endsWith("Shroud") || saviour.getParam("KW").endsWith("Hexproof"))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't bounce or blink a permanent that the human
|
||||||
|
// player owns or is a token
|
||||||
|
if (saviourApi == ApiType.ChangeZone && (c.getOwner().isHuman() || c.isToken())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
threatened.add(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
threatened.addAll(ComputerUtil.predictThreatenedObjects(aiPlayer, saviour, topStack.getSubAbility()));
|
||||||
|
return threatened;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -342,7 +342,7 @@ public class ComputerUtilCost {
|
|||||||
final GameState game = Singletons.getModel().getGame();
|
final GameState game = Singletons.getModel().getGame();
|
||||||
// Check for stuff like Nether Void
|
// Check for stuff like Nether Void
|
||||||
int extraManaNeeded = 0;
|
int extraManaNeeded = 0;
|
||||||
if (sa instanceof Spell && player.isComputer()) {
|
if (sa instanceof Spell) {
|
||||||
for (Player opp : player.getOpponents()) {
|
for (Player opp : player.getOpponents()) {
|
||||||
for (Card c : opp.getCardsIn(ZoneType.Battlefield)) {
|
for (Card c : opp.getCardsIn(ZoneType.Battlefield)) {
|
||||||
final String snem = c.getSVar("SpellsNeedExtraMana");
|
final String snem = c.getSVar("SpellsNeedExtraMana");
|
||||||
|
|||||||
@@ -1201,7 +1201,7 @@ public class CombatUtil {
|
|||||||
|
|
||||||
ability.setActivatingPlayer(c.getController());
|
ability.setActivatingPlayer(c.getController());
|
||||||
if (c.getController().isHuman()) {
|
if (c.getController().isHuman()) {
|
||||||
GameActionUtil.payCostDuringAbilityResolve(ability, attackCost, paidCommand, unpaidCommand, null, game);
|
GameActionUtil.payCostDuringAbilityResolve(c.getController(), ability, attackCost, paidCommand, unpaidCommand, null, game);
|
||||||
} else { // computer
|
} else { // computer
|
||||||
if (ComputerUtilCost.canPayCost(ability, c.getController())) {
|
if (ComputerUtilCost.canPayCost(ability, c.getController())) {
|
||||||
ComputerUtil.playNoStack(c.getController(), ability, game);
|
ComputerUtil.playNoStack(c.getController(), ability, game);
|
||||||
|
|||||||
@@ -197,7 +197,7 @@ public class Upkeep extends Phase {
|
|||||||
Player controller = c.getController();
|
Player controller = c.getController();
|
||||||
if (controller.isHuman()) {
|
if (controller.isHuman()) {
|
||||||
Cost cost = new Cost(c, c.getEchoCost().trim(), true);
|
Cost cost = new Cost(c, c.getEchoCost().trim(), true);
|
||||||
GameActionUtil.payCostDuringAbilityResolve(blankAbility, cost, paidCommand, unpaidCommand, null, game);
|
GameActionUtil.payCostDuringAbilityResolve(controller, blankAbility, cost, paidCommand, unpaidCommand, null, game);
|
||||||
} else { // computer
|
} else { // computer
|
||||||
if (ComputerUtilCost.canPayCost(blankAbility, controller)) {
|
if (ComputerUtilCost.canPayCost(blankAbility, controller)) {
|
||||||
ComputerUtil.playNoStack(controller, blankAbility, game);
|
ComputerUtil.playNoStack(controller, blankAbility, game);
|
||||||
@@ -357,7 +357,7 @@ public class Upkeep extends Phase {
|
|||||||
@Override
|
@Override
|
||||||
public void resolve() {
|
public void resolve() {
|
||||||
if (controller.isHuman()) {
|
if (controller.isHuman()) {
|
||||||
GameActionUtil.payCostDuringAbilityResolve(blankAbility, blankAbility.getPayCosts(),
|
GameActionUtil.payCostDuringAbilityResolve(controller, blankAbility, blankAbility.getPayCosts(),
|
||||||
paidCommand, unpaidCommand, null, game);
|
paidCommand, unpaidCommand, null, game);
|
||||||
} else { // computer
|
} else { // computer
|
||||||
if (ComputerUtilCost.shouldPayCost(controller, c, upkeepCost) && ComputerUtilCost.canPayCost(blankAbility, controller)) {
|
if (ComputerUtilCost.shouldPayCost(controller, c, upkeepCost) && ComputerUtilCost.canPayCost(blankAbility, controller)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user