mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 19:28:01 +00:00
- Added a more conservative version of AILogic PayEnergy for PutCounter AI that only pays energy if the creature is in combat (attacking/blocking) or if there's more energy available than the most expensive energy cost of a permanent SA on the battlefield requires plus whatever the PutCounter SA requires.
- Set this logic for Longtusk Cub and Bristling Hydra. - TODO: maybe somehow teach the AI to pay energy if it can save the creature from lethal damage from a spell?
This commit is contained in:
@@ -40,6 +40,8 @@ import forge.game.card.CardUtil;
|
|||||||
import forge.game.card.CounterType;
|
import forge.game.card.CounterType;
|
||||||
import forge.game.combat.Combat;
|
import forge.game.combat.Combat;
|
||||||
import forge.game.combat.CombatUtil;
|
import forge.game.combat.CombatUtil;
|
||||||
|
import forge.game.cost.CostPart;
|
||||||
|
import forge.game.cost.CostPayEnergy;
|
||||||
import forge.game.keyword.Keyword;
|
import forge.game.keyword.Keyword;
|
||||||
import forge.game.phase.PhaseHandler;
|
import forge.game.phase.PhaseHandler;
|
||||||
import forge.game.phase.PhaseType;
|
import forge.game.phase.PhaseType;
|
||||||
@@ -1587,4 +1589,28 @@ public class ComputerUtilCard {
|
|||||||
public static boolean isPresentOnBattlefield(final Game game, final String cardName) {
|
public static boolean isPresentOnBattlefield(final Game game, final String cardName) {
|
||||||
return !CardLists.filter(game.getCardsIn(ZoneType.Battlefield), CardPredicates.nameEquals(cardName)).isEmpty();
|
return !CardLists.filter(game.getCardsIn(ZoneType.Battlefield), CardPredicates.nameEquals(cardName)).isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int getMaxSAEnergyCostOnBattlefield(final Player ai) {
|
||||||
|
// returns the maximum energy cost of an ability that permanents on the battlefield under AI's control have
|
||||||
|
CardCollectionView otb = ai.getCardsIn(ZoneType.Battlefield);
|
||||||
|
int maxEnergyCost = 0;
|
||||||
|
|
||||||
|
for (Card c : otb) {
|
||||||
|
for (SpellAbility sa : c.getSpellAbilities()) {
|
||||||
|
if (sa.getPayCosts() == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
CostPayEnergy energyCost = sa.getPayCosts().getCostEnergy();
|
||||||
|
if (energyCost != null) {
|
||||||
|
int amount = energyCost.convertAmount();
|
||||||
|
if (amount > maxEnergyCost) {
|
||||||
|
maxEnergyCost = amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return maxEnergyCost;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -217,8 +217,19 @@ public class CountersPutAi extends SpellAbilityAi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ("PayEnergy".equals(sa.getParam("AILogic"))) {
|
if ("PayEnergy".equals(sa.getParam("AILogic"))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("PayEnergyConservatively".equals(sa.getParam("AILogic"))) {
|
||||||
|
if (ai.getGame().getCombat() != null && sa.getHostCard() != null) {
|
||||||
|
if (ai.getGame().getCombat().isAttacking(sa.getHostCard()) || ai.getGame().getCombat().isBlocking(sa.getHostCard())) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (ai.getCounters(CounterType.ENERGY) > ComputerUtilCard.getMaxSAEnergyCostOnBattlefield(ai) + sa.getPayCosts().getCostEnergy().convertAmount()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (sa.getConditions() != null && !sa.getConditions().areMet(sa) && sa.getSubAbility() == null) {
|
if (sa.getConditions() != null && !sa.getConditions().areMet(sa) && sa.getSubAbility() == null) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -494,6 +494,15 @@ public class Cost {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final CostPayEnergy getCostEnergy() {
|
||||||
|
for (final CostPart part : this.costParts) {
|
||||||
|
if (part instanceof CostPayEnergy) {
|
||||||
|
return (CostPayEnergy) part;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* refundPaidCost.
|
* refundPaidCost.
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ Types:Creature Hydra
|
|||||||
PT:4/3
|
PT:4/3
|
||||||
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigEnergy | TriggerDescription$ When CARDNAME enters the battlefield, you get {E}{E}{E} (three energy counters).
|
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigEnergy | TriggerDescription$ When CARDNAME enters the battlefield, you get {E}{E}{E} (three energy counters).
|
||||||
SVar:TrigEnergy:DB$ PutCounter | Defined$ You | CounterType$ ENERGY | CounterNum$ 3
|
SVar:TrigEnergy:DB$ PutCounter | Defined$ You | CounterType$ ENERGY | CounterNum$ 3
|
||||||
A:AB$ PutCounter | Cost$ PayEnergy<3> | CounterType$ P1P1 | CounterNum$ 1 | SubAbility$ DBPump | SpellDescription$ Put a +1/+1 counter on CARDNAME. It gains hexproof until end of turn.
|
A:AB$ PutCounter | Cost$ PayEnergy<3> | CounterType$ P1P1 | CounterNum$ 1 | SubAbility$ DBPump | AILogic$ PayEnergyConservatively | SpellDescription$ Put a +1/+1 counter on CARDNAME. It gains hexproof until end of turn.
|
||||||
SVar:DBPump:DB$Pump | Defined$ Self | KW$ Hexproof
|
SVar:DBPump:DB$Pump | Defined$ Self | KW$ Hexproof
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/bristling_hydra.jpg
|
SVar:Picture:http://www.wizards.com/global/images/magic/general/bristling_hydra.jpg
|
||||||
Oracle:When Bristling Hydra enters the battlefield, you gain {E}{E}{E} (three energy counters).\nPay {E}{E}{E}: Put a +1/+1 counter on Bristling Hydra. It gains hexproof until end of turn.
|
Oracle:When Bristling Hydra enters the battlefield, you gain {E}{E}{E} (three energy counters).\nPay {E}{E}{E}: Put a +1/+1 counter on Bristling Hydra. It gains hexproof until end of turn.
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ Types:Creature Cat
|
|||||||
PT:2/2
|
PT:2/2
|
||||||
T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | CombatDamage$ True | Execute$ TrigEnergy | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, you get {E}{E} (two energy counters).
|
T:Mode$ DamageDone | ValidSource$ Card.Self | ValidTarget$ Player | CombatDamage$ True | Execute$ TrigEnergy | TriggerZones$ Battlefield | TriggerDescription$ Whenever CARDNAME deals combat damage to a player, you get {E}{E} (two energy counters).
|
||||||
SVar:TrigEnergy:DB$PutCounter | Defined$ You | CounterType$ ENERGY | CounterNum$ 2
|
SVar:TrigEnergy:DB$PutCounter | Defined$ You | CounterType$ ENERGY | CounterNum$ 2
|
||||||
A:AB$ PutCounter | Cost$ PayEnergy<2> | CounterType$ P1P1 | CounterNum$ 1 | SpellDescription$ Put a +1/+1 counter on CARDNAME.
|
A:AB$ PutCounter | Cost$ PayEnergy<2> | CounterType$ P1P1 | CounterNum$ 1 | AILogic$ PayEnergyConservatively | SpellDescription$ Put a +1/+1 counter on CARDNAME.
|
||||||
DeckHints:Ability$Energy
|
DeckHints:Ability$Energy
|
||||||
DeckHas:Ability$Counters
|
DeckHas:Ability$Counters
|
||||||
SVar:Picture:http://www.wizards.com/global/images/magic/general/longtusk_cub.jpg
|
SVar:Picture:http://www.wizards.com/global/images/magic/general/longtusk_cub.jpg
|
||||||
|
|||||||
Reference in New Issue
Block a user