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:
Maxmtg
2013-02-05 06:51:09 +00:00
parent a1f7790968
commit db720acb01
12 changed files with 208 additions and 206 deletions

View File

@@ -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)) {

View File

@@ -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()) {

View File

@@ -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
} }

View File

@@ -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>();

View File

@@ -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;

View File

@@ -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")) {

View File

@@ -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>();

View File

@@ -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) {

View File

@@ -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;
}
} }

View File

@@ -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");

View File

@@ -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);

View File

@@ -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)) {