mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 04:08:01 +00:00
- Moved common AI functions from AbilityFactories to ComputerUtil.
This commit is contained in:
@@ -1503,24 +1503,6 @@ public class AbilityFactory {
|
|||||||
&& Singletons.getModel().getGame().getPhaseHandler().isNextTurn(PlayerType.COMPUTER));
|
&& Singletons.getModel().getGame().getPhaseHandler().isNextTurn(PlayerType.COMPUTER));
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns true if it's better to wait until blockers are declared
|
|
||||||
/**
|
|
||||||
* <p>
|
|
||||||
* waitForBlocking.
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @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)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* isSorcerySpeed.
|
* isSorcerySpeed.
|
||||||
|
|||||||
@@ -361,7 +361,7 @@ public class AbilityFactoryAlterLife {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Don't tap creatures that may be able to block
|
// Don't tap creatures that may be able to block
|
||||||
if (AbilityFactory.waitForBlocking(sa)) {
|
if (ComputerUtil.waitForBlocking(sa)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -777,6 +777,10 @@ public class AbilityFactoryAlterLife {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ComputerUtil.preventRunAwayActivations(sa)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (amount >= opp.getLife()) {
|
if (amount >= opp.getLife()) {
|
||||||
priority = true; // killing the human should be done asap
|
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
|
// Don't tap creatures that may be able to block
|
||||||
if (AbilityFactory.waitForBlocking(sa) && !priority) {
|
if (ComputerUtil.waitForBlocking(sa) && !priority) {
|
||||||
return false;
|
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();
|
final Target tgt = sa.getTarget();
|
||||||
|
|
||||||
if (sa.getTarget() != null) {
|
if (sa.getTarget() != null) {
|
||||||
@@ -811,7 +812,7 @@ public class AbilityFactoryAlterLife {
|
|||||||
randomReturn = true;
|
randomReturn = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (randomReturn && chance);
|
return (randomReturn);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1270,7 +1271,7 @@ public class AbilityFactoryAlterLife {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Don't tap creatures that may be able to block
|
// Don't tap creatures that may be able to block
|
||||||
if (AbilityFactory.waitForBlocking(sa)) {
|
if (ComputerUtil.waitForBlocking(sa)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1532,7 +1532,7 @@ public final class AbilityFactoryChoose {
|
|||||||
|
|
||||||
if (params.containsKey("AILogic")) {
|
if (params.containsKey("AILogic")) {
|
||||||
// Don't tap creatures that may be able to block
|
// Don't tap creatures that may be able to block
|
||||||
if (AbilityFactory.waitForBlocking(sa)) {
|
if (ComputerUtil.waitForBlocking(sa)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -310,9 +310,12 @@ public class AbilityFactoryCounters {
|
|||||||
Card choice = null;
|
Card choice = null;
|
||||||
final String type = params.get("CounterType");
|
final String type = params.get("CounterType");
|
||||||
final String amountStr = params.get("CounterNum");
|
final String amountStr = params.get("CounterNum");
|
||||||
|
|
||||||
final Player player = af.isCurse() ? ai.getOpponent() : ai;
|
final Player player = af.isCurse() ? ai.getOpponent() : ai;
|
||||||
|
|
||||||
|
if (ComputerUtil.preventRunAwayActivations(sa)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
list = player.getCardsIn(ZoneType.Battlefield);
|
list = player.getCardsIn(ZoneType.Battlefield);
|
||||||
list = CardLists.filter(list, new Predicate<Card>() {
|
list = CardLists.filter(list, new Predicate<Card>() {
|
||||||
@Override
|
@Override
|
||||||
@@ -367,9 +370,6 @@ public class AbilityFactoryCounters {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// prevent run-away activations - first time will always return true
|
|
||||||
boolean chance = r.nextFloat() <= Math.pow(.6667, sa.getActivationsThisTurn());
|
|
||||||
|
|
||||||
// Targeting
|
// Targeting
|
||||||
if (abTgt != null) {
|
if (abTgt != null) {
|
||||||
abTgt.resetTargets();
|
abTgt.resetTargets();
|
||||||
@@ -430,16 +430,16 @@ public class AbilityFactoryCounters {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AbilityFactory.waitForBlocking(sa)) {
|
if (ComputerUtil.waitForBlocking(sa)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
final AbilitySub subAb = sa.getSubAbility();
|
final AbilitySub subAb = sa.getSubAbility();
|
||||||
if (subAb != null) {
|
if (subAb != null && !subAb.chkAIDrawback()) {
|
||||||
chance &= subAb.chkAIDrawback();
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return chance;
|
return true;
|
||||||
} // putCanPlayAI
|
} // putCanPlayAI
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -845,8 +845,9 @@ public class AbilityFactoryPump {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (ComputerUtil.preventRunAwayActivations(sa)) {
|
||||||
final SpellAbilityRestriction restrict = sa.getRestrictions();
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Phase Restrictions
|
// Phase Restrictions
|
||||||
if ((Singletons.getModel().getGame().getStack().size() == 0) && ph.getPhase().isBefore(PhaseType.COMBAT_BEGIN)) {
|
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 activations = restrict.getNumberTurnActivations();
|
||||||
final int sacActivations = restrict.getActivationNumberSacrifice();
|
final int sacActivations = restrict.getActivationNumberSacrifice();
|
||||||
// don't risk sacrificing a creature just to pump it
|
// don't risk sacrificing a creature just to pump it
|
||||||
@@ -915,7 +917,6 @@ public class AbilityFactoryPump {
|
|||||||
if (cards.size() == 0) {
|
if (cards.size() == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
final Random r = MyRandom.getRandom();
|
|
||||||
|
|
||||||
// when this happens we need to expand AI to consider if its ok for
|
// when this happens we need to expand AI to consider if its ok for
|
||||||
// everything?
|
// everything?
|
||||||
@@ -929,10 +930,10 @@ public class AbilityFactoryPump {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
return r.nextFloat() <= Math.pow(.9, activations);
|
return true;
|
||||||
}
|
}
|
||||||
if (shouldPumpCard(ai, sa, card)) {
|
if (shouldPumpCard(ai, sa, card)) {
|
||||||
return r.nextFloat() <= Math.pow(.9, activations);
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -1714,15 +1715,15 @@ public class AbilityFactoryPump {
|
|||||||
*/
|
*/
|
||||||
private boolean pumpAllCanPlayAI(final Player ai, final SpellAbility sa) {
|
private boolean pumpAllCanPlayAI(final Player ai, final SpellAbility sa) {
|
||||||
String valid = "";
|
String valid = "";
|
||||||
final Random r = MyRandom.getRandom();
|
|
||||||
final Card source = sa.getSourceCard();
|
final Card source = sa.getSourceCard();
|
||||||
this.params = this.abilityFactory.getMapParams();
|
this.params = this.abilityFactory.getMapParams();
|
||||||
final int power = this.getNumAttack(sa);
|
final int power = this.getNumAttack(sa);
|
||||||
final int defense = this.getNumDefense(sa);
|
final int defense = this.getNumDefense(sa);
|
||||||
final PhaseType phase = Singletons.getModel().getGame().getPhaseHandler().getPhase();
|
final PhaseType phase = Singletons.getModel().getGame().getPhaseHandler().getPhase();
|
||||||
|
|
||||||
// prevent runaway activations
|
if (ComputerUtil.preventRunAwayActivations(sa)) {
|
||||||
final boolean chance = r.nextFloat() <= Math.pow(.6667, sa.getActivationsThisTurn()); // to
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.params.containsKey("ValidCards")) {
|
if (this.params.containsKey("ValidCards")) {
|
||||||
valid = this.params.get("ValidCards");
|
valid = this.params.get("ValidCards");
|
||||||
@@ -1794,7 +1795,7 @@ public class AbilityFactoryPump {
|
|||||||
if ((CardFactoryUtil.evaluateCreatureList(comp) + 200) >= CardFactoryUtil.evaluateCreatureList(human)) {
|
if ((CardFactoryUtil.evaluateCreatureList(comp) + 200) >= CardFactoryUtil.evaluateCreatureList(human)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return chance;
|
return true;
|
||||||
} // end Curse
|
} // end Curse
|
||||||
|
|
||||||
// don't use non curse PumpAll after Combat_Begin until AI is improved
|
// don't use non curse PumpAll after Combat_Begin until AI is improved
|
||||||
@@ -1823,7 +1824,7 @@ public class AbilityFactoryPump {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return chance;
|
return true;
|
||||||
} // pumpAllCanPlayAI()
|
} // pumpAllCanPlayAI()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -246,7 +246,7 @@ public class AbilityFactoryStoreSVar {
|
|||||||
//Tree of Redemption
|
//Tree of Redemption
|
||||||
final Player ai = sa.getActivatingPlayer();
|
final Player ai = sa.getActivatingPlayer();
|
||||||
final Card source = sa.getSourceCard();
|
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()))) {
|
|| (ai.getLife() > 5 && !CombatUtil.lifeInSeriousDanger(ai, Singletons.getModel().getGame().getCombat()))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -295,6 +295,10 @@ public class AbilityFactoryToken extends AbilityFactory {
|
|||||||
final AbilityFactory af = sa.getAbilityFactory();
|
final AbilityFactory af = sa.getAbilityFactory();
|
||||||
final HashMap<String, String> mapParams = af.getMapParams();
|
final HashMap<String, String> mapParams = af.getMapParams();
|
||||||
|
|
||||||
|
if (ComputerUtil.preventRunAwayActivations(sa)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Player opp = ai.getOpponent();
|
Player opp = ai.getOpponent();
|
||||||
for (final String type : this.tokenTypes) {
|
for (final String type : this.tokenTypes) {
|
||||||
if (type.equals("Legendary")) {
|
if (type.equals("Legendary")) {
|
||||||
@@ -340,7 +344,6 @@ public class AbilityFactoryToken extends AbilityFactory {
|
|||||||
// prevent run-away activations - first time will always return true
|
// prevent run-away activations - first time will always return true
|
||||||
final Random r = MyRandom.getRandom();
|
final Random r = MyRandom.getRandom();
|
||||||
final Card source = sa.getSourceCard();
|
final Card source = sa.getSourceCard();
|
||||||
final boolean chance = r.nextFloat() <= Math.pow(.9, sa.getActivationsThisTurn());
|
|
||||||
|
|
||||||
final Target tgt = sa.getTarget();
|
final Target tgt = sa.getTarget();
|
||||||
if (tgt != null) {
|
if (tgt != null) {
|
||||||
@@ -383,17 +386,17 @@ public class AbilityFactoryToken extends AbilityFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (AbilityFactory.playReusable(sa)) {
|
if (AbilityFactory.playReusable(sa)) {
|
||||||
return chance;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Singletons.getModel().getGame().getPhaseHandler().is(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY)) {
|
if (Singletons.getModel().getGame().getPhaseHandler().is(PhaseType.COMBAT_DECLARE_ATTACKERS_INSTANT_ABILITY)) {
|
||||||
return ((r.nextFloat() < .95) && chance);
|
return true;
|
||||||
}
|
}
|
||||||
if (sa.isAbility()) {
|
if (sa.isAbility()) {
|
||||||
return ((r.nextFloat() < .9) && chance);
|
return (r.nextFloat() < .9);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ((r.nextFloat() < .8) && chance);
|
return (r.nextFloat() < .8);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -351,7 +351,7 @@ public class AbilityFactoryZoneAffecting {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Don't tap creatures that may be able to block
|
// Don't tap creatures that may be able to block
|
||||||
if (AbilityFactory.waitForBlocking(sa)) {
|
if (ComputerUtil.waitForBlocking(sa)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -906,7 +906,7 @@ public class AbilityFactoryZoneAffecting {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Don't tap creatures that may be able to block
|
// Don't tap creatures that may be able to block
|
||||||
if (AbilityFactory.waitForBlocking(sa)) {
|
if (ComputerUtil.waitForBlocking(sa)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1688,7 +1688,7 @@ public class AbilityFactoryZoneAffecting {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Don't tap creatures that may be able to block
|
// 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import java.util.Collections;
|
|||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.base.Predicates;
|
import com.google.common.base.Predicates;
|
||||||
@@ -54,10 +55,12 @@ import forge.control.input.InputPayManaCostUtil;
|
|||||||
import forge.error.ErrorViewer;
|
import forge.error.ErrorViewer;
|
||||||
import forge.game.phase.Combat;
|
import forge.game.phase.Combat;
|
||||||
import forge.game.phase.CombatUtil;
|
import forge.game.phase.CombatUtil;
|
||||||
|
import forge.game.phase.PhaseHandler;
|
||||||
import forge.game.phase.PhaseType;
|
import forge.game.phase.PhaseType;
|
||||||
import forge.game.zone.ZoneType;
|
import forge.game.zone.ZoneType;
|
||||||
import forge.gui.GuiChoose;
|
import forge.gui.GuiChoose;
|
||||||
import forge.util.Aggregates;
|
import forge.util.Aggregates;
|
||||||
|
import forge.util.MyRandom;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2179,4 +2182,43 @@ public class ComputerUtil {
|
|||||||
sa.setTargetPlayer(human);
|
sa.setTargetPlayer(human);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// returns true if it's better to wait until blockers are declared
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* waitForBlocking.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @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
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* preventRunAwayActivations.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user