mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-17 19:28:01 +00:00
- 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:
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user