- Bristling Hydra AI: teach the AI to use a ping activation to save the hydra from death.

This commit is contained in:
Agetian
2017-08-25 10:57:12 +00:00
parent 8280401e10
commit 909b8e7127
3 changed files with 42 additions and 15 deletions

View File

@@ -45,6 +45,7 @@ public class AiCardMemory {
private final Set<Card> memAttachedThisTurn;
private final Set<Card> memAnimatedThisTurn;
private final Set<Card> memBouncedThisTurn;
private final Set<Card> memActivatedThisTurn;
public AiCardMemory() {
this.memMandatoryAttackers = new HashSet<>();
@@ -52,6 +53,7 @@ public class AiCardMemory {
this.memAttachedThisTurn = new HashSet<>();
this.memAnimatedThisTurn = new HashSet<>();
this.memBouncedThisTurn = new HashSet<>();
this.memActivatedThisTurn = new HashSet<>();
}
/**
@@ -65,6 +67,7 @@ public class AiCardMemory {
ATTACHED_THIS_TURN,
ANIMATED_THIS_TURN,
BOUNCED_THIS_TURN,
ACTIVATED_THIS_TURN,
//REVEALED_CARDS // stub, not linked to AI code yet
}
@@ -80,6 +83,8 @@ public class AiCardMemory {
return memAnimatedThisTurn;
case BOUNCED_THIS_TURN:
return memBouncedThisTurn;
case ACTIVATED_THIS_TURN:
return memActivatedThisTurn;
//case REVEALED_CARDS:
// return memRevealedCards;
default:
@@ -253,6 +258,7 @@ public class AiCardMemory {
clearMemorySet(MemorySet.ATTACHED_THIS_TURN);
clearMemorySet(MemorySet.ANIMATED_THIS_TURN);
clearMemorySet(MemorySet.BOUNCED_THIS_TURN);
clearMemorySet(MemorySet.ACTIVATED_THIS_TURN);
}
// Static functions to simplify access to AI card memory of a given AI player.

View File

@@ -1435,20 +1435,28 @@ public class ComputerUtil {
}
objects = canBeTargeted;
}
if (saviourApi == ApiType.Pump || saviourApi == ApiType.PumpAll) {
toughness = saviour.hasParam("NumDef") ?
AbilityUtils.calculateAmount(saviour.getHostCard(), saviour.getParam("NumDef"), saviour) : 0;
final List<String> keywords = saviour.hasParam("KW") ?
Arrays.asList(saviour.getParam("KW").split(" & ")) : new ArrayList<String>();
if (keywords.contains("Indestructible")) {
grantIndestructible = true;
}
if (keywords.contains("Hexproof") || keywords.contains("Shroud")) {
grantShroud = true;
SpellAbility saviorWithSubs = saviour;
while (saviorWithSubs != null) {
ApiType curApi = saviorWithSubs.getApi();
if (curApi == ApiType.Pump || curApi == ApiType.PumpAll) {
toughness = saviorWithSubs.hasParam("NumDef") ?
AbilityUtils.calculateAmount(saviorWithSubs.getHostCard(), saviorWithSubs.getParam("NumDef"), saviour) : 0;
final List<String> keywords = saviorWithSubs.hasParam("KW") ?
Arrays.asList(saviorWithSubs.getParam("KW").split(" & ")) : new ArrayList<String>();
if (keywords.contains("Indestructible")) {
grantIndestructible = true;
}
if (keywords.contains("Hexproof") || keywords.contains("Shroud")) {
grantShroud = true;
}
break;
}
// Consider pump in subabilities, e.g. Bristling Hydra hexproof subability
saviorWithSubs = saviorWithSubs.getSubAbility();
}
if (saviourApi == ApiType.PutCounter || saviourApi == ApiType.PutCounterAll) {
if (saviour.getParam("CounterType").equals("P1P1")) {
toughness = AbilityUtils.calculateAmount(saviour.getHostCard(), saviour.getParam("CounterNum"), saviour);
@@ -1588,9 +1596,11 @@ public class ComputerUtil {
// Destroy => regeneration/bounce/shroud
else if ((threatApi == ApiType.Destroy || threatApi == ApiType.DestroyAll)
&& (((saviourApi == ApiType.Regenerate || saviourApi == ApiType.RegenerateAll)
&& !topStack.hasParam("NoRegen")) || saviourApi == ApiType.ChangeZone
&& !topStack.hasParam("NoRegen")) || saviourApi == ApiType.ChangeZone
|| saviourApi == ApiType.Pump || saviourApi == ApiType.PumpAll
|| saviourApi == ApiType.Protection || saviourApi == null)) {
|| saviourApi == ApiType.Protection || saviourApi == null
|| saviorWithSubs.getApi() == ApiType.Pump
|| saviorWithSubs.getApi() == ApiType.PumpAll)) {
for (final Object o : objects) {
if (o instanceof Card) {
final Card c = (Card) o;
@@ -1604,7 +1614,9 @@ public class ComputerUtil {
continue;
}
if (saviourApi == ApiType.Pump || saviourApi == ApiType.PumpAll) {
if (saviourApi == ApiType.Pump || saviourApi == ApiType.PumpAll
|| saviorWithSubs.getApi() == ApiType.Pump
|| saviorWithSubs.getApi() == ApiType.PumpAll) {
if ((tgt == null && !grantIndestructible)
|| (!grantShroud && !grantIndestructible)) {
continue;

View File

@@ -249,6 +249,15 @@ public class CountersPutAi extends SpellAbilityAi {
return true;
}
}
} else if (sa.getSubAbility() != null
&& "Self".equals(sa.getSubAbility().getParam("Defined"))
&& sa.getSubAbility().getParamOrDefault("KW", "").contains("Hexproof")
&& !AiCardMemory.isRememberedCard(ai, source, AiCardMemory.MemorySet.ANIMATED_THIS_TURN)) {
// Bristling Hydra: save from death using a ping activation
if (ComputerUtil.predictThreatenedObjects(sa.getActivatingPlayer(), sa).contains(source)) {
AiCardMemory.rememberCard(ai, source, AiCardMemory.MemorySet.ACTIVATED_THIS_TURN);
return true;
}
} else if (ai.getCounters(CounterType.ENERGY) > ComputerUtilCard.getMaxSAEnergyCostOnBattlefield(ai) + sa.getPayCosts().getCostEnergy().convertAmount()) {
// outside of combat, this logic only works if the relevant AI profile option is enabled
// and if there is enough energy saved