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() {
Player p = recoverable.getController();
if (p.isHuman()) {
GameActionUtil.payCostDuringAbilityResolve(abRecover, abRecover.getPayCosts(),
GameActionUtil.payCostDuringAbilityResolve(p, abRecover, abRecover.getPayCosts(),
paidCommand, unpaidCommand, null, game);
} else { // computer
if (ComputerUtilCost.canPayCost(abRecover, p)) {

View File

@@ -423,11 +423,10 @@ public final class GameActionUtil {
* a {@link forge.Command} object.
* @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 Card source = ability.getSourceCard();
final List<CostPart> parts = cost.getCostParts();
Player p = Singletons.getControl().getPlayer();
ArrayList<CostPart> remainingParts = new ArrayList<CostPart>(cost.getCostParts());
CostPart costPart = null;
if (!parts.isEmpty()) {

View File

@@ -1237,196 +1237,6 @@ public class AbilityFactory {
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>
* handleRemembering.
@@ -1667,7 +1477,7 @@ public class AbilityFactory {
if (paid) {
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
break; // multiple human players are not supported
}

View File

@@ -600,7 +600,7 @@ public class ChangeZoneAi extends SpellAiLogic {
return false;
}
final ArrayList<Object> objects = AbilityFactory.predictThreatenedObjects(ai, sa);
final ArrayList<Object> objects = ComputerUtil.predictThreatenedObjects(ai, sa);
boolean contains = false;
for (final Card c : retrieval) {
if (objects.contains(c)) {
@@ -720,7 +720,7 @@ public class ChangeZoneAi extends SpellAiLogic {
// check stack for something on the stack that will kill
// anything i control
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>();

View File

@@ -13,6 +13,7 @@ import forge.card.cardfactory.CardFactoryUtil;
import forge.card.cost.Cost;
import forge.card.spellability.SpellAbility;
import forge.card.spellability.Target;
import forge.game.ai.ComputerUtil;
import forge.game.ai.ComputerUtilCombat;
import forge.game.ai.ComputerUtilCost;
import forge.game.phase.PhaseHandler;
@@ -56,7 +57,7 @@ public class DamagePreventAi extends SpellAiLogic {
// react to threats on the stack
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) {
if (threatenedObjects.contains(o)) {
chance = true;

View File

@@ -17,6 +17,7 @@ import forge.card.abilityfactory.SpellAiLogic;
import forge.card.cardfactory.CardFactoryUtil;
import forge.card.spellability.SpellAbility;
import forge.game.GameState;
import forge.game.ai.ComputerUtil;
import forge.game.ai.ComputerUtilCombat;
import forge.game.phase.Combat;
import forge.game.phase.CombatUtil;
@@ -336,7 +337,7 @@ public abstract class PumpAiBase extends SpellAiLogic {
return false;
}
} 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;
}
} else if (keyword.equals("Islandwalk")) {

View File

@@ -31,6 +31,7 @@ import forge.card.cardfactory.CardFactoryUtil;
import forge.card.cost.Cost;
import forge.card.spellability.SpellAbility;
import forge.card.spellability.Target;
import forge.game.ai.ComputerUtil;
import forge.game.ai.ComputerUtilCombat;
import forge.game.ai.ComputerUtilCost;
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);
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) {
if (objects.contains(c)) {
@@ -119,7 +120,7 @@ public class RegenerateAi extends SpellAiLogic {
if (Singletons.getModel().getGame().getStack().size() > 0) {
// check stack for something on the stack will kill anything i
// 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>();

View File

@@ -7,10 +7,10 @@ import forge.Card;
import forge.CardLists;
import forge.CardPredicates;
import forge.Singletons;
import forge.card.abilityfactory.AbilityFactory;
import forge.card.abilityfactory.SpellAiLogic;
import forge.card.cost.Cost;
import forge.card.spellability.SpellAbility;
import forge.game.ai.ComputerUtil;
import forge.game.ai.ComputerUtilCombat;
import forge.game.ai.ComputerUtilCost;
import forge.game.phase.PhaseType;
@@ -56,7 +56,7 @@ public class RegenerateAllAi extends SpellAiLogic {
int numSaved = 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) {
if (objects.contains(c) && c.getShield() == 0) {

View File

@@ -1047,4 +1047,194 @@ public class ComputerUtil {
return false;
} // 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();
// Check for stuff like Nether Void
int extraManaNeeded = 0;
if (sa instanceof Spell && player.isComputer()) {
if (sa instanceof Spell) {
for (Player opp : player.getOpponents()) {
for (Card c : opp.getCardsIn(ZoneType.Battlefield)) {
final String snem = c.getSVar("SpellsNeedExtraMana");

View File

@@ -1201,7 +1201,7 @@ public class CombatUtil {
ability.setActivatingPlayer(c.getController());
if (c.getController().isHuman()) {
GameActionUtil.payCostDuringAbilityResolve(ability, attackCost, paidCommand, unpaidCommand, null, game);
GameActionUtil.payCostDuringAbilityResolve(c.getController(), ability, attackCost, paidCommand, unpaidCommand, null, game);
} else { // computer
if (ComputerUtilCost.canPayCost(ability, c.getController())) {
ComputerUtil.playNoStack(c.getController(), ability, game);

View File

@@ -197,7 +197,7 @@ public class Upkeep extends Phase {
Player controller = c.getController();
if (controller.isHuman()) {
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
if (ComputerUtilCost.canPayCost(blankAbility, controller)) {
ComputerUtil.playNoStack(controller, blankAbility, game);
@@ -357,7 +357,7 @@ public class Upkeep extends Phase {
@Override
public void resolve() {
if (controller.isHuman()) {
GameActionUtil.payCostDuringAbilityResolve(blankAbility, blankAbility.getPayCosts(),
GameActionUtil.payCostDuringAbilityResolve(controller, blankAbility, blankAbility.getPayCosts(),
paidCommand, unpaidCommand, null, game);
} else { // computer
if (ComputerUtilCost.shouldPayCost(controller, c, upkeepCost) && ComputerUtilCost.canPayCost(blankAbility, controller)) {