- Separated vehicle crewing logic between "canPay" and "canPlay"

This commit is contained in:
excessum
2016-10-08 06:14:44 +00:00
parent 8fbfea317a
commit 1eb9fa375e
3 changed files with 44 additions and 11 deletions

View File

@@ -32,7 +32,6 @@ import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import forge.ai.ability.AnimateAi;
import forge.ai.ability.ProtectAi;
import forge.card.CardType;
import forge.card.MagicColor;
@@ -45,7 +44,6 @@ import forge.game.ability.effects.CharmEffect;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardFactory;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates;
import forge.game.card.CardPredicates.Presets;
@@ -504,7 +502,6 @@ public class ComputerUtil {
// Used for Crewing vehicles, ideally we sort by useless creatures. Can't Attack/Defender
int totalPower = 0;
final Card activate = sa.getHostCard();
int vehicleValue = 0;
CardCollection all = new CardCollection(ai.getCardsIn(ZoneType.Battlefield));
all.removeAll(exclude);
@@ -513,9 +510,6 @@ public class ComputerUtil {
if (sa.hasParam("Crew")) {
typeList = CardLists.getNotKeyword(typeList, "CARDNAME can't crew Vehicles.");
Card vehicle = CardFactory.copyCard(sa.getHostCard(), true);
AnimateAi.becomeAnimated(vehicle, false, sa);
vehicleValue = ComputerUtilCard.evaluateCreature(vehicle);
}
// is this needed?
@@ -524,14 +518,15 @@ public class ComputerUtil {
if (tap) {
typeList.remove(activate);
}
CardLists.sortByPowerAsc(typeList);
ComputerUtilCard.sortByEvaluateCreature(typeList);
Collections.reverse(typeList);
final CardCollection tapList = new CardCollection();
// Very very rudimentary
// Accumulate from "worst" creature
for (Card next : typeList) {
int pow = next.getNetPower();
if (pow <= 0 || ComputerUtilCard.evaluateCreature(next) > vehicleValue) {
if (pow <= 0) {
continue;
}
totalPower += pow;

View File

@@ -1,11 +1,16 @@
package forge.ai;
import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
import forge.ai.ability.AnimateAi;
import forge.card.ColorSet;
import forge.game.GameActionUtil;
import forge.game.ability.AbilityUtils;
import forge.game.ability.ApiType;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardFactory;
import forge.game.card.CardLists;
import forge.game.card.CardPredicates.Presets;
import forge.game.card.CounterType;
@@ -296,8 +301,39 @@ public class ComputerUtilCost {
if (cost == null) {
return true;
}
boolean isVehicle = source.hasStartOfKeyword("Crew");
for (final CostPart part : cost.getCostParts()) {
if (part instanceof CostTapType) {
/*
* Only crew with creatures weaker than vehicle
*
* Possible improvements:
* - block against evasive (flyers, intimidate, etc.)
* - break board stall by racing with evasive vehicle
*/
if (isVehicle) {
for (SpellAbility sa : source.getSpellAbilities()) {
if (sa.getApi() == ApiType.Animate) {
Card vehicle = CardFactory.copyCard(sa.getHostCard(), true);
AnimateAi.becomeAnimated(vehicle, false, sa);
final int vehicleValue = ComputerUtilCard.evaluateCreature(vehicle);
String type = part.getType();
String totalP = type.split("withTotalPowerGE")[1];
type = type.replace("+withTotalPowerGE" + totalP, "");
CardCollection exclude = CardLists.getValidCards(
new CardCollection(ai.getCardsIn(ZoneType.Battlefield)), type.split(";"),
source.getController(), source, sa);
exclude = CardLists.filter(exclude, new Predicate<Card>() {
@Override
public boolean apply(final Card c) {
return ComputerUtilCard.evaluateCreature(c) >= vehicleValue;
}
}); // exclude creatures >= vehicle
return ComputerUtil.chooseTapTypeAccumulatePower(ai, type, sa, true,
Integer.parseInt(totalP), exclude) != null;
}
}
}
return false;
}
}

View File

@@ -137,10 +137,12 @@ public class AnimateAi extends SpellAbilityAi {
if (sa.getConditions() != null && !sa.getConditions().areMet(sa) && sa.getSubAbility() == null) {
return false; // what is this for?
}
if (!game.getStack().isEmpty() && game.getStack().peekAbility().getApi() == ApiType.Sacrifice) {
return true; // interrupt sacrifice
}
if (!ComputerUtilCost.checkTapTypeCost(aiPlayer, sa.getPayCosts(), source)) {
return false; // prevent crewing with equal or better creatures
}
if (null == tgt) {
final List<Card> defined = AbilityUtils.getDefinedCards(source, sa.getParam("Defined"), sa);
boolean bFlag = false;