- 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).
This commit is contained in:
Agetian
2017-01-17 16:11:26 +00:00
parent 8d6991c6d3
commit f484f02f4d
4 changed files with 43 additions and 1 deletions

View File

@@ -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;

View File

@@ -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<String, String> 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<String, String> params = stAb.getMapParams();

View File

@@ -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

View File

@@ -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