Use current shard when trying to pay with combo mana (#3130)

* Use current shard when trying to pay with combo mana
This commit is contained in:
tool4ever
2023-05-18 09:21:08 +02:00
committed by GitHub
parent 1aac6d754b
commit 6de7dd6bcc
18 changed files with 32 additions and 41 deletions

View File

@@ -1507,7 +1507,7 @@ public class AiAttackController {
}
if (sa.usesTargeting()) {
sa.setActivatingPlayer(c.getController(), true);
List<Card> validTargets = CardUtil.getValidCardsToTarget(sa.getTargetRestrictions(), sa);
List<Card> validTargets = CardUtil.getValidCardsToTarget(sa);
if (validTargets.isEmpty()) {
missTarget = true;
break;

View File

@@ -644,7 +644,6 @@ public class AiController {
public SpellAbility predictSpellToCastInMain2(ApiType exceptSA) {
return predictSpellToCastInMain2(exceptSA, true);
}
private SpellAbility predictSpellToCastInMain2(ApiType exceptSA, boolean handOnly) {
if (!getBooleanProperty(AiProps.PREDICT_SPELLS_FOR_MAIN2)) {
return null;
@@ -684,15 +683,12 @@ public class AiController {
public boolean reserveManaSourcesForNextSpell(SpellAbility sa, SpellAbility exceptForSa) {
return reserveManaSources(sa, null, false, true, exceptForSa);
}
public boolean reserveManaSources(SpellAbility sa) {
return reserveManaSources(sa, PhaseType.MAIN2, false, false, null);
}
public boolean reserveManaSources(SpellAbility sa, PhaseType phaseType, boolean enemy) {
return reserveManaSources(sa, phaseType, enemy, true, null);
}
public boolean reserveManaSources(SpellAbility sa, PhaseType phaseType, boolean enemy, boolean forNextSpell, SpellAbility exceptForThisSa) {
ManaCostBeingPaid cost = ComputerUtilMana.calculateManaCost(sa, true, 0);
CardCollection manaSources = ComputerUtilMana.getManaSourcesToPayCost(cost, sa, player);

View File

@@ -868,7 +868,7 @@ public class ComputerUtilCost {
if (sa.usesTargeting()) {
// if announce is used as min targets, check what the max possible number would be
if ("X".equals(sa.getTargetRestrictions().getMinTargets())) {
val = ObjectUtils.min(val, CardUtil.getValidCardsToTarget(sa.getTargetRestrictions(), sa).size());
val = ObjectUtils.min(val, CardUtil.getValidCardsToTarget(sa).size());
}
if (sa.hasParam("AIMaxTgtsCount")) {

View File

@@ -962,6 +962,7 @@ public class ComputerUtilMana {
ManaCostShard toPay, SpellAbility saPayment) {
AbilityManaPart m = saPayment.getManaPart();
if (m.isComboMana()) {
m.setExpressChoice(ColorSet.fromMask(toPay.getColorMask()));
getComboManaChoice(ai, saPayment, sa, cost);
}
else if (saPayment.getApi() == ApiType.ManaReflected) {

View File

@@ -46,7 +46,7 @@ public class SpecialAiLogic {
return false;
}
List<Card> targetable = CardUtil.getValidCardsToTarget(sa.getTargetRestrictions(), sa);
List<Card> targetable = CardUtil.getValidCardsToTarget(sa);
CardCollection listOpp = CardLists.filterControlledBy(targetable, ai.getOpponents());
if (isDestroy) {

View File

@@ -228,7 +228,7 @@ public class AnimateAi extends SpellAbilityAi {
} else if (sa.usesTargeting() && mandatory) {
// fallback if animate is mandatory
sa.resetTargets();
List<Card> list = CardUtil.getValidCardsToTarget(sa.getTargetRestrictions(), sa);
List<Card> list = CardUtil.getValidCardsToTarget(sa);
if (list.isEmpty()) {
return false;
}

View File

@@ -123,8 +123,7 @@ public class AttachAi extends SpellAbilityAi {
if (ComputerUtilAbility.getAbilitySourceName(sa).equals("Chained to the Rocks")) {
final SpellAbility effectExile = AbilityFactory.getAbility(source.getSVar("TrigExile"), source);
effectExile.setActivatingPlayer(ai, true);
final TargetRestrictions exile_tgt = effectExile.getTargetRestrictions();
final List<Card> targets = CardUtil.getValidCardsToTarget(exile_tgt, effectExile);
final List<Card> targets = CardUtil.getValidCardsToTarget(effectExile);
return !targets.isEmpty();
}
@@ -1328,11 +1327,9 @@ public class AttachAi extends SpellAbilityAi {
return null;
}
final TargetRestrictions tgt = sa.getTargetRestrictions();
// Is a SA that moves target attachment
if ("MoveTgtAura".equals(sa.getParam("AILogic"))) {
CardCollection list = CardLists.filter(CardUtil.getValidCardsToTarget(tgt, sa), Predicates.or(CardPredicates.isControlledByAnyOf(aiPlayer.getOpponents()), new Predicate<Card>() {
CardCollection list = CardLists.filter(CardUtil.getValidCardsToTarget(sa), Predicates.or(CardPredicates.isControlledByAnyOf(aiPlayer.getOpponents()), new Predicate<Card>() {
@Override
public boolean apply(final Card card) {
return ComputerUtilCard.isUselessCreature(aiPlayer, card.getAttachedTo());
@@ -1341,7 +1338,7 @@ public class AttachAi extends SpellAbilityAi {
return !list.isEmpty() ? ComputerUtilCard.getBestAI(list) : null;
} else if ("Unenchanted".equals(sa.getParam("AILogic"))) {
List<Card> list = CardUtil.getValidCardsToTarget(tgt, sa);
List<Card> list = CardUtil.getValidCardsToTarget(sa);
CardCollection preferred = CardLists.filter(list, new Predicate<Card>() {
@Override
public boolean apply(final Card card) {
@@ -1358,10 +1355,10 @@ public class AttachAi extends SpellAbilityAi {
}
List<Card> list = null;
if (tgt == null) {
list = AbilityUtils.getDefinedCards(attachSource, sa.getParam("Defined"), sa);
if (sa.usesTargeting()) {
list = CardUtil.getValidCardsToTarget(sa);
} else {
list = CardUtil.getValidCardsToTarget(tgt, sa);
list = AbilityUtils.getDefinedCards(attachSource, sa.getParam("Defined"), sa);
}
if (list.isEmpty()) {

View File

@@ -1432,7 +1432,7 @@ public class ChangeZoneAi extends SpellAbilityAi {
final ZoneType destination = ZoneType.smartValueOf(sa.getParam("Destination"));
final TargetRestrictions tgt = sa.getTargetRestrictions();
List<Card> list = CardUtil.getValidCardsToTarget(tgt, sa);
List<Card> list = CardUtil.getValidCardsToTarget(sa);
if (list.isEmpty()) {
return false;

View File

@@ -130,7 +130,7 @@ public class CopyPermanentAi extends SpellAbilityAi {
if (sa.usesTargeting()) {
sa.resetTargets();
List<Card> list = CardUtil.getValidCardsToTarget(sa.getTargetRestrictions(), sa);
List<Card> list = CardUtil.getValidCardsToTarget(sa);
//Nothing to target
if (list.isEmpty()) {

View File

@@ -195,7 +195,7 @@ public class DebuffAi extends SpellAbilityAi {
*/
private boolean debuffMandatoryTarget(final Player ai, final SpellAbility sa, final boolean mandatory) {
final TargetRestrictions tgt = sa.getTargetRestrictions();
List<Card> list = CardUtil.getValidCardsToTarget(tgt, sa);
List<Card> list = CardUtil.getValidCardsToTarget(sa);
if (list.size() < tgt.getMinTargets(sa.getHostCard(), sa)) {
sa.resetTargets();

View File

@@ -215,7 +215,7 @@ public class EffectAi extends SpellAbilityAi {
} else if (logic.equals("Fight")) {
return FightAi.canFightAi(ai, sa, 0, 0);
} else if (logic.equals("Pump")) {
List<Card> options = CardUtil.getValidCardsToTarget(sa.getTargetRestrictions(), sa);
List<Card> options = CardUtil.getValidCardsToTarget(sa);
options = CardLists.filterControlledBy(options, ai);
if (sa.getPayCosts().hasTapCost()) {
options.remove(sa.getHostCard());

View File

@@ -213,11 +213,10 @@ public class PlayAi extends SpellAbilityAi {
private static List<Card> getPlayableCards(SpellAbility sa, Player ai) {
List<Card> cards = null;
final TargetRestrictions tgt = sa.getTargetRestrictions();
final Card source = sa.getHostCard();
if (tgt != null) {
cards = CardUtil.getValidCardsToTarget(tgt, sa);
if (sa.usesTargeting()) {
cards = CardUtil.getValidCardsToTarget(sa);
} else if (!sa.hasParam("Valid")) {
cards = AbilityUtils.getDefinedCards(source, sa.getParam("Defined"), sa);
}

View File

@@ -258,7 +258,7 @@ public class ProtectAi extends SpellAbilityAi {
private static boolean protectMandatoryTarget(final Player ai, final SpellAbility sa) {
final TargetRestrictions tgt = sa.getTargetRestrictions();
final Card source = sa.getHostCard();
final List<Card> list = CardUtil.getValidCardsToTarget(tgt, sa);
final List<Card> list = CardUtil.getValidCardsToTarget(sa);
if (list.size() < tgt.getMinTargets(source, sa)) {
sa.resetTargets();

View File

@@ -617,7 +617,7 @@ public class PumpAi extends PumpAiBase {
private boolean pumpMandatoryTarget(final Player ai, final SpellAbility sa) {
final TargetRestrictions tgt = sa.getTargetRestrictions();
List<Card> list = CardUtil.getValidCardsToTarget(tgt, sa);
List<Card> list = CardUtil.getValidCardsToTarget(sa);
if (list.size() < tgt.getMinTargets(sa.getHostCard(), sa)) {
sa.resetTargets();

View File

@@ -23,7 +23,6 @@ import forge.game.phase.PhaseType;
import forge.game.player.Player;
import forge.game.player.PlayerActionConfirmMode;
import forge.game.spellability.SpellAbility;
import forge.game.spellability.TargetRestrictions;
import forge.game.zone.ZoneType;
public class SetStateAi extends SpellAbilityAi {
@@ -79,11 +78,10 @@ public class SetStateAi extends SpellAbilityAi {
}
return shouldTransformCard(source, ai, ph) || "Always".equals(logic);
} else {
final TargetRestrictions tgt = sa.getTargetRestrictions();
sa.resetTargets();
// select only the ones that can transform
CardCollection list = CardLists.filter(CardUtil.getValidCardsToTarget(tgt, sa), CardPredicates.Presets.CREATURES, new Predicate<Card>() {
CardCollection list = CardLists.filter(CardUtil.getValidCardsToTarget(sa), CardPredicates.Presets.CREATURES, new Predicate<Card>() {
@Override
public boolean apply(Card c) {
return c.canTransform(sa);
@@ -106,17 +104,10 @@ public class SetStateAi extends SpellAbilityAi {
return sa.isMinTargetChosen();
}
} else if ("TurnFace".equals(mode)) {
if (!sa.usesTargeting()) {
CardCollection list = AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam("Defined"), sa);
if (list.isEmpty()) {
return false;
}
return shouldTurnFace(list.get(0), ai, ph) || "Always".equals(logic);
} else {
final TargetRestrictions tgt = sa.getTargetRestrictions();
if (sa.usesTargeting()) {
sa.resetTargets();
List<Card> list = CardUtil.getValidCardsToTarget(tgt, sa);
List<Card> list = CardUtil.getValidCardsToTarget(sa);
if (list.isEmpty()) {
return false;
@@ -132,6 +123,12 @@ public class SetStateAi extends SpellAbilityAi {
}
return sa.isTargetNumberValid();
} else {
CardCollection list = AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam("Defined"), sa);
if (list.isEmpty()) {
return false;
}
return shouldTurnFace(list.get(0), ai, ph) || "Always".equals(logic);
}
}
return true;

View File

@@ -544,7 +544,8 @@ public final class CardUtil {
// parameters for target selection.
// however, due to the changes necessary for SA_Requirements this is much
// different than the original
public static List<Card> getValidCardsToTarget(TargetRestrictions tgt, SpellAbility ability) {
public static List<Card> getValidCardsToTarget(final SpellAbility ability) {
final TargetRestrictions tgt = ability.getTargetRestrictions();
final Card activatingCard = ability.getHostCard();
final Game game = ability.getActivatingPlayer().getGame();
final List<ZoneType> zone = tgt.getZone();

View File

@@ -460,7 +460,7 @@ public class PlayerControllerHuman extends PlayerController implements IGameCont
if (ability.usesTargeting()) {
// if announce is used as min targets, check what the max possible number would be
if (announce.equals(ability.getTargetRestrictions().getMinTargets())) {
max = Math.min(max, CardUtil.getValidCardsToTarget(ability.getTargetRestrictions(), ability).size());
max = Math.min(max, CardUtil.getValidCardsToTarget(ability).size());
}
}
if (min > max) {

View File

@@ -140,7 +140,7 @@ public class TargetSelection {
return ability.getTargets().addAll(choices);
}
List<Card> validTargets = CardUtil.getValidCardsToTarget(tgt, ability);
List<Card> validTargets = CardUtil.getValidCardsToTarget(ability);
boolean mustTargetFiltered = false;
if (canFilterMustTarget) {
mustTargetFiltered = StaticAbilityMustTarget.filterMustTargetCards(controller.getPlayer(), validTargets, ability);