diff --git a/src/main/java/forge/card/abilityfactory/AbilityFactory.java b/src/main/java/forge/card/abilityfactory/AbilityFactory.java
index 598eb3d22e0..42df2d85c7c 100644
--- a/src/main/java/forge/card/abilityfactory/AbilityFactory.java
+++ b/src/main/java/forge/card/abilityfactory/AbilityFactory.java
@@ -1503,24 +1503,6 @@ public class AbilityFactory {
&& Singletons.getModel().getGame().getPhaseHandler().isNextTurn(PlayerType.COMPUTER));
}
- // returns true if it's better to wait until blockers are declared
- /**
- *
- * waitForBlocking.
- *
- *
- * @param sa
- * a {@link forge.card.spellability.SpellAbility} object.
- * @return a boolean.
- */
- public static boolean waitForBlocking(final SpellAbility sa) {
-
- return (sa.getSourceCard().isCreature()
- && sa.getPayCosts().getTap()
- && (Singletons.getModel().getGame().getPhaseHandler().getPhase().isBefore(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY)
- || Singletons.getModel().getGame().getPhaseHandler().isNextTurn(PlayerType.HUMAN)));
- }
-
/**
*
* isSorcerySpeed.
diff --git a/src/main/java/forge/card/abilityfactory/AbilityFactoryAlterLife.java b/src/main/java/forge/card/abilityfactory/AbilityFactoryAlterLife.java
index 18d938ebf3d..943447f496f 100644
--- a/src/main/java/forge/card/abilityfactory/AbilityFactoryAlterLife.java
+++ b/src/main/java/forge/card/abilityfactory/AbilityFactoryAlterLife.java
@@ -361,7 +361,7 @@ public class AbilityFactoryAlterLife {
}
// Don't tap creatures that may be able to block
- if (AbilityFactory.waitForBlocking(sa)) {
+ if (ComputerUtil.waitForBlocking(sa)) {
return false;
}
@@ -777,6 +777,10 @@ public class AbilityFactoryAlterLife {
return false;
}
+ if (ComputerUtil.preventRunAwayActivations(sa)) {
+ return false;
+ }
+
if (amount >= opp.getLife()) {
priority = true; // killing the human should be done asap
}
@@ -788,13 +792,10 @@ public class AbilityFactoryAlterLife {
}
// Don't tap creatures that may be able to block
- if (AbilityFactory.waitForBlocking(sa) && !priority) {
+ if (ComputerUtil.waitForBlocking(sa) && !priority) {
return false;
}
- // prevent run-away activations - first time will always return true
- final boolean chance = r.nextFloat() <= Math.pow(.6667, sa.getActivationsThisTurn());
-
final Target tgt = sa.getTarget();
if (sa.getTarget() != null) {
@@ -811,7 +812,7 @@ public class AbilityFactoryAlterLife {
randomReturn = true;
}
- return (randomReturn && chance);
+ return (randomReturn);
}
/**
@@ -1270,7 +1271,7 @@ public class AbilityFactoryAlterLife {
}
// Don't tap creatures that may be able to block
- if (AbilityFactory.waitForBlocking(sa)) {
+ if (ComputerUtil.waitForBlocking(sa)) {
return false;
}
diff --git a/src/main/java/forge/card/abilityfactory/AbilityFactoryChoose.java b/src/main/java/forge/card/abilityfactory/AbilityFactoryChoose.java
index c5fd56af695..abb5206b408 100644
--- a/src/main/java/forge/card/abilityfactory/AbilityFactoryChoose.java
+++ b/src/main/java/forge/card/abilityfactory/AbilityFactoryChoose.java
@@ -1532,7 +1532,7 @@ public final class AbilityFactoryChoose {
if (params.containsKey("AILogic")) {
// Don't tap creatures that may be able to block
- if (AbilityFactory.waitForBlocking(sa)) {
+ if (ComputerUtil.waitForBlocking(sa)) {
return false;
}
diff --git a/src/main/java/forge/card/abilityfactory/AbilityFactoryCounters.java b/src/main/java/forge/card/abilityfactory/AbilityFactoryCounters.java
index 3bd8cf25214..e7f174bbf3f 100644
--- a/src/main/java/forge/card/abilityfactory/AbilityFactoryCounters.java
+++ b/src/main/java/forge/card/abilityfactory/AbilityFactoryCounters.java
@@ -310,9 +310,12 @@ public class AbilityFactoryCounters {
Card choice = null;
final String type = params.get("CounterType");
final String amountStr = params.get("CounterNum");
-
final Player player = af.isCurse() ? ai.getOpponent() : ai;
+ if (ComputerUtil.preventRunAwayActivations(sa)) {
+ return false;
+ }
+
list = player.getCardsIn(ZoneType.Battlefield);
list = CardLists.filter(list, new Predicate() {
@Override
@@ -367,9 +370,6 @@ public class AbilityFactoryCounters {
return false;
}
- // prevent run-away activations - first time will always return true
- boolean chance = r.nextFloat() <= Math.pow(.6667, sa.getActivationsThisTurn());
-
// Targeting
if (abTgt != null) {
abTgt.resetTargets();
@@ -430,16 +430,16 @@ public class AbilityFactoryCounters {
return false;
}
- if (AbilityFactory.waitForBlocking(sa)) {
+ if (ComputerUtil.waitForBlocking(sa)) {
return false;
}
final AbilitySub subAb = sa.getSubAbility();
- if (subAb != null) {
- chance &= subAb.chkAIDrawback();
+ if (subAb != null && !subAb.chkAIDrawback()) {
+ return false;
}
- return chance;
+ return true;
} // putCanPlayAI
/**
diff --git a/src/main/java/forge/card/abilityfactory/AbilityFactoryPump.java b/src/main/java/forge/card/abilityfactory/AbilityFactoryPump.java
index 9e573895cf8..e92c2a0d2e5 100644
--- a/src/main/java/forge/card/abilityfactory/AbilityFactoryPump.java
+++ b/src/main/java/forge/card/abilityfactory/AbilityFactoryPump.java
@@ -845,8 +845,9 @@ public class AbilityFactoryPump {
return false;
}
}
-
- final SpellAbilityRestriction restrict = sa.getRestrictions();
+ if (ComputerUtil.preventRunAwayActivations(sa)) {
+ return false;
+ }
// Phase Restrictions
if ((Singletons.getModel().getGame().getStack().size() == 0) && ph.getPhase().isBefore(PhaseType.COMBAT_BEGIN)) {
@@ -861,6 +862,7 @@ public class AbilityFactoryPump {
}
}
+ final SpellAbilityRestriction restrict = sa.getRestrictions();
final int activations = restrict.getNumberTurnActivations();
final int sacActivations = restrict.getActivationNumberSacrifice();
// don't risk sacrificing a creature just to pump it
@@ -915,7 +917,6 @@ public class AbilityFactoryPump {
if (cards.size() == 0) {
return false;
}
- final Random r = MyRandom.getRandom();
// when this happens we need to expand AI to consider if its ok for
// everything?
@@ -929,10 +930,10 @@ public class AbilityFactoryPump {
continue;
}
- return r.nextFloat() <= Math.pow(.9, activations);
+ return true;
}
if (shouldPumpCard(ai, sa, card)) {
- return r.nextFloat() <= Math.pow(.9, activations);
+ return true;
}
}
return false;
@@ -1714,15 +1715,15 @@ public class AbilityFactoryPump {
*/
private boolean pumpAllCanPlayAI(final Player ai, final SpellAbility sa) {
String valid = "";
- final Random r = MyRandom.getRandom();
final Card source = sa.getSourceCard();
this.params = this.abilityFactory.getMapParams();
final int power = this.getNumAttack(sa);
final int defense = this.getNumDefense(sa);
final PhaseType phase = Singletons.getModel().getGame().getPhaseHandler().getPhase();
- // prevent runaway activations
- final boolean chance = r.nextFloat() <= Math.pow(.6667, sa.getActivationsThisTurn()); // to
+ if (ComputerUtil.preventRunAwayActivations(sa)) {
+ return false;
+ }
if (this.params.containsKey("ValidCards")) {
valid = this.params.get("ValidCards");
@@ -1794,7 +1795,7 @@ public class AbilityFactoryPump {
if ((CardFactoryUtil.evaluateCreatureList(comp) + 200) >= CardFactoryUtil.evaluateCreatureList(human)) {
return false;
}
- return chance;
+ return true;
} // end Curse
// don't use non curse PumpAll after Combat_Begin until AI is improved
@@ -1823,7 +1824,7 @@ public class AbilityFactoryPump {
return false;
}
- return chance;
+ return true;
} // pumpAllCanPlayAI()
/**
diff --git a/src/main/java/forge/card/abilityfactory/AbilityFactoryStoreSVar.java b/src/main/java/forge/card/abilityfactory/AbilityFactoryStoreSVar.java
index 80003e986a6..82c9875d0b5 100644
--- a/src/main/java/forge/card/abilityfactory/AbilityFactoryStoreSVar.java
+++ b/src/main/java/forge/card/abilityfactory/AbilityFactoryStoreSVar.java
@@ -246,7 +246,7 @@ public class AbilityFactoryStoreSVar {
//Tree of Redemption
final Player ai = sa.getActivatingPlayer();
final Card source = sa.getSourceCard();
- if (AbilityFactory.waitForBlocking(sa) || ai.getLife() + 1 >= source.getNetDefense()
+ if (ComputerUtil.waitForBlocking(sa) || ai.getLife() + 1 >= source.getNetDefense()
|| (ai.getLife() > 5 && !CombatUtil.lifeInSeriousDanger(ai, Singletons.getModel().getGame().getCombat()))) {
return false;
}
diff --git a/src/main/java/forge/card/abilityfactory/AbilityFactoryToken.java b/src/main/java/forge/card/abilityfactory/AbilityFactoryToken.java
index 5881e9532c3..217116e6f41 100644
--- a/src/main/java/forge/card/abilityfactory/AbilityFactoryToken.java
+++ b/src/main/java/forge/card/abilityfactory/AbilityFactoryToken.java
@@ -295,6 +295,10 @@ public class AbilityFactoryToken extends AbilityFactory {
final AbilityFactory af = sa.getAbilityFactory();
final HashMap mapParams = af.getMapParams();
+ if (ComputerUtil.preventRunAwayActivations(sa)) {
+ return false;
+ }
+
Player opp = ai.getOpponent();
for (final String type : this.tokenTypes) {
if (type.equals("Legendary")) {
@@ -340,7 +344,6 @@ public class AbilityFactoryToken extends AbilityFactory {
// prevent run-away activations - first time will always return true
final Random r = MyRandom.getRandom();
final Card source = sa.getSourceCard();
- final boolean chance = r.nextFloat() <= Math.pow(.9, sa.getActivationsThisTurn());
final Target tgt = sa.getTarget();
if (tgt != null) {
@@ -383,17 +386,17 @@ public class AbilityFactoryToken extends AbilityFactory {
}
if (AbilityFactory.playReusable(sa)) {
- return chance;
+ return true;
}
if (Singletons.getModel().getGame().getPhaseHandler().is(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY)) {
- return ((r.nextFloat() < .95) && chance);
+ return true;
}
if (sa.isAbility()) {
- return ((r.nextFloat() < .9) && chance);
+ return (r.nextFloat() < .9);
}
- return ((r.nextFloat() < .8) && chance);
+ return (r.nextFloat() < .8);
}
/**
diff --git a/src/main/java/forge/card/abilityfactory/AbilityFactoryZoneAffecting.java b/src/main/java/forge/card/abilityfactory/AbilityFactoryZoneAffecting.java
index c1029777ed5..722a43490ed 100644
--- a/src/main/java/forge/card/abilityfactory/AbilityFactoryZoneAffecting.java
+++ b/src/main/java/forge/card/abilityfactory/AbilityFactoryZoneAffecting.java
@@ -351,7 +351,7 @@ public class AbilityFactoryZoneAffecting {
}
// Don't tap creatures that may be able to block
- if (AbilityFactory.waitForBlocking(sa)) {
+ if (ComputerUtil.waitForBlocking(sa)) {
return false;
}
@@ -906,7 +906,7 @@ public class AbilityFactoryZoneAffecting {
}
// Don't tap creatures that may be able to block
- if (AbilityFactory.waitForBlocking(sa)) {
+ if (ComputerUtil.waitForBlocking(sa)) {
return false;
}
@@ -1688,7 +1688,7 @@ public class AbilityFactoryZoneAffecting {
}
// Don't tap creatures that may be able to block
- if (AbilityFactory.waitForBlocking(sa) && !params.containsKey("ActivationPhases")) {
+ if (ComputerUtil.waitForBlocking(sa) && !params.containsKey("ActivationPhases")) {
return false;
}
diff --git a/src/main/java/forge/game/player/ComputerUtil.java b/src/main/java/forge/game/player/ComputerUtil.java
index 70864996592..4beaae9be7a 100644
--- a/src/main/java/forge/game/player/ComputerUtil.java
+++ b/src/main/java/forge/game/player/ComputerUtil.java
@@ -22,6 +22,7 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
+import java.util.Random;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
@@ -54,10 +55,12 @@ import forge.control.input.InputPayManaCostUtil;
import forge.error.ErrorViewer;
import forge.game.phase.Combat;
import forge.game.phase.CombatUtil;
+import forge.game.phase.PhaseHandler;
import forge.game.phase.PhaseType;
import forge.game.zone.ZoneType;
import forge.gui.GuiChoose;
import forge.util.Aggregates;
+import forge.util.MyRandom;
/**
@@ -2179,4 +2182,43 @@ public class ComputerUtil {
sa.setTargetPlayer(human);
return true;
}
+
+ // returns true if it's better to wait until blockers are declared
+ /**
+ *
+ * waitForBlocking.
+ *
+ *
+ * @param sa
+ * a {@link forge.card.spellability.SpellAbility} object.
+ * @return a boolean (returns true if it's better to wait until blockers are declared).
+ */
+ public static boolean waitForBlocking(final SpellAbility sa) {
+ final PhaseHandler ph = Singletons.getModel().getGame().getPhaseHandler();
+
+ return (sa.getSourceCard().isCreature()
+ && sa.getPayCosts().getTap()
+ && (ph.getPhase().isBefore(PhaseType.COMBAT_DECLARE_BLOCKERS_INSTANT_ABILITY)
+ || !ph.getNextTurn().equals(sa.getActivatingPlayer())));
+ }
+
+ // returns true if the AI should stop using the ability
+ /**
+ *
+ * preventRunAwayActivations.
+ *
+ *
+ * @param sa
+ * a {@link forge.card.spellability.SpellAbility} object.
+ * @return a boolean (returns true if the AI should stop using the ability).
+ */
+ public static boolean preventRunAwayActivations(final SpellAbility sa) {
+ final int activations = sa.getRestrictions().getNumberTurnActivations();
+ if (activations < 10) { //10 activations per turn should still be acceptable
+ return false;
+ }
+ final Random r = MyRandom.getRandom();
+
+ return r.nextFloat() <= Math.pow(.95, activations);
+ }
}