Merge branch 'goadai' into 'master'

GoadAi: improve targeting for triggers

See merge request core-developers/forge!6010
This commit is contained in:
Michael Kamensky
2022-01-04 08:47:14 +00:00
7 changed files with 48 additions and 14 deletions

View File

@@ -1318,7 +1318,6 @@ public class AiBlockController {
}
int evalAtk = ComputerUtilCard.evaluateCreature(attacker, true, false);
int evalBlk = ComputerUtilCard.evaluateCreature(blocker, true, false);
boolean atkEmbalm = (attacker.hasStartOfKeyword("Embalm") || attacker.hasStartOfKeyword("Eternalize")) && !attacker.isToken();
boolean blkEmbalm = (blocker.hasStartOfKeyword("Embalm") || blocker.hasStartOfKeyword("Eternalize")) && !blocker.isToken();
@@ -1327,10 +1326,13 @@ public class AiBlockController {
chance = Math.max(0, chance - chanceModForEmbalm);
}
if (blocker.isFaceDown() && !checkingOther && blocker.getState(CardStateName.Original).getType().isCreature()) {
int evalBlk;
if (blocker.isFaceDown() && blocker.getView().canFaceDownBeShownTo(ai.getView(), false) && blocker.getState(CardStateName.Original).getType().isCreature()) {
// if the blocker is a face-down creature (e.g. cast via Morph, Manifest), evaluate it
// in relation to the original state, not to the Morph state
evalBlk = ComputerUtilCard.evaluateCreature(Card.fromPaperCard(blocker.getPaperCard(), ai), false, true);
} else {
evalBlk = ComputerUtilCard.evaluateCreature(blocker, true, false);
}
int chanceToSavePW = chanceToTradeDownToSaveWalker > 0 && evalAtk + 1 < evalBlk ? chanceToTradeDownToSaveWalker : chanceToTradeToSaveWalker;
boolean powerParityOrHigher = blocker.getNetPower() <= attacker.getNetPower();

View File

@@ -30,7 +30,7 @@ public class GoadAi extends SpellAbilityAi {
if (list.isEmpty())
return false;
if (game.getPlayers().size() >= 2) {
if (game.getPlayers().size() > 2) {
// use this part only in multiplayer
CardCollection betterList = CardLists.filter(list, new Predicate<Card>() {
@Override
@@ -79,10 +79,43 @@ public class GoadAi extends SpellAbilityAi {
// AI does not find a good creature to goad.
// because if it would goad a creature it would attack AI.
// AI might not have enough infomation to block it
// AI might not have enough information to block it
return false;
}
return true;
}
@Override
protected boolean doTriggerAINoCost(Player ai, SpellAbility sa, boolean mandatory) {
if (checkApiLogic(ai, sa)) {
return true;
}
if (!mandatory) {
return false;
}
if (sa.usesTargeting()) {
if (sa.getTargetRestrictions().canTgtPlayer()) {
for (Player opp : ai.getOpponents()) {
if (sa.canTarget(opp)) {
sa.getTargets().add(opp);
return true;
}
}
if (sa.canTarget(ai)) {
sa.getTargets().add(ai);
return true;
}
} else {
List<Card> list = CardLists.getTargetableCards(ai.getGame().getCardsIn(ZoneType.Battlefield), sa);
if (list.isEmpty())
return false;
sa.getTargets().add(ComputerUtilCard.getWorstCreatureAI(list));
return true;
}
}
return false;
}
}

View File

@@ -18,7 +18,7 @@ public class ReplaceDamageAi extends SpellAbilityAi {
if (c.hasSVar("MustBeBlocked")) {
return c;
}
// TODO check if target can receive counters
// TODO check if target can receive counters + sort these to the front if that can prevent loss
if (c.hasKeyword(Keyword.INFECT)) {
return c;
}

View File

@@ -18,7 +18,7 @@ public class RevealAi extends RevealAiBase {
@Override
protected boolean checkApiLogic(final Player ai, final SpellAbility sa) {
// we can reuse this function here...
final boolean bFlag = revealHandTargetAI(ai, sa/* , true, false */);
final boolean bFlag = revealHandTargetAI(ai, sa, false);
if (!bFlag) {
return false;
@@ -80,7 +80,7 @@ public class RevealAi extends RevealAiBase {
}
if (!revealHandTargetAI(ai, sa/*, false, mandatory*/)) {
if (!revealHandTargetAI(ai, sa, mandatory)) {
return false;
}

View File

@@ -15,7 +15,7 @@ import forge.game.zone.ZoneType;
public abstract class RevealAiBase extends SpellAbilityAi {
protected boolean revealHandTargetAI(final Player ai, final SpellAbility sa) {
protected boolean revealHandTargetAI(final Player ai, final SpellAbility sa, boolean mandatory) {
if (sa.usesTargeting()) {
// ability is targeted
sa.resetTargets();
@@ -29,7 +29,7 @@ public abstract class RevealAiBase extends SpellAbilityAi {
Player p = Collections.max(opps, PlayerPredicates.compareByZoneSize(ZoneType.Hand));
if (p.getCardsIn(ZoneType.Hand).isEmpty()) {
if (!mandatory && p.getCardsIn(ZoneType.Hand).isEmpty()) {
return false;
}
sa.getTargets().add(p);
@@ -45,7 +45,7 @@ public abstract class RevealAiBase extends SpellAbilityAi {
*/
@Override
public boolean chkAIDrawback(SpellAbility sa, Player ai) {
revealHandTargetAI(ai, sa);
revealHandTargetAI(ai, sa, false);
return true;
}
}

View File

@@ -12,7 +12,7 @@ public class RevealHandAi extends RevealAiBase {
*/
@Override
protected boolean checkApiLogic(final Player ai, final SpellAbility sa) {
final boolean bFlag = revealHandTargetAI(ai, sa/*, true, false*/);
final boolean bFlag = revealHandTargetAI(ai, sa, false);
if (!bFlag) {
return false;
@@ -29,8 +29,7 @@ public class RevealHandAi extends RevealAiBase {
@Override
protected boolean doTriggerAINoCost(Player ai, SpellAbility sa, boolean mandatory) {
return revealHandTargetAI(ai, sa/*, false, mandatory*/);
return revealHandTargetAI(ai, sa, mandatory);
}
}