SacrificeAllEffect: check timestamp for LKI objects

This commit is contained in:
Hans Mackowiak
2021-03-13 10:39:59 +01:00
parent a2e27f40c9
commit 174836a57f
43 changed files with 146 additions and 150 deletions

View File

@@ -316,9 +316,9 @@ public class GameAction {
cards.set(cards.indexOf(c), copied);
// 721.3b
if (cause != null && zoneTo.getZoneType() == ZoneType.Exile) {
cards = (CardCollection) cause.getHostCard().getController().getController().orderMoveToZoneList(cards, zoneTo.getZoneType());
cards = (CardCollection) cause.getHostCard().getController().getController().orderMoveToZoneList(cards, zoneTo.getZoneType(), cause);
} else {
cards = (CardCollection) c.getOwner().getController().orderMoveToZoneList(cards, zoneTo.getZoneType());
cards = (CardCollection) c.getOwner().getController().orderMoveToZoneList(cards, zoneTo.getZoneType(), cause);
}
cards.set(cards.indexOf(copied), c);
if (zoneTo.is(ZoneType.Library)) {
@@ -1169,7 +1169,7 @@ public class GameAction {
if (noRegCreats != null) {
if (noRegCreats.size() > 1 && !orderedNoRegCreats) {
noRegCreats = (CardCollection) GameActionUtil.orderCardsByTheirOwners(game, noRegCreats, ZoneType.Graveyard);
noRegCreats = (CardCollection) GameActionUtil.orderCardsByTheirOwners(game, noRegCreats, ZoneType.Graveyard, null);
orderedNoRegCreats = true;
}
for (Card c : noRegCreats) {
@@ -1180,7 +1180,7 @@ public class GameAction {
if (desCreats.size() > 1 && !orderedDesCreats) {
desCreats = CardLists.filter(desCreats, CardPredicates.Presets.CAN_BE_DESTROYED);
if (!desCreats.isEmpty()) {
desCreats = (CardCollection) GameActionUtil.orderCardsByTheirOwners(game, desCreats, ZoneType.Graveyard);
desCreats = (CardCollection) GameActionUtil.orderCardsByTheirOwners(game, desCreats, ZoneType.Graveyard, null);
}
orderedDesCreats = true;
}

View File

@@ -625,7 +625,7 @@ public final class GameActionUtil {
return sb.toString();
}
public static CardCollectionView orderCardsByTheirOwners(Game game, CardCollectionView list, ZoneType dest) {
public static CardCollectionView orderCardsByTheirOwners(Game game, CardCollectionView list, ZoneType dest, SpellAbility sa) {
CardCollection completeList = new CardCollection();
for (Player p : game.getPlayers()) {
CardCollection subList = new CardCollection();
@@ -636,7 +636,7 @@ public final class GameActionUtil {
}
CardCollectionView subListView = subList;
if (subList.size() > 1) {
subListView = p.getController().orderMoveToZoneList(subList, dest);
subListView = p.getController().orderMoveToZoneList(subList, dest, sa);
}
completeList.addAll(subListView);
}

View File

@@ -238,7 +238,7 @@ public abstract class SpellAbilityEffect {
}
protected static void registerDelayedTrigger(final SpellAbility sa, String location, final List<Card> crds) {
protected static void registerDelayedTrigger(final SpellAbility sa, String location, final Iterable<Card> crds) {
boolean intrinsic = sa.isIntrinsic();
boolean your = location.startsWith("Your");
boolean combat = location.endsWith("Combat");
@@ -298,9 +298,9 @@ public abstract class SpellAbilityEffect {
if (location.equals("Hand")) {
trigSA = "DB$ ChangeZone | Defined$ DelayTriggerRememberedLKI | Origin$ Battlefield | Destination$ Hand";
} else if (location.equals("SacrificeCtrl")) {
trigSA = "DB$ SacrificeAll | Defined$ DelayTriggerRemembered";
trigSA = "DB$ SacrificeAll | Defined$ DelayTriggerRememberedLKI";
} else if (location.equals("Sacrifice")) {
trigSA = "DB$ SacrificeAll | Defined$ DelayTriggerRemembered | Controller$ You";
trigSA = "DB$ SacrificeAll | Defined$ DelayTriggerRememberedLKI | Controller$ You";
} else if (location.equals("Exile")) {
trigSA = "DB$ ChangeZone | Defined$ DelayTriggerRememberedLKI | Origin$ Battlefield | Destination$ Exile";
} else if (location.equals("Destroy")) {

View File

@@ -126,14 +126,14 @@ public class ChangeZoneAllEffect extends SpellAbilityEffect {
if ((destination == ZoneType.Library || destination == ZoneType.PlanarDeck)
&& !sa.hasParam("Shuffle") && cards.size() >= 2 && !random) {
Player p = AbilityUtils.getDefinedPlayers(source, sa.getParamOrDefault("DefinedPlayer", "You"), sa).get(0);
cards = (CardCollection) p.getController().orderMoveToZoneList(cards, destination);
cards = (CardCollection) p.getController().orderMoveToZoneList(cards, destination, sa);
//the last card in this list will be the closest to the top, but we want the first card to be closest.
//so reverse it here before moving them to the library.
java.util.Collections.reverse(cards);
}
if (destination == ZoneType.Graveyard) {
cards = (CardCollection) GameActionUtil.orderCardsByTheirOwners(game, cards, ZoneType.Graveyard);
cards = (CardCollection) GameActionUtil.orderCardsByTheirOwners(game, cards, ZoneType.Graveyard, sa);
}
if (destination.equals(ZoneType.Library) && random) {

View File

@@ -797,6 +797,10 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
triggerList.triggerChangesZoneAll(game);
counterTable.triggerCountersPutAll(game);
if (sa.hasParam("AtEOT") && !triggerList.isEmpty()) {
registerDelayedTrigger(sa, sa.getParam("AtEOT"), triggerList.allCards());
}
// for things like Gaea's Blessing
if (destination.equals(ZoneType.Library) && sa.hasParam("Shuffle") && "True".equals(sa.getParam("Shuffle"))) {
PlayerCollection pl = new PlayerCollection();
@@ -1374,6 +1378,10 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
player.shuffle(sa);
}
if (sa.hasParam("AtEOT") && !movedCards.isEmpty()) {
registerDelayedTrigger(sa, sa.getParam("AtEOT"), movedCards);
}
if (combatChanged) {
game.updateCombatForView();
game.fireEvent(new GameEventCombatChanged());

View File

@@ -86,7 +86,7 @@ public class DestroyAllEffect extends SpellAbilityEffect {
list = CardLists.filter(list, CardPredicates.Presets.CAN_BE_DESTROYED);
if (list.size() > 1) {
list = GameActionUtil.orderCardsByTheirOwners(game, list, ZoneType.Graveyard);
list = GameActionUtil.orderCardsByTheirOwners(game, list, ZoneType.Graveyard, sa);
}
CardZoneTable table = new CardZoneTable();

View File

@@ -76,7 +76,7 @@ public class DestroyEffect extends SpellAbilityEffect {
CardCollection untargetedCards = CardUtil.getRadiance(sa);
if (tgtCards.size() > 1) {
tgtCards = (CardCollection) GameActionUtil.orderCardsByTheirOwners(game, tgtCards, ZoneType.Graveyard);
tgtCards = (CardCollection) GameActionUtil.orderCardsByTheirOwners(game, tgtCards, ZoneType.Graveyard, sa);
}
CardZoneTable table = new CardZoneTable();
@@ -95,7 +95,7 @@ public class DestroyEffect extends SpellAbilityEffect {
}
if (untargetedCards.size() > 1) {
untargetedCards = (CardCollection) GameActionUtil.orderCardsByTheirOwners(game, untargetedCards, ZoneType.Graveyard);
untargetedCards = (CardCollection) GameActionUtil.orderCardsByTheirOwners(game, untargetedCards, ZoneType.Graveyard, sa);
}
for (final Card unTgtC : untargetedCards) {

View File

@@ -353,9 +353,9 @@ public class DigEffect extends SpellAbilityEffect {
CardLists.shuffle(afterOrder);
} else if (!skipReorder && rest.size() > 1) {
if (destZone2 == ZoneType.Graveyard) {
afterOrder = (CardCollection) GameActionUtil.orderCardsByTheirOwners(game, rest, destZone2);
afterOrder = (CardCollection) GameActionUtil.orderCardsByTheirOwners(game, rest, destZone2, sa);
} else {
afterOrder = (CardCollection) chooser.getController().orderMoveToZoneList(rest, destZone2);
afterOrder = (CardCollection) chooser.getController().orderMoveToZoneList(rest, destZone2, sa);
}
}
if (libraryPosition2 != -1) {

View File

@@ -162,7 +162,7 @@ public class DigUntilEffect extends SpellAbilityEffect {
if (foundDest != null) {
// Allow ordering of found cards
if ((foundDest.isKnown()) && found.size() >= 2 && !foundDest.equals(ZoneType.Exile)) {
found = (CardCollection)p.getController().orderMoveToZoneList(found, foundDest);
found = (CardCollection)p.getController().orderMoveToZoneList(found, foundDest, sa);
}
final Iterator<Card> itr = found.iterator();
@@ -213,11 +213,11 @@ public class DigUntilEffect extends SpellAbilityEffect {
if (sa.hasParam("NoneFoundDestination") && found.size() < untilAmount) {
// Allow ordering the revealed cards
if ((noneFoundDest.isKnown()) && revealed.size() >= 2) {
revealed = (CardCollection)p.getController().orderMoveToZoneList(revealed, noneFoundDest);
revealed = (CardCollection)p.getController().orderMoveToZoneList(revealed, noneFoundDest, sa);
}
if (noneFoundDest == ZoneType.Library && !shuffle
&& !sa.hasParam("RevealRandomOrder") && revealed.size() >= 2) {
revealed = (CardCollection)p.getController().orderMoveToZoneList(revealed, noneFoundDest);
revealed = (CardCollection)p.getController().orderMoveToZoneList(revealed, noneFoundDest, sa);
}
final Iterator<Card> itr = revealed.iterator();
@@ -232,11 +232,11 @@ public class DigUntilEffect extends SpellAbilityEffect {
} else {
// Allow ordering the rest of the revealed cards
if ((revealedDest.isKnown()) && revealed.size() >= 2) {
revealed = (CardCollection)p.getController().orderMoveToZoneList(revealed, revealedDest);
revealed = (CardCollection)p.getController().orderMoveToZoneList(revealed, revealedDest, sa);
}
if (revealedDest == ZoneType.Library && !shuffle
&& !sa.hasParam("RevealRandomOrder") && revealed.size() >= 2) {
revealed = (CardCollection)p.getController().orderMoveToZoneList(revealed, revealedDest);
revealed = (CardCollection)p.getController().orderMoveToZoneList(revealed, revealedDest, sa);
}
final Iterator<Card> itr = revealed.iterator();

View File

@@ -145,7 +145,7 @@ public class DiscardEffect extends SpellAbilityEffect {
CardCollectionView toDiscard = AbilityUtils.getDefinedCards(source, sa.getParam("DefinedCards"), sa);
if (toDiscard.size() > 1) {
toDiscard = GameActionUtil.orderCardsByTheirOwners(game, toDiscard, ZoneType.Graveyard);
toDiscard = GameActionUtil.orderCardsByTheirOwners(game, toDiscard, ZoneType.Graveyard, sa);
}
for (final Card c : toDiscard) {
@@ -164,7 +164,7 @@ public class DiscardEffect extends SpellAbilityEffect {
CardCollectionView toDiscard = p.getCardsIn(ZoneType.Hand);
if (toDiscard.size() > 1) {
toDiscard = GameActionUtil.orderCardsByTheirOwners(game, toDiscard, ZoneType.Graveyard);
toDiscard = GameActionUtil.orderCardsByTheirOwners(game, toDiscard, ZoneType.Graveyard, sa);
}
for(Card c : Lists.newArrayList(toDiscard)) { // without copying will get concurrent modification exception
@@ -181,7 +181,7 @@ public class DiscardEffect extends SpellAbilityEffect {
}
CardCollectionView dPHand = CardLists.getValidCards(p.getCardsIn(ZoneType.Hand), "Card.IsNotRemembered", p, source);
if (dPHand.size() > 1) {
dPHand = GameActionUtil.orderCardsByTheirOwners(game, dPHand, ZoneType.Graveyard);
dPHand = GameActionUtil.orderCardsByTheirOwners(game, dPHand, ZoneType.Graveyard, sa);
}
for (final Card c : dPHand) {
@@ -221,7 +221,7 @@ public class DiscardEffect extends SpellAbilityEffect {
CardCollectionView toDiscardView = toDiscard;
if (toDiscard.size() > 1) {
toDiscardView = GameActionUtil.orderCardsByTheirOwners(game, toDiscard, ZoneType.Graveyard);
toDiscardView = GameActionUtil.orderCardsByTheirOwners(game, toDiscard, ZoneType.Graveyard, sa);
}
for (Card c : toDiscardView) {
@@ -242,7 +242,7 @@ public class DiscardEffect extends SpellAbilityEffect {
CardCollectionView toDiscard = p.getController().chooseCardsToDiscardUnlessType(Math.min(numCards, numCardsInHand), hand, sa.getParam("UnlessType"), sa);
if (toDiscard.size() > 1) {
toDiscard = GameActionUtil.orderCardsByTheirOwners(game, toDiscard, ZoneType.Graveyard);
toDiscard = GameActionUtil.orderCardsByTheirOwners(game, toDiscard, ZoneType.Graveyard, sa);
}
for (Card c : toDiscard) {
@@ -275,7 +275,7 @@ public class DiscardEffect extends SpellAbilityEffect {
CardCollectionView dPChHand = CardLists.getValidCards(dPHand, valid.split(","), source.getController(), source, sa);
dPChHand = CardLists.filter(dPChHand, Presets.NON_TOKEN);
if (dPChHand.size() > 1) {
dPChHand = GameActionUtil.orderCardsByTheirOwners(game, dPChHand, ZoneType.Graveyard);
dPChHand = GameActionUtil.orderCardsByTheirOwners(game, dPChHand, ZoneType.Graveyard, sa);
}
// Reveal cards that will be discarded?
@@ -322,7 +322,7 @@ public class DiscardEffect extends SpellAbilityEffect {
if (toBeDiscarded != null) {
if (toBeDiscarded.size() > 1) {
toBeDiscarded = GameActionUtil.orderCardsByTheirOwners(game, toBeDiscarded, ZoneType.Graveyard);
toBeDiscarded = GameActionUtil.orderCardsByTheirOwners(game, toBeDiscarded, ZoneType.Graveyard, sa);
}
if (mode.startsWith("Reveal") ) {

View File

@@ -5,10 +5,10 @@ import forge.game.Game;
import forge.game.ability.AbilityUtils;
import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.card.CardFactoryUtil;
import forge.game.event.GameEventCardStatsChanged;
import forge.game.player.Player;
import forge.game.player.PlayerCollection;
import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import forge.util.TextUtil;
@@ -16,11 +16,12 @@ import forge.util.TextUtil;
import java.util.Arrays;
import java.util.List;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
public class PumpAllEffect extends SpellAbilityEffect {
private static void applyPumpAll(final SpellAbility sa,
final List<Card> list, final int a, final int d,
final Iterable<Card> list, final int a, final int d,
final List<String> keywords, final List<ZoneType> affectedZones) {
final Game game = sa.getActivatingPlayer().getGame();
@@ -109,6 +110,10 @@ public class PumpAllEffect extends SpellAbilityEffect {
game.fireEvent(new GameEventCardStatsChanged(tgtC));
}
if (sa.hasParam("AtEOT") && !Iterables.isEmpty(list)) {
registerDelayedTrigger(sa, sa.getParam("AtEOT"), list);
}
}
@Override
@@ -127,7 +132,7 @@ public class PumpAllEffect extends SpellAbilityEffect {
@Override
public void resolve(final SpellAbility sa) {
final List<Player> tgtPlayers = getTargetPlayers(sa);
final PlayerCollection tgtPlayers = getTargetPlayers(sa);
final List<ZoneType> affectedZones = Lists.newArrayList();
final Game game = sa.getActivatingPlayer().getGame();
@@ -137,17 +142,11 @@ public class PumpAllEffect extends SpellAbilityEffect {
affectedZones.add(ZoneType.Battlefield);
}
CardCollection list = new CardCollection();
CardCollectionView list;
if (!sa.usesTargeting() && !sa.hasParam("Defined")) {
for (final ZoneType zone : affectedZones) {
list.addAll(game.getCardsIn(zone));
}
list = game.getCardsIn(affectedZones);
} else {
for (final ZoneType zone : affectedZones) {
for (final Player p : tgtPlayers) {
list.addAll(p.getCardsIn(zone));
}
}
list = tgtPlayers.getCardsIn(affectedZones);
}
String valid = "";
@@ -155,7 +154,7 @@ public class PumpAllEffect extends SpellAbilityEffect {
valid = sa.getParam("ValidCards");
}
list = (CardCollection)AbilityUtils.filterListByType(list, valid, sa);
list = AbilityUtils.filterListByType(list, valid, sa);
List<String> keywords = Lists.newArrayList();
if (sa.hasParam("KW")) {
@@ -174,6 +173,6 @@ public class PumpAllEffect extends SpellAbilityEffect {
applyPumpAll(sa, list, a, d, keywords, affectedZones);
replaceDying(sa);
} // pumpAllResolve()
}
}

View File

@@ -112,7 +112,7 @@ public class RearrangeTopOfLibraryEffect extends SpellAbilityEffect {
CardCollection topCards = player.getTopXCardsFromLibrary(numCards);
int maxCards = topCards.size();
CardCollectionView orderedCards = activator.getController().orderMoveToZoneList(topCards, ZoneType.Library);
CardCollectionView orderedCards = activator.getController().orderMoveToZoneList(topCards, ZoneType.Library, sa);
for (int i = maxCards - 1; i >= 0; i--) {
Card next = orderedCards.get(i);
player.getGame().getAction().moveToLibrary(next, 0, sa);

View File

@@ -89,7 +89,7 @@ public class RepeatEachEffect extends SpellAbilityEffect {
if (loopOverCards) {
if (sa.hasParam("ChooseOrder") && repeatCards.size() >= 2) {
repeatCards = player.getController().orderMoveToZoneList(repeatCards, ZoneType.Stack);
repeatCards = player.getController().orderMoveToZoneList(repeatCards, ZoneType.Stack, sa);
}
for (Card card : repeatCards) {

View File

@@ -40,39 +40,56 @@ public class SacrificeAllEffect extends SpellAbilityEffect {
final Player activator = sa.getActivatingPlayer();
final Game game = activator.getGame();
String valid = "";
if (sa.hasParam("ValidCards")) {
valid = sa.getParam("ValidCards");
}
CardCollectionView list;
if (sa.hasParam("Defined")) {
list = AbilityUtils.getDefinedCards(sa.getHostCard(), sa.getParam("Defined"), sa);
} else {
list = game.getCardsIn(ZoneType.Battlefield);
if (sa.hasParam("ValidCards")) {
list = AbilityUtils.filterListByType(list, sa.getParam("ValidCards"), sa);
}
}
else {
list = AbilityUtils.filterListByType(game.getCardsIn(ZoneType.Battlefield), valid, sa);
}
if (sa.hasParam("Controller")) {
list = CardLists.filterControlledBy(list, AbilityUtils.getDefinedPlayers(sa.getHostCard(), sa.getParam("Controller"), sa));
}
list = CardLists.filter(list, CardPredicates.canBeSacrificedBy(sa));
final boolean remSacrificed = sa.hasParam("RememberSacrificed");
if (remSacrificed) {
card.clearRemembered();
}
// update cards that where using LKI
CardCollection gameList = new CardCollection();
for (Card sac : list) {
final Card gameCard = game.getCardState(sac, null);
// gameCard is LKI in that case, the card is not in game anymore
// or the timestamp did change
// this should check Self too
if (gameCard == null || !sac.equalsWithTimestamp(gameCard) || !gameCard.canBeSacrificedBy(sa)) {
continue;
}
gameList.add(gameCard);
}
list = gameList;
// Do controller check after LKI got updated
if (sa.hasParam("Controller")) {
list = CardLists.filterControlledBy(list, AbilityUtils.getDefinedPlayers(sa.getHostCard(), sa.getParam("Controller"), sa));
}
if (list.size() > 1) {
list = GameActionUtil.orderCardsByTheirOwners(game, list, ZoneType.Graveyard);
list = GameActionUtil.orderCardsByTheirOwners(game, list, ZoneType.Graveyard, sa);
}
CardZoneTable table = new CardZoneTable();
Map<Integer, Card> cachedMap = Maps.newHashMap();
for (Card sac : list) {
final Card lKICopy = CardUtil.getLKICopy(sac, cachedMap);
if (game.getAction().sacrifice(sac, sa, table) != null && remSacrificed) {
card.addRemembered(lKICopy);
if (game.getAction().sacrifice(sac, sa, table) != null) {
if (remSacrificed) {
card.addRemembered(lKICopy);
}
if (sa.hasParam("ImprintSacrificed")) {
card.addImprintedCard(lKICopy);
}
}
}
table.triggerChangesZoneAll(game);

View File

@@ -138,7 +138,7 @@ public class SacrificeEffect extends SpellAbilityEffect {
}
if (choosenToSacrifice.size() > 1) {
choosenToSacrifice = GameActionUtil.orderCardsByTheirOwners(game, choosenToSacrifice, ZoneType.Graveyard);
choosenToSacrifice = GameActionUtil.orderCardsByTheirOwners(game, choosenToSacrifice, ZoneType.Graveyard, sa);
}
Map<Integer, Card> cachedMap = Maps.newHashMap();

View File

@@ -1136,7 +1136,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
newTop = c;
}
}
if (newTop != null) {
removeMutatedStates();
newTop.mergedCards = mergedCards;
@@ -6265,24 +6265,15 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars {
return true;
}
if (isCreature() && source.getActivatingPlayer().hasKeyword("You can't sacrifice creatures to cast spells or activate abilities.")) {
Cost srcCost = source.getPayCosts();
if (srcCost != null) {
if (srcCost.hasSpecificCostType(CostSacrifice.class)) {
return false;
}
if ((source.isSpell() || source.isActivatedAbility()) && source.getPayCosts().hasSpecificCostType(CostSacrifice.class)) {
if (isCreature() && source.getActivatingPlayer().hasKeyword("You can't sacrifice creatures to cast spells or activate abilities.")) {
return false;
}
if (isPermanent() && !isLand() && source.getActivatingPlayer().hasKeyword("You can't sacrifice nonland permanents to cast spells or activate abilities.")) {
return false;
}
}
if (isPermanent() && !isLand() && source.getActivatingPlayer().hasKeyword("You can't sacrifice nonland permanents to cast spells or activate abilities.")) {
Cost srcCost = source.getPayCosts();
if (srcCost != null) {
if (srcCost.hasSpecificCostType(CostSacrifice.class)) {
return false;
}
}
}
return getController().canSacrificeBy(source);
}

View File

@@ -3327,7 +3327,7 @@ public class CardFactoryUtil {
+ " the controller of the permanent it becomes sacrifices it at the beginning of the next cleanup step.";
final String strDelay = "DB$ DelayedTrigger | Mode$ Phase | Phase$ Cleanup | TriggerDescription$ At the beginning of the next cleanup step, sacrifice CARDNAME.";
final String strSac = "DB$ SacrificeAll | ValidCards$ Card.Self";
final String strSac = "DB$ SacrificeAll | Defined$ Self";
SpellAbility saDelay = AbilityFactory.getAbility(strDelay, card);
saDelay.setAdditionalAbility("Execute", (AbilitySub) AbilityFactory.getAbility(strSac, card));
@@ -4433,7 +4433,7 @@ public class CardFactoryUtil {
final String delTrigStr = "DB$ DelayedTrigger | Mode$ Phase | Phase$ End of Turn | RememberObjects$ Imprinted " +
"| StackDescription$ None | TriggerDescription$ Sacrifice them at the beginning of the next end step.";
final String sacStr = "DB$ SacrificeAll | Defined$ DelayTriggerRemembered";
final String sacStr = "DB$ SacrificeAll | Defined$ DelayTriggerRememberedLKI";
final String cleanupStr = "DB$ Cleanup | ClearRemembered$ True | ClearImprinted$ True";

View File

@@ -7,6 +7,7 @@ import java.util.Map;
import com.google.common.collect.ForwardingTable;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Iterables;
import com.google.common.collect.Table;
import forge.game.Game;
@@ -94,4 +95,8 @@ public class CardZoneTable extends ForwardingTable<ZoneType, ZoneType, CardColle
}
return allCards;
}
public Iterable<Card> allCards() {
return Iterables.concat(values());
}
}

View File

@@ -1780,7 +1780,7 @@ public class Player extends GameEntity implements Comparable<Player> {
CardCollectionView milledView = milled;
if (destination == ZoneType.Graveyard && milled.size() > 1) {
milledView = GameActionUtil.orderCardsByTheirOwners(game, milled, ZoneType.Graveyard);
milledView = GameActionUtil.orderCardsByTheirOwners(game, milled, ZoneType.Graveyard, sa);
}
for (Card m : milledView) {

View File

@@ -31,6 +31,14 @@ public class PlayerCollection extends FCollection<Player> {
}
return result;
}
public final CardCollection getCardsIn(Iterable<ZoneType> zones) {
CardCollection result = new CardCollection();
for (Player p : this) {
result.addAll(p.getCardsIn(zones));
}
return result;
}
public final CardCollection getCreaturesInPlay() {
CardCollection result = new CardCollection();

View File

@@ -163,9 +163,6 @@ public abstract class PlayerController {
public abstract ImmutablePair<CardCollection, CardCollection> arrangeForSurveil(CardCollection topN);
public abstract boolean willPutCardOnTop(Card c);
public final CardCollectionView orderMoveToZoneList(CardCollectionView cards, ZoneType destinationZone) {
return orderMoveToZoneList(cards, destinationZone, null);
}
public abstract CardCollectionView orderMoveToZoneList(CardCollectionView cards, ZoneType destinationZone, SpellAbility source);
/** p = target player, validCards - possible discards, min cards to discard */

View File

@@ -42,7 +42,8 @@ public class WrappedAbility extends Ability {
ApiType.Destroy,
ApiType.Token,
ApiType.SetState,
ApiType.Play
ApiType.Play,
ApiType.SacrificeAll
);
private final SpellAbility sa;