- More advanced Life Drain AI, now works with Soul Burn too, and also works correctly when the AI has other mana sources that do not provide black mana on the battlefield.

This commit is contained in:
Agetian
2017-01-27 05:58:44 +00:00
parent cdbb6b9e6f
commit dc01a30136
3 changed files with 50 additions and 10 deletions

View File

@@ -12,6 +12,7 @@ import forge.card.ColorSet;
import forge.card.MagicColor;
import forge.card.mana.ManaAtom;
import forge.card.mana.ManaCost;
import forge.card.mana.ManaCostParser;
import forge.card.mana.ManaCostShard;
import forge.game.Game;
import forge.game.GameActionUtil;
@@ -1295,6 +1296,34 @@ public class ComputerUtilMana {
return 99;
}
/**
* <p>
* determineLeftoverMana.
* </p>
*
* @param sa
* a {@link forge.game.spellability.SpellAbility} object.
* @param player
* a {@link forge.game.player.Player} object.
* @param shardColor
* a mana shard to specifically test for.
* @return a int.
* @since 1.0.15
*/
public static int determineLeftoverMana(final SpellAbility sa, final Player player, final String shardColor) {
ManaCost origCost = sa.getPayCosts().getTotalMana();
String shardSurplus = shardColor;
for (int i = 1; i < 100; i++) {
ManaCost extra = new ManaCost(new ManaCostParser(shardSurplus));
if (!canPayManaCost(new ManaCostBeingPaid(ManaCost.combine(origCost, extra)), sa, player)) {
return i - 1;
}
shardSurplus += " " + shardColor;
}
return 99;
}
// Returns basic mana abilities plus "reflected mana" abilities
/**
* <p>

View File

@@ -23,8 +23,10 @@ import forge.game.spellability.TargetChoices;
import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType;
import forge.util.Aggregates;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class DamageDealAi extends DamageAiBase {
@Override
@@ -57,14 +59,14 @@ public class DamageDealAi extends DamageAiBase {
}
if (damage.equals("X")) {
if (sa.getSVar(damage).equals("Count$xPaid")) {
// Life Drain
if ("XLifeDrain".equals(logic)) {
return doXLifeDrainLogic(ai, sa);
}
// Set PayX here to maximum value.
dmg = ComputerUtilMana.determineLeftoverMana(sa, ai);
source.setSVar("PayX", Integer.toString(dmg));
// Life Drain
if ("XLifeDrain".equals(logic)) {
return doXLifeDrainLogic(ai, sa, dmg);
}
} else if (sa.getSVar(damage).equals("Count$CardsInYourHand") && source.getZone().is(ZoneType.Hand)) {
dmg--; // the card will be spent casting the spell, so actual damage is 1 less
}
@@ -702,7 +704,7 @@ public class DamageDealAi extends DamageAiBase {
return true;
}
private boolean doXLifeDrainLogic(Player ai, SpellAbility sa, int origDmg) {
private boolean doXLifeDrainLogic(Player ai, SpellAbility sa) {
Card source = sa.getHostCard();
// detect the top ability that actually targets in Drain Life and Soul Burn scripts
@@ -711,10 +713,20 @@ public class DamageDealAi extends DamageAiBase {
saTgt = saTgt.getParent();
}
// TODO: somehow account for the cost reduction?
int dmg = origDmg - saTgt.getPayCosts().getTotalMana().getCMC(); // otherwise AI incorrectly calculates mana it can afford
Player opponent = ai.getOpponents().min(PlayerPredicates.compareByLife());
// TODO: somehow account for the possible cost reduction?
int xColorRemaining = ComputerUtilMana.determineLeftoverMana(sa, ai, saTgt.getParam("XColor"));
int dmg = xColorRemaining - saTgt.getPayCosts().getTotalMana().getCMC(); // otherwise AI incorrectly calculates mana it can afford
// set the color map for black X for the purpose of Soul Burn
// TODO: somehow generalize this calculation to allow other potential similar cards to function in the future
if ("Soul Burn".equals(source.getName())) {
Map<String, Integer> xByColor = new HashMap<>();
xByColor.put("B", dmg - ComputerUtilMana.determineLeftoverMana(sa, ai, "R"));
source.setXManaCostPaidByColor(xByColor);
}
if (dmg < 3 && dmg < opponent.getLife()) {
return false;
}
@@ -739,7 +751,6 @@ public class DamageDealAi extends DamageAiBase {
saTgt.resetTargets();
saTgt.getTargets().add(tgtCreature != null && dmg < opponent.getLife() ? tgtCreature : opponent);
// TODO: this currently does not work for Soul Burn because of xColorManaPaid (B/R) which the AI doesn't set
source.setSVar("PayX", Integer.toString(dmg));
return true;
}

View File

@@ -3,7 +3,7 @@ ManaCost:X 2 B
Types:Sorcery
A:SP$ StoreSVar | Cost$ X 2 B | XColor$ BR | ValidTgts$ Creature,Player | TgtPrompt$ Select target creature or player | SVar$ Limit | Type$ Targeted | Expression$ CardToughness | SubAbility$ StoreTgtP | ConditionDefined$ Targeted | ConditionPresent$ Card.Creature | ConditionCompare$ GE1 | SpellDescription$ Spend only black and/or red mana on X. CARDNAME deals X damage to target creature or player. You gain life equal to the damage dealt, but not more than the amount of {B} spent on X, the player's life total before Soul Burn dealt damage, or the creature's toughness.
SVar:StoreTgtP:DB$ StoreSVar | SVar$ Limit | Type$ Count | Expression$ TargetedLifeTotal | SubAbility$ DBDamage | ConditionDefined$ Targeted | ConditionPresent$ Card.Creature | ConditionCompare$ EQ0
SVar:DBDamage:DB$ DealDamage | Defined$ Targeted | NumDmg$ X | SubAbility$ DBGainLife | References$ X
SVar:DBDamage:DB$ DealDamage | Defined$ Targeted | NumDmg$ X | SubAbility$ DBGainLife | References$ X | AILogic$ XLifeDrain
SVar:X:Count$xPaid
SVar:DBGainLife:DB$ GainLife | Defined$ You | LifeAmount$ DrainedLifeCard | References$ DrainedLifeCard
SVar:DrainedLifeCard:SVar$BlackManaPaid/LimitMax.Limit