mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-18 19:58:00 +00:00
- Initial implementation: for the AI, consider dealing damage to planeswalkers directly when applicable.
This commit is contained in:
@@ -104,6 +104,20 @@ public class ComputerUtilCard {
|
|||||||
return Aggregates.itemWithMax(all, CardPredicates.Accessors.fnGetCmc);
|
return Aggregates.itemWithMax(all, CardPredicates.Accessors.fnGetCmc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the worst Planeswalker from a given list
|
||||||
|
* @param list list of cards to evaluate
|
||||||
|
* @return best Planeswalker
|
||||||
|
*/
|
||||||
|
public static Card getWorstPlaneswalkerAI(final List<Card> list) {
|
||||||
|
List<Card> all = CardLists.filter(list, CardPredicates.Presets.PLANEWALKERS);
|
||||||
|
if (all.size() == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// no AI logic, just return least expensive
|
||||||
|
return Aggregates.itemWithMin(all, CardPredicates.Accessors.fnGetCmc);
|
||||||
|
}
|
||||||
|
|
||||||
// The AI doesn't really pick the best enchantment, just the most expensive.
|
// The AI doesn't really pick the best enchantment, just the most expensive.
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
|
|||||||
@@ -271,25 +271,7 @@ public class DamageDealAi extends DamageAiBase {
|
|||||||
final Player activator = sa.getActivatingPlayer();
|
final Player activator = sa.getActivatingPlayer();
|
||||||
final Card source = sa.getHostCard();
|
final Card source = sa.getHostCard();
|
||||||
final Game game = source.getGame();
|
final Game game = source.getGame();
|
||||||
List<Card> hPlay = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), tgt.getValidTgts(), activator, source, sa);
|
List<Card> hPlay = getTargetableCards(ai, sa, pl, tgt, activator, source, game);
|
||||||
|
|
||||||
if (activator.equals(ai)) {
|
|
||||||
hPlay = CardLists.filterControlledBy(hPlay, pl);
|
|
||||||
}
|
|
||||||
|
|
||||||
final List<GameObject> objects = Lists.newArrayList(sa.getTargets().getTargets());
|
|
||||||
if (sa.hasParam("TargetUnique")) {
|
|
||||||
objects.addAll(sa.getUniqueTargets());
|
|
||||||
}
|
|
||||||
for (final Object o : objects) {
|
|
||||||
if (o instanceof Card) {
|
|
||||||
final Card c = (Card) o;
|
|
||||||
if (hPlay.contains(c)) {
|
|
||||||
hPlay.remove(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hPlay = CardLists.getTargetableCards(hPlay, sa);
|
|
||||||
|
|
||||||
List<Card> killables = CardLists.filter(hPlay, new Predicate<Card>() {
|
List<Card> killables = CardLists.filter(hPlay, new Predicate<Card>() {
|
||||||
@Override
|
@Override
|
||||||
@@ -338,6 +320,84 @@ public class DamageDealAi extends DamageAiBase {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* dealDamageChooseTgtPW.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param d
|
||||||
|
* a int.
|
||||||
|
* @param noPrevention
|
||||||
|
* a boolean.
|
||||||
|
* @param pl
|
||||||
|
* a {@link forge.game.player.Player} object.
|
||||||
|
* @param mandatory
|
||||||
|
* a boolean.
|
||||||
|
* @return a {@link forge.game.card.Card} object.
|
||||||
|
*/
|
||||||
|
private Card dealDamageChooseTgtPW(final Player ai, final SpellAbility sa, final int d, final boolean noPrevention,
|
||||||
|
final Player pl, final boolean mandatory) {
|
||||||
|
|
||||||
|
final TargetRestrictions tgt = sa.getTargetRestrictions();
|
||||||
|
final Player activator = sa.getActivatingPlayer();
|
||||||
|
final Card source = sa.getHostCard();
|
||||||
|
final Game game = source.getGame();
|
||||||
|
List<Card> hPlay = getTargetableCards(ai, sa, pl, tgt, activator, source, game);
|
||||||
|
|
||||||
|
List<Card> killables = CardLists.filter(hPlay, new Predicate<Card>() {
|
||||||
|
@Override
|
||||||
|
public boolean apply(final Card c) {
|
||||||
|
return c.getSVar("Targeting").equals("Dies")
|
||||||
|
|| (ComputerUtilCombat.getEnoughDamageToKill(c, d, source, false, noPrevention) <= d)
|
||||||
|
&& !ComputerUtil.canRegenerate(ai, c)
|
||||||
|
&& !(c.getSVar("SacMe").length() > 0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Filter AI-specific targets if provided
|
||||||
|
killables = ComputerUtil.filterAITgts(sa, ai, new CardCollection(killables), true);
|
||||||
|
|
||||||
|
Card targetCard = null;
|
||||||
|
if (pl.isOpponentOf(ai) && activator.equals(ai) && !killables.isEmpty()) {
|
||||||
|
return ComputerUtilCard.getBestPlaneswalkerAI(killables);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hPlay.isEmpty()) {
|
||||||
|
if (pl.isOpponentOf(ai) && activator.equals(ai)) {
|
||||||
|
return ComputerUtilCard.getBestPlaneswalkerAI(hPlay);
|
||||||
|
} else if (mandatory) {
|
||||||
|
return ComputerUtilCard.getWorstPlaneswalkerAI(hPlay);
|
||||||
|
}
|
||||||
|
|
||||||
|
return targetCard;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Card> getTargetableCards(Player ai, SpellAbility sa, Player pl, TargetRestrictions tgt, Player activator, Card source, Game game) {
|
||||||
|
List<Card> hPlay = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), tgt.getValidTgts(), activator, source, sa);
|
||||||
|
|
||||||
|
if (activator.equals(ai)) {
|
||||||
|
hPlay = CardLists.filterControlledBy(hPlay, pl);
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<GameObject> objects = Lists.newArrayList(sa.getTargets().getTargets());
|
||||||
|
if (sa.hasParam("TargetUnique")) {
|
||||||
|
objects.addAll(sa.getUniqueTargets());
|
||||||
|
}
|
||||||
|
for (final Object o : objects) {
|
||||||
|
if (o instanceof Card) {
|
||||||
|
final Card c = (Card) o;
|
||||||
|
if (hPlay.contains(c)) {
|
||||||
|
hPlay.remove(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hPlay = CardLists.getTargetableCards(hPlay, sa);
|
||||||
|
return hPlay;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* damageTargetAI.
|
* damageTargetAI.
|
||||||
@@ -475,7 +535,27 @@ public class DamageDealAi extends DamageAiBase {
|
|||||||
return targetingPlayer.getController().chooseTargetsFor(sa);
|
return targetingPlayer.getController().chooseTargetsFor(sa);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tgt.canTgtPlaneswalker()) {
|
||||||
|
// We can damage planeswalkers with this, consider targeting.
|
||||||
|
Card c = this.dealDamageChooseTgtPW(ai, sa, dmg, noPrevention, enemy, false);
|
||||||
|
if (c != null) {
|
||||||
|
tcs.add(c);
|
||||||
|
if (divided) {
|
||||||
|
final int assignedDamage = ComputerUtilCombat.getEnoughDamageToKill(c, dmg, source, false, noPrevention);
|
||||||
|
if (assignedDamage <= dmg) {
|
||||||
|
tgt.addDividedAllocation(c, assignedDamage);
|
||||||
|
}
|
||||||
|
dmg = dmg - assignedDamage;
|
||||||
|
if (dmg <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (tgt.canTgtCreatureAndPlayer()) {
|
if (tgt.canTgtCreatureAndPlayer()) {
|
||||||
|
Card c = null;
|
||||||
|
|
||||||
if (this.shouldTgtP(ai, sa, dmg, noPrevention)) {
|
if (this.shouldTgtP(ai, sa, dmg, noPrevention)) {
|
||||||
tcs.add(enemy);
|
tcs.add(enemy);
|
||||||
@@ -489,7 +569,8 @@ public class DamageDealAi extends DamageAiBase {
|
|||||||
dmg = dmg * sa.getTargets().getNumTargeted() / (sa.getTargets().getNumTargeted() +1);
|
dmg = dmg * sa.getTargets().getNumTargeted() / (sa.getTargets().getNumTargeted() +1);
|
||||||
}
|
}
|
||||||
|
|
||||||
final Card c = this.dealDamageChooseTgtC(ai, sa, dmg, noPrevention, enemy, false);
|
// look for creature targets; currently also catches planeswalkers that can be killed immediately
|
||||||
|
c = this.dealDamageChooseTgtC(ai, sa, dmg, noPrevention, enemy, false);
|
||||||
if (c != null) {
|
if (c != null) {
|
||||||
//option to hold removal instead only applies for single targeted removal
|
//option to hold removal instead only applies for single targeted removal
|
||||||
if (sa.isSpell() && !divided && !immediately && tgt.getMaxTargets(sa.getHostCard(), sa) == 1) {
|
if (sa.isSpell() && !divided && !immediately && tgt.getMaxTargets(sa.getHostCard(), sa) == 1) {
|
||||||
|
|||||||
Reference in New Issue
Block a user