diff --git a/forge-ai/src/main/java/forge/ai/AiProps.java b/forge-ai/src/main/java/forge/ai/AiProps.java index 413e1c45d1f..06436660893 100644 --- a/forge-ai/src/main/java/forge/ai/AiProps.java +++ b/forge-ai/src/main/java/forge/ai/AiProps.java @@ -35,6 +35,7 @@ public enum AiProps { /** */ MOVE_EQUIPMENT_TO_BETTER_CREATURES ("from_useless_only"), MOVE_EQUIPMENT_CREATURE_EVAL_THRESHOLD ("60"), PRIORITIZE_MOVE_EQUIPMENT_IF_USELESS ("true"), + SAC_TO_REATTACH_TARGET_EVAL_THRESHOLD ("400"), PREDICT_SPELLS_FOR_MAIN2 ("true"), /** */ RESERVE_MANA_FOR_MAIN2_CHANCE ("0"), /** */ PLAY_AGGRO ("false"), diff --git a/forge-ai/src/main/java/forge/ai/ability/AttachAi.java b/forge-ai/src/main/java/forge/ai/ability/AttachAi.java index 37602483b41..e762a23d12a 100644 --- a/forge-ai/src/main/java/forge/ai/ability/AttachAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/AttachAi.java @@ -838,7 +838,7 @@ public class AttachAi extends SpellAbilityAi { * @return the card */ private static Card attachAICursePreference(final SpellAbility sa, final List list, final boolean mandatory, - final Card attachSource) { + final Card attachSource, final Player ai) { // AI For choosing a Card to Curse of. // TODO Figure out some way to combine The "gathering of data" from @@ -930,6 +930,24 @@ public class AttachAi extends SpellAbilityAi { ); } + // If this is already attached and there's a sac cost, make sure we attach to something that's + // seriously better than whatever the attachment is currently attached to (e.g. Bound by Moonsilver) + if (sa.getHostCard().getAttachedTo() != null && sa.getHostCard().getAttachedTo().isCreature() + && sa.getPayCosts() != null && sa.getPayCosts().hasSpecificCostType(CostSacrifice.class)) { + final int oldEvalRating = ComputerUtilCard.evaluateCreature(sa.getHostCard().getAttachedTo()); + final int threshold = ai.isAI() ? ((PlayerControllerAi)ai.getController()).getAi().getIntProperty(AiProps.SAC_TO_REATTACH_TARGET_EVAL_THRESHOLD) : Integer.MAX_VALUE; + prefList = CardLists.filter(prefList, new Predicate() { + @Override + public boolean apply(Card card) { + if (!card.isCreature()) { + return false; + } + + return ComputerUtilCard.evaluateCreature(card) >= oldEvalRating + threshold; + } + }); + } + c = ComputerUtilCard.getBestAI(prefList); if (c == null) { @@ -1455,7 +1473,7 @@ public class AttachAi extends SpellAbilityAi { if ("GainControl".equals(logic)) { c = attachAIControlPreference(sa, prefList, mandatory, attachSource); } else if ("Curse".equals(logic)) { - c = attachAICursePreference(sa, prefList, mandatory, attachSource); + c = attachAICursePreference(sa, prefList, mandatory, attachSource, ai); } else if ("Pump".equals(logic)) { c = attachAIPumpPreference(ai, sa, prefList, mandatory, attachSource); } else if ("Curiosity".equals(logic)) { diff --git a/forge-gui/res/ai/Cautious.ai b/forge-gui/res/ai/Cautious.ai index f276aa1c9c9..f91debe53f2 100644 --- a/forge-gui/res/ai/Cautious.ai +++ b/forge-gui/res/ai/Cautious.ai @@ -100,6 +100,9 @@ PLANAR_DIE_ROLL_HESITATION_CHANCE=10 MOVE_EQUIPMENT_TO_BETTER_CREATURES=from_useless_only MOVE_EQUIPMENT_CREATURE_EVAL_THRESHOLD=60 PRIORITIZE_MOVE_EQUIPMENT_IF_USELESS=true +# If there's a sacrifice cost to reattach an aura/equipment to another target creature, how big of an evaluation difference +# should there be between the old target and the new one for the AI to decide to proceed with it. +SAC_TO_REATTACH_TARGET_EVAL_THRESHOLD=500 # Currently disabled PREDICT_SPELLS_FOR_MAIN2=true diff --git a/forge-gui/res/ai/Default.ai b/forge-gui/res/ai/Default.ai index 060ebb5f114..c8762118617 100644 --- a/forge-gui/res/ai/Default.ai +++ b/forge-gui/res/ai/Default.ai @@ -100,6 +100,9 @@ PLANAR_DIE_ROLL_HESITATION_CHANCE=10 MOVE_EQUIPMENT_TO_BETTER_CREATURES=from_useless_only MOVE_EQUIPMENT_CREATURE_EVAL_THRESHOLD=60 PRIORITIZE_MOVE_EQUIPMENT_IF_USELESS=true +# If there's a sacrifice cost to reattach an aura/equipment to another target creature, how big of an evaluation difference +# should there be between the old target and the new one for the AI to decide to proceed with it. +SAC_TO_REATTACH_TARGET_EVAL_THRESHOLD=400 # Currently disabled PREDICT_SPELLS_FOR_MAIN2=true diff --git a/forge-gui/res/ai/Experimental.ai b/forge-gui/res/ai/Experimental.ai index c5592fa230c..06a9d7c91e9 100644 --- a/forge-gui/res/ai/Experimental.ai +++ b/forge-gui/res/ai/Experimental.ai @@ -100,6 +100,9 @@ PLANAR_DIE_ROLL_HESITATION_CHANCE=10 MOVE_EQUIPMENT_TO_BETTER_CREATURES=always MOVE_EQUIPMENT_CREATURE_EVAL_THRESHOLD=60 PRIORITIZE_MOVE_EQUIPMENT_IF_USELESS=true +# If there's a sacrifice cost to reattach an aura/equipment to another target creature, how big of an evaluation difference +# should there be between the old target and the new one for the AI to decide to proceed with it. +SAC_TO_REATTACH_TARGET_EVAL_THRESHOLD=350 # Currently disabled PREDICT_SPELLS_FOR_MAIN2=true diff --git a/forge-gui/res/ai/Reckless.ai b/forge-gui/res/ai/Reckless.ai index 97cc512165f..6215a58e410 100644 --- a/forge-gui/res/ai/Reckless.ai +++ b/forge-gui/res/ai/Reckless.ai @@ -100,6 +100,9 @@ PLANAR_DIE_ROLL_HESITATION_CHANCE=0 MOVE_EQUIPMENT_TO_BETTER_CREATURES=always MOVE_EQUIPMENT_CREATURE_EVAL_THRESHOLD=50 PRIORITIZE_MOVE_EQUIPMENT_IF_USELESS=false +# If there's a sacrifice cost to reattach an aura/equipment to another target creature, how big of an evaluation difference +# should there be between the old target and the new one for the AI to decide to proceed with it. +SAC_TO_REATTACH_TARGET_EVAL_THRESHOLD=300 # Currently disabled PREDICT_SPELLS_FOR_MAIN2=true diff --git a/forge-gui/res/cardsfolder/b/bound_by_moonsilver.txt b/forge-gui/res/cardsfolder/b/bound_by_moonsilver.txt index 1f43bc4d5da..40f7e931e7a 100644 --- a/forge-gui/res/cardsfolder/b/bound_by_moonsilver.txt +++ b/forge-gui/res/cardsfolder/b/bound_by_moonsilver.txt @@ -5,5 +5,6 @@ K:Enchant creature A:SP$ Attach | Cost$ 2 W | ValidTgts$ Creature | AILogic$ Curse S:Mode$ Continuous | Affected$ Creature.EnchantedBy | AddHiddenKeyword$ CARDNAME can't attack or block. & CARDNAME can't transform | Description$ Enchanted creature can't attack, block, or transform. A:AB$ Attach | Cost$ Sac<1/Permanent.Other/another permanent> | ValidTgts$ Creature | TgtPrompt$ Select target creature | AILogic$ Curse | SorcerySpeed$ True | ActivationLimit$ 1 | SpellDescription$ Attach CARDNAME to target creature. Activate this ability only any time you could cast a sorcery and only once each turn. +SVar:AIPreference:SacCost$Card.token,Permanent.nonLand+cmcLE2,Land.Basic SVar:Picture:http://www.wizards.com/global/images/magic/general/bound_by_moonsilver.jpg Oracle:Enchant creature\nEnchanted creature can't attack, block, or transform.\nSacrifice another permanent: Attach Bound by Moonsilver to target creature. Activate this ability only any time you could cast a sorcery and only once each turn.