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));
|
||||
}
|
||||
|
||||
// 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>
|
||||
* isSorcerySpeed.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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<Card>() {
|
||||
@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
|
||||
|
||||
/**
|
||||
|
||||
@@ -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()
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -295,6 +295,10 @@ public class AbilityFactoryToken extends AbilityFactory {
|
||||
final AbilityFactory af = sa.getAbilityFactory();
|
||||
final HashMap<String, String> 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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
/**
|
||||
* <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