From 8f4c5039ed95932e0565670d4f16d93ca618deea Mon Sep 17 00:00:00 2001 From: tool4EvEr Date: Sun, 10 Jul 2022 15:07:47 +0200 Subject: [PATCH] Cleanup AI --- .../main/java/forge/ai/ComputerUtilCost.java | 68 +++++++++++++++ .../ai/ability/ChooseGenericEffectAi.java | 83 +------------------ 2 files changed, 69 insertions(+), 82 deletions(-) diff --git a/forge-ai/src/main/java/forge/ai/ComputerUtilCost.java b/forge-ai/src/main/java/forge/ai/ComputerUtilCost.java index 46f379218ce..2f39a64fbf5 100644 --- a/forge-ai/src/main/java/forge/ai/ComputerUtilCost.java +++ b/forge-ai/src/main/java/forge/ai/ComputerUtilCost.java @@ -7,6 +7,7 @@ import com.google.common.collect.Lists; import com.google.common.collect.Sets; import forge.ai.AiCardMemory.MemorySet; import forge.ai.ability.AnimateAi; +import forge.ai.ability.TokenAi; import forge.card.ColorSet; import forge.game.Game; import forge.game.ability.AbilityUtils; @@ -14,6 +15,7 @@ import forge.game.ability.ApiType; import forge.game.card.*; import forge.game.card.CardPredicates.Presets; import forge.game.combat.Combat; +import forge.game.combat.CombatUtil; import forge.game.cost.*; import forge.game.keyword.Keyword; import forge.game.phase.PhaseType; @@ -692,6 +694,72 @@ public class ComputerUtilCost { return false; } else if ("LowPriority".equals(aiLogic) && MyRandom.getRandom().nextInt(100) < 67) { return false; + } else if (aiLogic != null && aiLogic.startsWith("Fabricate")) { + final int n = Integer.valueOf(aiLogic.substring("Fabricate".length())); + + // if host would leave the play or if host is useless, create tokens + if (source.hasSVar("EndOfTurnLeavePlay") || ComputerUtilCard.isUselessCreature(payer, source)) { + return false; + } + + // need a copy for one with extra +1/+1 counter boost, + // without causing triggers to run + final Card copy = CardUtil.getLKICopy(source); + copy.setCounters(CounterEnumType.P1P1, copy.getCounters(CounterEnumType.P1P1) + n); + copy.setZone(source.getZone()); + + // if host would put into the battlefield attacking + Combat combat = source.getGame().getCombat(); + if (combat != null && combat.isAttacking(source)) { + final Player defender = combat.getDefenderPlayerByAttacker(source); + if (defender.canLoseLife() && !ComputerUtilCard.canBeBlockedProfitably(defender, copy, true)) { + return true; + } + return false; + } + + // if the host has haste and can attack + if (CombatUtil.canAttack(copy)) { + for (final Player opp : payer.getOpponents()) { + if (CombatUtil.canAttack(copy, opp) && + opp.canLoseLife() && + !ComputerUtilCard.canBeBlockedProfitably(opp, copy, true)) + return true; + } + } + + // TODO check for trigger to turn token ETB into +1/+1 counter for host + // TODO check for trigger to turn token ETB into damage or life loss for opponent + // in this cases Token might be prefered even if they would not survive + final Card tokenCard = TokenAi.spawnToken(payer, sa); + + // Token would not survive + if (!tokenCard.isCreature() || tokenCard.getNetToughness() < 1) { + return true; + } + + // Special Card logic, this one try to median its power with the number of artifacts + if ("Marionette Master".equals(source.getName())) { + CardCollection list = CardLists.filter(payer.getCardsIn(ZoneType.Battlefield), Presets.ARTIFACTS); + return list.size() >= copy.getNetPower(); + } else if ("Cultivator of Blades".equals(source.getName())) { + // Cultivator does try to median with number of Creatures + CardCollection list = payer.getCreaturesInPlay(); + return list.size() >= copy.getNetPower(); + } + + // evaluate Creature with +1/+1 + int evalCounter = ComputerUtilCard.evaluateCreature(copy); + + final CardCollection tokenList = new CardCollection(source); + for (int i = 0; i < n; ++i) { + tokenList.add(TokenAi.spawnToken(payer, sa)); + } + + // evaluate Host with Tokens + int evalToken = ComputerUtilCard.evaluateCreatureList(tokenList); + + return evalToken < evalCounter; } // Check for shocklands and similar ETB replacement effects diff --git a/forge-ai/src/main/java/forge/ai/ability/ChooseGenericEffectAi.java b/forge-ai/src/main/java/forge/ai/ability/ChooseGenericEffectAi.java index e81059371c7..596ee8f6671 100644 --- a/forge-ai/src/main/java/forge/ai/ability/ChooseGenericEffectAi.java +++ b/forge-ai/src/main/java/forge/ai/ability/ChooseGenericEffectAi.java @@ -9,7 +9,6 @@ import com.google.common.collect.Lists; import com.google.common.collect.Sets; import forge.ai.ComputerUtilAbility; -import forge.ai.ComputerUtilCard; import forge.ai.ComputerUtilCost; import forge.ai.SpecialCardAi; import forge.ai.SpellAbilityAi; @@ -19,12 +18,9 @@ import forge.game.Game; import forge.game.card.Card; import forge.game.card.CardCollection; import forge.game.card.CardCollectionView; -import forge.game.card.CardLists; -import forge.game.card.CardPredicates.Presets; import forge.game.card.CardUtil; import forge.game.card.CounterEnumType; import forge.game.combat.Combat; -import forge.game.combat.CombatUtil; import forge.game.cost.Cost; import forge.game.keyword.Keyword; import forge.game.phase.PhaseHandler; @@ -43,7 +39,7 @@ public class ChooseGenericEffectAi extends SpellAbilityAi { protected boolean checkAiLogic(final Player ai, final SpellAbility sa, final String aiLogic) { if ("Khans".equals(aiLogic) || "Dragons".equals(aiLogic)) { return true; - } else if (aiLogic.startsWith("Fabricate") || "Riot".equals(aiLogic)) { + } else if ("Riot".equals(aiLogic)) { return true; } else if ("Pump".equals(aiLogic) || "BestOption".equals(aiLogic)) { for (AbilitySub sb : sa.getAdditionalAbilityList("Choices")) { @@ -265,83 +261,6 @@ public class ChooseGenericEffectAi extends SpellAbilityAi { } // if unsure, random? return Aggregates.random(spells); - } else if (logic.startsWith("Fabricate")) { - final int n = Integer.valueOf(logic.substring("Fabricate".length())); - if(spells.size() < 2) { - // If the creature is no longer on the battlefield, the option - // to add counters is already removed at this point. Return the - // only available option: create servo tokens. - return spells.get(0); - } - SpellAbility counterSA = spells.get(0), tokenSA = spells.get(1); - - // check for something which might prevent the counters to be placed on host - if (!host.canReceiveCounters(CounterEnumType.P1P1)) { - return tokenSA; - } - - // if host would leave the play or if host is useless, create tokens - if (host.hasSVar("EndOfTurnLeavePlay") || ComputerUtilCard.isUselessCreature(player, host)) { - return tokenSA; - } - - // need a copy for one with extra +1/+1 counter boost, - // without causing triggers to run - final Card copy = CardUtil.getLKICopy(host); - copy.setCounters(CounterEnumType.P1P1, copy.getCounters(CounterEnumType.P1P1) + n); - copy.setZone(host.getZone()); - - // if host would put into the battlefield attacking - if (combat != null && combat.isAttacking(host)) { - final Player defender = combat.getDefenderPlayerByAttacker(host); - if (defender.canLoseLife() && !ComputerUtilCard.canBeBlockedProfitably(defender, copy, true)) { - return counterSA; - } - return tokenSA; - } - - // if the host has haste and can attack - if (CombatUtil.canAttack(copy)) { - for (final Player opp : player.getOpponents()) { - if (CombatUtil.canAttack(copy, opp) && - opp.canLoseLife() && - !ComputerUtilCard.canBeBlockedProfitably(opp, copy, true)) - return counterSA; - } - } - - // TODO check for trigger to turn token ETB into +1/+1 counter for host - // TODO check for trigger to turn token ETB into damage or life loss for opponent - // in this cases Token might be prefered even if they would not survive - final Card tokenCard = TokenAi.spawnToken(player, tokenSA); - - // Token would not survive - if (!tokenCard.isCreature() || tokenCard.getNetToughness() < 1) { - return counterSA; - } - - // Special Card logic, this one try to median its power with the number of artifacts - if ("Marionette Master".equals(sourceName)) { - CardCollection list = CardLists.filter(player.getCardsIn(ZoneType.Battlefield), Presets.ARTIFACTS); - return list.size() >= copy.getNetPower() ? counterSA : tokenSA; - } else if ("Cultivator of Blades".equals(sourceName)) { - // Cultivator does try to median with number of Creatures - CardCollection list = player.getCreaturesInPlay(); - return list.size() >= copy.getNetPower() ? counterSA : tokenSA; - } - - // evaluate Creature with +1/+1 - int evalCounter = ComputerUtilCard.evaluateCreature(copy); - - final CardCollection tokenList = new CardCollection(host); - for (int i = 0; i < n; ++i) { - tokenList.add(TokenAi.spawnToken(player, tokenSA)); - } - - // evaluate Host with Tokens - int evalToken = ComputerUtilCard.evaluateCreatureList(tokenList); - - return evalToken >= evalCounter ? tokenSA : counterSA; } else if ("CombustibleGearhulk".equals(logic)) { Player controller = sa.getActivatingPlayer(); List zones = ZoneType.listValueOf("Graveyard, Battlefield, Exile");