This commit is contained in:
tool4ever
2022-12-05 19:43:56 +01:00
committed by GitHub
parent 3f831bc036
commit bdf09485a2
17 changed files with 39 additions and 52 deletions

View File

@@ -2961,7 +2961,7 @@ public class ComputerUtil {
return false; return false;
} }
public static boolean targetPlayableSpellCard(final Player ai, CardCollection options, final SpellAbility sa, final boolean withoutPayingManaCost, boolean mandatory) { public static boolean targetPlayableSpellCard(final Player ai, Iterable<Card> options, final SpellAbility sa, final boolean withoutPayingManaCost, boolean mandatory) {
// determine and target a card with a SA that the AI can afford and will play // determine and target a card with a SA that the AI can afford and will play
AiController aic = ((PlayerControllerAi) ai.getController()).getAi(); AiController aic = ((PlayerControllerAi) ai.getController()).getAi();
sa.resetTargets(); sa.resetTargets();
@@ -2993,8 +2993,8 @@ public class ComputerUtil {
} }
if (targets.isEmpty()) { if (targets.isEmpty()) {
if (mandatory && !options.isEmpty()) { if (mandatory && !Iterables.isEmpty(options)) {
targets = options; targets.addAll(options);
} else { } else {
return false; return false;
} }

View File

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

View File

@@ -68,7 +68,6 @@ public class DebuffAi extends SpellAbilityAi {
if (!sa.usesTargeting()) { if (!sa.usesTargeting()) {
List<Card> cards = AbilityUtils.getDefinedCards(source, sa.getParam("Defined"), sa); List<Card> cards = AbilityUtils.getDefinedCards(source, sa.getParam("Defined"), sa);
final Combat combat = game.getCombat(); final Combat combat = game.getCombat();
return Iterables.any(cards, new Predicate<Card>() { return Iterables.any(cards, new Predicate<Card>() {
@Override @Override
@@ -121,7 +120,6 @@ public class DebuffAi extends SpellAbilityAi {
final TargetRestrictions tgt = sa.getTargetRestrictions(); final TargetRestrictions tgt = sa.getTargetRestrictions();
sa.resetTargets(); sa.resetTargets();
CardCollection list = getCurseCreatures(ai, sa, kws == null ? Lists.newArrayList() : kws); CardCollection list = getCurseCreatures(ai, sa, kws == null ? Lists.newArrayList() : kws);
list = CardLists.getValidCards(list, tgt.getValidTgts(), sa.getActivatingPlayer(), sa.getHostCard(), sa);
// several uses here: // several uses here:
// 1. make human creatures lose evasion when they are attacking // 1. make human creatures lose evasion when they are attacking
@@ -205,9 +203,7 @@ public class DebuffAi extends SpellAbilityAi {
} }
// Remove anything that's already been targeted // Remove anything that's already been targeted
for (final Card c : sa.getTargets().getTargetCards()) { list.removeAll(sa.getTargets().getTargetCards());
list.remove(c);
}
final CardCollection pref = CardLists.filterControlledBy(list, ai.getOpponents()); final CardCollection pref = CardLists.filterControlledBy(list, ai.getOpponents());
final CardCollection forced = CardLists.filterControlledBy(list, ai); final CardCollection forced = CardLists.filterControlledBy(list, ai);

View File

@@ -40,7 +40,7 @@ public class PlayAi extends SpellAbilityAi {
return false; // prevent infinite loop return false; // prevent infinite loop
} }
CardCollection cards = getPlayableCards(sa, ai); List<Card> cards = getPlayableCards(sa, ai);
if (cards.isEmpty()) { if (cards.isEmpty()) {
return false; return false;
} }
@@ -188,14 +188,14 @@ public class PlayAi extends SpellAbilityAi {
}); });
return ComputerUtilCard.getBestAI(tgtCards); return ComputerUtilCard.getBestAI(tgtCards);
} }
private static CardCollection getPlayableCards(SpellAbility sa, Player ai) { private static List<Card> getPlayableCards(SpellAbility sa, Player ai) {
CardCollection cards = new CardCollection(); List<Card> cards = null;
final TargetRestrictions tgt = sa.getTargetRestrictions(); final TargetRestrictions tgt = sa.getTargetRestrictions();
final Card source = sa.getHostCard(); final Card source = sa.getHostCard();
if (tgt != null) { if (tgt != null) {
cards = CardLists.getValidCards(ai.getGame().getCardsIn(tgt.getZone()), tgt.getValidTgts(), ai, source, sa); cards = CardUtil.getValidCardsToTarget(tgt, sa);
} else if (!sa.hasParam("Valid")) { } else if (!sa.hasParam("Valid")) {
cards = AbilityUtils.getDefinedCards(source, sa.getParam("Defined"), sa); cards = AbilityUtils.getDefinedCards(source, sa.getParam("Defined"), sa);
} }

View File

@@ -518,7 +518,7 @@ public class PumpAi extends PumpAiBase {
} }
} }
list = CardLists.getValidCards(list, tgt.getValidTgts(), ai, source, sa); list = CardLists.getTargetableCards(list, sa);
if (game.getStack().isEmpty()) { if (game.getStack().isEmpty()) {
// If the cost is tapping, don't activate before declare attack/block // If the cost is tapping, don't activate before declare attack/block
if (sa.getPayCosts().hasTapCost()) { if (sa.getPayCosts().hasTapCost()) {

View File

@@ -2918,8 +2918,7 @@ public class AbilityUtils {
sas.add(s); sas.add(s);
} }
} else { } else {
final Spell newSA = (Spell) s.copy(); final Spell newSA = (Spell) s.copy(controller);
newSA.setActivatingPlayer(controller);
SpellAbilityRestriction res = new SpellAbilityRestriction(); SpellAbilityRestriction res = new SpellAbilityRestriction();
// timing restrictions still apply // timing restrictions still apply
res.setPlayerTurn(s.getRestrictions().getPlayerTurn()); res.setPlayerTurn(s.getRestrictions().getPlayerTurn());

View File

@@ -237,10 +237,7 @@ public class CharmEffect extends SpellAbilityEffect {
for (AbilitySub sub : chosen) { for (AbilitySub sub : chosen) {
// Clone the chosen, just in case the same subAb gets chosen multiple times // Clone the chosen, just in case the same subAb gets chosen multiple times
AbilitySub clone = (AbilitySub)sub.copy(); AbilitySub clone = (AbilitySub)sub.copy(sa.getActivatingPlayer());
// update ActivatingPlayer
clone.setActivatingPlayer(sa.getActivatingPlayer());
// make StackDescription be the SpellDescription if it doesn't already have one // make StackDescription be the SpellDescription if it doesn't already have one
if (!clone.hasParam("StackDescription")) { if (!clone.hasParam("StackDescription")) {

View File

@@ -20,6 +20,7 @@ import forge.game.card.CardLists;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.util.Aggregates; import forge.util.Aggregates;
import forge.util.Lang;
import forge.util.Localizer; import forge.util.Localizer;
public class ChooseCardNameEffect extends SpellAbilityEffect { public class ChooseCardNameEffect extends SpellAbilityEffect {
@@ -28,9 +29,7 @@ public class ChooseCardNameEffect extends SpellAbilityEffect {
protected String getStackDescription(SpellAbility sa) { protected String getStackDescription(SpellAbility sa) {
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
for (final Player p : getTargetPlayers(sa)) { sb.append(Lang.joinHomogenous(getTargetPlayers(sa)));
sb.append(p).append(" ");
}
sb.append("names a card."); sb.append("names a card.");
return sb.toString(); return sb.toString();

View File

@@ -21,9 +21,8 @@ public class ChooseColorEffect extends SpellAbilityEffect {
protected String getStackDescription(SpellAbility sa) { protected String getStackDescription(SpellAbility sa) {
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
for (final Player p : getTargetPlayers(sa)) { sb.append(Lang.joinHomogenous(getTargetPlayers(sa)));
sb.append(p).append(" ");
}
sb.append("chooses a color"); sb.append("chooses a color");
if (sa.hasParam("OrColors")) { if (sa.hasParam("OrColors")) {
sb.append(" or colors"); sb.append(" or colors");

View File

@@ -6,6 +6,7 @@ import forge.game.card.Card;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.player.PlayerController.BinaryChoiceType; import forge.game.player.PlayerController.BinaryChoiceType;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.util.Lang;
import forge.util.Localizer; import forge.util.Localizer;
public class ChooseEvenOddEffect extends SpellAbilityEffect { public class ChooseEvenOddEffect extends SpellAbilityEffect {
@@ -17,9 +18,7 @@ public class ChooseEvenOddEffect extends SpellAbilityEffect {
protected String getStackDescription(SpellAbility sa) { protected String getStackDescription(SpellAbility sa) {
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
for (final Player p : getTargetPlayers(sa)) { sb.append(Lang.joinHomogenous(getTargetPlayers(sa)));
sb.append(p).append(" ");
}
sb.append("chooses even or odd."); sb.append("chooses even or odd.");
return sb.toString(); return sb.toString();

View File

@@ -13,6 +13,7 @@ import forge.game.event.GameEventCardModeChosen;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.util.Aggregates; import forge.util.Aggregates;
import forge.util.Lang;
public class ChooseGenericEffect extends SpellAbilityEffect { public class ChooseGenericEffect extends SpellAbilityEffect {
@@ -20,9 +21,7 @@ public class ChooseGenericEffect extends SpellAbilityEffect {
protected String getStackDescription(SpellAbility sa) { protected String getStackDescription(SpellAbility sa) {
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
for (final Player p : getTargetPlayers(sa)) { sb.append(Lang.joinHomogenous(getDefinedPlayersOrTargeted(sa)));
sb.append(p).append(" ");
}
sb.append("chooses from a list."); sb.append("chooses from a list.");
return sb.toString(); return sb.toString();

View File

@@ -12,6 +12,7 @@ import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.util.Lang;
import forge.util.Localizer; import forge.util.Localizer;
import forge.util.MyRandom; import forge.util.MyRandom;
@@ -24,9 +25,8 @@ public class ChooseNumberEffect extends SpellAbilityEffect {
protected String getStackDescription(SpellAbility sa) { protected String getStackDescription(SpellAbility sa) {
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
for (final Player p : getTargetPlayers(sa)) { sb.append(Lang.joinHomogenous(getTargetPlayers(sa)));
sb.append(p).append(" ");
}
sb.append("chooses a number."); sb.append("chooses a number.");
return sb.toString(); return sb.toString();

View File

@@ -18,6 +18,7 @@ import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
import forge.util.Aggregates; import forge.util.Aggregates;
import forge.util.Lang;
import forge.util.Localizer; import forge.util.Localizer;
public class MultiplePilesEffect extends SpellAbilityEffect { public class MultiplePilesEffect extends SpellAbilityEffect {
@@ -29,15 +30,13 @@ public class MultiplePilesEffect extends SpellAbilityEffect {
protected String getStackDescription(SpellAbility sa) { protected String getStackDescription(SpellAbility sa) {
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
final List<Player> tgtPlayers = getTargetPlayers(sa);
String piles = sa.getParam("Piles"); String piles = sa.getParam("Piles");
final String valid = sa.getParamOrDefault("ValidCards", ""); final String valid = sa.getParamOrDefault("ValidCards", "");
sb.append("Separate all ").append(valid).append(" cards "); sb.append("Separate all ").append(valid).append(" cards ");
for (final Player p : tgtPlayers) { sb.append(Lang.joinHomogenous(getTargetPlayers(sa)));
sb.append(p).append(" ");
}
sb.append("controls into ").append(piles).append(" piles."); sb.append("controls into ").append(piles).append(" piles.");
return sb.toString(); return sb.toString();
} }

View File

@@ -153,7 +153,7 @@ public class SacrificeEffect extends SpellAbilityEffect {
boolean isStrict = sa.hasParam("StrictAmount"); boolean isStrict = sa.hasParam("StrictAmount");
int minTargets = optional && !isStrict ? 0 : amount; int minTargets = optional && !isStrict ? 0 : amount;
boolean notEnoughTargets = validTargets.size() < minTargets; boolean notEnoughTargets = isStrict && validTargets.size() < minTargets;
if (sa.hasParam("Random")) { if (sa.hasParam("Random")) {
choosenToSacrifice = new CardCollection(Aggregates.random(validTargets, Math.min(amount, validTargets.size()))); choosenToSacrifice = new CardCollection(Aggregates.random(validTargets, Math.min(amount, validTargets.size())));

View File

@@ -243,21 +243,21 @@ public final class CardUtil {
newCopy.setDamageHistory(in.getDamageHistory()); newCopy.setDamageHistory(in.getDamageHistory());
newCopy.setDamageReceivedThisTurn(in.getDamageReceivedThisTurn()); newCopy.setDamageReceivedThisTurn(in.getDamageReceivedThisTurn());
for (Card c : in.getBlockedThisTurn()) {
newCopy.addBlockedThisTurn(c); // these are LKI already
} newCopy.getBlockedThisTurn().addAll(in.getBlockedThisTurn());
for (Card c : in.getBlockedByThisTurn()) { newCopy.getBlockedByThisTurn().addAll(in.getBlockedByThisTurn());
newCopy.addBlockedByThisTurn(c);
}
newCopy.setAttachedCards(getLKICopyList(in.getAttachedCards(), cachedMap)); newCopy.setAttachedCards(getLKICopyList(in.getAttachedCards(), cachedMap));
newCopy.setEntityAttachedTo(getLKICopy(in.getEntityAttachedTo(), cachedMap)); newCopy.setEntityAttachedTo(getLKICopy(in.getEntityAttachedTo(), cachedMap));
newCopy.setHaunting(in.getHaunting());
newCopy.setCopiedPermanent(in.getCopiedPermanent()); newCopy.setCopiedPermanent(in.getCopiedPermanent());
newCopy.setHaunting(in.getHaunting());
for (final Card haunter : in.getHauntedBy()) { for (final Card haunter : in.getHauntedBy()) {
newCopy.addHauntedBy(haunter, false); newCopy.addHauntedBy(haunter, false);
} }
newCopy.addRemembered(in.getRemembered()); newCopy.addRemembered(in.getRemembered());
newCopy.addImprintedCards(in.getImprintedCards()); newCopy.addImprintedCards(in.getImprintedCards());
newCopy.setChosenCards(new CardCollection(in.getChosenCards())); newCopy.setChosenCards(new CardCollection(in.getChosenCards()));
@@ -278,6 +278,8 @@ public final class CardUtil {
newCopy.copyChangedTextFrom(in); newCopy.copyChangedTextFrom(in);
newCopy.setTimestamp(in.getTimestamp());
newCopy.setBestowTimestamp(in.getBestowTimestamp()); newCopy.setBestowTimestamp(in.getBestowTimestamp());
newCopy.setForetold(in.isForetold()); newCopy.setForetold(in.isForetold());
@@ -286,8 +288,6 @@ public final class CardUtil {
newCopy.setMeldedWith(getLKICopy(in.getMeldedWith(), cachedMap)); newCopy.setMeldedWith(getLKICopy(in.getMeldedWith(), cachedMap));
newCopy.setTimestamp(in.getTimestamp());
// update keyword cache on all states // update keyword cache on all states
for (CardStateName s : newCopy.getStates()) { for (CardStateName s : newCopy.getStates()) {
newCopy.updateKeywordsCache(newCopy.getState(s)); newCopy.updateKeywordsCache(newCopy.getState(s));

View File

@@ -1141,7 +1141,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
clone.payingMana.addAll(payingMana); clone.payingMana.addAll(payingMana);
} }
clone.paidAbilities = Lists.newArrayList(); clone.paidAbilities = Lists.newArrayList();
clone.setPaidHash(Maps.newHashMap(getPaidHash())); clone.setPaidHash(getPaidHash());
// copy last chapter flag for Trigger // copy last chapter flag for Trigger
clone.lastChapter = this.lastChapter; clone.lastChapter = this.lastChapter;

View File

@@ -4,5 +4,5 @@ Types:Legendary Creature Human Advisor
PT:2/3 PT:2/3
K:Flying K:Flying
S:Mode$ CantTarget | AffectedZone$ Battlefield,Graveyard | ValidCard$ Land | Activator$ Opponent | Description$ Lands on the battlefield and land cards in graveyards can't be the targets of spells or abilities your opponents control. S:Mode$ CantTarget | AffectedZone$ Battlefield,Graveyard | ValidCard$ Land | Activator$ Opponent | Description$ Lands on the battlefield and land cards in graveyards can't be the targets of spells or abilities your opponents control.
S:Mode$ CantPlayLand | ValidCard$ Land.OppCtrl | Origin$ Graveyard | Description$ Your opponents can't play land cards from graveyards. S:Mode$ CantPlayLand | ValidCard$ Land | Player$ Opponent | Origin$ Graveyard | Description$ Your opponents can't play land cards from graveyards.
Oracle:Flying\nLands on the battlefield and land cards in graveyards can't be the targets of spells or abilities your opponents control.\nYour opponents can't play land cards from graveyards. Oracle:Flying\nLands on the battlefield and land cards in graveyards can't be the targets of spells or abilities your opponents control.\nYour opponents can't play land cards from graveyards.