mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-18 19:58:00 +00:00
- Separated vehicle crewing logic between "canPay" and "canPlay"
This commit is contained in:
@@ -32,7 +32,6 @@ import com.google.common.collect.Iterables;
|
|||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Multimap;
|
import com.google.common.collect.Multimap;
|
||||||
|
|
||||||
import forge.ai.ability.AnimateAi;
|
|
||||||
import forge.ai.ability.ProtectAi;
|
import forge.ai.ability.ProtectAi;
|
||||||
import forge.card.CardType;
|
import forge.card.CardType;
|
||||||
import forge.card.MagicColor;
|
import forge.card.MagicColor;
|
||||||
@@ -45,7 +44,6 @@ import forge.game.ability.effects.CharmEffect;
|
|||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.card.CardCollection;
|
import forge.game.card.CardCollection;
|
||||||
import forge.game.card.CardCollectionView;
|
import forge.game.card.CardCollectionView;
|
||||||
import forge.game.card.CardFactory;
|
|
||||||
import forge.game.card.CardLists;
|
import forge.game.card.CardLists;
|
||||||
import forge.game.card.CardPredicates;
|
import forge.game.card.CardPredicates;
|
||||||
import forge.game.card.CardPredicates.Presets;
|
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
|
// Used for Crewing vehicles, ideally we sort by useless creatures. Can't Attack/Defender
|
||||||
int totalPower = 0;
|
int totalPower = 0;
|
||||||
final Card activate = sa.getHostCard();
|
final Card activate = sa.getHostCard();
|
||||||
int vehicleValue = 0;
|
|
||||||
|
|
||||||
CardCollection all = new CardCollection(ai.getCardsIn(ZoneType.Battlefield));
|
CardCollection all = new CardCollection(ai.getCardsIn(ZoneType.Battlefield));
|
||||||
all.removeAll(exclude);
|
all.removeAll(exclude);
|
||||||
@@ -513,9 +510,6 @@ public class ComputerUtil {
|
|||||||
|
|
||||||
if (sa.hasParam("Crew")) {
|
if (sa.hasParam("Crew")) {
|
||||||
typeList = CardLists.getNotKeyword(typeList, "CARDNAME can't crew Vehicles.");
|
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?
|
// is this needed?
|
||||||
@@ -524,14 +518,15 @@ public class ComputerUtil {
|
|||||||
if (tap) {
|
if (tap) {
|
||||||
typeList.remove(activate);
|
typeList.remove(activate);
|
||||||
}
|
}
|
||||||
CardLists.sortByPowerAsc(typeList);
|
ComputerUtilCard.sortByEvaluateCreature(typeList);
|
||||||
|
Collections.reverse(typeList);
|
||||||
|
|
||||||
final CardCollection tapList = new CardCollection();
|
final CardCollection tapList = new CardCollection();
|
||||||
|
|
||||||
// Very very rudimentary
|
// Accumulate from "worst" creature
|
||||||
for (Card next : typeList) {
|
for (Card next : typeList) {
|
||||||
int pow = next.getNetPower();
|
int pow = next.getNetPower();
|
||||||
if (pow <= 0 || ComputerUtilCard.evaluateCreature(next) > vehicleValue) {
|
if (pow <= 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
totalPower += pow;
|
totalPower += pow;
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
package forge.ai;
|
package forge.ai;
|
||||||
|
|
||||||
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
|
import forge.ai.ability.AnimateAi;
|
||||||
import forge.card.ColorSet;
|
import forge.card.ColorSet;
|
||||||
import forge.game.GameActionUtil;
|
import forge.game.GameActionUtil;
|
||||||
import forge.game.ability.AbilityUtils;
|
import forge.game.ability.AbilityUtils;
|
||||||
|
import forge.game.ability.ApiType;
|
||||||
import forge.game.card.Card;
|
import forge.game.card.Card;
|
||||||
import forge.game.card.CardCollection;
|
import forge.game.card.CardCollection;
|
||||||
|
import forge.game.card.CardFactory;
|
||||||
import forge.game.card.CardLists;
|
import forge.game.card.CardLists;
|
||||||
import forge.game.card.CardPredicates.Presets;
|
import forge.game.card.CardPredicates.Presets;
|
||||||
import forge.game.card.CounterType;
|
import forge.game.card.CounterType;
|
||||||
@@ -296,8 +301,39 @@ public class ComputerUtilCost {
|
|||||||
if (cost == null) {
|
if (cost == null) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
boolean isVehicle = source.hasStartOfKeyword("Crew");
|
||||||
for (final CostPart part : cost.getCostParts()) {
|
for (final CostPart part : cost.getCostParts()) {
|
||||||
if (part instanceof CostTapType) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -137,10 +137,12 @@ public class AnimateAi extends SpellAbilityAi {
|
|||||||
if (sa.getConditions() != null && !sa.getConditions().areMet(sa) && sa.getSubAbility() == null) {
|
if (sa.getConditions() != null && !sa.getConditions().areMet(sa) && sa.getSubAbility() == null) {
|
||||||
return false; // what is this for?
|
return false; // what is this for?
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!game.getStack().isEmpty() && game.getStack().peekAbility().getApi() == ApiType.Sacrifice) {
|
if (!game.getStack().isEmpty() && game.getStack().peekAbility().getApi() == ApiType.Sacrifice) {
|
||||||
return true; // interrupt sacrifice
|
return true; // interrupt sacrifice
|
||||||
}
|
}
|
||||||
|
if (!ComputerUtilCost.checkTapTypeCost(aiPlayer, sa.getPayCosts(), source)) {
|
||||||
|
return false; // prevent crewing with equal or better creatures
|
||||||
|
}
|
||||||
if (null == tgt) {
|
if (null == tgt) {
|
||||||
final List<Card> defined = AbilityUtils.getDefinedCards(source, sa.getParam("Defined"), sa);
|
final List<Card> defined = AbilityUtils.getDefinedCards(source, sa.getParam("Defined"), sa);
|
||||||
boolean bFlag = false;
|
boolean bFlag = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user