Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into formats/pauper
Browse files Browse the repository at this point in the history
  • Loading branch information
leriomaggio committed May 20, 2023
2 parents 7699c2f + 2be1885 commit 3d5ab82
Show file tree
Hide file tree
Showing 81 changed files with 753 additions and 675 deletions.
2 changes: 1 addition & 1 deletion forge-ai/src/main/java/forge/ai/AiAttackController.java
Original file line number Diff line number Diff line change
Expand Up @@ -1507,7 +1507,7 @@ public static List<Card> exertAttackers(final List<Card> attackers, int aggressi
}
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;
Expand Down
15 changes: 11 additions & 4 deletions forge-ai/src/main/java/forge/ai/AiController.java
Original file line number Diff line number Diff line change
Expand Up @@ -644,7 +644,6 @@ private SpellAbility chooseCounterSpell(final List<SpellAbility> possibleCounter
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;
Expand Down Expand Up @@ -684,15 +683,12 @@ private SpellAbility predictSpellToCastInMain2(ApiType exceptSA, boolean handOnl
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);
Expand Down Expand Up @@ -1086,6 +1082,17 @@ public int compare(final SpellAbility a, final SpellAbility b) {
}
}

// If both are permanent creature spells, prefer the one that evaluates higher
if (a1 == b1 && a.getApi() == ApiType.PermanentCreature && b.getApi() == ApiType.PermanentCreature) {
int evalA = ComputerUtilCard.evaluateCreature(a);
int evalB = ComputerUtilCard.evaluateCreature(b);
if (evalA > evalB) {
a1++;
} else if (evalB > evalA) {
b1++;
}
}

a1 += getSpellAbilityPriority(a);
b1 += getSpellAbilityPriority(b);

Expand Down
21 changes: 21 additions & 0 deletions forge-ai/src/main/java/forge/ai/ComputerUtilCard.java
Original file line number Diff line number Diff line change
Expand Up @@ -582,7 +582,28 @@ public int compare(final Card a, final Card b) {
public static int evaluateCreature(final Card c) {
return creatureEvaluator.evaluateCreature(c);
}
public static int evaluateCreature(final SpellAbility sa) {
final Card host = sa.getHostCard();

if (sa.getApi() != ApiType.PermanentCreature) {
System.err.println("Warning: tried to evaluate a non-creature spell with evaluateCreature for card " + host + " via SA " + sa);
return 0;
}

// switch to the needed card face
CardStateName currentState = sa.getCardState() != null && host.getCurrentStateName() != sa.getCardStateName() && !host.isInPlay() ? host.getCurrentStateName() : null;
if (currentState != null) {
host.setState(sa.getCardStateName(), false);
}

int eval = creatureEvaluator.evaluateCreature(host);

if (currentState != null) {
host.setState(currentState, false);
}

return eval;
}
public static int evaluateCreature(final Card c, final boolean considerPT, final boolean considerCMC) {
return creatureEvaluator.evaluateCreature(c, considerPT, considerCMC);
}
Expand Down
2 changes: 1 addition & 1 deletion forge-ai/src/main/java/forge/ai/ComputerUtilCost.java
Original file line number Diff line number Diff line change
Expand Up @@ -868,7 +868,7 @@ public static int getMaxXValue(SpellAbility sa, Player ai, final boolean effect)
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")) {
Expand Down
1 change: 1 addition & 0 deletions forge-ai/src/main/java/forge/ai/ComputerUtilMana.java
Original file line number Diff line number Diff line change
Expand Up @@ -962,6 +962,7 @@ private static void setExpressColorChoice(final SpellAbility sa, final Player ai
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) {
Expand Down
2 changes: 1 addition & 1 deletion forge-ai/src/main/java/forge/ai/SpecialAiLogic.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public static boolean doPongifyLogic(final Player ai, final SpellAbility sa) {
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) {
Expand Down
2 changes: 1 addition & 1 deletion forge-ai/src/main/java/forge/ai/ability/AnimateAi.java
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ protected boolean doTriggerAINoCost(Player aiPlayer, SpellAbility sa, boolean ma
} 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;
}
Expand Down
15 changes: 6 additions & 9 deletions forge-ai/src/main/java/forge/ai/ability/AttachAi.java
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,7 @@ protected boolean canPlayAI(Player ai, SpellAbility sa) {
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();
}

Expand Down Expand Up @@ -1328,11 +1327,9 @@ private static Card attachToCardAIPreferences(final Player aiPlayer, final Spell
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());
Expand All @@ -1341,7 +1338,7 @@ public boolean apply(final Card card) {

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) {
Expand All @@ -1358,10 +1355,10 @@ public boolean apply(final Card card) {
}

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()) {
Expand Down
2 changes: 1 addition & 1 deletion forge-ai/src/main/java/forge/ai/ability/ChangeZoneAi.java
Original file line number Diff line number Diff line change
Expand Up @@ -1432,7 +1432,7 @@ private static boolean isUnpreferredTarget(final Player ai, final SpellAbility s
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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ protected boolean doTriggerAINoCost(final Player aiPlayer, SpellAbility sa, bool
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()) {
Expand Down
2 changes: 1 addition & 1 deletion forge-ai/src/main/java/forge/ai/ability/DebuffAi.java
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ public boolean apply(final Card c) {
*/
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();
Expand Down
2 changes: 1 addition & 1 deletion forge-ai/src/main/java/forge/ai/ability/EffectAi.java
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ public boolean apply(final Card c) {
} 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());
Expand Down
5 changes: 2 additions & 3 deletions forge-ai/src/main/java/forge/ai/ability/PlayAi.java
Original file line number Diff line number Diff line change
Expand Up @@ -213,11 +213,10 @@ public boolean apply(final Card c) {

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);
}
Expand Down
2 changes: 1 addition & 1 deletion forge-ai/src/main/java/forge/ai/ability/ProtectAi.java
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ private boolean protectTgtAI(final Player ai, final SpellAbility sa, final boole
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();
Expand Down
2 changes: 1 addition & 1 deletion forge-ai/src/main/java/forge/ai/ability/PumpAi.java
Original file line number Diff line number Diff line change
Expand Up @@ -617,7 +617,7 @@ public boolean apply(Card card) {

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();
Expand Down
21 changes: 9 additions & 12 deletions forge-ai/src/main/java/forge/ai/ability/SetStateAi.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
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 {
Expand Down Expand Up @@ -79,11 +78,10 @@ protected boolean checkPhaseRestrictions(Player ai, SpellAbility sa, PhaseHandle
}
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);
Expand All @@ -106,17 +104,10 @@ public boolean apply(Card c) {
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;
Expand All @@ -132,6 +123,12 @@ public boolean apply(Card c) {
}

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;
Expand Down
19 changes: 17 additions & 2 deletions forge-core/src/main/java/forge/card/CardType.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ public final class CardType implements Comparable<CardType>, CardTypeView {
private static final long serialVersionUID = 4629853583167022151L;

public static final CardTypeView EMPTY = new CardType(false);
private static final Set<String> multiWordTypes = ImmutableSet.of("Serra's Realm", "Bolas's Meditation Realm", "Dungeon Master", "The Library");

public enum CoreType {
Artifact(true, "artifacts"),
Expand Down Expand Up @@ -622,6 +621,9 @@ public void sanisfySubtypes() {
if (!isBattle()) {
Iterables.removeIf(subtypes, Predicates.IS_BATTLE_TYPE);
}
if (!isPlane()) {
Iterables.removeIf(subtypes, Predicates.IS_PLANAR_TYPE);
}
}

@Override
Expand Down Expand Up @@ -781,7 +783,7 @@ public static CardType combine(final CardType a, final CardType b) {
}

private static boolean isMultiwordType(final String type) {
return multiWordTypes.contains(type);
return Constant.MultiwordTypes.contains(type);
}

public static class Constant {
Expand All @@ -797,6 +799,8 @@ public static class Constant {
public static final Set<String> BATTLE_TYPES = Sets.newHashSet();
public static final Set<String> PLANAR_TYPES = Sets.newHashSet();

public static final Set<String> MultiwordTypes = Sets.newHashSet();

// singular -> plural
public static final BiMap<String,String> pluralTypes = HashBiMap.create();
// plural -> singular
Expand Down Expand Up @@ -867,6 +871,13 @@ public boolean apply(String input) {
return CardType.isABattleType(input);
}
};

public static Predicate<String> IS_PLANAR_TYPE = new Predicate<String>() {
@Override
public boolean apply(String input) {
return CardType.isAPlanarType(input);
}
};
}

///////// Utility methods
Expand Down Expand Up @@ -901,6 +912,7 @@ public static List<String> getSortedSubTypes() {
sortedSubTypes.addAll(Constant.WALKER_TYPES);
sortedSubTypes.addAll(Constant.DUNGEON_TYPES);
sortedSubTypes.addAll(Constant.BATTLE_TYPES);
sortedSubTypes.addAll(Constant.PLANAR_TYPES);
Collections.sort(sortedSubTypes);
}
return sortedSubTypes;
Expand Down Expand Up @@ -965,6 +977,9 @@ public static boolean isADungeonType(final String cardType) {
public static boolean isABattleType(final String cardType) {
return Constant.BATTLE_TYPES.contains(cardType);
}
public static boolean isAPlanarType(final String cardType) {
return Constant.PLANAR_TYPES.contains(cardType);
}
/**
* If the input is a plural type, return the corresponding singular form.
* Otherwise, simply return the input.
Expand Down
3 changes: 2 additions & 1 deletion forge-game/src/main/java/forge/game/card/Card.java
Original file line number Diff line number Diff line change
Expand Up @@ -4662,6 +4662,7 @@ public final KeywordInterface getKeywordForStaticAbility(String kw, final long s
if (staticId < 1 || !storedKeywords.containsKey(triple)) {
result = Keyword.getInstance(kw);
result.setStaticId(staticId);
result.setIdx(idx);
result.createTraits(this, false);
if (staticId > 0) {
storedKeywords.put(triple, result);
Expand All @@ -4674,7 +4675,7 @@ public final KeywordInterface getKeywordForStaticAbility(String kw, final long s

public final void addKeywordForStaticAbility(KeywordInterface kw) {
if (kw.getStaticId() > 0) {
storedKeywords.put(Triple.of(kw.getOriginal(), kw.getStaticId(), 0l), kw);
storedKeywords.put(Triple.of(kw.getOriginal(), kw.getStaticId(), kw.getIdx()), kw);
}
}

Expand Down
3 changes: 2 additions & 1 deletion forge-game/src/main/java/forge/game/card/CardUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -544,7 +544,8 @@ public static Set<String> canProduce(final int maxChoices, final SpellAbility sa
// 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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public abstract class KeywordInstance<T extends KeywordInstance<?>> implements K
private Keyword keyword;
private String original;
private long staticId = 0;
private long idx = -1;

private List<Trigger> triggers = Lists.newArrayList();
private List<ReplacementEffect> replacements = Lists.newArrayList();
Expand Down Expand Up @@ -364,4 +365,12 @@ public long getStaticId() {
public void setStaticId(long v) {
this.staticId = v;
}

public long getIdx() {
return idx;
}
public void setIdx(long i) {
idx = i;
}

}
Loading

0 comments on commit 3d5ab82

Please sign in to comment.