- More work on flash aura logic.

This commit is contained in:
Agetian
2018-11-22 19:06:44 +03:00
parent 0b0c08631a
commit 12ec6e24a2
7 changed files with 94 additions and 52 deletions

View File

@@ -120,10 +120,10 @@ public enum AiProps { /** */
FLASH_CHANCE_TO_CAST_FOR_ETB_BEFORE_MAIN1("10"), /** */
FLASH_CHANCE_TO_RESPOND_TO_STACK_WITH_ETB("0"), /** */
FLASH_CHANCE_TO_CAST_AS_VALUABLE_BLOCKER("100"),
FLASH_USE_AURAS_AS_COMBAT_TRICKS("true"),
FLASH_AURA_CHANCE_TO_CAST_EARLY("0"),
FLASH_AURA_CHANCE_CAST_AT_EOT("10"),
FLASH_AURA_CHANCE_TO_RESPOND_TO_STACK("0"); /** */
FLASH_USE_BUFF_AURAS_AS_COMBAT_TRICKS("true"),
FLASH_BUFF_AURA_CHANCE_TO_CAST_EARLY("0"),
FLASH_BUFF_AURA_CHANCE_CAST_AT_EOT("10"),
FLASH_BUFF_AURA_CHANCE_TO_RESPOND_TO_STACK("0"); /** */
// Experimental features, must be promoted or removed after extensive testing and, ideally, defaulting
// <-- There are no experimental options here -->

View File

@@ -2,6 +2,7 @@ package forge.ai.ability;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Lists;
import forge.ai.*;
import forge.game.Game;
import forge.game.GameObject;
@@ -49,15 +50,6 @@ public class AttachAi extends SpellAbilityAi {
return false;
}
// Flash logic
boolean advancedFlash = false;
if (ai.getController().isAI()) {
advancedFlash = ((PlayerControllerAi)ai.getController()).getAi().getBooleanProperty(AiProps.FLASH_ENABLE_ADVANCED_LOGIC);
}
if (source.withFlash(ai) && source.isAura() && advancedFlash && !doAdvancedFlashAuraLogic(ai)) {
return false;
}
if (abCost != null) {
// AI currently disabled for these costs
if (!ComputerUtilCost.checkSacrificeCost(ai, abCost, source, sa)) {
@@ -97,6 +89,15 @@ public class AttachAi extends SpellAbilityAi {
}
}
// Flash logic
boolean advancedFlash = false;
if (ai.getController().isAI()) {
advancedFlash = ((PlayerControllerAi)ai.getController()).getAi().getBooleanProperty(AiProps.FLASH_ENABLE_ADVANCED_LOGIC);
}
if (source.withFlash(ai) && source.isAura() && advancedFlash && !doAdvancedFlashAuraLogic(ai, sa, sa.getTargetCard())) {
return false;
}
if (abCost.getTotalMana().countX() > 0 && source.getSVar("X").equals("Count$xPaid")) {
// Set PayX here to maximum value. (Endless Scream and Venarian
// Gold)
@@ -128,26 +129,72 @@ public class AttachAi extends SpellAbilityAi {
return true;
}
private boolean doAdvancedFlashAuraLogic(Player ai) {
private boolean doAdvancedFlashAuraLogic(Player ai, SpellAbility sa, Card attachTarget) {
Card source = sa.getHostCard();
Game game = ai.getGame();
Combat combat = game.getCombat();
AiController aic = ((PlayerControllerAi)ai.getController()).getAi();
if (!aic.getBooleanProperty(AiProps.FLASH_USE_BUFF_AURAS_AS_COMBAT_TRICKS)) {
// Currently this only works with buff auras, so if the relevant toggle is disabled, just return true
// for instant speed use. To be improved later.
return true;
}
int power = 0, toughness = 0;
List<String> keywords = Lists.newArrayList();
for (StaticAbility stAb : source.getStaticAbilities()) {
if ("Continuous".equals(stAb.getParam("Mode"))) {
if (stAb.hasParam("AddPower")) {
power += AbilityUtils.calculateAmount(source, stAb.getParam("AddPower"), stAb);
}
if (stAb.hasParam("AddToughness")) {
toughness += AbilityUtils.calculateAmount(source, stAb.getParam("AddToughness"), stAb);
}
if (stAb.hasParam("AddKeyword")) {
keywords.addAll(Lists.newArrayList(stAb.getParam("AddKeyword").split(" & ")));
}
}
}
boolean isBuffAura = !sa.isCurse() && (power > 0 || toughness > 0 || !keywords.isEmpty());
if (!isBuffAura) {
// Currently only works with buff auras, otherwise returns for instant speed use. To be improved later.
return true;
}
boolean canRespondToStack = false;
if (!game.getStack().isEmpty()) {
SpellAbility peekSa = game.getStack().peekAbility();
Player activator = peekSa.getActivatingPlayer();
if (activator != null && activator.isOpponentOf(ai) && peekSa.getApi() != ApiType.DestroyAll &&
peekSa.getApi() != ApiType.Destroy) {
// TODO: improve this so that the AI predicts how much damage will be dealt to the creature
// so that it can try to save it (and won't bother targeting it if it can't be saved)
canRespondToStack = true;
if (activator != null && activator.isOpponentOf(ai)
&& (!peekSa.usesTargeting() || peekSa.getTargets().getTargetCards().contains(attachTarget))) {
if (peekSa.getApi() == ApiType.DealDamage || peekSa.getApi() == ApiType.DamageAll) {
int dmg = AbilityUtils.calculateAmount(peekSa.getHostCard(), peekSa.getParam("NumDmg"), peekSa);
if (dmg < toughness + attachTarget.getNetToughness()) {
canRespondToStack = true;
}
} else if (peekSa.getApi() == ApiType.Destroy || peekSa.getApi() == ApiType.DestroyAll) {
if (!attachTarget.hasKeyword(Keyword.INDESTRUCTIBLE) && !ComputerUtil.canRegenerate(ai, attachTarget)
&& keywords.contains("Indestructible")) {
canRespondToStack = true;
}
} else if (peekSa.getApi() == ApiType.Pump || peekSa.getApi() == ApiType.PumpAll) {
int p = AbilityUtils.calculateAmount(peekSa.getHostCard(), peekSa.getParam("NumAtt"), peekSa);
int t = AbilityUtils.calculateAmount(peekSa.getHostCard(), peekSa.getParam("NumDef"), peekSa);
if (t < 0 && toughness > 0 && attachTarget.getNetToughness() + t + toughness > 0) {
canRespondToStack = true;
} else if (p < 0 && power > 0 && attachTarget.getNetToughness() + t + toughness > 0) {
// Yep, still need to ensure that the net toughness will be positive here even if buffing for power
canRespondToStack = true;
}
}
}
}
boolean useAurasAsTricks = aic.getBooleanProperty(AiProps.FLASH_USE_AURAS_AS_COMBAT_TRICKS);
int chanceToCastAtEOT = aic.getIntProperty(AiProps.FLASH_AURA_CHANCE_CAST_AT_EOT);
int chanceToCastEarly = aic.getIntProperty(AiProps.FLASH_AURA_CHANCE_TO_CAST_EARLY);
int chanceToRespondToStack = aic.getIntProperty(AiProps.FLASH_AURA_CHANCE_TO_RESPOND_TO_STACK);
int chanceToCastAtEOT = aic.getIntProperty(AiProps.FLASH_BUFF_AURA_CHANCE_CAST_AT_EOT);
int chanceToCastEarly = aic.getIntProperty(AiProps.FLASH_BUFF_AURA_CHANCE_TO_CAST_EARLY);
int chanceToRespondToStack = aic.getIntProperty(AiProps.FLASH_BUFF_AURA_CHANCE_TO_RESPOND_TO_STACK);
boolean hasFloatMana = ai.getManaPool().totalMana() > 0;
boolean willDiscardNow = game.getPhaseHandler().is(PhaseType.END_OF_TURN, ai)
@@ -155,11 +202,11 @@ public class AttachAi extends SpellAbilityAi {
boolean willRespondToStack = canRespondToStack && MyRandom.percentTrue(chanceToRespondToStack);
boolean willCastEarly = MyRandom.percentTrue(chanceToCastEarly);
boolean willCastAtEOT = game.getPhaseHandler().is(PhaseType.END_OF_TURN)
&& game.getPhaseHandler().getNextTurn().equals(ai) && MyRandom.percentTrue(chanceToCastAtEOT) || !useAurasAsTricks;
&& game.getPhaseHandler().getNextTurn().equals(ai) && MyRandom.percentTrue(chanceToCastAtEOT);
boolean alternativeConsiderations = hasFloatMana || willDiscardNow || willRespondToStack || willCastAtEOT || willCastEarly;
if (!alternativeConsiderations && (combat == null || game.getPhaseHandler().getPhase().isBefore(PhaseType.COMBAT_DECLARE_BLOCKERS))) {
if (!alternativeConsiderations && (combat == null || game.getPhaseHandler().getPhase().isBefore(PhaseType.COMBAT_DECLARE_BLOCKERS)) || (!combat.isAttacking(attachTarget) && !combat.isBlocking(attachTarget))) {
return false;
}

View File

@@ -123,7 +123,8 @@ public class PermanentCreatureAi extends PermanentAi {
if (!game.getStack().isEmpty()) {
SpellAbility peekSa = game.getStack().peekAbility();
Player activator = peekSa.getActivatingPlayer();
if (activator != null && activator.isOpponentOf(ai) && peekSa.getApi() != ApiType.DestroyAll) {
if (activator != null && activator.isOpponentOf(ai) && peekSa.getApi() != ApiType.DestroyAll
&& peekSa.getApi() != ApiType.DamageAll) {
canRespondToStack = true;
}
}

View File

@@ -171,14 +171,13 @@ FLASH_CHANCE_TO_RESPOND_TO_STACK_WITH_ETB=0
FLASH_CHANCE_TO_CAST_AS_VALUABLE_BLOCKER=100
# If enabled, the AI will try to hold off playing auras with Flash until the declare blockers step in combat.
# If disabled, but advanced logic is enabled, will generally try to play these auras before its own turn.
FLASH_USE_AURAS_AS_COMBAT_TRICKS=true
FLASH_USE_BUFF_AURAS_AS_COMBAT_TRICKS=true
# The chance that the AI will cast a flash aura enchantment at the earliest opportunity
FLASH_AURA_CHANCE_TO_CAST_EARLY=0
FLASH_BUFF_AURA_CHANCE_TO_CAST_EARLY=0
# The chance that the AI will cast a flash aura at the end of turn before its own turn
FLASH_AURA_CHANCE_CAST_AT_EOT=5
# The chance that the AI will respond to stack with a flash aura (may do silly things sometimes, so better left
# disabled or at a low chance until improved)
FLASH_AURA_CHANCE_TO_RESPOND_TO_STACK=0
FLASH_BUFF_AURA_CHANCE_CAST_AT_EOT=5
# The chance that the AI will respond to stack with a flash aura which makes sense in context
FLASH_BUFF_AURA_CHANCE_TO_RESPOND_TO_STACK=100
# Scry AI toggles
# The total number of mana-producing lands at which the AI will still consider scrying away non-lands

View File

@@ -172,14 +172,13 @@ FLASH_CHANCE_TO_RESPOND_TO_STACK_WITH_ETB=0
FLASH_CHANCE_TO_CAST_AS_VALUABLE_BLOCKER=100
# If enabled, the AI will try to hold off playing auras with Flash until the declare blockers step in combat.
# If disabled, but advanced logic is enabled, will generally try to play these auras before its own turn.
FLASH_USE_AURAS_AS_COMBAT_TRICKS=true
FLASH_USE_BUFF_AURAS_AS_COMBAT_TRICKS=true
# The chance that the AI will cast a flash aura enchantment at the earliest opportunity
FLASH_AURA_CHANCE_TO_CAST_EARLY=5
FLASH_BUFF_AURA_CHANCE_TO_CAST_EARLY=1
# The chance that the AI will cast a flash aura at the end of turn before its own turn
FLASH_AURA_CHANCE_CAST_AT_EOT=10
# The chance that the AI will respond to stack with a flash aura (may do silly things sometimes, so better left
# disabled or at a low chance until improved)
FLASH_AURA_CHANCE_TO_RESPOND_TO_STACK=0
FLASH_BUFF_AURA_CHANCE_CAST_AT_EOT=5
# The chance that the AI will respond to stack with a flash aura which makes sense in context
FLASH_BUFF_AURA_CHANCE_TO_RESPOND_TO_STACK=100
# Scry AI toggles
# The total number of mana-producing lands at which the AI will still consider scrying away non-lands

View File

@@ -170,18 +170,15 @@ FLASH_CHANCE_TO_RESPOND_TO_STACK_WITH_ETB=15
# The chance the AI will attempt to add a new blocker in combat where it's low on creature count compared to the
# number of attacking creatures.
FLASH_CHANCE_TO_CAST_AS_VALUABLE_BLOCKER=100
# The chance that the AI will try to hold off playing auras with Flash until the declare blockers step in combat.
FLASH_CHANCE_TO_USE_AURAS_AS_COMBAT_TRICKS=100
# If enabled, the AI will try to hold off playing auras with Flash until the declare blockers step in combat.
# If disabled, but advanced logic is enabled, will generally try to play these auras before its own turn.
FLASH_USE_AURAS_AS_COMBAT_TRICKS=true
FLASH_USE_BUFF_AURAS_AS_COMBAT_TRICKS=true
# The chance that the AI will cast a flash aura enchantment at the earliest opportunity
FLASH_AURA_CHANCE_TO_CAST_EARLY=0
FLASH_BUFF_AURA_CHANCE_TO_CAST_EARLY=0
# The chance that the AI will cast a flash aura at the end of turn before its own turn
FLASH_AURA_CHANCE_CAST_AT_EOT=10
# The chance that the AI will respond to stack with a flash aura (may do silly things sometimes, so better left
# disabled or at a low chance until improved)
FLASH_AURA_CHANCE_TO_RESPOND_TO_STACK=100
FLASH_BUFF_AURA_CHANCE_CAST_AT_EOT=10
# The chance that the AI will respond to stack with a flash aura which makes sense in context
FLASH_BUFF_AURA_CHANCE_TO_RESPOND_TO_STACK=100
# Scry AI toggles
# The total number of mana-producing lands at which the AI will still consider scrying away non-lands

View File

@@ -172,14 +172,13 @@ FLASH_CHANCE_TO_RESPOND_TO_STACK_WITH_ETB=10
FLASH_CHANCE_TO_CAST_AS_VALUABLE_BLOCKER=100
# If enabled, the AI will try to hold off playing auras with Flash until the declare blockers step in combat.
# If disabled, but advanced logic is enabled, will generally try to play these auras before its own turn.
FLASH_USE_AURAS_AS_COMBAT_TRICKS=true
FLASH_USE_BUFF_AURAS_AS_COMBAT_TRICKS=true
# The chance that the AI will cast a flash aura enchantment at the earliest opportunity
FLASH_AURA_CHANCE_TO_CAST_EARLY=10
FLASH_BUFF_AURA_CHANCE_TO_CAST_EARLY=3
# The chance that the AI will cast a flash aura at the end of turn before its own turn
FLASH_AURA_CHANCE_CAST_AT_EOT=30
# The chance that the AI will respond to stack with a flash aura (may do silly things sometimes, so better left
# disabled or at a low chance until improved)
FLASH_AURA_CHANCE_TO_RESPOND_TO_STACK=10
FLASH_BUFF_AURA_CHANCE_CAST_AT_EOT=10
# The chance that the AI will respond to stack with a flash aura which makes sense in context
FLASH_BUFF_AURA_CHANCE_TO_RESPOND_TO_STACK=100
# Scry AI toggles
# The total number of mana-producing lands at which the AI will still consider scrying away non-lands