- Some work on the AI for new keywords.

- NPE prevention in AI code.
This commit is contained in:
Agetian
2018-12-22 20:30:54 +03:00
committed by Hanmac
parent b87f247c09
commit 2a02fd124e
3 changed files with 55 additions and 43 deletions

View File

@@ -20,6 +20,7 @@ package forge.ai;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.*;
import forge.ai.ability.ChooseGenericEffectAi;
import forge.ai.ability.ProtectAi;
import forge.ai.ability.TokenAi;
import forge.card.CardType;
@@ -986,6 +987,11 @@ public class ComputerUtil {
return true;
}
if (card.hasKeyword(Keyword.RIOT) && ChooseGenericEffectAi.preferHasteForRiot(sa, ai)) {
// Planning to choose Haste for Riot, so do this in Main 1
return true;
}
// if we have non-persistent mana in our pool, would be good to try to use it and not waste it
if (ai.getManaPool().willManaBeLostAtEndOfPhase()) {
boolean canUseToPayCost = false;

View File

@@ -1455,7 +1455,7 @@ public class ComputerUtilCombat {
continue;
}
if (ability.hasParam("Adapt") && blocker.getCounters(CounterType.P1P1) > 0) {
if (ability.hasParam("Adapt") && blocker != null && blocker.getCounters(CounterType.P1P1) > 0) {
continue;
}

View File

@@ -350,48 +350,54 @@ public class ChooseGenericEffectAi extends SpellAbilityAi {
}
} else if ("Riot".equals(logic)) {
SpellAbility counterSA = spells.get(0), hasteSA = spells.get(1);
final Card copy = CardUtil.getLKICopy(host);
copy.setLastKnownZone(player.getZone(ZoneType.Battlefield));
// check state it would have on the battlefield
CardCollection preList = new CardCollection(copy);
game.getAction().checkStaticAbilities(false, Sets.newHashSet(copy), preList);
// reset again?
game.getAction().checkStaticAbilities(false);
// can't gain counters, use Haste
if (!copy.canReceiveCounters(CounterType.P1P1)) {
return hasteSA;
}
// already has Haste, use counter
if (copy.hasKeyword(Keyword.HASTE)) {
return counterSA;
}
// not AI turn
if (!game.getPhaseHandler().isPlayerTurn(player)) {
return counterSA;
}
// not before Combat
if (!game.getPhaseHandler().getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS)) {
return counterSA;
}
// TODO check other opponents too if able
final Player opp = player.getWeakestOpponent();
if (opp != null) {
// TODO add predict Combat Damage?
if (opp.getLife() < copy.getNetPower()) {
return hasteSA;
}
}
// haste might not be good enough?
return counterSA;
return preferHasteForRiot(sa, player) ? hasteSA : counterSA;
}
return spells.get(0); // return first choice if no logic found
}
public static boolean preferHasteForRiot(SpellAbility sa, Player player) {
// returning true means preferring Haste, returning false means preferring a +1/+1 counter
final Card host = sa.getHostCard();
final Game game = host.getGame();
final Card copy = CardUtil.getLKICopy(host);
copy.setLastKnownZone(player.getZone(ZoneType.Battlefield));
// check state it would have on the battlefield
CardCollection preList = new CardCollection(copy);
game.getAction().checkStaticAbilities(false, Sets.newHashSet(copy), preList);
// reset again?
game.getAction().checkStaticAbilities(false);
// can't gain counters, use Haste
if (!copy.canReceiveCounters(CounterType.P1P1)) {
return true;
}
// already has Haste, use counter
if (copy.hasKeyword(Keyword.HASTE)) {
return false;
}
// not AI turn
if (!game.getPhaseHandler().isPlayerTurn(player)) {
return false;
}
// not before Combat
if (!game.getPhaseHandler().getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS)) {
return false;
}
// TODO check other opponents too if able
final Player opp = player.getWeakestOpponent();
if (opp != null) {
// TODO add predict Combat Damage?
if (opp.getLife() < copy.getNetPower()) {
return true;
}
}
// haste might not be good enough?
return false;
}
}