diff --git a/forge-ai/src/main/java/forge/ai/AiCardMemory.java b/forge-ai/src/main/java/forge/ai/AiCardMemory.java index 436c87e6c57..13e02210809 100644 --- a/forge-ai/src/main/java/forge/ai/AiCardMemory.java +++ b/forge-ai/src/main/java/forge/ai/AiCardMemory.java @@ -41,6 +41,7 @@ import java.util.Set; public class AiCardMemory { private final Set memMandatoryAttackers; + private final Set memTrickAttackers; private final Set memHeldManaSources; private final Set memAttachedThisTurn; private final Set memAnimatedThisTurn; @@ -54,6 +55,7 @@ public class AiCardMemory { this.memAnimatedThisTurn = new HashSet<>(); this.memBouncedThisTurn = new HashSet<>(); this.memActivatedThisTurn = new HashSet<>(); + this.memTrickAttackers = new HashSet<>(); } /** @@ -63,6 +65,7 @@ public class AiCardMemory { */ public enum MemorySet { MANDATORY_ATTACKERS, + TRICK_ATTACKERS, HELD_MANA_SOURCES, ATTACHED_THIS_TURN, ANIMATED_THIS_TURN, @@ -75,6 +78,8 @@ public class AiCardMemory { switch (set) { case MANDATORY_ATTACKERS: return memMandatoryAttackers; + case TRICK_ATTACKERS: + return memTrickAttackers; case HELD_MANA_SOURCES: return memHeldManaSources; case ATTACHED_THIS_TURN: @@ -254,6 +259,7 @@ public class AiCardMemory { */ public void clearAllRemembered() { clearMemorySet(MemorySet.MANDATORY_ATTACKERS); + clearMemorySet(MemorySet.TRICK_ATTACKERS); clearMemorySet(MemorySet.HELD_MANA_SOURCES); clearMemorySet(MemorySet.ATTACHED_THIS_TURN); clearMemorySet(MemorySet.ANIMATED_THIS_TURN); diff --git a/forge-ai/src/main/java/forge/ai/AiProps.java b/forge-ai/src/main/java/forge/ai/AiProps.java index 0997a363a75..26cf043a56d 100644 --- a/forge-ai/src/main/java/forge/ai/AiProps.java +++ b/forge-ai/src/main/java/forge/ai/AiProps.java @@ -38,6 +38,8 @@ public enum AiProps { /** */ PLAY_AGGRO ("false"), CHANCE_TO_ATTACK_INTO_TRADE ("100"), /** */ ATTACK_INTO_TRADE_WHEN_TAPPED_OUT ("false"), /** */ + TRY_TO_HOLD_COMBAT_TRICKS_UNTIL_BLOCK ("false"), /** */ + CHANCE_TO_HOLD_COMBAT_TRICKS_UNTIL_BLOCK ("30"), /** */ ENABLE_RANDOM_FAVORABLE_TRADES_ON_BLOCK ("false"), /** */ RANDOMLY_TRADE_EVEN_WHEN_HAVE_LESS_CREATS ("false"), /** */ MAX_DIFF_IN_CREATURE_COUNT_TO_TRADE ("1"), /** */ diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java b/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java index e980f9e5e90..0dd32e8036a 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java @@ -1164,6 +1164,16 @@ public class ComputerUtilCard { final PhaseHandler phase = game.getPhaseHandler(); final Combat combat = phase.getCombat(); final boolean isBerserk = "Berserk".equals(sa.getParam("AILogic")); + + boolean combatTrick = false; + boolean holdCombatTricks = false; + int chanceHoldCombatTricks = 0; + + if (ai.getController().isAI()) { + AiController aic = ((PlayerControllerAi)ai.getController()).getAi(); + holdCombatTricks = aic.getBooleanProperty(AiProps.TRY_TO_HOLD_COMBAT_TRICKS_UNTIL_BLOCK); + chanceHoldCombatTricks = aic.getIntProperty(AiProps.CHANCE_TO_HOLD_COMBAT_TRICKS_UNTIL_BLOCK); + } if (!c.canBeTargetedBy(sa)) { return false; @@ -1224,6 +1234,7 @@ public class ComputerUtilCard { threat *= 4; //over-value self +attack for 0 power creatures which may be pumped further after attacking } chance += threat; + combatTrick = true; } //2. grant haste @@ -1393,6 +1404,23 @@ public class ComputerUtilCard { } } + boolean isHeldCombatTrick = combatTrick && holdCombatTricks && MyRandom.percentTrue(chanceHoldCombatTricks); + + if (isHeldCombatTrick) { + if (AiCardMemory.isMemorySetEmpty(ai, AiCardMemory.MemorySet.TRICK_ATTACKERS)) { + // Attempt to hold combat tricks until blockers are declared, and try to lure the opponent into blocking + // (The AI will only do it for one attacker at the moment, otherwise it risks running his attackers into + // an army of opposing blockers with only one combat trick in hand + AiCardMemory.rememberCard(ai, c, AiCardMemory.MemorySet.MANDATORY_ATTACKERS); + AiCardMemory.rememberCard(ai, c, AiCardMemory.MemorySet.TRICK_ATTACKERS); + return false; + } else { + // Don't try to mix "lure" and "precast" paradigms for combat tricks, since that creates issues with + // the AI overextending the attack + return false; + } + } + return MyRandom.getRandom().nextFloat() < chance; } diff --git a/forge-gui/res/ai/Cautious.ai b/forge-gui/res/ai/Cautious.ai index 1384f88b75d..a333297d134 100644 --- a/forge-gui/res/ai/Cautious.ai +++ b/forge-gui/res/ai/Cautious.ai @@ -14,6 +14,11 @@ CHANCE_TO_ATTACK_INTO_TRADE=0 ATTACK_INTO_TRADE_WHEN_TAPPED_OUT=false # When enabled, the AI will use Berserk on offense to try to severely damage the opponent at the expense of the creature USE_BERSERK_AGGRESSIVELY=false +# Try to hold combat tricks until blockers are declared in an attempt to trick the opponent into blocking a weak creature +# and dying to it (currently has some limitations, the AI will only try to do it to one creature) +TRY_TO_HOLD_COMBAT_TRICKS_UNTIL_BLOCK=false +# The chance to hold combat tricks and try to lure the opponent into blocking a weaker creature +CHANCE_TO_HOLD_COMBAT_TRICKS_UNTIL_BLOCK=30 # Trade blocking preferences (enabling these will make the AI trade more aggressively when considering blocks, # but only with creatures that are worse in abilities and have lower or the same power as the attacker). Note diff --git a/forge-gui/res/ai/Default.ai b/forge-gui/res/ai/Default.ai index f1dabad6a4d..0ab5d50bc1a 100644 --- a/forge-gui/res/ai/Default.ai +++ b/forge-gui/res/ai/Default.ai @@ -14,6 +14,11 @@ CHANCE_TO_ATTACK_INTO_TRADE=0 ATTACK_INTO_TRADE_WHEN_TAPPED_OUT=false # When enabled, the AI will use Berserk on offense to try to severely damage the opponent at the expense of the creature USE_BERSERK_AGGRESSIVELY=false +# Try to hold combat tricks until blockers are declared in an attempt to trick the opponent into blocking a weak creature +# and dying to it (currently has some limitations, the AI will only try to do it to one creature) +TRY_TO_HOLD_COMBAT_TRICKS_UNTIL_BLOCK=false +# The chance to hold combat tricks and try to lure the opponent into blocking a weaker creature +CHANCE_TO_HOLD_COMBAT_TRICKS_UNTIL_BLOCK=30 # Trade blocking preferences (enabling these will make the AI trade more aggressively when considering blocks, # but only with creatures that are worse in abilities and have lower or the same power as the attacker). Note diff --git a/forge-gui/res/ai/Experimental.ai b/forge-gui/res/ai/Experimental.ai index 791dd01ce92..47b415c4c8e 100644 --- a/forge-gui/res/ai/Experimental.ai +++ b/forge-gui/res/ai/Experimental.ai @@ -14,6 +14,11 @@ CHANCE_TO_ATTACK_INTO_TRADE=20 ATTACK_INTO_TRADE_WHEN_TAPPED_OUT=false # When enabled, the AI will use Berserk on offense to try to severely damage the opponent at the expense of the creature USE_BERSERK_AGGRESSIVELY=true +# Try to hold combat tricks until blockers are declared in an attempt to trick the opponent into blocking a weak creature +# and dying to it (currently has some limitations, the AI will only try to do it to one creature) +TRY_TO_HOLD_COMBAT_TRICKS_UNTIL_BLOCK=true +# The chance to hold combat tricks and try to lure the opponent into blocking a weaker creature +CHANCE_TO_HOLD_COMBAT_TRICKS_UNTIL_BLOCK=30 # Trade blocking preferences (enabling these will make the AI trade more aggressively when considering blocks, # but only with creatures that are worse in abilities and have lower or the same power as the attacker). Note @@ -23,7 +28,7 @@ ENABLE_RANDOM_FAVORABLE_TRADES_ON_BLOCK=true RANDOMLY_TRADE_EVEN_WHEN_HAVE_LESS_CREATS=true # If the previous option is enabled, then the next option controls how big of a handicap in creature count the AI # is allowed to have to still decide to trade -MAX_DIFF_IN_CREATURE_COUNT_TO_TRADE=1 +MAX_DIFF_IN_CREATURE_COUNT_TO_TRADE=999 # Min and max chance to randomly aggressively trade when blocking (note that it will become 100 if the AI is in danger) MIN_CHANCE_TO_RANDOMLY_TRADE_ON_BLOCK=20 MAX_CHANCE_TO_RANDOMLY_TRADE_ON_BLOCK=65 diff --git a/forge-gui/res/ai/Reckless.ai b/forge-gui/res/ai/Reckless.ai index a44d65366c7..f03bf895e63 100644 --- a/forge-gui/res/ai/Reckless.ai +++ b/forge-gui/res/ai/Reckless.ai @@ -14,6 +14,11 @@ CHANCE_TO_ATTACK_INTO_TRADE=100 ATTACK_INTO_TRADE_WHEN_TAPPED_OUT=true # When enabled, the AI will use Berserk on offense to try to severely damage the opponent at the expense of the creature USE_BERSERK_AGGRESSIVELY=true +# Try to hold combat tricks until blockers are declared in an attempt to trick the opponent into blocking a weak creature +# and dying to it (currently has some limitations, the AI will only try to do it to one creature) +TRY_TO_HOLD_COMBAT_TRICKS_UNTIL_BLOCK=false +# The chance to hold combat tricks and try to lure the opponent into blocking a weaker creature +CHANCE_TO_HOLD_COMBAT_TRICKS_UNTIL_BLOCK=30 # Trade blocking preferences (enabling these will make the AI trade more aggressively when considering blocks, # but only with creatures that are worse in abilities and have lower or the same power as the attacker). Note