mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-20 20:58:03 +00:00
Merge branch 'drawing' into 'master'
Move all hidden zone changing after choosing See merge request core-developers/forge!4256
This commit is contained in:
@@ -2,6 +2,7 @@ package forge.game.ability;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@@ -661,4 +662,35 @@ public abstract class SpellAbilityEffect {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
protected static void discard(SpellAbility sa, CardZoneTable table, Map<Player, CardCollectionView> discardedMap) {
|
||||
Set<Player> discarders = discardedMap.keySet();
|
||||
for (Player p : discarders) {
|
||||
final CardCollection discardedByPlayer = new CardCollection();
|
||||
for (Card card : Lists.newArrayList(discardedMap.get(p))) { // without copying will get concurrent modification exception
|
||||
if (card == null) { continue; }
|
||||
if (p.discard(card, sa, table) != null) {
|
||||
discardedByPlayer.add(card);
|
||||
}
|
||||
}
|
||||
discardedMap.put(p, discardedByPlayer);
|
||||
}
|
||||
|
||||
for (Player p : discarders) {
|
||||
CardCollectionView discardedByPlayer = discardedMap.get(p);
|
||||
if (!discardedByPlayer.isEmpty()) {
|
||||
boolean firstDiscard = p.getNumDiscardedThisTurn() - discardedByPlayer.size() == 0;
|
||||
final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
|
||||
runParams.put(AbilityKey.Player, p);
|
||||
runParams.put(AbilityKey.Cards, discardedByPlayer);
|
||||
runParams.put(AbilityKey.Cause, sa);
|
||||
runParams.put(AbilityKey.FirstTime, firstDiscard);
|
||||
p.getGame().getTriggerHandler().runTrigger(TriggerType.DiscardedAll, runParams, false);
|
||||
|
||||
if (sa.hasParam("RememberDiscardingPlayers")) {
|
||||
sa.getHostCard().addRemembered(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,16 +4,17 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import forge.game.Game;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardCollection;
|
||||
import forge.game.card.CardCollectionView;
|
||||
import forge.game.card.CardLists;
|
||||
import forge.game.card.CardZoneTable;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.trigger.TriggerType;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.util.collect.FCollectionView;
|
||||
|
||||
@@ -38,6 +39,7 @@ public class BalanceEffect extends SpellAbilityEffect {
|
||||
|
||||
final FCollectionView<Player> players = game.getPlayersInTurnOrder();
|
||||
final List<CardCollection> validCards = new ArrayList<>(players.size());
|
||||
Map<Player, CardCollectionView> discardedMap = Maps.newHashMap();
|
||||
|
||||
for(int i = 0; i < players.size(); i++) {
|
||||
// Find the minimum of each Valid per player
|
||||
@@ -46,37 +48,26 @@ public class BalanceEffect extends SpellAbilityEffect {
|
||||
}
|
||||
|
||||
CardZoneTable table = new CardZoneTable();
|
||||
for(int i = 0; i < players.size(); i++) {
|
||||
for (int i = 0; i < players.size(); i++) {
|
||||
Player p = players.get(i);
|
||||
int numToBalance = validCards.get(i).size() - min;
|
||||
if (numToBalance == 0) {
|
||||
continue;
|
||||
}
|
||||
if (zone.equals(ZoneType.Hand)) {
|
||||
boolean firstDiscard = p.getNumDiscardedThisTurn() == 0;
|
||||
final CardCollection discardedByPlayer = new CardCollection();
|
||||
for (Card card : p.getController().chooseCardsToDiscardFrom(p, sa, validCards.get(i), numToBalance, numToBalance)) {
|
||||
if ( null == card ) continue;
|
||||
if (p.discard(card, sa, table) != null) {
|
||||
discardedByPlayer.add(card);
|
||||
}
|
||||
}
|
||||
|
||||
if (!discardedByPlayer.isEmpty()) {
|
||||
final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
|
||||
runParams.put(AbilityKey.Player, p);
|
||||
runParams.put(AbilityKey.Cards, discardedByPlayer);
|
||||
runParams.put(AbilityKey.Cause, sa);
|
||||
runParams.put(AbilityKey.FirstTime, firstDiscard);
|
||||
game.getTriggerHandler().runTrigger(TriggerType.DiscardedAll, runParams, false);
|
||||
}
|
||||
discardedMap.put(p, p.getController().chooseCardsToDiscardFrom(p, sa, validCards.get(i), numToBalance, numToBalance));
|
||||
} else { // Battlefield
|
||||
for(Card card : p.getController().choosePermanentsToSacrifice(sa, numToBalance, numToBalance, validCards.get(i), valid)) {
|
||||
for (Card card : p.getController().choosePermanentsToSacrifice(sa, numToBalance, numToBalance, validCards.get(i), valid)) {
|
||||
if ( null == card ) continue;
|
||||
game.getAction().sacrifice(card, sa, table);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (zone.equals(ZoneType.Hand)) {
|
||||
discard(sa, table, discardedMap);
|
||||
}
|
||||
|
||||
table.triggerChangesZoneAll(game);
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,10 +5,10 @@ import java.util.Map;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import forge.game.Game;
|
||||
import forge.game.GameActionUtil;
|
||||
import forge.game.ability.AbilityKey;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.ability.SpellAbilityEffect;
|
||||
import forge.game.card.Card;
|
||||
@@ -21,7 +21,6 @@ import forge.game.player.Player;
|
||||
import forge.game.player.PlayerActionConfirmMode;
|
||||
import forge.game.player.PlayerPredicates;
|
||||
import forge.game.spellability.SpellAbility;
|
||||
import forge.game.trigger.TriggerType;
|
||||
import forge.game.zone.ZoneType;
|
||||
import forge.util.Aggregates;
|
||||
import forge.util.Lang;
|
||||
@@ -112,7 +111,6 @@ public class DiscardEffect extends SpellAbilityEffect {
|
||||
final Game game = source.getGame();
|
||||
//final boolean anyNumber = sa.hasParam("AnyNumber");
|
||||
|
||||
final List<Card> discarded = Lists.newArrayList();
|
||||
final List<Player> targets = getTargetPlayers(sa),
|
||||
discarders;
|
||||
Player firstTarget = null;
|
||||
@@ -127,11 +125,10 @@ public class DiscardEffect extends SpellAbilityEffect {
|
||||
discarders = targets;
|
||||
}
|
||||
|
||||
|
||||
final CardZoneTable table = new CardZoneTable();
|
||||
Map<Player, CardCollectionView> discardedMap = Maps.newHashMap();
|
||||
for (final Player p : discarders) {
|
||||
boolean firstDiscard = p.getNumDiscardedThisTurn() == 0;
|
||||
final CardCollection discardedByPlayer = new CardCollection();
|
||||
CardCollectionView toBeDiscarded = new CardCollection();
|
||||
if ((mode.equals("RevealTgtChoose") && firstTarget != null) || !sa.usesTargeting() || p.canBeTargetedBy(sa)) {
|
||||
if (sa.hasParam("RememberDiscarder") && p.canDiscardBy(sa)) {
|
||||
source.addRemembered(p);
|
||||
@@ -145,17 +142,10 @@ public class DiscardEffect extends SpellAbilityEffect {
|
||||
boolean runDiscard = !sa.hasParam("Optional")
|
||||
|| p.getController().confirmAction(sa, PlayerActionConfirmMode.Random, sa.getParam("DiscardMessage"));
|
||||
if (runDiscard) {
|
||||
CardCollectionView toDiscard = AbilityUtils.getDefinedCards(source, sa.getParam("DefinedCards"), sa);
|
||||
toBeDiscarded = AbilityUtils.getDefinedCards(source, sa.getParam("DefinedCards"), sa);
|
||||
|
||||
if (toDiscard.size() > 1) {
|
||||
toDiscard = GameActionUtil.orderCardsByTheirOwners(game, toDiscard, ZoneType.Graveyard, sa);
|
||||
}
|
||||
|
||||
for (final Card c : toDiscard) {
|
||||
if (p.discard(c, sa, table) != null) {
|
||||
discarded.add(c);
|
||||
discardedByPlayer.add(c);
|
||||
}
|
||||
if (toBeDiscarded.size() > 1) {
|
||||
toBeDiscarded = GameActionUtil.orderCardsByTheirOwners(game, toBeDiscarded, ZoneType.Graveyard, sa);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -164,17 +154,10 @@ public class DiscardEffect extends SpellAbilityEffect {
|
||||
if (!p.canDiscardBy(sa)) {
|
||||
continue;
|
||||
}
|
||||
CardCollectionView toDiscard = p.getCardsIn(ZoneType.Hand);
|
||||
toBeDiscarded = p.getCardsIn(ZoneType.Hand);
|
||||
|
||||
if (toDiscard.size() > 1) {
|
||||
toDiscard = GameActionUtil.orderCardsByTheirOwners(game, toDiscard, ZoneType.Graveyard, sa);
|
||||
}
|
||||
|
||||
for(Card c : Lists.newArrayList(toDiscard)) { // without copying will get concurrent modification exception
|
||||
if (p.discard(c, sa, table) != null) {
|
||||
discarded.add(c);
|
||||
discardedByPlayer.add(c);
|
||||
}
|
||||
if (toBeDiscarded.size() > 1) {
|
||||
toBeDiscarded = GameActionUtil.orderCardsByTheirOwners(game, toBeDiscarded, ZoneType.Graveyard, sa);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,16 +165,9 @@ public class DiscardEffect extends SpellAbilityEffect {
|
||||
if (!p.canDiscardBy(sa)) {
|
||||
continue;
|
||||
}
|
||||
CardCollectionView dPHand = CardLists.getValidCards(p.getCardsIn(ZoneType.Hand), "Card.IsNotRemembered", p, source, sa);
|
||||
if (dPHand.size() > 1) {
|
||||
dPHand = GameActionUtil.orderCardsByTheirOwners(game, dPHand, ZoneType.Graveyard, sa);
|
||||
}
|
||||
|
||||
for (final Card c : dPHand) {
|
||||
if (p.discard(c, sa, table) != null) {
|
||||
discarded.add(c);
|
||||
discardedByPlayer.add(c);
|
||||
}
|
||||
toBeDiscarded = CardLists.getValidCards(p.getCardsIn(ZoneType.Hand), "Card.IsNotRemembered", p, source, sa);
|
||||
if (toBeDiscarded.size() > 1) {
|
||||
toBeDiscarded = GameActionUtil.orderCardsByTheirOwners(game, toBeDiscarded, ZoneType.Graveyard, sa);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,16 +198,9 @@ public class DiscardEffect extends SpellAbilityEffect {
|
||||
list.remove(disc);
|
||||
}
|
||||
|
||||
CardCollectionView toDiscardView = toDiscard;
|
||||
if (toDiscard.size() > 1) {
|
||||
toDiscardView = GameActionUtil.orderCardsByTheirOwners(game, toDiscard, ZoneType.Graveyard, sa);
|
||||
}
|
||||
|
||||
for (Card c : toDiscardView) {
|
||||
if (p.discard(c, sa, table) != null) {
|
||||
discarded.add(c);
|
||||
discardedByPlayer.add(c);
|
||||
}
|
||||
toBeDiscarded = toDiscard;
|
||||
if (toBeDiscarded.size() > 1) {
|
||||
toBeDiscarded = GameActionUtil.orderCardsByTheirOwners(game, toBeDiscarded, ZoneType.Graveyard, sa);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -239,20 +208,13 @@ public class DiscardEffect extends SpellAbilityEffect {
|
||||
if (!p.canDiscardBy(sa)) {
|
||||
continue;
|
||||
}
|
||||
if( numCardsInHand > 0 ) {
|
||||
if (numCardsInHand > 0) {
|
||||
CardCollectionView hand = p.getCardsIn(ZoneType.Hand);
|
||||
hand = CardLists.filter(hand, Presets.NON_TOKEN);
|
||||
CardCollectionView toDiscard = p.getController().chooseCardsToDiscardUnlessType(Math.min(numCards, numCardsInHand), hand, sa.getParam("UnlessType"), sa);
|
||||
toBeDiscarded = p.getController().chooseCardsToDiscardUnlessType(Math.min(numCards, numCardsInHand), hand, sa.getParam("UnlessType"), sa);
|
||||
|
||||
if (toDiscard.size() > 1) {
|
||||
toDiscard = GameActionUtil.orderCardsByTheirOwners(game, toDiscard, ZoneType.Graveyard, sa);
|
||||
}
|
||||
|
||||
for (Card c : toDiscard) {
|
||||
if (c.getController().discard(c, sa, table) != null) {
|
||||
discarded.add(c);
|
||||
discardedByPlayer.add(c);
|
||||
}
|
||||
if (toBeDiscarded.size() > 1) {
|
||||
toBeDiscarded = GameActionUtil.orderCardsByTheirOwners(game,toBeDiscarded, ZoneType.Graveyard, sa);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -275,18 +237,10 @@ public class DiscardEffect extends SpellAbilityEffect {
|
||||
"X", Integer.toString(AbilityUtils.calculateAmount(source, "X", sa)));
|
||||
}
|
||||
|
||||
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, sa);
|
||||
}
|
||||
|
||||
// Reveal cards that will be discarded?
|
||||
for (final Card c : dPChHand) {
|
||||
if (p.discard(c, sa, table) != null) {
|
||||
discarded.add(c);
|
||||
discardedByPlayer.add(c);
|
||||
}
|
||||
toBeDiscarded = CardLists.getValidCards(dPHand, valid.split(","), source.getController(), source, sa);
|
||||
toBeDiscarded = CardLists.filter(toBeDiscarded, Presets.NON_TOKEN);
|
||||
if (toBeDiscarded.size() > 1) {
|
||||
toBeDiscarded = GameActionUtil.orderCardsByTheirOwners(game, toBeDiscarded, ZoneType.Graveyard, sa);
|
||||
}
|
||||
} else if (mode.equals("RevealYouChoose") || mode.equals("RevealTgtChoose") || mode.equals("TgtChoose")) {
|
||||
CardCollectionView dPHand = p.getCardsIn(ZoneType.Hand);
|
||||
@@ -321,47 +275,27 @@ public class DiscardEffect extends SpellAbilityEffect {
|
||||
int min = sa.hasParam("AnyNumber") || sa.hasParam("Optional") ? 0 : Math.min(validCards.size(), numCards);
|
||||
int max = sa.hasParam("AnyNumber") ? validCards.size() : Math.min(validCards.size(), numCards);
|
||||
|
||||
CardCollectionView toBeDiscarded = validCards.isEmpty() ? null : chooser.getController().chooseCardsToDiscardFrom(p, sa, validCards, min, max);
|
||||
toBeDiscarded = validCards.isEmpty() ? null : chooser.getController().chooseCardsToDiscardFrom(p, sa, validCards, min, max);
|
||||
|
||||
if (toBeDiscarded != null) {
|
||||
if (toBeDiscarded.size() > 1) {
|
||||
toBeDiscarded = GameActionUtil.orderCardsByTheirOwners(game, toBeDiscarded, ZoneType.Graveyard, sa);
|
||||
}
|
||||
if (toBeDiscarded.size() > 1) {
|
||||
toBeDiscarded = GameActionUtil.orderCardsByTheirOwners(game, toBeDiscarded, ZoneType.Graveyard, sa);
|
||||
}
|
||||
|
||||
if (mode.startsWith("Reveal") ) {
|
||||
p.getController().reveal(toBeDiscarded, ZoneType.Hand, p, Localizer.getInstance().getMessage("lblPlayerHasChosenCardsFrom", chooser.getName()));
|
||||
}
|
||||
for (Card card : toBeDiscarded) {
|
||||
if (card == null) { continue; }
|
||||
if (p.discard(card, sa, table) != null) {
|
||||
discarded.add(card);
|
||||
discardedByPlayer.add(card);
|
||||
}
|
||||
}
|
||||
if (mode.startsWith("Reveal") ) {
|
||||
p.getController().reveal(toBeDiscarded, ZoneType.Hand, p, Localizer.getInstance().getMessage("lblPlayerHasChosenCardsFrom", chooser.getName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!discardedByPlayer.isEmpty()) {
|
||||
final Map<AbilityKey, Object> runParams = AbilityKey.newMap();
|
||||
runParams.put(AbilityKey.Player, p);
|
||||
runParams.put(AbilityKey.Cards, discardedByPlayer);
|
||||
runParams.put(AbilityKey.Cause, sa);
|
||||
runParams.put(AbilityKey.FirstTime, firstDiscard);
|
||||
game.getTriggerHandler().runTrigger(TriggerType.DiscardedAll, runParams, false);
|
||||
if (sa.hasParam("RememberDiscardingPlayers")) {
|
||||
source.addRemembered(p);
|
||||
}
|
||||
}
|
||||
discardedMap.put(p, toBeDiscarded);
|
||||
}
|
||||
|
||||
discard(sa, table, discardedMap);
|
||||
|
||||
if (sa.hasParam("RememberDiscarded")) {
|
||||
for (final Card c : discarded) {
|
||||
source.addRemembered(c);
|
||||
}
|
||||
source.addRemembered(discardedMap.values());
|
||||
}
|
||||
|
||||
// run trigger if something got milled
|
||||
table.triggerChangesZoneAll(source.getGame());
|
||||
table.triggerChangesZoneAll(game);
|
||||
} // discardResolve()
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
Name:Scheming Symmetry
|
||||
ManaCost:B
|
||||
Types:Sorcery
|
||||
A:SP$ RepeatEach | Cost$ B | ValidTgts$ Player | TargetMin$ 2 | TargetMax$ 2 | RepeatPlayers$ Targeted | RepeatSubAbility$ DBChange | StackDescription$ SpellDescription | SpellDescription$ Choose two target players. Each of them searches their library for a card, then shuffles their library and puts that card on top of it.
|
||||
SVar:DBChange:DB$ ChangeZone | DefinedPlayer$ Remembered | Chooser$ Remembered | Origin$ Library | Destination$ Library | LibraryPosition$ 0 | Mandatory$ True | ChangeType$ Card | ChangeNum$ 1
|
||||
A:SP$ ChangeZone | Cost$ B | DefinedPlayer$ Targeted | ValidTgts$ Player | TargetMin$ 2 | TargetMax$ 2 | Origin$ Library | Destination$ Library | LibraryPosition$ 0 | ChangeType$ Card | ChangeNum$ 1 | StackDescription$ SpellDescription | SpellDescription$ Choose two target players. Each of them searches their library for a card, then shuffles their library and puts that card on top of it.
|
||||
AI:RemoveDeck:All
|
||||
Oracle:Choose two target players. Each of them searches their library for a card, then shuffles their library and puts that card on top of it.
|
||||
|
||||
Reference in New Issue
Block a user