mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-20 04:38:00 +00:00
- Revamped Planeswalkers logic: evaluate more expensive abilities first to prevent spamming of good "plus" abilities, try not to "minus" all loyalty if not under threat
- Added flag in TokensAi to allow Planeswalkers to create tokens in Main1 - AI can now use all the abilities of Gideon, Ally of Zendikar
This commit is contained in:
@@ -64,6 +64,8 @@ import forge.game.combat.CombatUtil;
|
||||
import forge.game.cost.Cost;
|
||||
import forge.game.cost.CostDiscard;
|
||||
import forge.game.cost.CostPart;
|
||||
import forge.game.cost.CostPutCounter;
|
||||
import forge.game.cost.CostRemoveCounter;
|
||||
import forge.game.mana.ManaCostBeingPaid;
|
||||
import forge.game.phase.PhaseType;
|
||||
import forge.game.player.Player;
|
||||
@@ -857,22 +859,25 @@ public class AiController {
|
||||
if ("True".equals(source.getSVar("NonStackingEffect")) && ai.isCardInPlay(source.getName())) {
|
||||
p -= 9;
|
||||
}
|
||||
// sort planeswalker abilities for ultimate
|
||||
// sort planeswalker abilities with most costly first
|
||||
if (sa.getRestrictions().isPwAbility()) {
|
||||
final CostPart cost = sa.getPayCosts().getCostParts().get(0);
|
||||
if (cost instanceof CostRemoveCounter) {
|
||||
p += cost.convertAmount();
|
||||
} else if (cost instanceof CostPutCounter) {
|
||||
p -= cost.convertAmount();
|
||||
}
|
||||
if (sa.hasParam("Ultimate")) {
|
||||
p += 9;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (ApiType.DestroyAll == sa.getApi()) {
|
||||
p += 4;
|
||||
}
|
||||
if (ApiType.Token == sa.getApi() && noCreatures) {
|
||||
//hack to force planeswalkers to defend themselves
|
||||
p += 3;
|
||||
}
|
||||
|
||||
else if (ApiType.Mana == sa.getApi()) {
|
||||
p -= 9;
|
||||
p -= 9;
|
||||
}
|
||||
|
||||
return p;
|
||||
|
||||
@@ -390,6 +390,17 @@ public class ComputerUtilCost {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Try not to lose Planeswalker if not threatened
|
||||
if (sa.getRestrictions().isPwAbility()) {
|
||||
final CostPart cost = sa.getPayCosts().getCostParts().get(0);
|
||||
if (cost instanceof CostRemoveCounter && cost.convertAmount() == sa.getHostCard().getCurrentLoyalty()) {
|
||||
// refuse to pay if opponent has no creature threats or
|
||||
if (player.getOpponent().getCreaturesInPlay().isEmpty() || MyRandom.getRandom().nextFloat() < .5f) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ComputerUtilMana.canPayManaCost(sa, player, extraManaNeeded)
|
||||
&& CostPayment.canPayAdditionalCosts(sa.getPayCosts(), sa);
|
||||
|
||||
@@ -21,6 +21,8 @@ import forge.game.card.CardFactory;
|
||||
import forge.game.card.CardLists;
|
||||
import forge.game.card.CardPredicates;
|
||||
import forge.game.cost.Cost;
|
||||
import forge.game.cost.CostPart;
|
||||
import forge.game.cost.CostRemoveCounter;
|
||||
import forge.game.phase.PhaseHandler;
|
||||
import forge.game.phase.PhaseType;
|
||||
import forge.game.player.Player;
|
||||
@@ -121,6 +123,22 @@ public class TokenAi extends SpellAbilityAi {
|
||||
}
|
||||
}
|
||||
|
||||
boolean pwAbility = sa.getRestrictions().isPwAbility();
|
||||
if (pwAbility) {
|
||||
// Planeswalker token ability with loyalty costs should be played in Main1 or it might
|
||||
// never be used due to other positive abilities. AI is kept from spamming them by the
|
||||
// loyalty cost of each usage. Zero/loyalty gain token abilities can be evaluated as
|
||||
// per normal.
|
||||
boolean hasCost = false;
|
||||
for (CostPart c : sa.getPayCosts().getCostParts()) {
|
||||
if (c instanceof CostRemoveCounter) {
|
||||
hasCost = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
pwAbility = hasCost;
|
||||
}
|
||||
|
||||
PhaseHandler ph = game.getPhaseHandler();
|
||||
// Don't generate tokens without haste before main 2 if possible
|
||||
if (ph.getPhase().isBefore(PhaseType.MAIN2)
|
||||
@@ -133,13 +151,13 @@ public class TokenAi extends SpellAbilityAi {
|
||||
buff = true;
|
||||
}
|
||||
}
|
||||
if (!buff && !sacOnStack) {
|
||||
if (!buff && !sacOnStack && !pwAbility) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if ((ph.isPlayerTurn(ai) || ph.getPhase().isBefore(PhaseType.COMBAT_DECLARE_ATTACKERS))
|
||||
&& !sa.hasParam("ActivationPhases") && !sa.hasParam("PlayerTurn")
|
||||
&& !SpellAbilityAi.isSorcerySpeed(sa) && !haste && !sacOnStack) {
|
||||
&& !SpellAbilityAi.isSorcerySpeed(sa) && !haste && !sacOnStack && !pwAbility) {
|
||||
return false;
|
||||
}
|
||||
if ((ph.getPhase().isAfter(PhaseType.COMBAT_BEGIN) || game.getPhaseHandler().isPlayerTurn(opp))
|
||||
|
||||
Reference in New Issue
Block a user