mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-18 11:48:02 +00:00
changed parameters consumed by HumanPlay.payCostDuringAbilityResolve - it does not really need a surrogate ability.
AiController.confirmAction - spread choices made for specific apis among their matching XxxxxAi classes - to avoid a huge switch and keep all related code in a single place.
This commit is contained in:
@@ -1102,22 +1102,20 @@ public class AbilityUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final Cost cost = new Cost(unlessCost, true);
|
final Cost cost = new Cost(unlessCost, true);
|
||||||
final Ability ability = new AbilityStatic(source, cost, sa.getTarget()) {
|
|
||||||
@Override
|
|
||||||
public void resolve() { /* nothing to do here */ }
|
|
||||||
};
|
|
||||||
|
|
||||||
boolean paid = false;
|
boolean paid = false;
|
||||||
for (Player payer : payers) {
|
for (Player payer : payers) {
|
||||||
|
final Ability ability = new AbilityStatic(source, cost, sa.getTarget()) { @Override public void resolve() { } };
|
||||||
ability.setActivatingPlayer(payer);
|
ability.setActivatingPlayer(payer);
|
||||||
if (payer.isComputer()) {
|
if (payer.isComputer()) {
|
||||||
if (ComputerUtilCost.willPayUnlessCost(sa, payer, ability, paid, payers) && ComputerUtilCost.canPayCost(ability, payer)) {
|
if (ComputerUtilCost.willPayUnlessCost(sa, payer, cost, paid, payers) && ComputerUtilCost.canPayCost(ability, payer)) {
|
||||||
ComputerUtil.playNoStack(payer, ability, game); // Unless cost was payed - no resolve
|
ComputerUtil.playNoStack(payer, ability, game); // Unless cost was payed - no resolve
|
||||||
paid = true;
|
paid = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// if it's paid by the AI already the human can pay, but it won't change anything
|
// if it's paid by the AI already the human can pay, but it won't change anything
|
||||||
paid |= HumanPlay.payCostDuringAbilityResolve(ability, cost, sa);
|
paid |= HumanPlay.payCostDuringAbilityResolve(payer, source, cost, sa);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -242,7 +242,6 @@ public enum ApiType {
|
|||||||
|
|
||||||
public SpellAbilityEffect getSpellEffect() {
|
public SpellAbilityEffect getSpellEffect() {
|
||||||
return clsEffect == null ? null : ReflectionUtil.makeDefaultInstanceOf(clsEffect);
|
return clsEffect == null ? null : ReflectionUtil.makeDefaultInstanceOf(clsEffect);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public SpellAbilityAi getAi() {
|
public SpellAbilityAi getAi() {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import forge.game.ai.ComputerUtilCost;
|
|||||||
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;
|
||||||
|
import forge.game.player.PlayerActionConfirmMode;
|
||||||
|
|
||||||
public abstract class SpellAbilityAi {
|
public abstract class SpellAbilityAi {
|
||||||
|
|
||||||
@@ -103,4 +104,9 @@ public abstract class SpellAbilityAi {
|
|||||||
final AbilitySub subAb = ab.getSubAbility();
|
final AbilitySub subAb = ab.getSubAbility();
|
||||||
return ab.getAi().chkAIDrawback(ab, aiPlayer) && (subAb == null || chkDrawbackWithSubs(aiPlayer, subAb));
|
return ab.getAi().chkAIDrawback(ab, aiPlayer) && (subAb == null || chkDrawbackWithSubs(aiPlayer, subAb));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean confirmAction(Player player, SpellAbility sa, PlayerActionConfirmMode mode, String message) {
|
||||||
|
System.err.println("Warning: default (ie. inherited from base class) implementation of confirmAction is used for " + this.getClass().getName() + ". Consider declaring an overloaded method");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import forge.card.spellability.Target;
|
|||||||
import forge.game.ai.ComputerUtilCard;
|
import forge.game.ai.ComputerUtilCard;
|
||||||
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.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
import forge.util.MyRandom;
|
import forge.util.MyRandom;
|
||||||
|
|
||||||
@@ -112,4 +113,13 @@ public class CopyPermanentAi extends SpellAbilityAi {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see forge.card.ability.SpellAbilityAi#confirmAction(forge.game.player.Player, forge.card.spellability.SpellAbility, forge.game.player.PlayerActionConfirmMode, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean confirmAction(Player player, SpellAbility sa, PlayerActionConfirmMode mode, String message) {
|
||||||
|
//TODO: add logic here
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,13 @@ package forge.card.ability.ai;
|
|||||||
|
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
|
import forge.Card;
|
||||||
import forge.card.ability.SpellAbilityAi;
|
import forge.card.ability.SpellAbilityAi;
|
||||||
import forge.card.spellability.SpellAbility;
|
import forge.card.spellability.SpellAbility;
|
||||||
import forge.card.spellability.Target;
|
import forge.card.spellability.Target;
|
||||||
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.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
import forge.util.MyRandom;
|
import forge.util.MyRandom;
|
||||||
|
|
||||||
@@ -65,4 +67,13 @@ public class DigAi extends SpellAbilityAi {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see forge.card.ability.SpellAbilityAi#confirmAction(forge.card.spellability.SpellAbility, forge.game.player.PlayerActionConfirmMode, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean confirmAction(Player player, SpellAbility sa, PlayerActionConfirmMode mode, String message) {
|
||||||
|
// looks like perfect code for Delver of Secrets, but what about other cards?
|
||||||
|
Card topc = player.getZone(ZoneType.Library).get(0);
|
||||||
|
return topc.isInstant() || topc.isSorcery();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import forge.game.ai.ComputerUtilCost;
|
|||||||
import forge.game.ai.ComputerUtilMana;
|
import forge.game.ai.ComputerUtilMana;
|
||||||
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.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
import forge.util.MyRandom;
|
import forge.util.MyRandom;
|
||||||
|
|
||||||
@@ -165,4 +166,13 @@ public class DiscardAi extends SpellAbilityAi {
|
|||||||
// TODO: check for some extra things
|
// TODO: check for some extra things
|
||||||
return true;
|
return true;
|
||||||
} // discardCheckDrawbackAI()
|
} // discardCheckDrawbackAI()
|
||||||
|
|
||||||
|
|
||||||
|
public boolean confirmAction(Player player, SpellAbility sa, PlayerActionConfirmMode mode, String message) {
|
||||||
|
if ( mode == PlayerActionConfirmMode.Random ) { //
|
||||||
|
// TODO For now AI will always discard Random used currently with: Balduvian Horde and similar cards
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return super.confirmAction(player, sa, mode, message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ import forge.game.ai.ComputerUtilCost;
|
|||||||
import forge.game.ai.ComputerUtilMana;
|
import forge.game.ai.ComputerUtilMana;
|
||||||
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.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
import forge.util.MyRandom;
|
import forge.util.MyRandom;
|
||||||
|
|
||||||
@@ -267,4 +268,14 @@ public class DrawAi extends SpellAbilityAi {
|
|||||||
return targetAI(ai, sa, mandatory);
|
return targetAI(ai, sa, mandatory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see forge.card.ability.SpellAbilityAi#confirmAction(forge.game.player.Player, forge.card.spellability.SpellAbility, forge.game.player.PlayerActionConfirmMode, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean confirmAction(Player player, SpellAbility sa, PlayerActionConfirmMode mode, String message) {
|
||||||
|
int numCards = sa.hasParam("NumCards") ? AbilityUtils.calculateAmount(sa.getSourceCard(), sa.getParam("NumCards"), sa) : 1;
|
||||||
|
// AI shouldn't mill itself
|
||||||
|
return numCards < player.getZone(ZoneType.Library).size();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ package forge.card.ability.ai;
|
|||||||
import forge.card.ability.SpellAbilityAi;
|
import forge.card.ability.SpellAbilityAi;
|
||||||
import forge.card.spellability.SpellAbility;
|
import forge.card.spellability.SpellAbility;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
|
import forge.game.player.PlayerActionConfirmMode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
@@ -51,4 +52,10 @@ public final class EncodeAi extends SpellAbilityAi {
|
|||||||
public boolean chkAIDrawback(SpellAbility sa, Player ai) {
|
public boolean chkAIDrawback(SpellAbility sa, Player ai) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean confirmAction(Player player, SpellAbility sa, PlayerActionConfirmMode mode, String message) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
package forge.card.ability.ai;
|
package forge.card.ability.ai;
|
||||||
|
|
||||||
import forge.card.ability.SpellAbilityAi;
|
import forge.card.ability.SpellAbilityAi;
|
||||||
|
import forge.card.spellability.AbilitySub;
|
||||||
import forge.card.spellability.SpellAbility;
|
import forge.card.spellability.SpellAbility;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
|
import forge.game.player.PlayerActionConfirmMode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: Write javadoc for this type.
|
* TODO: Write javadoc for this type.
|
||||||
@@ -20,4 +22,13 @@ public class PeekAndRevealAi extends SpellAbilityAi {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see forge.card.ability.SpellAbilityAi#confirmAction(forge.game.player.Player, forge.card.spellability.SpellAbility, forge.game.player.PlayerActionConfirmMode, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean confirmAction(Player player, SpellAbility sa, PlayerActionConfirmMode mode, String message) {
|
||||||
|
AbilitySub subAb = sa.getSubAbility();
|
||||||
|
return subAb != null && subAb.getAi().chkDrawbackWithSubs(player, subAb);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import forge.game.ai.ComputerUtilMana;
|
|||||||
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;
|
||||||
|
import forge.game.player.PlayerActionConfirmMode;
|
||||||
import forge.game.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
|
|
||||||
public class PumpAi extends PumpAiBase {
|
public class PumpAi extends PumpAiBase {
|
||||||
@@ -446,4 +447,14 @@ public class PumpAi extends PumpAiBase {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
} // pumpDrawbackAI()
|
} // pumpDrawbackAI()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean confirmAction(Player player, SpellAbility sa, PlayerActionConfirmMode mode, String message) {
|
||||||
|
//TODO Add logic here if necessary but I think the AI won't cast
|
||||||
|
//the spell in the first place if it would curse its own creature
|
||||||
|
//and the pump isn't mandatory
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import forge.card.ability.SpellAbilityAi;
|
|||||||
import forge.card.spellability.SpellAbility;
|
import forge.card.spellability.SpellAbility;
|
||||||
import forge.card.spellability.Target;
|
import forge.card.spellability.Target;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
|
import forge.game.player.PlayerActionConfirmMode;
|
||||||
|
|
||||||
public class RepeatAi extends SpellAbilityAi {
|
public class RepeatAi extends SpellAbilityAi {
|
||||||
|
|
||||||
@@ -21,4 +22,11 @@ public class RepeatAi extends SpellAbilityAi {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean confirmAction(Player player, SpellAbility sa, PlayerActionConfirmMode mode, String message) {
|
||||||
|
//TODO add logic to have computer make better choice (ArsenalNut)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package forge.card.ability.ai;
|
|||||||
import forge.card.ability.SpellAbilityAi;
|
import forge.card.ability.SpellAbilityAi;
|
||||||
import forge.card.spellability.SpellAbility;
|
import forge.card.spellability.SpellAbility;
|
||||||
import forge.game.player.Player;
|
import forge.game.player.Player;
|
||||||
|
import forge.game.player.PlayerActionConfirmMode;
|
||||||
|
|
||||||
public class ShuffleAi extends SpellAbilityAi {
|
public class ShuffleAi extends SpellAbilityAi {
|
||||||
@Override
|
@Override
|
||||||
@@ -47,4 +48,12 @@ public class ShuffleAi extends SpellAbilityAi {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean confirmAction(Player player, SpellAbility sa, PlayerActionConfirmMode mode, String message) {
|
||||||
|
// ai could analyze parameter denoting the player to shuffle
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -506,9 +506,7 @@ public class GameAction {
|
|||||||
private static final long serialVersionUID = 8858061639236920054L;
|
private static final long serialVersionUID = 8858061639236920054L;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void resolve() {
|
public void resolve() {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getStackDescription() {
|
public String getStackDescription() {
|
||||||
@@ -533,7 +531,7 @@ public class GameAction {
|
|||||||
Player p = recoverable.getController();
|
Player p = recoverable.getController();
|
||||||
boolean hasPaid = false;
|
boolean hasPaid = false;
|
||||||
if (p.isHuman()) {
|
if (p.isHuman()) {
|
||||||
hasPaid = HumanPlay.payCostDuringAbilityResolve(abRecover, abRecover.getPayCosts(), null);
|
hasPaid = HumanPlay.payCostDuringAbilityResolve(p, recoverable, cost, null);
|
||||||
} else { // computer
|
} else { // computer
|
||||||
if (ComputerUtilCost.canPayCost(abRecover, p)) {
|
if (ComputerUtilCost.canPayCost(abRecover, p)) {
|
||||||
ComputerUtil.playNoStack(p, abRecover, game);
|
ComputerUtil.playNoStack(p, abRecover, game);
|
||||||
|
|||||||
@@ -35,12 +35,10 @@ import forge.CardPredicates;
|
|||||||
import forge.CardPredicates.Presets;
|
import forge.CardPredicates.Presets;
|
||||||
import forge.Constant;
|
import forge.Constant;
|
||||||
import forge.GameEntity;
|
import forge.GameEntity;
|
||||||
import forge.card.ability.AbilityUtils;
|
|
||||||
import forge.card.ability.ApiType;
|
import forge.card.ability.ApiType;
|
||||||
import forge.card.cardfactory.CardFactoryUtil;
|
import forge.card.cardfactory.CardFactoryUtil;
|
||||||
import forge.card.cost.CostDiscard;
|
import forge.card.cost.CostDiscard;
|
||||||
import forge.card.cost.CostPart;
|
import forge.card.cost.CostPart;
|
||||||
import forge.card.spellability.AbilitySub;
|
|
||||||
import forge.card.spellability.Spell;
|
import forge.card.spellability.Spell;
|
||||||
import forge.card.spellability.SpellAbility;
|
import forge.card.spellability.SpellAbility;
|
||||||
import forge.card.spellability.SpellPermanent;
|
import forge.card.spellability.SpellPermanent;
|
||||||
@@ -711,50 +709,12 @@ public class AiController {
|
|||||||
if( mode != null ) switch (mode) {
|
if( mode != null ) switch (mode) {
|
||||||
case BraidOfFire: return true;
|
case BraidOfFire: return true;
|
||||||
}
|
}
|
||||||
} else switch(api) {
|
|
||||||
case Discard:
|
|
||||||
if ( mode == PlayerActionConfirmMode.Random ) { //
|
|
||||||
// TODO For now AI will always discard Random used currently with: Balduvian Horde and similar cards
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Encode:
|
String exMsg = String.format("AI confirmAction does not know what to decide about %s mode (api is null).", mode);
|
||||||
return true;
|
|
||||||
|
|
||||||
case Dig:
|
|
||||||
Card topc = player.getZone(ZoneType.Library).get(0);
|
|
||||||
return topc.isInstant() || topc.isSorcery();
|
|
||||||
|
|
||||||
case Repeat:
|
|
||||||
//TODO add logic to have computer make better choice (ArsenalNut)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
case PeekAndReveal:
|
|
||||||
AbilitySub subAb = sa.getSubAbility();
|
|
||||||
return subAb != null && subAb.getAi().chkDrawbackWithSubs(player, subAb);
|
|
||||||
|
|
||||||
case Shuffle: // ai could analyze parameter denoting the player to shuffle
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case Pump: //TODO Add logic here if necessary but I think the AI won't cast
|
|
||||||
//the spell in the first place if it would curse its own creature
|
|
||||||
//and the pump isn't mandatory
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case Draw:
|
|
||||||
int numCards = sa.hasParam("NumCards") ? AbilityUtils.calculateAmount(sa.getSourceCard(), sa.getParam("NumCards"), sa) : 1;
|
|
||||||
// AI shouldn't mill itself
|
|
||||||
return numCards < player.getZone(ZoneType.Library).size();
|
|
||||||
|
|
||||||
case CopyPermanent:
|
|
||||||
//TODO: add logic here
|
|
||||||
return true;
|
|
||||||
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
String exMsg = String.format("AI confirmAction does not know what to decide about %s API with %s mode.", api, mode);
|
|
||||||
throw new InvalidParameterException(exMsg);
|
throw new InvalidParameterException(exMsg);
|
||||||
|
|
||||||
|
} else
|
||||||
|
return api.getAi().confirmAction(player, sa, mode, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean confirmStaticApplication(Card hostCard, GameEntity affected, String logic, String message) {
|
public boolean confirmStaticApplication(Card hostCard, GameEntity affected, String logic, String message) {
|
||||||
|
|||||||
@@ -312,8 +312,7 @@ public class ComputerUtilCost {
|
|||||||
* a {@link java.lang.String} object.
|
* a {@link java.lang.String} object.
|
||||||
* @return a boolean.
|
* @return a boolean.
|
||||||
*/
|
*/
|
||||||
public static boolean shouldPayCost(final Player ai, final Card hostCard, final String costString) {
|
public static boolean shouldPayCost(final Player ai, final Card hostCard, final Cost cost) {
|
||||||
final Cost cost = new Cost(costString, false);
|
|
||||||
|
|
||||||
for (final CostPart part : cost.getCostParts()) {
|
for (final CostPart part : cost.getCostParts()) {
|
||||||
if (part instanceof CostPayLife) {
|
if (part instanceof CostPayLife) {
|
||||||
@@ -368,7 +367,7 @@ public class ComputerUtilCost {
|
|||||||
&& CostPayment.canPayAdditionalCosts(sa.getPayCosts(), sa);
|
&& CostPayment.canPayAdditionalCosts(sa.getPayCosts(), sa);
|
||||||
} // canPayCost()
|
} // canPayCost()
|
||||||
|
|
||||||
public static boolean willPayUnlessCost(SpellAbility sa, Player payer, SpellAbility ability, boolean alreadyPaid, List<Player> payers) {
|
public static boolean willPayUnlessCost(SpellAbility sa, Player payer, Cost cost, boolean alreadyPaid, List<Player> payers) {
|
||||||
final Card source = sa.getSourceCard();
|
final Card source = sa.getSourceCard();
|
||||||
boolean payForOwnOnly = "OnlyOwn".equals(sa.getParam("UnlessAI"));
|
boolean payForOwnOnly = "OnlyOwn".equals(sa.getParam("UnlessAI"));
|
||||||
boolean payOwner = sa.hasParam("UnlessAI") ? sa.getParam("UnlessAI").startsWith("Defined") : false;
|
boolean payOwner = sa.hasParam("UnlessAI") ? sa.getParam("UnlessAI").startsWith("Defined") : false;
|
||||||
@@ -409,9 +408,9 @@ public class ComputerUtilCost {
|
|||||||
// AI was crashing because the blank ability used to pay costs
|
// AI was crashing because the blank ability used to pay costs
|
||||||
// Didn't have any of the data on the original SA to pay dependant costs
|
// Didn't have any of the data on the original SA to pay dependant costs
|
||||||
|
|
||||||
return checkLifeCost(payer, ability.getPayCosts(), source, 4, sa)
|
return checkLifeCost(payer, cost, source, 4, sa)
|
||||||
&& checkDamageCost(payer, ability.getPayCosts(), source, 4)
|
&& checkDamageCost(payer, cost, source, 4)
|
||||||
&& (isMine || checkDiscardCost(payer, ability.getPayCosts(), source))
|
&& (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)
|
||||||
|
|||||||
@@ -1005,7 +1005,7 @@ public class CombatUtil {
|
|||||||
ability.setActivatingPlayer(c.getController());
|
ability.setActivatingPlayer(c.getController());
|
||||||
|
|
||||||
if (c.getController().isHuman()) {
|
if (c.getController().isHuman()) {
|
||||||
isPaid = HumanPlay.payCostDuringAbilityResolve(ability, attackCost, null);
|
isPaid = HumanPlay.payCostDuringAbilityResolve(c.getController(), c, attackCost, null);
|
||||||
} 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);
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ public class PhaseUtil {
|
|||||||
ability.setActivatingPlayer(blocker.getController());
|
ability.setActivatingPlayer(blocker.getController());
|
||||||
|
|
||||||
if (blocker.getController().isHuman()) {
|
if (blocker.getController().isHuman()) {
|
||||||
hasPaid = HumanPlay.payCostDuringAbilityResolve(ability, blockCost, null);
|
hasPaid = HumanPlay.payCostDuringAbilityResolve(blocker.getController(), blocker, blockCost, null);
|
||||||
} else { // computer
|
} else { // computer
|
||||||
if (ComputerUtilCost.canPayCost(ability, blocker.getController())) {
|
if (ComputerUtilCost.canPayCost(ability, blocker.getController())) {
|
||||||
ComputerUtil.playNoStack(blocker.getController(), ability, game);
|
ComputerUtil.playNoStack(blocker.getController(), ability, game);
|
||||||
|
|||||||
@@ -165,7 +165,8 @@ public class Upkeep extends Phase {
|
|||||||
for (int i = 0; i < list.size(); i++) {
|
for (int i = 0; i < list.size(); i++) {
|
||||||
final Card c = list.get(i);
|
final Card c = list.get(i);
|
||||||
if (c.hasStartOfKeyword("(Echo unpaid)")) {
|
if (c.hasStartOfKeyword("(Echo unpaid)")) {
|
||||||
final Ability blankAbility = Upkeep.getBlankAbility(c, c.getEchoCost());
|
Cost cost = new Cost(c.getEchoCost(), true);
|
||||||
|
final Ability blankAbility = Upkeep.getBlankAbility(c, cost);
|
||||||
blankAbility.setActivatingPlayer(c.getController());
|
blankAbility.setActivatingPlayer(c.getController());
|
||||||
|
|
||||||
final StringBuilder sb = new StringBuilder();
|
final StringBuilder sb = new StringBuilder();
|
||||||
@@ -178,7 +179,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.getEchoCost().trim(), true);
|
Cost cost = new Cost(c.getEchoCost().trim(), true);
|
||||||
hasPaid = HumanPlay.payCostDuringAbilityResolve(blankAbility, cost, null);
|
hasPaid = HumanPlay.payCostDuringAbilityResolve(controller, c, cost, null);
|
||||||
} else { // computer
|
} else { // computer
|
||||||
if (ComputerUtilCost.canPayCost(blankAbility, controller)) {
|
if (ComputerUtilCost.canPayCost(blankAbility, controller)) {
|
||||||
ComputerUtil.playNoStack(controller, blankAbility, game);
|
ComputerUtil.playNoStack(controller, blankAbility, game);
|
||||||
@@ -230,7 +231,7 @@ public class Upkeep extends Phase {
|
|||||||
Singletons.getControl().getInputQueue().setInputAndWait(inp);
|
Singletons.getControl().getInputQueue().setInputAndWait(inp);
|
||||||
isUpkeepPaid = inp.isPaid();
|
isUpkeepPaid = inp.isPaid();
|
||||||
} else { // computer
|
} else { // computer
|
||||||
Ability aiPaid = Upkeep.getBlankAbility(c, upkeepCost.toString());
|
Ability aiPaid = Upkeep.getBlankAbility(c, new Cost(upkeepCost, true));
|
||||||
isUpkeepPaid = ComputerUtilCost.canPayCost(aiPaid, controller) && !c.hasKeyword("Indestructible");
|
isUpkeepPaid = ComputerUtilCost.canPayCost(aiPaid, controller) && !c.hasKeyword("Indestructible");
|
||||||
if (isUpkeepPaid) {
|
if (isUpkeepPaid) {
|
||||||
ComputerUtil.playNoStack(controller, aiPaid, game);
|
ComputerUtil.playNoStack(controller, aiPaid, game);
|
||||||
@@ -271,24 +272,27 @@ public class Upkeep extends Phase {
|
|||||||
sb.append("Cumulative upkeep for ").append(c).append("\n");
|
sb.append("Cumulative upkeep for ").append(c).append("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
final String upkeepCost = cost;
|
final Cost upkeepCost = new Cost(cost, true);
|
||||||
final Ability blankAbility = Upkeep.getBlankAbility(c, upkeepCost);
|
final Ability blankAbility = Upkeep.getBlankAbility(c, upkeepCost);
|
||||||
blankAbility.setActivatingPlayer(controller);
|
blankAbility.setActivatingPlayer(controller);
|
||||||
|
|
||||||
final Ability upkeepAbility = new Ability(c, ManaCost.ZERO) {
|
final Ability upkeepAbility = new Ability(c, ManaCost.ZERO) {
|
||||||
@Override
|
@Override
|
||||||
public void resolve() {
|
public void resolve() {
|
||||||
|
boolean isPaid = false;
|
||||||
if (controller.isHuman()) {
|
if (controller.isHuman()) {
|
||||||
if ( !HumanPlay.payCostDuringAbilityResolve(blankAbility, blankAbility.getPayCosts(), this))
|
isPaid = HumanPlay.payCostDuringAbilityResolve(controller, c, upkeepCost, this);
|
||||||
game.getAction().sacrifice(c, null);
|
|
||||||
} else { // computer
|
} else { // computer
|
||||||
if (ComputerUtilCost.shouldPayCost(controller, c, upkeepCost) && ComputerUtilCost.canPayCost(blankAbility, controller)) {
|
if (ComputerUtilCost.shouldPayCost(controller, c, upkeepCost) && ComputerUtilCost.canPayCost(blankAbility, controller)) {
|
||||||
ComputerUtil.playNoStack(controller, blankAbility, game); // this makes AI pay
|
ComputerUtil.playNoStack(controller, blankAbility, game); // this makes AI pay
|
||||||
} else {
|
isPaid = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!isPaid)
|
||||||
game.getAction().sacrifice(c, null);
|
game.getAction().sacrifice(c, null);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
upkeepAbility.setActivatingPlayer(controller);
|
upkeepAbility.setActivatingPlayer(controller);
|
||||||
upkeepAbility.setStackDescription(sb.toString());
|
upkeepAbility.setStackDescription(sb.toString());
|
||||||
@@ -315,7 +319,7 @@ public class Upkeep extends Phase {
|
|||||||
Singletons.getControl().getInputQueue().setInputAndWait(inp);
|
Singletons.getControl().getInputQueue().setInputAndWait(inp);
|
||||||
isUpkeepPaid = inp.isPaid();
|
isUpkeepPaid = inp.isPaid();
|
||||||
} else { // computers
|
} else { // computers
|
||||||
final Ability aiPaid = Upkeep.getBlankAbility(c, upkeepCost.toString());
|
final Ability aiPaid = Upkeep.getBlankAbility(c, new Cost(upkeepCost, true));
|
||||||
if (ComputerUtilCost.canPayCost(aiPaid, controller) && ComputerUtilCombat.predictDamageTo(controller, upkeepDamage, c, false) > 0) {
|
if (ComputerUtilCost.canPayCost(aiPaid, controller) && ComputerUtilCombat.predictDamageTo(controller, upkeepDamage, c, false) > 0) {
|
||||||
ComputerUtil.playNoStack(controller, aiPaid, game);
|
ComputerUtil.playNoStack(controller, aiPaid, game);
|
||||||
isUpkeepPaid = true;
|
isUpkeepPaid = true;
|
||||||
@@ -350,8 +354,8 @@ public class Upkeep extends Phase {
|
|||||||
* a {@link java.lang.String} object.
|
* a {@link java.lang.String} object.
|
||||||
* @return a {@link forge.card.spellability.Ability} object.
|
* @return a {@link forge.card.spellability.Ability} object.
|
||||||
*/
|
*/
|
||||||
public static Ability getBlankAbility(final Card c, final String costString) {
|
public static Ability getBlankAbility(final Card c, final Cost cost) {
|
||||||
return new AbilityStatic(c, new Cost(costString, true), null) {
|
return new AbilityStatic(c, cost, null) {
|
||||||
@Override
|
@Override
|
||||||
public void resolve() {}
|
public void resolve() {}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ import forge.gui.input.InputPayManaExecuteCommands;
|
|||||||
import forge.gui.input.InputPayManaSimple;
|
import forge.gui.input.InputPayManaSimple;
|
||||||
import forge.gui.input.InputSelectCards;
|
import forge.gui.input.InputSelectCards;
|
||||||
import forge.gui.input.InputSelectCardsFromList;
|
import forge.gui.input.InputSelectCardsFromList;
|
||||||
|
import forge.util.Lang;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: Write javadoc for this type.
|
* TODO: Write javadoc for this type.
|
||||||
@@ -280,11 +281,9 @@ public class HumanPlay {
|
|||||||
* a {@link forge.Command} object.
|
* a {@link forge.Command} object.
|
||||||
* @param sourceAbility TODO
|
* @param sourceAbility TODO
|
||||||
*/
|
*/
|
||||||
public static boolean payCostDuringAbilityResolve(final SpellAbility ability, final Cost cost, SpellAbility sourceAbility) {
|
public static boolean payCostDuringAbilityResolve(final Player p, final Card source, final Cost cost, SpellAbility sourceAbility) {
|
||||||
|
|
||||||
// Only human player pays this way
|
// Only human player pays this way
|
||||||
final Player p = ability.getActivatingPlayer();
|
|
||||||
final Card source = ability.getSourceCard();
|
|
||||||
Card current = null; // Used in spells with RepeatEach effect to distinguish cards, Cut the Tethers
|
Card current = null; // Used in spells with RepeatEach effect to distinguish cards, Cut the Tethers
|
||||||
if (!source.getRemembered().isEmpty()) {
|
if (!source.getRemembered().isEmpty()) {
|
||||||
if (source.getRemembered().get(0) instanceof Card) {
|
if (source.getRemembered().get(0) instanceof Card) {
|
||||||
@@ -295,6 +294,8 @@ public class HumanPlay {
|
|||||||
current = source.getImprinted().get(0);
|
current = source.getImprinted().get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String promptCurrent = current == null ? "" : "Current Card: " + current + "\r\n";
|
||||||
|
|
||||||
final List<CostPart> parts = cost.getCostParts();
|
final List<CostPart> parts = cost.getCostParts();
|
||||||
ArrayList<CostPart> remainingParts = new ArrayList<CostPart>(cost.getCostParts());
|
ArrayList<CostPart> remainingParts = new ArrayList<CostPart>(cost.getCostParts());
|
||||||
CostPart costPart = null;
|
CostPart costPart = null;
|
||||||
@@ -353,8 +354,7 @@ public class HumanPlay {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
String plural = amount > 1 ? "s" : "";
|
if (false == GuiDialog.confirm(source, "Do you want to put " + Lang.nounWithAmount(amount, counterType.getName() + " counter") + " on " + source + "?"))
|
||||||
if (false == GuiDialog.confirm(source, "Do you want to put " + amount + " " + counterType.getName() + " counter" + plural + " on " + source + "?"))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
source.addCounter(counterType, amount, false);
|
source.addCounter(counterType, amount, false);
|
||||||
@@ -363,12 +363,11 @@ public class HumanPlay {
|
|||||||
else if (part instanceof CostRemoveCounter) {
|
else if (part instanceof CostRemoveCounter) {
|
||||||
CounterType counterType = ((CostRemoveCounter) part).getCounter();
|
CounterType counterType = ((CostRemoveCounter) part).getCounter();
|
||||||
int amount = getAmountFromPartX(part, source, sourceAbility);
|
int amount = getAmountFromPartX(part, source, sourceAbility);
|
||||||
String plural = amount > 1 ? "s" : "";
|
|
||||||
|
|
||||||
if (!part.canPay(sourceAbility))
|
if (!part.canPay(sourceAbility))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if ( false == GuiDialog.confirm(source, "Do you want to remove " + amount + " " + counterType.getName() + " counter" + plural + " from " + source + "?"))
|
if ( false == GuiDialog.confirm(source, "Do you want to remove " + Lang.nounWithAmount(amount, counterType.getName() + " counter") + " from " + source + "?"))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
source.subtractCounter(counterType, amount);
|
source.subtractCounter(counterType, amount);
|
||||||
@@ -387,7 +386,7 @@ public class HumanPlay {
|
|||||||
CostExile costExile = (CostExile) part;
|
CostExile costExile = (CostExile) part;
|
||||||
ZoneType from = costExile.getFrom();
|
ZoneType from = costExile.getFrom();
|
||||||
List<Card> list = CardLists.getValidCards(p.getCardsIn(from), part.getType().split(";"), p, source);
|
List<Card> list = CardLists.getValidCards(p.getCardsIn(from), part.getType().split(";"), p, source);
|
||||||
final int nNeeded = AbilityUtils.calculateAmount(source, part.getAmount(), ability);
|
final int nNeeded = getAmountFromPart(costPart, source, sourceAbility);
|
||||||
if (list.size() < nNeeded)
|
if (list.size() < nNeeded)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -453,9 +452,8 @@ public class HumanPlay {
|
|||||||
if (!(costPart instanceof CostPartMana ))
|
if (!(costPart instanceof CostPartMana ))
|
||||||
throw new RuntimeException("GameActionUtil.payCostDuringAbilityResolve - The remaining payment type is not Mana.");
|
throw new RuntimeException("GameActionUtil.payCostDuringAbilityResolve - The remaining payment type is not Mana.");
|
||||||
|
|
||||||
InputPayMana toSet = current == null
|
String prompt = source + "\r\n" + promptCurrent;
|
||||||
? new InputPayManaExecuteCommands(p, source + "\r\n", cost.getCostMana().getManaToPay())
|
InputPayMana toSet = new InputPayManaExecuteCommands(p, prompt, cost.getCostMana().getManaToPay());
|
||||||
: new InputPayManaExecuteCommands(p, source + "\r\n" + "Current Card: " + current + "\r\n" , cost.getCostMana().getManaToPay());
|
|
||||||
Singletons.getControl().getInputQueue().setInputAndWait(toSet);
|
Singletons.getControl().getInputQueue().setInputAndWait(toSet);
|
||||||
return toSet.isPaid();
|
return toSet.isPaid();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user