From f484f02f4d5c39a724fb6561c67239018def3fdc Mon Sep 17 00:00:00 2001 From: Agetian Date: Tue, 17 Jan 2017 16:11:26 +0000 Subject: [PATCH] - Added an experimental (and disabled by default in all profiles) AI profile option ACTIVELY_DESTROY_ARTS_AND_NONAURA_ENCHS, which makes the AI more willing to not hold back using removal on artifacts and global (non-aura) enchantments that have "suspicious" (potentially beneficial for the opponent/disruptive for the AI) intrinsic static or triggered abilities. - Currently very basic and requires tweaking and expansion, from hence it's disabled by default until I experiment enough with it, see how it works in practice and tweak it to account for other cases and corner cases that may be viable (and prove that it does not make the AI take stupider decisions than without this option). --- forge-ai/src/main/java/forge/ai/AiProps.java | 3 +- .../main/java/forge/ai/ComputerUtilCard.java | 39 +++++++++++++++++++ forge-gui/res/ai/Default.ai | 1 + forge-gui/res/ai/Reckless.ai | 1 + 4 files changed, 43 insertions(+), 1 deletion(-) diff --git a/forge-ai/src/main/java/forge/ai/AiProps.java b/forge-ai/src/main/java/forge/ai/AiProps.java index bea832392df..1b87cc27d84 100644 --- a/forge-ai/src/main/java/forge/ai/AiProps.java +++ b/forge-ai/src/main/java/forge/ai/AiProps.java @@ -34,7 +34,8 @@ public enum AiProps { /** */ PRIORITIZE_MOVE_EQUIPMENT_IF_USELESS ("true"), PREDICT_SPELLS_FOR_MAIN2 ("true"), /** */ RESERVE_MANA_FOR_MAIN2_CHANCE ("0"), /** */ - PLAY_AGGRO ("false"); /** */ + PLAY_AGGRO ("false"), /** */ + ACTIVELY_DESTROY_ARTS_AND_NONAURA_ENCHS ("false"); /** */ private final String strDefaultVal; diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java b/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java index 8a9aae1eab2..69075c17d51 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtilCard.java @@ -44,6 +44,7 @@ import forge.game.phase.PhaseType; import forge.game.player.Player; import forge.game.spellability.SpellAbility; import forge.game.staticability.StaticAbility; +import forge.game.trigger.Trigger; import forge.game.zone.MagicStack; import forge.game.zone.ZoneType; import forge.item.PaperCard; @@ -846,6 +847,7 @@ public class ComputerUtilCard { public static boolean useRemovalNow(final SpellAbility sa, final Card c, final int dmg, ZoneType destination) { final Player ai = sa.getActivatingPlayer(); + final AiController aic = ((PlayerControllerAi)ai.getController()).getAi(); final Player opp = ai.getOpponent(); final Game game = ai.getGame(); final PhaseHandler ph = game.getPhaseHandler(); @@ -992,6 +994,43 @@ public class ComputerUtilCard { } } else if (c.isPlaneswalker()) { threat = 1; + } else if (aic.getBooleanProperty(AiProps.ACTIVELY_DESTROY_ARTS_AND_NONAURA_ENCHS) && (c.isArtifact() && !c.isCreature()) || (c.isEnchantment() && !c.isAura())) { + // non-creature artifacts and global enchantments with suspicious intrinsic abilities + boolean priority = false; + if (c.getOwner().isOpponentOf(ai) && c.getController().isOpponentOf(ai)) { + // if this thing is both owned and controlled by an opponent and it has a continuous ability, + // assume it either benefits the player or disrupts the opponent + for (final StaticAbility stAb : c.getStaticAbilities()) { + final Map params = stAb.getMapParams(); + if (params.get("Mode").equals("Continuous") && stAb.isIntrinsic() && !stAb.isTemporary()) { + priority = true; + break; + } + } + if (!priority) { + for (final Trigger t : c.getTriggers()) { + if (t.isIntrinsic() && !t.isTemporary()) { + // has a triggered ability, could be benefitting the opponent or disrupting the AI + priority = true; + break; + } + } + } + // if this thing has AILogic set to "Curse", it's probably meant as some form of disruption + if (!priority) { + for (final String sVar : c.getSVars().keySet()) { + if (c.getSVars().get(sVar).contains("AILogic$ Curse")) { + // this is a curse ability, so prioritize its removal + priority = true; + break; + } + } + } + // if it's a priority object, set its threat level to high + if (priority) { + threat = 1.0f; + } + } } else { for (final StaticAbility stAb : c.getStaticAbilities()) { final Map params = stAb.getMapParams(); diff --git a/forge-gui/res/ai/Default.ai b/forge-gui/res/ai/Default.ai index 86665c7c964..cfe5d9609c2 100644 --- a/forge-gui/res/ai/Default.ai +++ b/forge-gui/res/ai/Default.ai @@ -8,5 +8,6 @@ MOVE_EQUIPMENT_TO_BETTER_CREATURES=from_useless_only PRIORITIZE_MOVE_EQUIPMENT_IF_USELESS=true PREDICT_SPELLS_FOR_MAIN2=true RESERVE_MANA_FOR_MAIN2_CHANCE=100 +ACTIVELY_DESTROY_ARTS_AND_NONAURA_ENCHS=false PLAY_AGGRO=false diff --git a/forge-gui/res/ai/Reckless.ai b/forge-gui/res/ai/Reckless.ai index c980ae46748..5f68167e17f 100644 --- a/forge-gui/res/ai/Reckless.ai +++ b/forge-gui/res/ai/Reckless.ai @@ -8,4 +8,5 @@ MOVE_EQUIPMENT_TO_BETTER_CREATURES=always PRIORITIZE_MOVE_EQUIPMENT_IF_USELESS=false PREDICT_SPELLS_FOR_MAIN2=true RESERVE_MANA_FOR_MAIN2_CHANCE=100 +ACTIVELY_DESTROY_ARTS_AND_NONAURA_ENCHS=false PLAY_AGGRO=true