diff --git a/src/main/java/forge/card/ability/AbilityUtils.java b/src/main/java/forge/card/ability/AbilityUtils.java index c24027d6a61..dd036c9553d 100644 --- a/src/main/java/forge/card/ability/AbilityUtils.java +++ b/src/main/java/forge/card/ability/AbilityUtils.java @@ -1102,22 +1102,20 @@ public class AbilityUtils { } 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; for (Player payer : payers) { + final Ability ability = new AbilityStatic(source, cost, sa.getTarget()) { @Override public void resolve() { } }; ability.setActivatingPlayer(payer); 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 paid = true; } } else { // 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); } } diff --git a/src/main/java/forge/card/ability/ApiType.java b/src/main/java/forge/card/ability/ApiType.java index 6e8bcbe739a..d0ca6aeb841 100644 --- a/src/main/java/forge/card/ability/ApiType.java +++ b/src/main/java/forge/card/ability/ApiType.java @@ -242,7 +242,6 @@ public enum ApiType { public SpellAbilityEffect getSpellEffect() { return clsEffect == null ? null : ReflectionUtil.makeDefaultInstanceOf(clsEffect); - } public SpellAbilityAi getAi() { diff --git a/src/main/java/forge/card/ability/SpellAbilityAi.java b/src/main/java/forge/card/ability/SpellAbilityAi.java index 8262b3673a2..9cf43e0c972 100644 --- a/src/main/java/forge/card/ability/SpellAbilityAi.java +++ b/src/main/java/forge/card/ability/SpellAbilityAi.java @@ -7,6 +7,7 @@ import forge.game.ai.ComputerUtilCost; import forge.game.phase.PhaseHandler; import forge.game.phase.PhaseType; import forge.game.player.Player; +import forge.game.player.PlayerActionConfirmMode; public abstract class SpellAbilityAi { @@ -103,4 +104,9 @@ public abstract class SpellAbilityAi { final AbilitySub subAb = ab.getSubAbility(); 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; + } } diff --git a/src/main/java/forge/card/ability/ai/CopyPermanentAi.java b/src/main/java/forge/card/ability/ai/CopyPermanentAi.java index bccecd8994d..226b7154690 100644 --- a/src/main/java/forge/card/ability/ai/CopyPermanentAi.java +++ b/src/main/java/forge/card/ability/ai/CopyPermanentAi.java @@ -15,6 +15,7 @@ import forge.card.spellability.Target; import forge.game.ai.ComputerUtilCard; import forge.game.phase.PhaseType; import forge.game.player.Player; +import forge.game.player.PlayerActionConfirmMode; import forge.game.zone.ZoneType; import forge.util.MyRandom; @@ -111,5 +112,14 @@ public class CopyPermanentAi extends SpellAbilityAi { 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; + } } diff --git a/src/main/java/forge/card/ability/ai/DigAi.java b/src/main/java/forge/card/ability/ai/DigAi.java index 1259a5eb76b..c3796ae4e33 100644 --- a/src/main/java/forge/card/ability/ai/DigAi.java +++ b/src/main/java/forge/card/ability/ai/DigAi.java @@ -2,11 +2,13 @@ package forge.card.ability.ai; import java.util.Random; +import forge.Card; import forge.card.ability.SpellAbilityAi; import forge.card.spellability.SpellAbility; import forge.card.spellability.Target; import forge.game.phase.PhaseType; import forge.game.player.Player; +import forge.game.player.PlayerActionConfirmMode; import forge.game.zone.ZoneType; import forge.util.MyRandom; @@ -65,4 +67,13 @@ public class DigAi extends SpellAbilityAi { 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(); + } } diff --git a/src/main/java/forge/card/ability/ai/DiscardAi.java b/src/main/java/forge/card/ability/ai/DiscardAi.java index 7402e1dc3f3..2c5c794ce9c 100644 --- a/src/main/java/forge/card/ability/ai/DiscardAi.java +++ b/src/main/java/forge/card/ability/ai/DiscardAi.java @@ -14,6 +14,7 @@ import forge.game.ai.ComputerUtilCost; import forge.game.ai.ComputerUtilMana; import forge.game.phase.PhaseType; import forge.game.player.Player; +import forge.game.player.PlayerActionConfirmMode; import forge.game.zone.ZoneType; import forge.util.MyRandom; @@ -165,4 +166,13 @@ public class DiscardAi extends SpellAbilityAi { // TODO: check for some extra things return true; } // 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); + } } diff --git a/src/main/java/forge/card/ability/ai/DrawAi.java b/src/main/java/forge/card/ability/ai/DrawAi.java index 704c6f767b7..c8693c5e800 100644 --- a/src/main/java/forge/card/ability/ai/DrawAi.java +++ b/src/main/java/forge/card/ability/ai/DrawAi.java @@ -37,6 +37,7 @@ import forge.game.ai.ComputerUtilCost; import forge.game.ai.ComputerUtilMana; import forge.game.phase.PhaseType; import forge.game.player.Player; +import forge.game.player.PlayerActionConfirmMode; import forge.game.zone.ZoneType; import forge.util.MyRandom; @@ -267,4 +268,14 @@ public class DrawAi extends SpellAbilityAi { 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(); + } } diff --git a/src/main/java/forge/card/ability/ai/EncodeAi.java b/src/main/java/forge/card/ability/ai/EncodeAi.java index a57c3c9bdf8..50f64a9a2d4 100644 --- a/src/main/java/forge/card/ability/ai/EncodeAi.java +++ b/src/main/java/forge/card/ability/ai/EncodeAi.java @@ -20,6 +20,7 @@ package forge.card.ability.ai; import forge.card.ability.SpellAbilityAi; import forge.card.spellability.SpellAbility; import forge.game.player.Player; +import forge.game.player.PlayerActionConfirmMode; /** *
@@ -51,4 +52,10 @@ public final class EncodeAi extends SpellAbilityAi {
public boolean chkAIDrawback(SpellAbility sa, Player ai) {
return true;
}
+
+
+ @Override
+ public boolean confirmAction(Player player, SpellAbility sa, PlayerActionConfirmMode mode, String message) {
+ return true;
+ }
}
diff --git a/src/main/java/forge/card/ability/ai/PeekAndRevealAi.java b/src/main/java/forge/card/ability/ai/PeekAndRevealAi.java
index 79f410d40d2..a6ada4cb287 100644
--- a/src/main/java/forge/card/ability/ai/PeekAndRevealAi.java
+++ b/src/main/java/forge/card/ability/ai/PeekAndRevealAi.java
@@ -1,8 +1,10 @@
package forge.card.ability.ai;
import forge.card.ability.SpellAbilityAi;
+import forge.card.spellability.AbilitySub;
import forge.card.spellability.SpellAbility;
import forge.game.player.Player;
+import forge.game.player.PlayerActionConfirmMode;
/**
* TODO: Write javadoc for this type.
@@ -19,5 +21,14 @@ public class PeekAndRevealAi extends SpellAbilityAi {
// once things get converted from Dig + NoMove
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);
+ }
}
diff --git a/src/main/java/forge/card/ability/ai/PumpAi.java b/src/main/java/forge/card/ability/ai/PumpAi.java
index 175a35a63f8..11de5a2fd29 100644
--- a/src/main/java/forge/card/ability/ai/PumpAi.java
+++ b/src/main/java/forge/card/ability/ai/PumpAi.java
@@ -25,6 +25,7 @@ import forge.game.ai.ComputerUtilMana;
import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType;
import forge.game.player.Player;
+import forge.game.player.PlayerActionConfirmMode;
import forge.game.zone.ZoneType;
public class PumpAi extends PumpAiBase {
@@ -446,4 +447,14 @@ public class PumpAi extends PumpAiBase {
return true;
} // 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;
+ }
}
diff --git a/src/main/java/forge/card/ability/ai/RepeatAi.java b/src/main/java/forge/card/ability/ai/RepeatAi.java
index 0e1f74fc3aa..0af52f14586 100644
--- a/src/main/java/forge/card/ability/ai/RepeatAi.java
+++ b/src/main/java/forge/card/ability/ai/RepeatAi.java
@@ -5,6 +5,7 @@ import forge.card.ability.SpellAbilityAi;
import forge.card.spellability.SpellAbility;
import forge.card.spellability.Target;
import forge.game.player.Player;
+import forge.game.player.PlayerActionConfirmMode;
public class RepeatAi extends SpellAbilityAi {
@@ -21,4 +22,11 @@ public class RepeatAi extends SpellAbilityAi {
}
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;
+ }
+
}
diff --git a/src/main/java/forge/card/ability/ai/ShuffleAi.java b/src/main/java/forge/card/ability/ai/ShuffleAi.java
index 4b82e6b4074..06737476cf5 100644
--- a/src/main/java/forge/card/ability/ai/ShuffleAi.java
+++ b/src/main/java/forge/card/ability/ai/ShuffleAi.java
@@ -3,6 +3,7 @@ package forge.card.ability.ai;
import forge.card.ability.SpellAbilityAi;
import forge.card.spellability.SpellAbility;
import forge.game.player.Player;
+import forge.game.player.PlayerActionConfirmMode;
public class ShuffleAi extends SpellAbilityAi {
@Override
@@ -47,4 +48,12 @@ public class ShuffleAi extends SpellAbilityAi {
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;
+ }
}
diff --git a/src/main/java/forge/game/GameAction.java b/src/main/java/forge/game/GameAction.java
index b171a217dc9..a6af3ac9a3e 100644
--- a/src/main/java/forge/game/GameAction.java
+++ b/src/main/java/forge/game/GameAction.java
@@ -506,9 +506,7 @@ public class GameAction {
private static final long serialVersionUID = 8858061639236920054L;
@Override
- public void resolve() {
-
- }
+ public void resolve() {}
@Override
public String getStackDescription() {
@@ -533,7 +531,7 @@ public class GameAction {
Player p = recoverable.getController();
boolean hasPaid = false;
if (p.isHuman()) {
- hasPaid = HumanPlay.payCostDuringAbilityResolve(abRecover, abRecover.getPayCosts(), null);
+ hasPaid = HumanPlay.payCostDuringAbilityResolve(p, recoverable, cost, null);
} else { // computer
if (ComputerUtilCost.canPayCost(abRecover, p)) {
ComputerUtil.playNoStack(p, abRecover, game);
diff --git a/src/main/java/forge/game/ai/AiController.java b/src/main/java/forge/game/ai/AiController.java
index 5787921df74..4742839a551 100644
--- a/src/main/java/forge/game/ai/AiController.java
+++ b/src/main/java/forge/game/ai/AiController.java
@@ -35,12 +35,10 @@ import forge.CardPredicates;
import forge.CardPredicates.Presets;
import forge.Constant;
import forge.GameEntity;
-import forge.card.ability.AbilityUtils;
import forge.card.ability.ApiType;
import forge.card.cardfactory.CardFactoryUtil;
import forge.card.cost.CostDiscard;
import forge.card.cost.CostPart;
-import forge.card.spellability.AbilitySub;
import forge.card.spellability.Spell;
import forge.card.spellability.SpellAbility;
import forge.card.spellability.SpellPermanent;
@@ -711,50 +709,12 @@ public class AiController {
if( mode != null ) switch (mode) {
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:
- 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);
+ String exMsg = String.format("AI confirmAction does not know what to decide about %s mode (api is null).", mode);
+ throw new InvalidParameterException(exMsg);
- 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);
+ } else
+ return api.getAi().confirmAction(player, sa, mode, message);
}
public boolean confirmStaticApplication(Card hostCard, GameEntity affected, String logic, String message) {
diff --git a/src/main/java/forge/game/ai/ComputerUtilCost.java b/src/main/java/forge/game/ai/ComputerUtilCost.java
index 8dc760ae724..c7aca5f5a3a 100644
--- a/src/main/java/forge/game/ai/ComputerUtilCost.java
+++ b/src/main/java/forge/game/ai/ComputerUtilCost.java
@@ -312,8 +312,7 @@ public class ComputerUtilCost {
* a {@link java.lang.String} object.
* @return a boolean.
*/
- public static boolean shouldPayCost(final Player ai, final Card hostCard, final String costString) {
- final Cost cost = new Cost(costString, false);
+ public static boolean shouldPayCost(final Player ai, final Card hostCard, final Cost cost) {
for (final CostPart part : cost.getCostParts()) {
if (part instanceof CostPayLife) {
@@ -368,7 +367,7 @@ public class ComputerUtilCost {
&& CostPayment.canPayAdditionalCosts(sa.getPayCosts(), sa);
} // canPayCost()
- public static boolean willPayUnlessCost(SpellAbility sa, Player payer, SpellAbility ability, boolean alreadyPaid, List