mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-19 04:08:01 +00:00
- Some work on the AI for new keywords.
- NPE prevention in AI code.
This commit is contained in:
@@ -20,6 +20,7 @@ package forge.ai;
|
|||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.base.Predicates;
|
import com.google.common.base.Predicates;
|
||||||
import com.google.common.collect.*;
|
import com.google.common.collect.*;
|
||||||
|
import forge.ai.ability.ChooseGenericEffectAi;
|
||||||
import forge.ai.ability.ProtectAi;
|
import forge.ai.ability.ProtectAi;
|
||||||
import forge.ai.ability.TokenAi;
|
import forge.ai.ability.TokenAi;
|
||||||
import forge.card.CardType;
|
import forge.card.CardType;
|
||||||
@@ -986,6 +987,11 @@ public class ComputerUtil {
|
|||||||
return true;
|
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 we have non-persistent mana in our pool, would be good to try to use it and not waste it
|
||||||
if (ai.getManaPool().willManaBeLostAtEndOfPhase()) {
|
if (ai.getManaPool().willManaBeLostAtEndOfPhase()) {
|
||||||
boolean canUseToPayCost = false;
|
boolean canUseToPayCost = false;
|
||||||
|
|||||||
@@ -1455,7 +1455,7 @@ public class ComputerUtilCombat {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ability.hasParam("Adapt") && blocker.getCounters(CounterType.P1P1) > 0) {
|
if (ability.hasParam("Adapt") && blocker != null && blocker.getCounters(CounterType.P1P1) > 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -350,48 +350,54 @@ public class ChooseGenericEffectAi extends SpellAbilityAi {
|
|||||||
}
|
}
|
||||||
} else if ("Riot".equals(logic)) {
|
} else if ("Riot".equals(logic)) {
|
||||||
SpellAbility counterSA = spells.get(0), hasteSA = spells.get(1);
|
SpellAbility counterSA = spells.get(0), hasteSA = spells.get(1);
|
||||||
|
return preferHasteForRiot(sa, player) ? hasteSA : counterSA;
|
||||||
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 spells.get(0); // return first choice if no logic found
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user